Допустим, у меня есть следующий фрейм данных:
df = pd.DataFrame({"unique_id": [1, 1, 1], "att1_amr": [11, 11, 11], "att2_nominal": [1, np.nan, np.nan], "att3_nominal": [np.nan, 1, np.nan], "att4_bok": [33.33, 33.33, 33.33], "att5_nominal": [np.nan, np.nan, np.nan], "att6_zpq": [22.22, 22.22, 22.22]})
Что я хочу сделать, так это сгруппировать по строкам кадра данных с помощью unique_id
, чтобы я мог применить отдельную операцию группирования к столбцам, содержащим слово nominal
, и отдельно ко всем остальным. Чтобы быть более конкретным, я хочу сгруппировать столбцы, содержащие nominal
, используя sum(min_count = 1)
, а другие — с помощью first()
или last()
. Результат должен быть следующим:
df_result = pd.DataFrame({"unique_id": [1], "att1_amr": [11], "att2_nominal": [1], "att3_nominal": [1], "att4_bok": [33.33], "att5_nominal": [np.nan], "att6_zpq": [22.22]})
Спасибо!
Почему бы просто не:
>>> df.ffill().bfill().drop_duplicates()
att1_amr att2_nominal att3_nominal att4_bok att5_nominal att6_zpq \
0 11 1.0 1.0 33.33 NaN 22.22
unique_id
0 1
>>>
Вы можете создать словарь динамически - сначала все столбцы с nominal
с лямбда-функцией, а затем все остальные столбцы с last
и объединить их вместе, последний вызов DataFrameGroupBy.agg
:
d1 = dict.fromkeys(df.columns[df.columns.str.contains('nominal')],
lambda x : x.sum(min_count=1))
d2 = dict.fromkeys(df.columns.difference(['unique_id'] + list(d1)), 'last')
d = {**d1, **d2}
df = df.groupby('unique_id').agg(d)
print (df)
att2_nominal att3_nominal att5_nominal att1_amr att4_bok \
unique_id
1 1.0 1.0 NaN 11 33.33
att6_zpq
unique_id
1 22.22
Еще одно более чистое решение:
d = {k: (lambda x : x.sum(min_count=1))
if 'nominal' in k
else 'last'
for k in df.columns.difference(['unique_id'])}
df = df.groupby('unique_id').agg(d)
print (df)
att1_amr att2_nominal att3_nominal att4_bok att5_nominal \
unique_id
1 11 1.0 1.0 33.33 NaN
att6_zpq
unique_id
1 22.22
Спасибо за ответ. Это именно то, что я искал, и я отметил это как правильное. С другой стороны, у меня сейчас серьезные проблемы с производительностью. Раньше это был df.groupby("unique_id").sum(min_count=1)
(это было ошибкой, когда речь шла об ожидаемом результате), и это занимало намного меньше времени, чем сейчас. Вы хоть представляете, что происходит? Кроме того, размер моего кадра данных составляет 600 000 x 1700, однако меня смущает огромная разница между операцией groupby, которая у меня была, и той, что была сейчас.
Решение, предоставленное @jezrael, прекрасно работает, хотя и является самым элегантным, однако я столкнулся с серьезными проблемами с производительностью. Удивительно, но я обнаружил, что это гораздо более быстрое решение при достижении той же цели.
nominal_cols = df.filter(like = "nominal").columns.values
other_cols = [col for col in df.columns.values if col not in nominal_cols and col != "unique_id"]
df1 = df.groupby('unique_id', as_index=False)[nominal_cols].sum(min_count=1)
df2 = df.groupby('unique_id', as_index=False)[other_cols].first()
pd.merge(df1, df2, on=["unique_id"], how = "inner")
Фрейм данных будет содержать много разных
unique_ids
, плюс мне также нужно будет сгруппировать по другому дополнительному столбцу. Вопрос задается без этих деталей, потому что я довольно прямо сказал, что хочу сделать.