Заполнение NaN с использованием средних значений за тот же час предыдущих дней - PullRequest
5 голосов
/ 11 апреля 2019

Я хочу заполнить NaN, используя среднее значение из тех же часов-минут предыдущих дней. Чтобы упростить это пример моего df.

timstamp         data
22/04/2016 09:00 1
22/04/2016 09:05 2
...
23/04/2016 09:00 3
23/04/2016 09:05 4
...
24/04/2016 09:00 5
24/04/2016 09:05 6
...
25/04/2016 09:00 7
25/04/2016 09:05 8
...
25/04/2016 10:00 NaN
25/04/2016 10:05 NaN

Реальные данные содержат много дней с непрерывными 5-минутными интервалами.

df = df.groupby(df.index.minute).fillna(df.data.rolling(3).mean()) попытался выполнить скользящее среднее с предыдущего часа-минуты в прошлые дни, но это не сработало.

Альтернативный метод df = df.groupby(df.index.minute).ffill() принимает значения из двух предыдущих строк (т.е. 7 и 8), которые берутся из тех же минут предыдущего часа того же дня.

Однако мне нужен следующий результат:

timstamp         data
22/04/2016 09:00 1
22/04/2016 09:05 2
...
23/04/2016 09:00 3
23/04/2016 09:05 4
...
24/04/2016 09:00 5
24/04/2016 09:05 6
...
25/04/2016 09:00 7
25/04/2016 09:05 8
25/04/2016 10:00 3
25/04/2016 10:05 4

где значение 3 (вторая последняя строка) является средним значением из того же часа-минуты предыдущих дней (среднее значение 1, 3 и 5), а 4 (последняя строка) является средним значением 2 , 4 и 6. Учитывая размер моего df, я хочу взять среднее значение из десятков предыдущих дней.

Редактировать
Я все ближе. Используя следующий код, среднее значение данных рассчитывается по тем же часам и минутам, что и я:

df.set_index('timstamp', inplace=True)
df=df.groupby([df.index.hour, df.index.minute]).mean()
df.index.names = ["hour", "minute"]

Но он использует все данные, чтобы получить среднее значение часа-минуты. Я хотел использовать те же часы-минуты, что и в предыдущие дни, где я могу указать количество прошедших дней в расчете. Затем полученное среднее значение следует использовать для заполнения NaN.

1 Ответ

1 голос
/ 11 апреля 2019

Давайте попробуем это:

# time sample every 5 mins
idx = pd.date_range('2018-01-01', '2018-01-31', freq='300s')
np.random.seed(2019)

# create toy data
df = pd.DataFrame({'idx':idx,
                   'data':np.random.uniform(0,5, len(idx))})
df.loc[np.random.uniform(0,1,len(idx)) > 0.95, 'data'] = None

# means by the hour, can also use median
means = df.resample('H', on='idx').data.mean()

# get the timestamp on the hour
df['hour'] = df['idx'] - pd.to_timedelta(df.idx.dt.minute, unit='m')

# get the hour stamp of previous day
df['hour'] -= pd.to_timedelta(1, unit='d')

# update NaN
# df.loc[df.data.isna(), 'data'] = means[nan_hour]

# the original mapping raised a ValueError due to duplicates in nan_hour
df.loc[df.data.isna(), 'data'] = df.loc[df.data.isna(), 'hour'].\   
                                    replace({'hour': means})
...