Pandas dataframe:填写每个类别的插值日期值

Pandas dataframe: Fill in interpolated date values per category

我在 Python 3 中使用 Pandas DataFrame 工作。它有类别、日期和值的列。对于每个类别,我想添加缺少天数的行,这样的值是线性插值的。

为了创建最小示例,我使用了以下代码

df = pd.DataFrame({
'cat':['A', 'A', 'A', 'A', 'B', 'B', 'B'],
'date': ['2021-1-1', '2021-1-4', '2021-1-5', '2021-1-7', '2021-11-1', '2021-11-2', '2021-11-5'],
'value': [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 9.0]})

df['cat'] = df['cat'].astype('category')
df['date'] = df['date'].astype('datetime64')

给出以下数据框

cat date          value
A   2021-01-01    1.0
A   2021-01-04    2.0
A   2021-01-05    3.0
A   2021-01-07    4.0
B   2021-11-01    5.0
B   2021-11-02    6.0
B   2021-11-05    9.0

我希望输出像这个例子一样,我用'<'来表示新插入的行

cat date          value
A   2021-01-01    1.0
A   2021-01-02    1.333  <
A   2021-01-03    1.667  <
A   2021-01-04    2.0
A   2021-01-05    3.0
A   2021-01-06    3.5    <
A   2021-01-07    4.0
B   2021-11-01    5.0
B   2021-11-02    6.0
B   2021-11-03    7.0    <
B   2021-11-04    8.0    <
B   2021-11-05    9.0

在实际问题中,我不想要周末(周六和周日),但我已经像上面那样陈述了问题,以防止添加额外的层(我可以很容易地过滤掉周末)如果需要的话)。但是,首先不包括它们可能会允许更高效的代码,所以我想我也会提到这个障碍。感谢您的帮助!

使用 DataFrame.groupby with resample or Series.asfreq 作为天数的缺失值,然后在 lambda 函数中对每个组进行插值:

df = (df.set_index('date')
        .groupby('cat')['value']
        .apply(lambda x: x.asfreq('d').interpolate())
        .reset_index())
print (df)
   cat       date     value
0    A 2021-01-01  1.000000
1    A 2021-01-02  1.333333
2    A 2021-01-03  1.666667
3    A 2021-01-04  2.000000
4    A 2021-01-05  3.000000
5    A 2021-01-06  3.500000
6    A 2021-01-07  4.000000
7    B 2021-11-01  5.000000
8    B 2021-11-02  6.000000
9    B 2021-11-03  7.000000
10   B 2021-11-04  8.000000
11   B 2021-11-05  9.000000

df = (df.set_index('date')
        .groupby('cat')['value']
        .apply(lambda x: x.resample('d').first().interpolate())
        .reset_index())
print (df)
   cat       date     value
0    A 2021-01-01  1.000000
1    A 2021-01-02  1.333333
2    A 2021-01-03  1.666667
3    A 2021-01-04  2.000000
4    A 2021-01-05  3.000000
5    A 2021-01-06  3.500000
6    A 2021-01-07  4.000000
7    B 2021-11-01  5.000000
8    B 2021-11-02  6.000000
9    B 2021-11-03  7.000000
10   B 2021-11-04  8.000000
11   B 2021-11-05  9.000000

或者:

f = lambda x: x.interpolate()
s = df.set_index('date').groupby('cat')['value'].resample('d').first().groupby(level=0).apply(f)
print (s)
cat  date      
A    2021-01-01    1.000000
     2021-01-02    1.333333
     2021-01-03    1.666667
     2021-01-04    2.000000
     2021-01-05    3.000000
     2021-01-06    3.500000
     2021-01-07    4.000000
B    2021-11-01    5.000000
     2021-11-02    6.000000
     2021-11-03    7.000000
     2021-11-04    8.000000
     2021-11-05    9.000000
Name: value, dtype: float64

您可以使用辅助函数:

def interpolate(d, on='date', vals=['value']):
    return (d.set_index(on).reindex(pd.date_range(d[on].min(), d[on].max()))
             [vals].interpolate()
             .rename_axis(on)
           ) 

df.groupby('cat').apply(interpolate).reset_index()

输出:

   cat       date     value
0    A 2021-01-01  1.000000
1    A 2021-01-02  1.333333
2    A 2021-01-03  1.666667
3    A 2021-01-04  2.000000
4    A 2021-01-05  3.000000
5    A 2021-01-06  3.500000
6    A 2021-01-07  4.000000
7    B 2021-11-01  5.000000
8    B 2021-11-02  6.000000
9    B 2021-11-03  7.000000
10   B 2021-11-04  8.000000
11   B 2021-11-05  9.000000

一个选项是interpolate with complete:

的组合
# pip install git+https://github.com/pyjanitor-devs/pyjanitor.git
import pandas as pd
import janitor

dates = dict(date = lambda df: pd.date_range(df.min(), df.max(), freq='1D'))

(df.complete(dates, by='cat', sort = True)
   .assign(value = lambda df: df.value.interpolate())
)
   cat       date     value
0    A 2021-01-01  1.000000
1    A 2021-01-02  1.333333
2    A 2021-01-03  1.666667
3    A 2021-01-04  2.000000
4    A 2021-01-05  3.000000
5    A 2021-01-06  3.500000
6    A 2021-01-07  4.000000
7    B 2021-11-01  5.000000
8    B 2021-11-02  6.000000
9    B 2021-11-03  7.000000
10   B 2021-11-04  8.000000
11   B 2021-11-05  9.000000

complete 公开缺失值,然后我们在 linear 方法上进行插值。