移位组的滚动总和不用于第一组条目的数据帧

时间:2018-06-04 14:08:28

标签: python pandas dataframe

我在尝试向DataFrame添加字段时遇到问题,该字段总计过去三个月(即不包括本月)。

我有一个DataFrame,显示与channel_id相关的月费:

+-------+---------+------------+----------+-------------------------+
| index |  date   | channel_id |   fee    |       NEW COLUMN        |
+-------+---------+------------+----------+-------------------------+
|    10 | 2018-03 |         22 | 24525.88 | (depends on rows above) |
|    11 | 2018-04 |         22 |    10493 | (depends on rows above) |
|    12 | 2018-05 |         22 |    12500 | (depends on rows above) |
|    13 | 2017-10 |         43 |     1000 | 0                       |
|    14 | 2017-11 |         43 |     1000 | 0                       |
|    15 | 2017-12 |         43 |     1000 | 0                       |
|    16 | 2018-01 |         43 |     1000 | 3000                    |
|    17 | 2018-02 |         43 |     1000 | 3000                    |
|    18 | 2018-03 |         43 |     1000 | 3000                    |
|    19 | 2018-04 |         43 |     1000 | 3000                    |
|    20 | 2018-05 |         43 |     1000 | 3000                    |
|    21 | 2017-10 |         58 |     1750 | 0                       |
|    22 | 2017-11 |         58 |     1750 | 0                       |
|    23 | 2017-12 |         58 |   3302.1 | 0                       |
|    .. | ..      |         .. |   ..     | ..                      |
+-------+---------+------------+----------+-------------------------+

对于每个channel_id,我想汇总最近3个月的费用。每个channel_id的前三个月(例如行索引4,5,6)应该为0,因为前几个月没有总和。

为了达到这个目的,我正在使用:

df.groupby(['channel_id']).rolling(3)[fee].sum().shift(1).sort_index(level=1).fillna(0)

这个主要是,但是对于一些 channel_ids的第一个实例,它会填充一个我无法绑定到任何东西的值......:

+---------+------------+----------+----------+----------+
|  date   | channel_id |   fee    | NEW_COL  | Correct? |
+---------+------------+----------+----------+----------+
| 2018-03 |         22 | 24525.88 | 52572.85 | YES      |
| 2018-04 |         22 |    10493 | 60211.76 | YES      |
| 2018-05 |         22 |    12500 | 53933.88 | YES      |
| 2017-10 |         43 |     1000 |     2400 | NO!!!    |
| 2017-11 |         43 |     1000 |        0 | YES      |
| 2017-12 |         43 |     1000 |        0 | YES      |
| 2018-01 |         43 |     1000 |     3000 | YES      |
| 2018-02 |         43 |     1000 |     3000 | YES      |
| 2018-03 |         43 |     1000 |     3000 | YES      |
| 2018-04 |         43 |     1000 |     3000 | YES      |
| 2018-05 |         43 |     1000 |     3000 | YES      |
| 2017-10 |         58 |     1750 |        0 | YES      |
| 2017-11 |         58 |     1750 |        0 | YES      |
| 2017-12 |         58 |   3302.1 |        0 | YES      |
+---------+------------+----------+----------+----------+

我对df操作的理解有点粗略,但我对链的理解是:

df.groupby(['channel_id']):通过channel_id

对数据进行分组

.rolling(3)[fee].sum():对groupby dfs

应用滚动的3个月总和

.shift(1):将值向上移动1(因为我们不想要当前月份)

.sort_index(level=1):不确定这在上下文中是做什么的,但它是必需的......

.fillna(0):将NaNs填充为0,其中前3个月不可用。

我玩过不同的sort_index值(和shift),但无法理解这是如何处理错误的值。

2 个答案:

答案 0 :(得分:4)

使用apply

df.groupby(['channel_id'])['fee'].apply(lambda x :x.rolling(3).sum().shift(1).fillna(0))
Out[319]: 
0        0.0
1        0.0
2        0.0
3        0.0
4        0.0
5        0.0
6     3000.0
7     3000.0
8     3000.0
9     3000.0
10    3000.0
11       0.0
12       0.0
13       0.0
Name: fee, dtype: float64

答案 1 :(得分:1)

我认为需要DataFrameGroupBy.shift

df['new'] = (df.groupby(['channel_id']).rolling(3)['fee'].sum()
              .groupby(level=0)
              .shift(1)
              .sort_index(level=1)
              .fillna(0)
              .reset_index(level=0, drop=True))
print (df)
          date  channel_id       fee  NEW COLUMN     new
index                                                   
10     2018-03          22  24525.88         NaN     0.0
11     2018-04          22  10493.00         NaN     0.0
12     2018-05          22  12500.00         NaN     0.0
13     2017-10          43   1000.00         0.0     0.0
14     2017-11          43   1000.00         0.0     0.0
15     2017-12          43   1000.00         0.0     0.0
16     2018-01          43   1000.00      3000.0  3000.0
17     2018-02          43   1000.00      3000.0  3000.0
18     2018-03          43   1000.00      3000.0  3000.0
19     2018-04          43   1000.00      3000.0  3000.0
20     2018-05          43   1000.00      3000.0  3000.0
21     2017-10          58   1750.00         0.0     0.0
22     2017-11          58   1750.00         0.0     0.0
23     2017-12          58   3302.10         0.0     0.0

或者可以按4滚动:

df['new'] = (df.groupby(['channel_id']).rolling(4)['fee'].sum()
              .sort_index(level=1)
              .fillna(0)
              .reset_index(level=0, drop=True))