Pandas groupby +转换5000万行需要3个小时

时间:2015-08-08 07:06:00

标签: python pandas group-by transform

我正在使用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变得像下面的表

    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秒钟。我认为这是需要很长时间的转换。 有什么方法可以改善效果吗?

更新: 为了提供更清晰的添加示例 一些账户持有人在6月份收到2000美元,在7月收到8000美元,因此他的比例在6月份为0.2,在7月份为.8。我的目的是计算这个比例。

2 个答案:

答案 0 :(得分:4)

嗯,你需要更明确,并准确显示你在做什么。这是熊猫擅长的。

@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

再花一点时间。但同样这应该是一个相对快速的操作。

答案 1 :(得分:0)

我会使用不同的方法 第一次排序,

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不需要将分组数据保存在内存中。