给出以下DataFrame,
df = pd.DataFrame({
'a': [3, 5, 7, 9],
'b': [4, 12, 24, 40]
})
我想执行一些步骤,每个步骤都向此DataFrame添加列。为了保持清洁,我想为每个添加列的任务提供一个功能。我至少可以想到三种方法。每种方法的优缺点是什么?
使用apply()
创建一个系列,并将其作为新列添加到DataFrame中:
def method1(row):
return np.sqrt(row['a']**2 + row['b']**2)
# This is the line that will appear in main()
df['c'] = df.apply(method1, axis=1)
优点:
缺点:
将整个DataFrame传递给函数
def method2(df):
df['c'] = np.sqrt(df['a']**2 + df['b']**2)
method2(df)
优点:
apply
的行为(仅次要问题)缺点:
df
main()
的影响模糊不清
使用apply()
def method3(row):
row['c'] = np.sqrt(row['a']**2 + row['b']**2)
return row
df = df.apply(method3, axis=1)
优点:
缺点:
答案 0 :(得分:3)
你的误解是apply
并行操作... 它不。
它只是一个循环的包装器。它的工作原理如下:
df['c'] = df.apply(method1, axis=1)
相当于,
temp = []
for i, row in df.iterrows():
temp.append(method1(row))
df['c'] = temp
另一方面,只是做
df['c'] = (df['a'] ** 2 + df['b'] ** 2) ** .5
隐式地对整个操作进行矢量化。这是因为numpy在C中实现了许多基本例程,并使用SIMD操作,这比传统循环更快。将此时间与apply
的版本进行比较并了解。
df = pd.concat([df] * 100000, ignore_index=True)
%timeit df.apply(method1, axis=1)
1 loop, best of 3: 19.1 s per loop
%timeit (df['a'] ** 2 + df['b'] ** 2) ** .5
100 loops, best of 3: 14.7 ms per loop
经验法则是始终避免使用类似循环/循环的解决方案,除非您的操作非常复杂以至于无法避免。在这种情况下,使用简单的 for 循环,开销实际上小于apply
。你会为此感谢你。
答案 1 :(得分:0)
我按优先顺序排列:
方法2 :这是矢量化的,适用于大多数数据集。请注意,pandas
使用numpy
,因此使用np.sqrt
执行向量化计算是有效的。
方法1 :df.apply
未进行矢量化。它是一个薄薄的环状。是的,您可以使用numba
或cython
等工具优化循环,但是您也可以保留数据并在numpy
中完成所有计算并生成pd.DataFrame
一旦你的计算完成,纯粹出于审美原因。
方法3 :对df.apply
的不透明和不必要的使用。你永远不会在方法1之前选择这种方法,因此它最后一次。