Fillna 一次使用多种方法 - pandas

Posted

技术标签:

【中文标题】Fillna 一次使用多种方法 - pandas【英文标题】:Fillna using multiple approaches at a time - pandas 【发布时间】:2021-07-06 17:41:21 【问题描述】:

我有一个如下所示的数据框

df = pd.DataFrame('person_id': [101,101,101,101,202,202,202],
                        'start_date':['5/7/2013 09:27:00 AM','09/08/2013 11:21:00 AM','06/06/2014 08:00:00 AM','06/06/2014 05:00:00 AM','12/11/2011 10:00:00 AM','13/10/2012 12:00:00 AM','13/12/2012 11:45:00 AM'],
                        'end_date':['5/12/2013 09:27:00 AM',np.nan,'06/11/2014 08:00:00 AM',np.nan,'12/16/2011 10:00:00','10/18/2012 00:00:00',np.nan],
                        'type':['O','I','O','O','I','O','I'])
df.start_date = pd.to_datetime(df.start_date)
df['end_date'] = pd.to_datetime(df.end_date)

我想根据以下两种方法在end_date 列下fillna()

a) 如果在该人的除最后一行之外的任何行中找到NA,则通过复制下一行的值来fillna

b) 如果在 该人的最后一行 fillna 中找到NA,则在他的start_date 上添加 10 天(因为该人没有下一行可供复制. 所以,我们给出 10 天的随机值)

规则ab 仅适用于type=I 的人。

对于具有type=O 的人,只需复制start_date 中的值即可。

这是我尝试过的。你可以看到我写了两次相同的代码行。

  df['end_date'] = np.where(df['type'].str.contains('I'),pd.DatetimeIndex(df['end_date'].bfill()),pd.DatetimeIndex(df.start_date.dt.date))
  df['end_date'] = np.where(df['type'].str.contains('I'),pd.DatetimeIndex(df['start_date'] + pd.DateOffset(10)),pd.DatetimeIndex(df.start_date.dt.date))

任何优雅而有效的方式来编写这个,因为我必须将它应用到一个有 1500 万行的大数据上?

我希望我的输出如下所示

【问题讨论】:

您的预期输出似乎不正确。请再次检查并相应地更新预期输出。谢谢。 如果在除该人的最后一行之外的任何行中找到 NA,则通过复制下一行的值来填充您是指来自 @​​987654337@ 的下一行还是start_date 专栏? 该特定人员的start_date 列的下一行。不是来自其他 person_ids。 更新了预期的输出 @ShubhamSharma - 顺便说一句,几周前你帮我解决了一个问题。但是忘记写答案了。如果您也可以为旧问题写一个答案(我相信它会在我们的聊天窗口中,我无法访问),我可以投票并接受它。 【参考方案1】:

解决方案

s1 = df.groupby('person_id')['start_date'].shift(-1)
s1 = s1.fillna(df['start_date'] + pd.DateOffset(days=10))
s1 = df['end_date'].fillna(s1)

s2 = df['end_date'].fillna(df['start_date'])
df['end_date'] = np.where(df['type'].eq('I'), s1, s2)

说明

Group person_idshift 列上的数据框 start_date 向上一个单位。

>>> df.groupby('person_id')['start_date'].shift(-1)

0   2013-09-08 11:21:00
1   2014-06-06 08:00:00
2   2014-06-06 05:00:00
3                   NaT
4   2012-10-13 00:00:00
5   2012-12-13 11:45:00
6                   NaT
Name: start_date, dtype: datetime64[ns]

添加10 days 的偏移量后,用start_date 列中的值填充移位列中的NaN

>>> s1.fillna(df['start_date'] + pd.DateOffset(days=10))

0   2013-09-08 11:21:00
1   2014-06-06 08:00:00
2   2014-06-06 05:00:00
3   2014-06-16 05:00:00
4   2012-10-13 00:00:00
5   2012-12-13 11:45:00
6   2012-12-23 11:45:00
Name: start_date, dtype: datetime64[ns]

现在用上述系列s1 填充end_date 列中的NaN

>>>  df['end_date'].fillna(s1)

0   2013-05-12 09:27:00
1   2014-06-06 08:00:00
2   2014-06-11 08:00:00
3   2014-06-16 05:00:00
4   2011-12-16 10:00:00
5   2012-10-18 00:00:00
6   2012-12-23 11:45:00
Name: end_date, dtype: datetime64[ns]

类似地用start_date 列中的值填充end_date 列中的NaN 值以创建系列s2

>>> df['end_date'].fillna(df['start_date'])

0   2013-05-12 09:27:00
1   2013-09-08 11:21:00
2   2014-06-11 08:00:00
3   2014-06-06 05:00:00
4   2011-12-16 10:00:00
5   2012-10-18 00:00:00
6   2012-12-13 11:45:00
Name: end_date, dtype: datetime64[ns]

然后根据类型为IO的条件,使用np.wheres1/s2中选择值

>>> df

   person_id          start_date            end_date type
0        101 2013-05-07 09:27:00 2013-05-12 09:27:00    O
1        101 2013-09-08 11:21:00 2014-06-06 08:00:00    I
2        101 2014-06-06 08:00:00 2014-06-11 08:00:00    O
3        101 2014-06-06 05:00:00 2014-06-06 05:00:00    O
4        202 2011-12-11 10:00:00 2011-12-16 10:00:00    I
5        202 2012-10-13 00:00:00 2012-10-18 00:00:00    O
6        202 2012-12-13 11:45:00 2012-12-23 11:45:00    I

【讨论】:

以上是关于Fillna 一次使用多种方法 - pandas的主要内容,如果未能解决你的问题,请参考以下文章

python - Pandas - FillNa 与另一个具有相似列的非空行

有没有更好的方法来对大熊猫使用'ffill'方法进行分段的fillna?

如何在 pandas fillna() 方法中为不同的列应用不同的方法参数

Pandas:具有多索引的 fillna() 方法 - NaN 填充了错误的列

pandas 处理缺失值[dropna、drop、fillna]

pd如何把0填充为null