Pandas分组变换随条件累积



我有一个大表,里面有很多产品id和iso_codes:总共200万行。所以答案应该(如果可能的话(也考虑到内存问题,我有16GB的内存

我想看看对于每个(id,iso_code(组合,在行的buy_date之前返回的项目数是多少(如此累积(,但有一个问题
我只想计算上次销售中发生的退货,其中return_date在我要查看的buy_date之前。

例如,我添加了列items_returned这是应该计算的列

想法如下:
在销售时,我只能计算已经发生的退货,而不能计算未来会发生的退货

我尝试了df.groupby(['id', 'iso_code']).transform(np.cumsum).transform(lambda x: only count returns that happened before my buy_date)的组合,但不知道如何在这些特殊条件下进行.groupby.transform(np.cumsum)

购买的物品也有类似的问题,我只计算比购买日期小几天的累积物品。

希望你能帮助我。

示例结果表:

+-------+------+------------+----------+------------+---------------+----------------+------------------+
|   row |   id | iso_code   |   return | buy_date   | return_date   |   items_bought |   items_returned |
|-------+------+------------+----------+------------+---------------+----------------+------------------|
|     0 |  177 | DE         |        1 | 2019-05-16 | 2019-05-24    |              0 |                0 |
|     1 |  177 | DE         |        1 | 2019-05-29 | 2019-06-03    |              1 |                1 |
|     2 |  177 | DE         |        1 | 2019-10-27 | 2019-11-06    |              2 |                2 |
|     3 |  177 | DE         |        0 | 2019-11-06 | None          |              3 |                2 |
|     4 |  177 | DE         |        1 | 2019-11-18 | 2019-11-28    |              4 |                3 |
|     5 |  177 | DE         |        1 | 2019-11-21 | 2019-12-11    |              5 |                3 |
|     6 |  177 | DE         |        1 | 2019-11-25 | 2019-12-06    |              6 |                3 |
|     7 |  177 | DE         |        0 | 2019-11-30 | None          |              7 |                4 |
|     8 |  177 | DE         |        1 | 2020-04-30 | 2020-05-27    |              8 |                6 |
|     9 |  177 | DE         |        1 | 2020-04-30 | 2020-09-18    |              8 |                6 |
+-------+------+------------+----------+------------+---------------+----------------+------------------+

示例代码:

import pandas as pd
from io import StringIO
df_text = """
row id  iso_code    return  buy_date    return_date
0   177 DE  1   2019-05-16  2019-05-24
1   177 DE  1   2019-05-29  2019-06-03
2   177 DE  1   2019-10-27  2019-11-06
3   177 DE  0   2019-11-06  None
4   177 DE  1   2019-11-18  2019-11-28
5   177 DE  1   2019-11-21  2019-12-11
6   177 DE  1   2019-11-25  2019-12-06
7   177 DE  0   2019-11-30  None
8   177 DE  1   2020-04-30  2020-05-27
9   177 DE  1   2020-04-30  2020-09-18
"""
df = pd.read_csv(StringIO(df_text), sep='t', index_col=0)
df['items_bought'] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 8]
df['items_returned'] = [0, 1, 2, 2, 3, 3, 3, 4, 6, 6]

这似乎需要交叉合并:

(df[['id','iso_code', 'buy_date']].reset_index()
.merge(df[['id','iso_code', 'return','return_date','buy_date']], on=['id','iso_code'])
.assign(items_returned=lambda x: x['return_date'].lt(x['buy_date_x'])*x['return'],
items_bought=lambda x: x['buy_date_y'].lt(x['buy_date_x']))
.groupby('row')[['items_bought','items_returned']].sum()
)

输出:

items_bought  items_returned
row                              
0               0               0
1               1               1
2               2               2
3               3               2
4               4               3
5               5               3
6               6               3
7               7               4
8               8               6
9               8               6

更新对于较大的数据,由于内存需求,交叉合并并不理想。然后我们可以进行groupby(),这样我们只合并较小的组:

def myfunc(df):
return (df[['id','iso_code', 'buy_date']].reset_index()
.merge(df[['id','iso_code', 'return','return_date','buy_date']], on=['id','iso_code'])
.assign(items_returned=lambda x: x['return_date'].lt(x['buy_date_x'])*x['return'],
items_bought=lambda x: x['buy_date_y'].lt(x['buy_date_x']))
.groupby('row')[['items_bought','items_returned']].sum()
)
df.groupby(['id','iso_code']).apply(myfunc).reset_index(level=[0,1], drop=True)

你会得到相同的输出:

items_bought  items_returned
row                              
0               0               0
1               1               1
2               2               2
3               3               2
4               4               3
5               5               3
6               6               3
7               7               4
8               8               6
9               8               6

最新更新