Pandas:根据条件向每个组添加行
Pandas: add row to each group depending on condition
假设我有一个这样的 DataFrame:
date id val
0 2017-01-01 1 10
1 2019-01-01 1 20
2 2017-01-01 2 50
我想按 id
对这个数据集进行分组。
对于每个组,我想向其中添加一个新行,日期是从现在起 1 年。仅当该行晚于组中的最后一个日期时才应添加该行。该行的 val 应与组中的最后一行相同。
最后的 table 应该是这样的:
date id val
0 2017-01-01 1 10
1 2019-01-01 1 20
2 2017-01-01 2 50
3 2018-09-25 2 50 <-- new row
当前代码如下。我可以获得一个掩码,显示哪些组需要附加一行,但不确定下一步该做什么。
>>> df = pd.DataFrame(data={'d': [datetime.date(2017, 1, 1), datetime.date(2019,1,1), datetime.date(2017,1,1)], 'id': [1,1,2], 'val': [10,20,50]})
>>> df = df.sort_values(by='d')
>>> future_date = (pd.datetime.now().date() + pd.DateOffset(years=1)).date()
>>> maxd = df.groupby('id')['d'].max()
>>> maxd < future_date
id
1 False
2 True
Name: d, dtype: bool
这是一种方法
In [3481]: def add_row(x):
...: next_year = pd.to_datetime('today') + pd.DateOffset(years=1)
...: if x['date'].max() < next_year:
...: last_row = x.iloc[-1]
...: last_row['date'] = next_year
...: return x.append(last_row)
...: return x
...:
In [3482]: df.groupby('id').apply(add_row).reset_index(drop=True)
Out[3482]:
date id val
0 2017-01-01 1 10
1 2019-01-01 1 20
2 2017-01-01 2 50
3 2018-09-25 2 50
您可以对具有 max
date
:
的行使用 idxmax
withloc
future_date = pd.to_datetime('today') + pd.DateOffset(years=1)
maxd = df.loc[df.groupby('id')['d'].idxmax()]
maxd = maxd[maxd['d'] < future_date]
maxd['d'] = future_date
print (maxd)
d id val
2 2018-09-25 2 50
df = pd.concat([df, maxd]).sort_values(['id','d']).reset_index(drop=True)
print (df)
d id val
0 2017-01-01 1 10
1 2019-01-01 1 20
2 2017-01-01 2 50
3 2018-09-25 2 50
另一种方式,使用 duplicated
查找每个 'id'
的最后一行
t = df[~df.duplicated('id', 'last')]
df.append(
t.assign(
date=pd.to_datetime('today') + pd.DateOffset(years=1)
).pipe(lambda d: d[d.date > t.date]),
ignore_index=True).sort_values(['id', 'date'])
date id val
0 2017-01-01 1 10
1 2019-01-01 1 20
2 2017-01-01 2 50
3 2018-09-24 2 50
假设我有一个这样的 DataFrame:
date id val
0 2017-01-01 1 10
1 2019-01-01 1 20
2 2017-01-01 2 50
我想按 id
对这个数据集进行分组。
对于每个组,我想向其中添加一个新行,日期是从现在起 1 年。仅当该行晚于组中的最后一个日期时才应添加该行。该行的 val 应与组中的最后一行相同。
最后的 table 应该是这样的:
date id val
0 2017-01-01 1 10
1 2019-01-01 1 20
2 2017-01-01 2 50
3 2018-09-25 2 50 <-- new row
当前代码如下。我可以获得一个掩码,显示哪些组需要附加一行,但不确定下一步该做什么。
>>> df = pd.DataFrame(data={'d': [datetime.date(2017, 1, 1), datetime.date(2019,1,1), datetime.date(2017,1,1)], 'id': [1,1,2], 'val': [10,20,50]})
>>> df = df.sort_values(by='d')
>>> future_date = (pd.datetime.now().date() + pd.DateOffset(years=1)).date()
>>> maxd = df.groupby('id')['d'].max()
>>> maxd < future_date
id
1 False
2 True
Name: d, dtype: bool
这是一种方法
In [3481]: def add_row(x):
...: next_year = pd.to_datetime('today') + pd.DateOffset(years=1)
...: if x['date'].max() < next_year:
...: last_row = x.iloc[-1]
...: last_row['date'] = next_year
...: return x.append(last_row)
...: return x
...:
In [3482]: df.groupby('id').apply(add_row).reset_index(drop=True)
Out[3482]:
date id val
0 2017-01-01 1 10
1 2019-01-01 1 20
2 2017-01-01 2 50
3 2018-09-25 2 50
您可以对具有 max
date
:
idxmax
withloc
future_date = pd.to_datetime('today') + pd.DateOffset(years=1)
maxd = df.loc[df.groupby('id')['d'].idxmax()]
maxd = maxd[maxd['d'] < future_date]
maxd['d'] = future_date
print (maxd)
d id val
2 2018-09-25 2 50
df = pd.concat([df, maxd]).sort_values(['id','d']).reset_index(drop=True)
print (df)
d id val
0 2017-01-01 1 10
1 2019-01-01 1 20
2 2017-01-01 2 50
3 2018-09-25 2 50
另一种方式,使用 duplicated
查找每个 'id'
t = df[~df.duplicated('id', 'last')]
df.append(
t.assign(
date=pd.to_datetime('today') + pd.DateOffset(years=1)
).pipe(lambda d: d[d.date > t.date]),
ignore_index=True).sort_values(['id', 'date'])
date id val
0 2017-01-01 1 10
1 2019-01-01 1 20
2 2017-01-01 2 50
3 2018-09-24 2 50