#python #pandas #time-series #nan #fillna
Вопрос:
У меня есть большой фрейм данных csv погоды, содержащий несколько сотен тысяч строк, а также множество столбцов. Строки представляют собой временные ряды, которые отбираются каждые 10 минут в течение многих лет. Столбец данных индекса, представляющий дату и время, состоит из года, месяца, дня, часа, минуты и секунды. К сожалению, было несколько тысяч отсутствующих строк, содержащих только NAN. Цель состоит в том, чтобы заполнить эти строки, используя значения других строк, собранных в то же время, но за другие годы, если они не являются NAN.
Я написал python для кода цикла, но это кажется очень трудоемким решением. Мне нужна ваша помощь для более эффективного и быстрого решения.
Необработанный кадр данных выглядит следующим образом:
print(df)
p (mbar) T (degC) Tpot (K) Tdew (degC) rh (%)
datetime
2004-01-01 00:10:00 996.52 -8.02 265.40 -8.90 93.30
2004-01-01 00:20:00 996.57 -8.41 265.01 -9.28 93.40
2004-01-01 00:40:00 996.51 -8.31 265.12 -9.07 94.20
2004-01-01 00:50:00 996.51 -8.27 265.15 -9.04 94.10
2004-01-01 01:00:00 996.53 -8.51 264.91 -9.31 93.90
... ... ... ... ... ...
2020-12-31 23:20:00 1000.07 -4.05 269.10 -8.13 73.10
2020-12-31 23:30:00 999.93 -3.35 269.81 -8.06 69.71
2020-12-31 23:40:00 999.82 -3.16 270.01 -8.21 67.91
2020-12-31 23:50:00 999.81 -4.23 268.94 -8.53 71.80
2021-01-01 00:00:00 999.82 -4.82 268.36 -8.42 75.70
[820551 rows x 5 columns]
По какой-либо причине в кадре данных df отсутствовали строки. Чтобы идентифицировать их, можно применить приведенную ниже функцию:
findnanrows(df.groupby(pd.Grouper(freq='10T')).mean())
p (mbar) T (degC) Tpot (K) Tdew (degC) rh (%)
datetime
2004-01-01 00:30:00 NaN NaN NaN NaN NaN
2009-10-08 09:50:00 NaN NaN NaN NaN NaN
2009-10-08 10:00:00 NaN NaN NaN NaN NaN
2013-05-16 09:00:00 NaN NaN NaN NaN NaN
2014-07-30 08:10:00 NaN NaN NaN NaN NaN
... ... ... ... ... ...
2016-10-28 12:00:00 NaN NaN NaN NaN NaN
2016-10-28 12:10:00 NaN NaN NaN NaN NaN
2016-10-28 12:20:00 NaN NaN NaN NaN NaN
2016-10-28 12:30:00 NaN NaN NaN NaN NaN
2016-10-28 12:40:00 NaN NaN NaN NaN NaN
[5440 rows x 5 columns]
Цель состоит в том, чтобы заполнить все эти строки NaN. Например, первая строка NaN, соответствующая дате 2004-01-01 00:30:00
-времени, должна быть заполнена значениями not NaN другой строки, собранными в ту же дату xxxx-01-01 00:30:00
-время другого года, например 2005-01-01 00:30:00
или 2006-01-01 00:30:00
и так далее, даже 2003-01-01 00:30:00
2002-01-01 00:30:00
если они существуют. Можно применить среднее значение за все эти другие годы.
Просмотр значений строки с индексом даты и времени 2005-01-01 00:30:00
:
print(df.loc["2005-01-01 00:30:00", :])
p (mbar) T (degC) Tpot (K) Tdew (degC) rh (%)
datetime
2005-01-01 00:30:00 996.36 12.67 286.13 7.11 68.82
После заполнения строки , соответствующей индексу datetime 2004-01-01 00:30:00
, с использованием значений строки, имеющей индекс datetime 2005-01-01 00:30:00
, фрейм данных df будет иметь следующую строку:
print(df.loc["2004-01-01 00:30:00", :])
p (mbar) T (degC) Tpot (K) Tdew (degC) rh (%)
datetime
2004-01-01 00:30:00 996.36 12.67 286.13 7.11 68.82
Две функции, которые я создал, следующие. Первый — определить строки NaN. Второе-заполнить их.
def findnanrows(df):
is_NaN = df.isnull()
row_has_NaN = is_NaN.any(axis=1)
rows_with_NaN = df[row_has_NaN]
return rows_with_NaN
def filldata(weatherdata):
fillweatherdata = weatherdata.copy()
allyears = fillweatherdata.index.year.unique().tolist()
dfnan = findnanrows(fillweatherdata.groupby(pd.Grouper(freq='10T')).mean())
for i in range(dfnan.shape[0]):
dnan = dfnan.index[i]
if dnan.year == min(allyears):
y = 0
dnew = dnan.replace(year=dnan.year y)
while dnew in dfnan.index:
dnew = dnew.replace(year=dnew.year y)
y = 1
else:
y = 0
dnew = dnan.replace(year=dnan.year-y)
while dnew in dfnan.index:
dnew = dnew.replace(year=dnew.year-y)
y = 1
new_row = pd.DataFrame(np.array([fillweatherdata.loc[dnew, :]]).tolist(), columns=fillweatherdata.columns.tolist(), index=[dnan])
fillweatherdata = pd.concat([fillweatherdata, pd.DataFrame(new_row)], ignore_index=False)
#fillweatherdata = fillweatherdata.drop_duplicates()
fillweatherdata = fillweatherdata.sort_index()
return fillweatherdata
Комментарии:
1. Было бы полезно, если бы вы привели часть входных данных в качестве примера, например, 10 строк по крайней мере с одной строкой с nan
2. Какой у вас актуальный вопрос?
3. Я переформулировал свой вопрос с помощью входных данных в качестве примера.
4. Не было бы более уместно интерполировать значения из данных непосредственно до и после отсутствующих данных, если таковые имеются? Погода десятиминутной давности, похоже, будет намного лучше предсказывать текущую погоду, чем погода ровно в эту минуту в прошлом году.
5. Если вы решите, что интерполяция-хороший подход, я бы просто использовал
df.interpolate()
.