Панды: группировать каждый столбец по-разному - PullRequest
0 голосов
/ 22 января 2019

Допустим, у меня есть следующий фрейм данных:

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]})

Спасибо!

Ответы [ 3 ]

0 голосов
/ 22 января 2019

Вы можете создать словарь динамически - сначала все столбцы с 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  
0 голосов
/ 23 января 2019

Решение, предоставленное @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")
0 голосов
/ 22 января 2019

Почему бы просто:

>>> 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  
>>> 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...