基于每个组的高效优雅的方式在pandas列中填充值

时间:2019-08-13 08:53:01

标签: python python-3.x pandas dataframe pandas-groupby

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']
})

看起来如下图

enter image description here

我想做的是用同一组中的实际日期值替换/填充NA类型的行。为此,我尝试了以下

m1 = df_new['obs_date'].str.contains('^\d')
df_new['obs_date'] = df_new.groupby((m1).cumsum())['obs_date'].transform('first')

但这会产生意外的输出,如下所示

enter image description here

在第二行中,应该是person_id = 3的11/25/2009,而不是来自person_id = 1的第一组。

如何获得如下所示的预期输出

enter image description here

当我处理超过百万条记录时,任何优雅而有效的解决方案都会有所帮助

3 个答案:

答案 0 :(得分:2)

首先使用to_datetimeonCreate()将非日期时间转换为缺失值,然后使用GroupBy.first获取GroupBy.transform数据填充的新列中的第一个非缺失值:

errors='coerce'

另一个想法是将DataFrame.sort_valuesGroupBy.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之后将非日期值分别填充为NaTffillbfill

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