熊猫:groupby向前填充日期时间索引

时间:2016-07-26 18:21:45

标签: python datetime pandas group-by missing-data

我有一个包含两列的数据集:company和value 它有一个日期时间索引,其中包含重复项(在同一天,不同的公司具有不同的值)。这些值缺少数据,因此我想使用同一公司的前一个数据点转发缺少的数据。

但是,我似乎无法找到一个很好的方法来做到这一点,而不会遇到奇怪的groupby错误,这表明我做错了什么。

玩具数据:

a = pd.DataFrame({'a': [1, 2, None], 'b': [12,None,14]})
a.index = pd.DatetimeIndex(['2010', '2011', '2012'])  
a = a.unstack() 
a = a.reset_index().set_index('level_1') 
a.columns = ['company', 'value'] 
a.sort_index(inplace=True)

尝试的解决方案(不起作用:ValueError: cannot reindex from a duplicate axis):

a.groupby('company').ffill() 
a.groupby('company')['value'].ffill() 
a.groupby('company').fillna(method='ffill')

Hacky解决方案(提供所需的结果,但显然只是一个丑陋的解决方法):

a['value'] = a.reset_index().groupby(
    'company').fillna(method='ffill')['value'].values

这可能是一种简单而优雅的方式,这是如何在熊猫中进行的?

3 个答案:

答案 0 :(得分:5)

一种方法是使用transform功能在分组后填充value列:

import pandas as pd
a['value'] = a.groupby('company')['value'].transform(lambda v: v.ffill())

a
#          company  value
#level_1        
#2010-01-01      a    1.0
#2010-01-01      b   12.0
#2011-01-01      a    2.0
#2011-01-01      b   12.0
#2012-01-01      a    2.0
#2012-01-01      b   14.0

要进行比较,原始数据框如下所示:

#            company    value
#level_1        
#2010-01-01        a      1.0
#2010-01-01        b     12.0
#2011-01-01        a      2.0
#2011-01-01        b      NaN
#2012-01-01        a      NaN
#2012-01-01        b     14.0

答案 1 :(得分:5)

您可以将'company'添加到索引中,使其唯一,并通过ffill执行简单的groupby

a = a.set_index('company', append=True)
a = a.groupby(level=1).ffill()

从这里开始,如果需要,您可以使用reset_index将索引恢复为正确的日期。我建议将'company'作为索引的一部分(或者只是将其添加到索引中),因此您的索引仍然是唯一的:

a = a.reset_index(level=1)

答案 2 :(得分:2)

我喜欢使用堆叠和取消堆叠。在这种情况下,它要求我使用'company'附加索引。

a.set_index('company', append=True).unstack().ffill() \
                                   .stack().reset_index('company')

enter image description here

时序

结论 @ Psidom的解决方案在两种情况下都能发挥最佳效果。

玩具数据

enter image description here

更大的玩具

np.random.seed([3,1415])
n = 10000
a = pd.DataFrame(np.random.randn(n, 10),
                 pd.date_range('2014-01-01', periods=n, freq='H', name='Time'),
                 pd.Index(list('abcdefghij'), name='company'))

a *= np.random.choice((1, np.nan), (n, 10), p=(.6, .4))

a = a.stack(dropna=False).rename('value').reset_index('company')

enter image description here