通过“填充”和“内插”来填充NaN,具体取决于Python中NaN出现的时间

时间:2018-12-09 22:33:09

标签: python pandas datetime dataframe series

我想根据NaN发生在一天中的什么时间,使用“均值”和“内插”在df中填充NaN。如下所示,第一个NaN发生在上午6点,第二个NaN发生在上午8点。

02/03/2016 05:00    8
02/03/2016 06:00    NaN
02/03/2016 07:00    1
02/03/2016 08:00    NaN
02/03/2016 09:00    3

我的df由数千天组成。我想为上午7点之前发生的所有NaN申请“填充”,并为上午7点之后发生的所有NaN申请“插值”。我的数据是从早上6点到下午6点。

我的尝试是:

df_imputed = (df.between_time("00:00:00", "07:00:00", include_start=True, include_end=False)).ffill()
df_imputed = (df.between_time("07:00:00", "18:00:00", include_start=True, include_end=True)).interpolate()   

但是它将我的df缩短到了指定的时间段,而不是按我的意愿填充NaN。

编辑:我的df包含大约400列,因此该过程将应用于所有列。

1 个答案:

答案 0 :(得分:4)

原始问题:单个值序列

您可以根据自己的条件定义布尔序列,然后根据需要通过interpolate定义ffillnumpy.where

# setup
df = pd.DataFrame({'date': ['02/03/2016 05:00', '02/03/2016 06:00', '02/03/2016 07:00',
                            '02/03/2016 08:00', '02/03/2016 09:00'],
                   'value': [8, np.nan, 1, np.nan, 3]})
df['date'] = pd.to_datetime(df['date'])

# construct Boolean switch series
switch = (df['date'] - df['date'].dt.normalize()) > pd.to_timedelta('07:00:00')

# use numpy.where to differentiate between two scenarios
df['value'] = np.where(switch, df['value'].interpolate(), df['value'].ffill())

print(df)

                 date  value
0 2016-02-03 05:00:00    8.0
1 2016-02-03 06:00:00    8.0
2 2016-02-03 07:00:00    1.0
3 2016-02-03 08:00:00    2.0
4 2016-02-03 09:00:00    3.0

更新后的问题:一系列值

对于多个值列,您可以使用pd.DataFrame.whereiloc来调整上述解决方案。或者,您可以使用loc或其他方式(例如filter)来选择列,而不是iloc

# setup
df = pd.DataFrame({'date': ['02/03/2016 05:00', '02/03/2016 06:00', '02/03/2016 07:00',
                            '02/03/2016 08:00', '02/03/2016 09:00'],
                   'value': [8, np.nan, 1, np.nan, 3],
                   'value2': [3, np.nan, 2, np.nan, 6]})
df['date'] = pd.to_datetime(df['date'])

# construct Boolean switch series
switch = (df['date'] - df['date'].dt.normalize()) > pd.to_timedelta('07:00:00')

# use numpy.where to differentiate between two scenarios
df.iloc[:, 1:] = df.iloc[:, 1:].interpolate().where(switch, df.iloc[:, 1:].ffill())

print(df)

                 date  value  value2
0 2016-02-03 05:00:00    8.0     3.0
1 2016-02-03 06:00:00    8.0     3.0
2 2016-02-03 07:00:00    1.0     2.0
3 2016-02-03 08:00:00    2.0     4.0
4 2016-02-03 09:00:00    3.0     6.0