Я читал много сообщений о merge()
и join()
методах pandas.DataFrames
и пробовал их на своей собственной проблеме, но не нашел решения.
У меня оченьбольшой файл данных (.csv), содержащий почасовое потребление чего-либо для различных идентификаторов.Я хочу агрегировать потребление для каждого идентификатора за каждый месяц.
Из-за ограничений памяти мне нужно обработать файл почасового потребления с read_csv
порциями (используя опцию chunk_size
) и получитьзагрузка DataFrames потребления для идентификаторов за несколько месяцев, например:
df1 =
Month Dec Nov
ID
XXX 4.0 1.0
YYY 8.0 3.0
ZZZ 4.0 1.0
df2 =
Month Dec Nov Oct
ID
AAA 1.0 7.0 9.0
BBB 0.0 NaN 2.0
YYY 5.0 5.0 0.0
Генерируется для этого поста с помощью:
df1 = pd.DataFrame({'ID': ['XXX','XXX','YYY','YYY','ZZZ','ZZZ'],
'Month': ['Nov','Dec']*3,
'Consumption': [1.0,4.0,3.0,8.0,1.0,4.0]})
df1 = df1.pivot(index='ID', columns='Month', values='Consumption')
df2 = pd.DataFrame({'ID': ['AAA','AAA','AAA','YYY','YYY','YYY','BBB','BBB','BBB'],
'Month': ['Oct','Nov','Dec']*3,
'Consumption': [9,7,1,0,5,5,2,np.nan,0]})
df2 = df2.pivot(index='ID', columns='Month', values='Consumption')
Обратите внимание, что существует разница между потреблением0.0
и NaN
.0.0
означает, что по крайней мере один показатель потребления составил 0.0
в месяц, но NaN
означает, что вообще не было зарегистрировано никакого значения потребления, и в этом случае 0 не может быть принято.Для моих целей это различие должно быть разным.
Поскольку файл данных обрабатывается порциями, есть несколько идентификаторов, которые появляются в нескольких кадрах данных, например, YYY
, и для этих идентификаторовиногда месяцы тоже перекрываются, например Nov
для ID YYY
.В этом случае потребление в первой половине месяца составляет df1
, а во второй половине - df2
.
Поэтому для агрегирования потребления мне необходимо объединить эти фреймы данных по 'ID' и суммезначения в перекрывающихся 'Месяцах'.
Прямое суммирование DataFrames дает много NaN:
df1 + df2 =
Month Dec Nov Oct
ID
AAA NaN NaN NaN
BBB NaN NaN NaN
XXX NaN NaN NaN
YYY 13.0 8.0 NaN
ZZZ NaN NaN NaN
Я предполагаю, что это потому, что при суммировании идентификаторов / месяцев df1
которые не отображаются df2
, возвращает NaN.
Внешнее объединение создает суффиксированные столбцы для перекрывающихся месяцев:
df1.merge(df2,how='outer',on='ID') =
Month Dec_x Nov_x Dec_y Nov_y Oct
ID
XXX 4.0 1.0 NaN NaN NaN
YYY 8.0 3.0 5.0 5.0 0.0
ZZZ 4.0 1.0 NaN NaN NaN
AAA NaN NaN 1.0 7.0 9.0
BBB NaN NaN 0.0 NaN 2.0
Я не смог получить combine_first
делать то, что я хочу либо.
Что-то, что я хочу, это что-то посередине, это выглядит так:
Month Dec Nov Oct
ID
XXX 4.0 1.0 NaN
YYY 13.0 8.0 0.0
ZZZ 4.0 1.0 NaN
AAA 1.0 7.0 9.0
BBB 0.0 NaN 2.0
Где перекрывающиеся месяцы суммируются так, что x + NaN = x
, NaN + y = y
и NaN + NaN = NaN
.
Одно решение, которое я вижу, чтобы выполнить слияние, а затем суммировать перекрывающиеся столбцы, игнорируя NaN:
df3 = df1.merge(df2,how='outer',on='ID',suffixes=['','_x'])
overlapping_months_sufx = df3.columns.values[df3.columns.str.endswith('_x')]
for mnth_sufx in overlapping_months_sufx:
mnth = mnth_sufx[:-2]
df3[mnth][df3[mnth_sufx].notnull()] = df3[mnth].fillna(0) + df3[mnth_sufx]
df3=df3.drop(columns=mnth_sufx)
df3 =
Month Dec Nov Oct
ID
XXX 4.0 1.0 NaN
YYY 13.0 8.0 0.0
ZZZ 4.0 1.0 NaN
AAA 1.0 7.0 9.0
BBB 0.0 NaN 2.0
Учитывая размер этого набора данных, было бы здорово иметь наиболее эффективный способ агрегировать все это.Есть ли лучший способ сделать это, возможно, за один шаг?
Спасибо, Крис