我有一个有两列的熊猫数据框。我需要在不影响第二列的情况下更改第一列的值,并在仅更改第一列值的情况下返回整个数据帧。我如何在熊猫身上使用apply?
给定以下数据框df
和函数complex_function
,
import pandas as pd
def complex_function(x, y=0):
if x > 5 and x > y:
return 1
else:
return 2
df = pd.DataFrame(data={'col1': [1, 4, 6, 2, 7], 'col2': [6, 7, 1, 2, 8]})
col1 col2
0 1 6
1 4 7
2 6 1
3 2 2
4 7 8
有几种解决方案可以仅在一个列上使用应用()。在下面我将详细解释它们。
直截了当的解决方案来自@Fabio Lamanna:
df['col1'] = df['col1'].apply(complex_function)
输出:
col1 col2
0 2 6
1 2 7
2 1 1
3 2 2
4 1 8
仅修改第一列,第二列不变。这个解决方案很漂亮。它只是一行代码,读起来几乎像英语:“取'col1'并将函数complex_函数应用于它。”
但是,如果您需要来自另一列的数据,例如“col2”,它将不起作用。如果要将'col2'的值传递给复杂函数
的变量y
,则需要其他内容。
或者,您可以使用这个或这个SO帖子中描述的整个数据框:
df['col1'] = df.apply(lambda x: complex_function(x['col1']), axis=1)
或者如果你喜欢(像我一样)没有lambda函数的解决方案:
def apply_complex_function(x): return complex_function(x['col1'])
df['col1'] = df.apply(apply_complex_function, axis=1)
这个解决方案中有很多问题需要解释。函数的作用是:pd.Series和pd.DataFrame。但是不能使用df['col1']=df.apply(complex_function).loc[:,'col1']
,因为它会抛出ValueError
。
因此,您需要给出要使用哪个列的信息。使事情复杂化的是,apply()函数只接受可调用项。要解决这个问题,您需要定义一个(lambda)函数,其中列x['col1']
作为参数;i、 我们将列信息包装在另一个函数中。
不幸的是,axis参数的默认值为零(axis=0
),这意味着它将尝试按列而不是按行执行。这在第一个解决方案中不是问题,因为我们给apply()一个pd.Series。但是现在输入是一个数据帧,我们必须是显式的(axis=1
)。(我很惊讶我经常忘记这一点。)
您是否喜欢带有lambda函数的版本是主观的。在我看来,这一行代码足够复杂,即使没有插入lambda函数也能阅读。您只需要(lambda)函数作为包装器。这只是锅炉代码。读者不应该为此烦恼。
现在,您可以轻松修改此解决方案,以考虑第二列:
def apply_complex_function(x): return complex_function(x['col1'], x['col2'])
df['col1'] = df.apply(apply_complex_function, axis=1)
输出:
col1 col2
0 2 6
1 2 7
2 1 1
3 2 2
4 2 8
在索引4处,该值已从1更改为2,因为第一个条件7
请注意,您只需要更改第一行代码(即函数),而不需要更改第二行。
切勿将列信息放入函数中。
def bad_idea(x):
return x['col1'] ** 2
通过这样做,您可以创建一个依赖于列名称的通用函数!这是一个糟糕的主意,因为下次你想使用这个功能时,你不能。更糟糕的是:也许你在不同的数据框中重命名一列,只是为了让它与你现有的函数一起工作。(去过那里,做到了。这是一个滑坡!)
尽管OP特别要求使用apply()解决方案,但还是建议了其他解决方案。例如,@George Petrov的答案建议使用map(),而@Thibaut Dubernet的答案建议使用assign()。
我完全同意应用()很少是最好的解决方案,因为应用()没有矢量化。它是一种元素操作,具有昂贵的函数调用和pd开销。系列。
使用apply()的一个原因是您希望使用现有函数,而性能不是问题。或者您的函数非常复杂,不存在矢量化版本。
另一个使用应用()的原因是与Groupby()结合使用。请注意,DataFrame.apply()和GroupBy.apply()是不同的函数。
所以考虑一些替代方案是有意义的:
map()
仅适用于pd.Series,但接受dict和pd.Series作为输入。在函数中使用map()与使用apply()几乎可以互换。它可以比apply()更快。有关更多详细信息,请参阅此SO帖子
df['col1'] = df['col1'].map(complex_function)
applymap()
对于数据帧几乎相同。它不支持pd.Series,它将始终返回数据帧。但是,它可以更快。文档中说:“在当前的实现中,applymap在第一列/行上调用func两次,以决定它可以采用快速还是慢速代码路径。”。但如果性能真的很重要,你应该寻找一条替代路线
df['col1'] = df.applymap(complex_function).loc[:, 'col1']
assign()
不能替代apply()。它仅在最基本的用例中具有类似的行为。它不适用于复杂函数
。您仍然需要apply(),如下面的示例所示。assign()的主要用例是方法链接,因为它返回数据帧而不更改原始数据帧
df['col1'] = df.assign(col1=df.col1.apply(complex_function))
我在这里提到这一点,是因为其他答案,例如@durjoy,都提出了这一点。清单并非详尽无遗:
不要使用apply()。这不是开玩笑。对于大多数数值操作,熊猫中存在向量化方法。If/else块通常可以通过布尔索引和.loc
组合进行重构。我的示例复杂函数
可以用这种方式重构。
对于单个列,最好使用map()
,如下所示:
df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])
a b c
0 15 15 5
1 20 10 7
2 25 30 9
df['a'] = df['a'].map(lambda a: a / 2.)
a b c
0 7.5 15 5
1 10.0 10 7
2 12.5 30 9
给定一个示例数据帧df
,如下所示:
a,b
1,2
2,3
3,4
4,5
你想要的是:
df['a'] = df['a'].apply(lambda x: x + 1)
返回:
a b
0 2 2
1 3 3
2 4 4
3 5 5
问题内容: 我有两列的熊猫数据框。我需要在不影响第二列的情况下更改第一列的值,并只更改第一列的值即可获取整个数据帧。如何使用大熊猫应用程序? 问题答案: 给定一个示例数据框为: 您想要的是: 返回:
考虑这个例子 我有一个函数,它以作为输入,并返回三个值,我想存储到三个不同的变量。下面的似乎工作正确 然而,当我试图创建相应的变量时,我得到了一个错误 你怎么认为? 我曾经在pandas apply()的返回多列中使用伟大的解决方案,但在当前的pandas中,此解决方案不再有效 谢谢!
本文向大家介绍Pandas对每个分组应用apply函数的实现,包括了Pandas对每个分组应用apply函数的实现的使用技巧和注意事项,需要的朋友参考一下 Pandas的apply函数概念(图解) 实例1:怎样对数值按分组的归一化 实例2:怎样取每个分组的TOPN数据 到此这篇关于Pandas对每个分组应用apply函数的实现的文章就介绍到这了,更多相关Pandas 应用apply函数内容请搜索呐
我有一个数据框,如: 我需要为每个列应用一些函数,并在这个数据帧中创建具有特殊名称的新列。 所以我需要根据列和(如name)乘以两个额外的列,名称为和由两个。是否可以使用或其他结构来完成此操作?
本文向大家介绍对pandas中apply函数的用法详解,包括了对pandas中apply函数的用法详解的使用技巧和注意事项,需要的朋友参考一下 最近在使用apply函数,总结一下用法。 apply函数可以对DataFrame对象进行操作,既可以作用于一行或者一列的元素,也可以作用于单个元素。 例:列元素 行元素 列 行 以上这篇对pandas中apply函数的用法详解就是小编分享给大家的全部内容了
我有2个微服务:我们称它们为A和B。 由B处理的实体(其中引用了a的实体)被实现为简单的长id(例如groupId) 我想要实现的是使用mapstruct填充B(由A持有)的缺失组数据。到目前为止,我尝试使用@AfterMapping函数向a请求缺失的数据。我的映射器是: 给我映射功能的实现接口是: 生成的代码的问题在于,将实体列表映射到DTO列表的函数对每个实体使用EntityToToTo,导致