对于向DataFrames添加列的函数,我应采用哪种约定?

时间:2018-01-28 02:44:08

标签: python pandas performance numpy dataframe

给出以下DataFrame,

df = pd.DataFrame({
    'a': [3, 5, 7, 9],
    'b': [4, 12, 24, 40]
})

我想执行一些步骤,每个步骤都向此DataFrame添加列。为了保持清洁,我想为每个添加列的任务提供一个功能。我至少可以想到三种方法。每种方法的优缺点是什么?

方法1:

使用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)

优点:

  • 在调用签名时清除正在添加列
  • 适合并行化

缺点:

  • 不允许通过函数
  • 添加多个列

方法2:

将整个DataFrame传递给函数

def method2(df):
    df['c'] = np.sqrt(df['a']**2 + df['b']**2)

method2(df)

优点:

  • 少输入
  • 避免第一行运行该函数两次的apply的行为(仅次要问题)

缺点:

  • 不太适合并行化
  • "就地"操作(没有显式请求)与pandas约定不一致,df
  • 中函数对main()的影响模糊不清

方法3:

使用apply()

从加长的行重建DataFrame
def method3(row):
    row['c'] = np.sqrt(row['a']**2 + row['b']**2)
    return row

df = df.apply(method3, axis=1)

优点:

  • 允许通过单个功能添加多个列
  • 适合并行化

缺点:

  • 添加列的事实在呼叫签名
  • 中不明确
  • 表现(?)

2 个答案:

答案 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)

我按优先顺序排列:

  1. 方法2 :这是矢量化的,适用于大多数数据集。请注意,pandas使用numpy,因此使用np.sqrt执行向量化计算是有效的。

  2. 方法1 df.apply未进行矢量化。它是一个薄薄的环状。是的,您可以使用numbacython等工具优化循环,但是您也可以保留数据并在numpy中完成所有计算并生成pd.DataFrame一旦你的计算完成,纯粹出于审美原因。

  3. 方法3 :对df.apply的不透明和不必要的使用。你永远不会在方法1之前选择这种方法,因此它最后一次。