Pandas 5000 万行的 groupby+transform 需要 3 小时
Pandas groupby+transform on 50 million rows is taking 3 hours
我正在使用 pandas 模块。在我的 DataFrame 中,3 个字段是帐户、月份和薪水。
account month Salary
1 201501 10000
2 201506 20000
2 201506 20000
3 201508 30000
3 201508 30000
3 201506 10000
3 201506 10000
3 201506 10000
3 201506 10000
我正在对帐户和月份进行分组,并将薪水转换为其所属组的薪水百分比。
MyDataFrame['salary'] = MyDataFrame.groupby(['account'], ['month'])['salary'].transform(lambda x: x/x.sum())
现在 MyDataFrame 变成如下 table
account month Salary
1 201501 1
2 201506 .5
2 201506 .5
3 201508 .5
3 201508 .5
3 201506 .25
3 201506 .25
3 201506 .25
3 201506 .25
问题是:对 5000 万个此类行的操作需要 3 个小时。
我单独执行groupyby它很快需要5秒only.I 认为它在这里花费很长时间。 有什么方法可以提高性能吗?
更新:
为了提供更清晰的添加示例
某个帐户持有人在 6 月和 7 月分别收到 2000 和 8000 的工资,因此他的比例在 6 月变为 .2,在 7 月变为 .8。我的目的是计算这个比例。
我会使用不同的方法
第一排序,
MyDataFrame.sort(['account','month'],inplace=True)
然后迭代求和
(account,month)=('','') #some invalid values
salary=0.0
res=[]
for index, row in MyDataFrame.iterrows():
if (row['account'],row['month'])==(account,month):
salary+=row['salary']
else:
res.append([account,month,salary])
salary=0.0
(account,month)=(row['account'],row['month'])
df=pd.DataFrame(res,columns=['account','month','salary'])
这样,pandas不需要在内存中保存分组数据。
好吧,你需要更明确地展示你在做什么。这是 pandas 擅长的。
@Uri Goren 的注意事项。这是一个常量内存过程,一次只有 1 个组在内存中。这将与组数成线性比例。也不需要排序。
In [20]: np.random.seed(1234)
In [21]: ngroups = 1000
In [22]: nrows = 50000000
In [23]: dates = pd.date_range('20000101',freq='MS',periods=ngroups)
In [24]: df = DataFrame({'account' : np.random.randint(0,ngroups,size=nrows),
'date' : dates.take(np.random.randint(0,ngroups,size=nrows)),
'values' : np.random.randn(nrows) })
In [25]:
In [25]: df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 50000000 entries, 0 to 49999999
Data columns (total 3 columns):
account int64
date datetime64[ns]
values float64
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 1.5 GB
In [26]: df.head()
Out[26]:
account date values
0 815 2048-02-01 -0.412587
1 723 2023-01-01 -0.098131
2 294 2020-11-01 -2.899752
3 53 2058-02-01 -0.469925
4 204 2080-11-01 1.389950
In [27]: %timeit df.groupby(['account','date']).sum()
1 loops, best of 3: 8.08 s per loop
如果你想转换输出,那么就这样做
In [37]: g = df.groupby(['account','date'])['values']
In [38]: result = 100*df['values']/g.transform('sum')
In [41]: result.head()
Out[41]:
0 4.688957
1 -2.340621
2 -80.042089
3 -13.813078
4 -70.857014
dtype: float64
In [43]: len(result)
Out[43]: 50000000
In [42]: %timeit 100*df['values']/g.transform('sum')
1 loops, best of 3: 30.9 s per loop
时间稍长一些。但同样这应该是一个相对较快的操作。
我正在使用 pandas 模块。在我的 DataFrame 中,3 个字段是帐户、月份和薪水。
account month Salary
1 201501 10000
2 201506 20000
2 201506 20000
3 201508 30000
3 201508 30000
3 201506 10000
3 201506 10000
3 201506 10000
3 201506 10000
我正在对帐户和月份进行分组,并将薪水转换为其所属组的薪水百分比。
MyDataFrame['salary'] = MyDataFrame.groupby(['account'], ['month'])['salary'].transform(lambda x: x/x.sum())
现在 MyDataFrame 变成如下 table
account month Salary
1 201501 1
2 201506 .5
2 201506 .5
3 201508 .5
3 201508 .5
3 201506 .25
3 201506 .25
3 201506 .25
3 201506 .25
问题是:对 5000 万个此类行的操作需要 3 个小时。 我单独执行groupyby它很快需要5秒only.I 认为它在这里花费很长时间。 有什么方法可以提高性能吗?
更新: 为了提供更清晰的添加示例 某个帐户持有人在 6 月和 7 月分别收到 2000 和 8000 的工资,因此他的比例在 6 月变为 .2,在 7 月变为 .8。我的目的是计算这个比例。
我会使用不同的方法 第一排序,
MyDataFrame.sort(['account','month'],inplace=True)
然后迭代求和
(account,month)=('','') #some invalid values
salary=0.0
res=[]
for index, row in MyDataFrame.iterrows():
if (row['account'],row['month'])==(account,month):
salary+=row['salary']
else:
res.append([account,month,salary])
salary=0.0
(account,month)=(row['account'],row['month'])
df=pd.DataFrame(res,columns=['account','month','salary'])
这样,pandas不需要在内存中保存分组数据。
好吧,你需要更明确地展示你在做什么。这是 pandas 擅长的。
@Uri Goren 的注意事项。这是一个常量内存过程,一次只有 1 个组在内存中。这将与组数成线性比例。也不需要排序。
In [20]: np.random.seed(1234)
In [21]: ngroups = 1000
In [22]: nrows = 50000000
In [23]: dates = pd.date_range('20000101',freq='MS',periods=ngroups)
In [24]: df = DataFrame({'account' : np.random.randint(0,ngroups,size=nrows),
'date' : dates.take(np.random.randint(0,ngroups,size=nrows)),
'values' : np.random.randn(nrows) })
In [25]:
In [25]: df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 50000000 entries, 0 to 49999999
Data columns (total 3 columns):
account int64
date datetime64[ns]
values float64
dtypes: datetime64[ns](1), float64(1), int64(1)
memory usage: 1.5 GB
In [26]: df.head()
Out[26]:
account date values
0 815 2048-02-01 -0.412587
1 723 2023-01-01 -0.098131
2 294 2020-11-01 -2.899752
3 53 2058-02-01 -0.469925
4 204 2080-11-01 1.389950
In [27]: %timeit df.groupby(['account','date']).sum()
1 loops, best of 3: 8.08 s per loop
如果你想转换输出,那么就这样做
In [37]: g = df.groupby(['account','date'])['values']
In [38]: result = 100*df['values']/g.transform('sum')
In [41]: result.head()
Out[41]:
0 4.688957
1 -2.340621
2 -80.042089
3 -13.813078
4 -70.857014
dtype: float64
In [43]: len(result)
Out[43]: 50000000
In [42]: %timeit 100*df['values']/g.transform('sum')
1 loops, best of 3: 30.9 s per loop
时间稍长一些。但同样这应该是一个相对较快的操作。