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
方法上进行插值。
我在 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
方法上进行插值。