对于每一天,获取一个非常大的 Pandas DataFrame 中所有行的总和,这些行在两个特定列中匹配
For each day get the sum of all rows in a very large Pandas DataFrame which match in two specific columns
我有一个非常大的 Pandas DataFrame,有 28171643 行和 4 列。此 DataFrame 一天的子集如下所示。
我现在的任务是计算每天 pair
的总金额。天数范围从 90 到 320。请注意(如名称所示)reversed
列的每一行始终包含来自列 pair
的翻转元组。
举个例子:
第 0、1、2 和 4 行都包含相同的元组组合,无论是在 pair
列还是 reversed
列中,因此需要求和为 5+17+1604+ 1558 = 3184。理想情况下,此信息存储在具有列 day
、amount
和 tuple
的新 DataFrame 中。 tuple
是否包含来自 pair
或 reversed
的值并不重要,因为组合不是定向的。
我在下面显示了一个解决方案,但是对于这个庞大的数据集来说,这花费的时间太长了!
作为硬件,我有一个具有 48 核 186GB RAM 和 Quadro RTX 8000 GPU 的工作站。如果有一个简单的解决方案,例如 Dask 或者 rapids.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']]
请考虑将一些示例添加为代码,而不是 img
,因为这样可以更轻松地使用您的代码。
你可以做的是 groupby
对,然后聚合 amount
的摘要。
如果上面的table是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
与之前使用 groupby 和 agg 的响应类似,但在唯一键组合上求和:
result = my_df.groupby(['day', my_df.pair.apply(set).apply(tuple)])[['amount']].agg('sum').reset_index()
使用随机 5000 长度的 DataFrame,用你的函数在几天内循环需要 4.38 s ± 204 ms,现在是 9.86 ms ± 185 µs
我有一个非常大的 Pandas DataFrame,有 28171643 行和 4 列。此 DataFrame 一天的子集如下所示。
我现在的任务是计算每天 pair
的总金额。天数范围从 90 到 320。请注意(如名称所示)reversed
列的每一行始终包含来自列 pair
的翻转元组。
举个例子:
第 0、1、2 和 4 行都包含相同的元组组合,无论是在 pair
列还是 reversed
列中,因此需要求和为 5+17+1604+ 1558 = 3184。理想情况下,此信息存储在具有列 day
、amount
和 tuple
的新 DataFrame 中。 tuple
是否包含来自 pair
或 reversed
的值并不重要,因为组合不是定向的。
我在下面显示了一个解决方案,但是对于这个庞大的数据集来说,这花费的时间太长了! 作为硬件,我有一个具有 48 核 186GB RAM 和 Quadro RTX 8000 GPU 的工作站。如果有一个简单的解决方案,例如 Dask 或者 rapids.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']]
请考虑将一些示例添加为代码,而不是 img
,因为这样可以更轻松地使用您的代码。
你可以做的是 groupby
对,然后聚合 amount
的摘要。
如果上面的table是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
与之前使用 groupby 和 agg 的响应类似,但在唯一键组合上求和:
result = my_df.groupby(['day', my_df.pair.apply(set).apply(tuple)])[['amount']].agg('sum').reset_index()
使用随机 5000 长度的 DataFrame,用你的函数在几天内循环需要 4.38 s ± 204 ms,现在是 9.86 ms ± 185 µs