Buradaki en iyi iki cevap şunları öneriyor:
df.groupby(cols).agg(lambda x:x.value_counts().index[0])
veya tercihen
df.groupby(cols).agg(pd.Series.mode)
Ancak, burada gösterildiği gibi, bunların her ikisi de basit uç durumlarda başarısız olur:
df = pd.DataFrame({
'client_id':['A', 'A', 'A', 'A', 'B', 'B', 'B', 'C'],
'date':['2019-01-01', '2019-01-01', '2019-01-01', '2019-01-01', '2019-01-01', '2019-01-01', '2019-01-01', '2019-01-01'],
'location':['NY', 'NY', 'LA', 'LA', 'DC', 'DC', 'LA', np.NaN]
})
İlk:
df.groupby(['client_id', 'date']).agg(lambda x:x.value_counts().index[0])
getiri IndexError
(grup tarafından döndürülen boş Seriler nedeniyle C
). İkinci:
df.groupby(['client_id', 'date']).agg(pd.Series.mode)
döndürür ValueError: Function does not reduce
, çünkü ilk grup iki liste döndürür (iki mod olduğundan). (As belgelenmiş burada ilk grup bu işe yarar tek bir mod döndü eğer!)
Bu durum için iki olası çözüm:
import scipy
x.groupby(['client_id', 'date']).agg(lambda x: scipy.stats.mode(x)[0])
Ve çözüm yorumlarında cs95 tarafından bana verildi burada :
def foo(x):
m = pd.Series.mode(x);
return m.values[0] if not m.empty else np.nan
df.groupby(['client_id', 'date']).agg(foo)
Ancak bunların tümü yavaştır ve büyük veri kümeleri için uygun değildir. Sonunda, a) bu durumlarla başa çıkabilen ve b) çok, çok daha hızlı olan, abw33'ün cevabının (daha yüksek olması gereken) hafifçe değiştirilmiş bir versiyonu olan bir çözüm:
def get_mode_per_column(dataframe, group_cols, col):
return (dataframe.fillna(-1)
.groupby(group_cols + [col])
.size()
.to_frame('count')
.reset_index()
.sort_values('count', ascending=False)
.drop_duplicates(subset=group_cols)
.drop(columns=['count'])
.sort_values(group_cols)
.replace(-1, np.NaN))
group_cols = ['client_id', 'date']
non_grp_cols = list(set(df).difference(group_cols))
output_df = get_mode_per_column(df, group_cols, non_grp_cols[0]).set_index(group_cols)
for col in non_grp_cols[1:]:
output_df[col] = get_mode_per_column(df, group_cols, col)[col].values
Esasen, yöntem bir seferde bir sütun üzerinde çalışır ve bir df verir, bu nedenle concat
, yoğun olan yerine , ilkini bir df olarak kabul edersiniz ve ardından çıktı dizisini ( values.flatten()
) yinelemeli olarak df'ye bir sütun olarak eklersiniz .