Учитывая следующий фрейм данных:
Temperature Datetime
1 24.72 2021-01-01 10:00:00
2 25.76 2021-01-01 11:00:00
3 40 2021-01-01 12:00:00
4 25.31 2021-01-01 13:00:00
5 26.21 2021-01-01 14:00:00
6 26.59 2021-01-01 15:00:00
7 26.64 2021-01-01 20:00:00
8 26.38 2021-01-01 21:00:00
9 45 2021-01-01 22:00:00
10 26.23 2021-01-01 23:00:00
... ... ...
Чего мы хотим добиться, так это удалить выбросы, как, например, в id 3 температура равна 40, и это явно выброс. Мы хотим удалить всю строку с идентификатором 3. Мы уже читали эту ветку: Обнаружение выбросов на основе скользящего среднего в Python.
В треде описано, что выбросы можно удалить с помощью следующего кода:
# Import Libraries
import pandas as pd
import numpy as np
# Create DataFrame
df = pd.DataFrame({
'Temperatura': [24.72, 25.76, 40, 25.31, 26.21, 26.59],
'Date':[2.3,4.6,7.0,9.3,15.6,17.9]
})
# Set threshold for difference with rolling median
upper_threshold = 1
lower_threshold = -1
# Calculate rolling median
df['rolling_temp'] = df['Temperatura'].rolling(window=3).median()
# Calculate difference
df['diff'] = df['Temperatura'] - df['rolling_temp']
# Flag rows to be dropped as `1`
df['drop_flag'] = np.where((df['diff']>upper_threshold)|(df['diff']<lower_threshold),1,0)
# Drop flagged rows
df = df[df['drop_flag']!=1]
df = df.drop(['rolling_temp', 'rolling_temp', 'diff', 'drop_flag'],axis=1)
Но мы хотим расширить его еще больше, чтобы медиана перезапускалась всякий раз, когда есть пропущенное значение. Итак, при рассмотрении проиллюстрированного нами фрейма данных мы видим пример, в котором отсутствуют значения:
Temperature Datetime
1 24.72 2021-01-01 10:00:00
2 25.76 2021-01-01 11:00:00
3 40 2021-01-01 12:00:00
4 25.31 2021-01-01 13:00:00
5 26.21 2021-01-01 14:00:00
6 26.59 2021-01-01 15:00:00
7 26.64 2021-01-01 20:00:00 <-- Reset due to missing data between this point and the one before
8 26.38 2021-01-01 21:00:00
9 45 2021-01-01 22:00:00
10 26.23 2021-01-01 23:00:00
... ... ...
И мы хотим, чтобы код, который удаляет выбросы, также учитывал дату и время, чтобы в идентификаторе 7 мы заметили, что дата и время на 5 часов позже идентификатора 6, и поэтому мы можем сделать вывод, что данные отсутствуют, и поэтому мы хотим сбросить медиану, так как нам не нужна скользящая медиана/среднее значение, которое использует данные, не относящиеся к обнаружению выбросов. У нас могут быть примеры, когда данные отсутствуют в течение нескольких часов или, может быть, даже дней, и если скользящая медиана не учитывает этого, это приведет к плохой очистке данных. Идеальным порогом для этого был бы 1 час, поэтому, если вторая строка не ровно через час после строки 1, сбросьте медиану. Это возможно?
На мой взгляд, вы должны использовать возможности даты и времени для вычисления вашего скользящего среднего. Что-то вроде вычисления средней температуры за n часов в заданное время, а затем сравнения текущей температуры с использованием порога.
Что-то вроде:
df['Datetime'] = pd.to_datetime(df['Datetime'])
s = (df
.rolling('5h', center=True, on='Datetime')
['Temperature'].mean()
)
# 10° diff, absolute threshold
df['outlier'] = df['Temperature'].sub(s).abs().gt(10)
df.loc[mask, 'outlier'] = True
# to drop the rows:
# df = df.loc[~mask]
выход:
Temperature Datetime outlier
1 24.72 2021-01-01 10:00:00 False
2 25.76 2021-01-01 11:00:00 False
3 40.00 2021-01-01 12:00:00 True
4 25.31 2021-01-01 13:00:00 False
5 26.21 2021-01-01 14:00:00 False
6 26.59 2021-01-01 15:00:00 False
7 26.64 2021-01-01 20:00:00 False
8 26.38 2021-01-01 21:00:00 False
9 45.00 2021-01-01 22:00:00 True
10 26.23 2021-01-01 23:00:00 False
какая у тебя версия панды? Можете ли вы обновить до последней? Удаление center
не приведет к центрированию скользящего среднего, хорошо это или нет, зависит от вас;)
Работало после обновления pandas. Использовал версию 1.1.4, но после обновления до 1.4.1 заработало! Спасибо
Не за что @Buster3650
Спасибо за ваш ответ, но я получаю следующую ошибку: «NotImplementedError: центр не реализован для окон на основе даты и времени и смещения». Как это исправить? Безопасно ли удалять center=true?