每天获取一个非常大的 Pandas DataFrame 中所有行的总和,这些行在两个特定列中匹配

Posted

技术标签:

【中文标题】每天获取一个非常大的 Pandas DataFrame 中所有行的总和,这些行在两个特定列中匹配【英文标题】:For each day get the sum of all rows in a very large Pandas DataFrame which match in two specific columns 【发布时间】:2021-05-05 13:43:41 【问题描述】:

我有一个非常大的 Pandas DataFrame,它有 28171643 行和 4 列。一天的这个DataFrame的一个子集如下所示。

我现在的任务是计算pair 每天的总金额。天数范围从 90 到 320。请注意(顾名思义)reversed 列始终包含每行中 pair 列的翻转元组。

这里是一个例子:

第 0、1、2 和 4 行都包含相同的元组组合,无论是在列pair 还是reversed,因此需要求和为 5+17+1604+1558 = 3184。理想情况下,这个信息将存储在一个新的 DataFrame 中,其中包含 dayamounttuple 列。 tuple 是否包含来自 pairreversed 的值并不重要,因为组合不是定向的。

我在下面显示了一个解决方案,但这对于这个庞大的数据集来说太长了! 作为硬件,我有一个 48 核 186GB RAM 和 Quadro RTX 8000 GPU 的工作站。如果有一个简单的解决方案,例如 Daskrapids.ai,这完全没问题!

我每天的慢动作:

如果有办法将其并行化,那也会有所帮助!

def analysis(d, t):

    combinations_df = d.loc[d['day'] == t]

    index = []

    for idx, row in combinations_df.iterrows():
        
        idd = combinations_df[combinations_df['reversed'] == row['pair']].index
        
        if len(idd) != 0:
            index.append(idd[0])
        else:
            index.append(-1)

    combinations_df['reversed_idx'] = index

    skippy = []
    to_drop = []
    
    def add_occurences(row):
        if row['reversed_idx'] == -1 or row['reversed_idx'] in skippy:
            return row
        else:
            row['amount'] += combinations_df.loc[row['reversed_idx']]['amount']
            skippy.append(row.name)
            to_drop.append(row['reversed_idx'])
            return row

    res = combinations_df.apply(lambda x: add_occurences(x), axis=1)
    skippy = set(skippy)
    to_drop = list(set(to_drop))
    return res.drop(to_drop)[['day', 'amount', 'pair']]

【问题讨论】:

【参考方案1】:

与之前使用 groupby 和 agg 的响应类似,但在唯一的组合键上求和:

result = my_df.groupby(['day', my_df.pair.apply(set).apply(tuple)])[['amount']].agg('sum').reset_index()

使用随机 5000 长度的 DataFrame,使用您的函数在几天内进行循环需要 4.38 秒 ± 204 毫秒,而现在,我需要 9.86 毫秒 ± 185 微秒

【讨论】:

正是我想要的——非常感谢!【参考方案2】:

请考虑将一些示例添加为代码而不是img,因为它会使您的代码更容易使用。

你可以做的是groupby对然后聚合amount的摘要。

如果上表是df你可以这样做:

>>> df = 'day': [226, 226, 226, 226, 226],
 'amount': [5, 17, 1604, 127, 1558],
 'pair': ['(B2141043,B2161043)',
  '(B2141043,B2161043)',
  '(B2141043,B2161043)',
  '(B2141043,C22D1043)',
  '(B2141043,B2161043)'],
 'reversed': ['(B2161043,B2141043)',
  '(B2161043,B2141043)',
  '(B2161043,B2141043)',
  '(C22D1043,B2141043)',
  '(B2161043,B2141043)']

>>> df.groupby('pair').agg('day' : 'first','amount': 'sum')

                     day  amount
pair
(B2141043,B2161043)  226    3184
(B2141043,C22D1043)  226     127

【讨论】:

非常感谢您的帮助,但是通过您的解决方案,我的 DataFrame 中仍然有两个元组订单。 @Boul 的解决方案克服了这个问题。

以上是关于每天获取一个非常大的 Pandas DataFrame 中所有行的总和,这些行在两个特定列中匹配的主要内容,如果未能解决你的问题,请参考以下文章

肝了3天,整理了90个Pandas案例!

如何读取非常大的 CSV 的一小部分行。 Pandas - 时间序列 - 大型数据集

将非常大的 CSV 数据集加载到 Python 和 R 中,Pandas 陷入困境

Python / Pandas:重命名非常大的数据文件的列

在 python pandas 中迭代非常大的数据帧效率太耗时

Python数据分析 Pandas模块 基础数据结构与简介