df_new = pd.DataFrame(
{
'person_id': [1, 1, 3, 3, 5, 5],
'obs_date': ['12/31/2007', 'NA-NA-NA NA:NA:NA', 'NA-NA-NA NA:NA:NA', '11/25/2009', '10/15/2019', 'NA-NA-NA NA:NA:NA']
})
看起来如下图
我想做的是用同一组中的实际日期值替换/填充NA
类型的行。为此,我尝试了以下
m1 = df_new['obs_date'].str.contains('^\d')
df_new['obs_date'] = df_new.groupby((m1).cumsum())['obs_date'].transform('first')
但这会产生意外的输出,如下所示
在第二行中,应该是person_id = 3的11/25/2009
,而不是来自person_id = 1的第一组。
如何获得如下所示的预期输出
当我处理超过百万条记录时,任何优雅而有效的解决方案都会有所帮助
答案 0 :(得分:2)
首先使用to_datetime
和onCreate()
将非日期时间转换为缺失值,然后使用GroupBy.first
获取GroupBy.transform
数据填充的新列中的第一个非缺失值:>
errors='coerce'
另一个想法是将DataFrame.sort_values
与GroupBy.first
结合使用:
df_new['obs_date'] = pd.to_datetime(df_new['obs_date'], format='%m/%d/%Y', errors='coerce')
df_new['obs_date'] = df_new.groupby('person_id')['obs_date'].transform('first')
#alternative - minimal value per group
#df_new['obs_date'] = df_new.groupby('person_id')['obs_date'].transform('min')
print (df_new)
person_id obs_date
0 1 2007-12-31
1 1 2007-12-31
2 3 2009-11-25
3 3 2009-11-25
4 5 2019-10-15
5 5 2019-10-15
答案 1 :(得分:1)
您可以执行pd.to_datetime(..,errors='coerce')
以在groupby之后将非日期值分别填充为NaT
和ffill
和bfill
:
df_new['obs_date']=(df_new.assign(obs_date=pd.to_datetime(df_new['obs_date'],
errors='coerce')).groupby('person_id')['obs_date'].apply(lambda x: x.ffill().bfill()))
print(df_new)
person_id obs_date
0 1 2007-12-31
1 1 2007-12-31
2 3 2009-11-25
3 3 2009-11-25
4 5 2019-10-15
5 5 2019-10-15
答案 2 :(得分:1)
df_new= df_new.join(df_new.groupby('person_id')["obs_date"].min(),
on='person_id',
rsuffix="_clean")
输出:
person_id obs_date obs_date_clean
0 1 12/31/2007 12/31/2007
1 1 NA-NA-NA NA:NA:NA 12/31/2007
2 3 NA-NA-NA NA:NA:NA 11/25/2009
3 3 11/25/2009 11/25/2009
4 5 10/15/2019 10/15/2019
5 5 NA-NA-NA NA:NA:NA 10/15/2019