熊猫:使用groupby中的日期重新索引,根据需要填充/维护值

时间:2017-09-26 12:13:02

标签: python pandas pandas-groupby

我有以下DataFrame。

>>> df = pd.DataFrame(data={'date': ['2010-05-01', '2010-07-01', '2010-06-01', '2010-10-01'], 'id': [1,1,2,2], 'val': [50,60,70,80], 'other': ['uno', 'uno', 'dos', 'dos']})
>>> df['date'] = df['date'].apply(lambda d: pd.to_datetime(d))
>>> df
        date  id other  val
0 2010-05-01   1   uno   50
1 2010-07-01   1   uno   60
2 2010-06-01   2   dos   70
3 2010-10-01   2   dos   80

我想扩展此DataFrame,使其包含2010年所有月份的行。

  • DataFrame按id分组,因此每个ID都有12行。在这种情况下,总共24行。
  • 如果缺少初始DataFrame,则每月val应为0.
  • otherid有一对一的关系,所以我想保持这种方式。

我想要的结果如下:

         date  id other  val
0  2010-01-01   1   uno    0
1  2010-02-01   1   uno    0
2  2010-03-01   1   uno    0
3  2010-04-01   1   uno    0
4  2010-05-01   1   uno    50
5  2010-06-01   1   uno    0
6  2010-07-01   1   uno    60
7  2010-08-01   1   uno    0
8  2010-09-01   1   uno    0
9  2010-10-01   1   uno    0
10 2010-11-01   1   uno    0
11 2010-12-01   1   uno    0
12 2010-01-01   2   dos    0
13 2010-02-01   2   dos    0
14 2010-03-01   2   dos    0
15 2010-04-01   2   dos    0
16 2010-05-01   2   dos    0
17 2010-06-01   2   dos    70
18 2010-07-01   2   dos    0
19 2010-08-01   2   dos    0
20 2010-09-01   2   dos    0
21 2010-10-01   2   dos    80
22 2010-11-01   2   dos    0
23 2010-12-01   2   dos    0

我尝试过:

我尝试过groupby(' id'),然后申请。应用的函数重新索引组。但我还没有设法用{0}填充val,并保持other

1 个答案:

答案 0 :(得分:3)

您可以groupby使用自定义功能reindexNaN填充otherffill bfillval(转发和fillna回填)和def f(x): x = x.reindex(pd.date_range('2010-01-01', '2010-12-01', freq='MS')) x['other'] = x['other'].ffill().bfill() x['val'] = x['val'].fillna(0) return (x) df = df.set_index('date') .groupby('id') .apply(f).rename_axis(('id','date')) .drop('id', 1).reset_index() print (df) id date other val 0 1 2010-01-01 uno 0.0 1 1 2010-02-01 uno 0.0 2 1 2010-03-01 uno 0.0 3 1 2010-04-01 uno 0.0 4 1 2010-05-01 uno 50.0 5 1 2010-06-01 uno 0.0 6 1 2010-07-01 uno 60.0 7 1 2010-08-01 uno 0.0 8 1 2010-09-01 uno 0.0 9 1 2010-10-01 uno 0.0 10 1 2010-11-01 uno 0.0 11 1 2010-12-01 uno 0.0 12 2 2010-01-01 dos 0.0 13 2 2010-02-01 dos 0.0 14 2 2010-03-01 dos 0.0 15 2 2010-04-01 dos 0.0 16 2 2010-05-01 dos 0.0 17 2 2010-06-01 dos 70.0 18 2 2010-07-01 dos 0.0 19 2 2010-08-01 dos 0.0 20 2 2010-09-01 dos 0.0 21 2 2010-10-01 dos 80.0 22 2 2010-11-01 dos 0.0 23 2 2010-12-01 dos 0.0 之间的常数:

mux = pd.MultiIndex.from_product([df['id'].unique(),
                                  pd.date_range('2010-01-01', '2010-12-01', freq='MS')], 
                                  names=('id','date'))

df = df.set_index(['id','date']).reindex(mux).reset_index()
df['val'] = df['val'].fillna(0)
df['other'] = df.groupby('id')['other'].apply(lambda x: x.ffill().bfill())
print (df)
    id       date other   val
0    1 2010-01-01   uno   0.0
1    1 2010-02-01   uno   0.0
2    1 2010-03-01   uno   0.0
3    1 2010-04-01   uno   0.0
4    1 2010-05-01   uno  50.0
5    1 2010-06-01   uno   0.0
6    1 2010-07-01   uno  60.0
7    1 2010-08-01   uno   0.0
8    1 2010-09-01   uno   0.0
9    1 2010-10-01   uno   0.0
10   1 2010-11-01   uno   0.0
11   1 2010-12-01   uno   0.0
12   2 2010-01-01   dos   0.0
13   2 2010-02-01   dos   0.0
14   2 2010-03-01   dos   0.0
15   2 2010-04-01   dos   0.0
16   2 2010-05-01   dos   0.0
17   2 2010-06-01   dos  70.0
18   2 2010-07-01   dos   0.0
19   2 2010-08-01   dos   0.0
20   2 2010-09-01   dos   0.0
21   2 2010-10-01   dos  80.0
22   2 2010-11-01   dos   0.0
23   2 2010-12-01   dos   0.0

另一个解决方案是创建MultiIndex.from_product并通过它重新索引:

<script>
(function () {
    function scrollH(e) {
        e = window.event || e;
        var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
        document.getElementById('myDiv').scrollLeft -= (delta * 40);
        e.preventDefault();
    }
    if (window.addEventListener) {
        window.addEventListener("mousewheel", scrollH, false);
        window.addEventListener("DOMMouseScroll", scrollH, false);
    } else {
        window.attachEvent("onmousewheel", scrollH);
    }
    if "scrollingLeft" {
        // do something
    }
    else
    {
        // do something else
    }
})();
</script>
var isleft = e.delta < 0;
if isleft = true { do something }