【问题标题】:A fast alternative to pandas groupby + apply?pandas groupby + apply 的快速替代方案?
【发布时间】:2021-09-11 18:47:45
【问题描述】:

我有一个 pandas 数据框,如下所示(大约 100 万行):

Column_1    Column_2    Column_3    Column_4    Column_5    Column_6    Column_7    Column_8    Column_9    Column_10
…           …           …           …           …           …           …           …           …           …
…           …           …           …           …           …           …           …           …           …
…           …           …           …           …           …           …           …           …           …
…           …           …           …           …           …           …           …           …           …

我想做:

grouping = ["Column_1", "Column_2", "Column_3", "Column_4"]
df.groupby(grouping).apply(lambda x: pd.Series({
              'new_column_1':func_1(x),
              'new_column_2':func_2(x),
              'new_column_3':func_3(x)}
            )).reset_index()

这可行,但速度非常慢。函数 [func_1, func_2, func_3] 是我想应用于每个组的自定义函数。

我阅读了其他关于为什么这么慢的堆栈溢出讨论。我发现的原因是 pandas groupby + apply 使用 python 循环而不是矢量化。但是,我怎样才能加快速度呢?

例如,假设:

def func_1(x) {
     return sum(x["Column_5"] >= x["Column_6"]) / sum(x["Column_5"] <= x["Column_6"])
}

def func_2(x) {
         return max(x["Column_8"]) + min(x["Column_9"])
    }

def func_3(x) {
         return len(x)
    }

如果没有 pandas groupby + numpy,我们怎么能做同样的操作?

【问题讨论】:

  • groupby + apply 默认在组上循环。相反,您想根据内置的 groupby 聚合重新编写聚合,这些聚合都在 cython 中进行了优化。比如func_3就是GroupBy.size()fun_2可以写成两个独立的GroupBy.min() + GroupBy.max。两个单独的 groupbys 会更快,因为 .groupby() 并没有真正任何事情:stackoverflow.com/questions/63306888/…
  • “向量化”是指在编译后的代码中执行循环。这需要对pandasnumpy 有足够的了解,才能知道哪些操作(通常是methods)是这些快速(呃)构建块。我对pandas 的内部结构了解不多,但对于numpy,更快的东西以“并行”方式与整个数字数组一起工作。它确实在低级别进行迭代,但您作为用户并不关心顺序。
  • @ALollz 我实际上是做了 fun_2 和 fun_3,但在这个例子中我真正需要的是 fun_1。有没有办法用 pandas groupby 聚合来做到这一点?否则,我可以使用 numpy,但是如何复制 groupby 逻辑?
  • numpy 没有 groupby 工具。

标签: python pandas numpy vectorization


【解决方案1】:

看起来您想比较每一行中 2 个不同列的值,然后逐行计算比较的结果,然后对计算结果进行数学运算。如果是这样,请创建 2 个具有比较结果的新列,然后对这些新列求和并比较数字。矢量化而不是迭代。看这个玩具例子:

row1list = [1, 2]
row2list = [5, 3]
row3list = [5, 4]
row4list = [5, 5]
df = pd.DataFrame([row1list, row2list, row3list, row4list],
                  columns=['Column_5', 'Column_6'])

df[['col5 >= col6', 'col6 <= col5']] = 0, 0  
# start with 0, else you get nan or 1 in the next comparison

df.loc[df['Column_5'] >= df['Column_6'], 'col5 >= col6'] = 1
df.loc[df['Column_5'] <= df['Column_6'], 'col6 <= col5'] = 1
print(df)
#    Column_5  Column_6  col5 >= col6  col6 <= col5
# 0         1         2             0             1
# 1         5         3             1             0
# 2         5         4             1             0
# 3         5         5             1             1

answer_of_func1 = sum(df['col5 >= col6']) / sum(df['col6 <= col5'])
print(answer_of_func1)
# 1.5

【讨论】:

    猜你喜欢
    • 2022-01-25
    • 2019-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-15
    • 2012-07-14
    相关资源
    最近更新 更多