【问题标题】:Filling gaps for cumulative sum with Pandas用 Pandas 填补累积金额的空白
【发布时间】:2015-01-11 09:20:56
【问题描述】:

我正在尝试从 Pandas 中每月存储桶中的表格计算库存。这是表格:

Goods  |  Incoming  | Date
-------+------------+-----------
'a'    |        10  | 2014-01-10
'a'    |        20  | 2014-02-01
'b'    |        30  | 2014-01-02
'b'    |        40  | 2014-05-13
'a'    |        20  | 2014-06-30
'c'    |        10  | 2014-02-10
'c'    |        50  | 2014-05-10
'b'    |        70  | 2014-03-10
'a'    |        10  | 2014-02-10

这是我目前的代码:

import pandas as pd
df = pd.DataFrame({
  'goods': ['a', 'a', 'b', 'b', 'a', 'c', 'c', 'b', 'a'], 
  'incoming': [0, 20, 30, 40, 20, 10, 50, 70, 10], 
  'date': ['2014-01-10', '2014-02-01', '2014-01-02', '2014-05-13', '2014-06-30', '2014-02-10', '2014-05-10', '2014-03-10', '2014-02-10']})

df['date'] = pd.to_datetime(df['date'])
# we don't care about year in this example
df['month'] = df['date'].map(lambda x: x.month)
dfg = df.groupby(['goods', 'month'])['incoming'].sum()
# flatten multi-index
dfg = dfg.reset_index ()
dfg['level'] = dfg.groupby(['goods'])['incoming'].cumsum()
dfg

返回

    goods   month   incoming    level
0   a       1              0    0
1   a       2             30    30
2   a       6             20    50
3   b       1             30    30
4   b       3             70    100
5   b       5             40    140
6   c       2             10    10
7   c       5             50    60

虽然这很好,但我使用的可视化方法需要 (1) 每组相同数量的数据点(“商品”),(2) 相同程度的时间序列(即最早/最晚月份是所有时间序列都相同)和(3)在任何时间序列中都没有“差距”(min(month) 和 max(month) 之间的一个月,有一个数据点)。

如何使用 Pandas 做到这一点?请注意,即使这种结构可能有点低效,我还是想坚持一般的事情流程。也许可以插入一些“后处理”来填补空白。

更新

为了总结下面的回复,我选择这样做:

piv = dfg.pivot_table(["level"], "month", "goods")
piv = piv.reindex(np.arange(piv.index[0], piv.index[-1] + 1))
piv = piv.ffill(axis=0)
piv = piv.fillna(0)
piv.index.name = 'month'

我也加了

piv = piv.stack()
print r.reset_index()

得到一个类似于输入表的表:

   month goods  level
0       1     a      0
1       1     b     30
2       1     c      0
3       2     a     30
4       2     b     30
5       2     c     10
6       3     a     30
7       3     b    100
8       3     c     10
9       4     a     30
10      4     b    100
11      4     c     10
12      5     a     30
13      5     b    140
14      5     c     60
15      6     a     50
16      6     b    140
17      6     c     60

【问题讨论】:

  • 这感觉有点像XY Problem,可能对您的绘图方式有所帮助?
  • 在发布之前,我对替代方案进行了长时间的思考。不幸的是,绘图无法更改。

标签: python pandas time-series cumsum


【解决方案1】:

我想你想用pivot_table:

In [11]: df.pivot_table(values="incoming", index="month", columns="goods", aggfunc="sum")
Out[11]:
goods   a   b   c
month
1       0  30 NaN
2      30 NaN  10
3     NaN  70 NaN
5     NaN  40  50
6      20 NaN NaN

要在几个月内完成填写,您可以重新索引(这感觉有点老套,可能有更简洁的方法):

In [12]: res.reindex(np.arange(res.index[0], res.index[-1] + 1))
Out[12]:
goods   a   b   c
1       0  30 NaN
2      30 NaN  10
3     NaN  70 NaN
4     NaN NaN NaN
5     NaN  40  50
6      20 NaN NaN

这里的一个问题是月份与年份无关,最好有一个周期索引:

In [21]: df.pivot_table(values="incoming", index=pd.DatetimeIndex(df.date).to_period("M"), columns="goods", aggfunc="sum")
Out[21]:
goods     a   b   c
2014-01   0  30 NaN
2014-02  30 NaN  10
2014-03 NaN  70 NaN
2014-05 NaN  40  50
2014-06  20 NaN NaN

然后您可以按周期范围重新索引:

In [22]: res2.reindex(pd.period_range(res2.index[0], res2.index[-1], freq="M"))
Out[22]:
goods     a   b   c
2014-01   0  30 NaN
2014-02  30 NaN  10
2014-03 NaN  70 NaN
2014-04 NaN NaN NaN
2014-05 NaN  40  50
2014-06  20 NaN NaN

也就是说,你可以用你的dfg做同样的事情:

In [31]: dfg.pivot_table(["incoming", "level"], "month", "goods")
Out[31]:
      incoming         level
goods        a   b   c     a    b   c
month
1            0  30 NaN     0   30 NaN
2           30 NaN  10    30  NaN  10
3          NaN  70 NaN   NaN  100 NaN
5          NaN  40  50   NaN  140  60
6           20 NaN NaN    50  NaN NaN

并重新索引。

【讨论】:

  • 我想知道最后做这个重新索引是否应该更容易,这感觉是一件很自然的事情。也许值得提交功能请求。
  • 感谢您的解决方案。这至少填补了 NaN 的空白。如果没有其他值(NaN),我将如何用以前的值填充它。例如好的'a' 会有一个级别[0, 30, 30, 30, 50]
  • 你可以做 res.ffill() 来“向前填充”。
  • 关于一种更简洁的重新索引方式:这样做的效果相同,但要短一些:res.reindex(res.count())。不知道这是否更整洁:-)
  • 我刚刚意识到,在您的 dfg.pivot_table 中 - 例如,缺少第 4 个月。对此我能做些什么?
猜你喜欢
  • 2017-08-01
  • 1970-01-01
  • 2015-08-19
  • 2013-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-05
  • 2017-09-19
相关资源
最近更新 更多