คำตอบยอดนิยมสองข้อแนะนำ:
df.groupby(cols).agg(lambda x:x.value_counts().index[0])
หรือโดยเฉพาะอย่างยิ่ง
df.groupby(cols).agg(pd.Series.mode)
อย่างไรก็ตามทั้งสองข้อล้มเหลวในกรณีขอบธรรมดาดังที่แสดงไว้ที่นี่:
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]
})
ครั้งแรก:
df.groupby(['client_id', 'date']).agg(lambda x:x.value_counts().index[0])
ผลตอบแทนIndexError
(เนื่องจากซีรี่ส์ว่างที่ส่งคืนโดยกลุ่มC
) ที่สอง:
df.groupby(['client_id', 'date']).agg(pd.Series.mode)
ส่งคืนValueError: Function does not reduce
เนื่องจากกลุ่มแรกส่งคืนรายการสองรายการ (เนื่องจากมีสองโหมด) (ตามเอกสารที่นี่หากกลุ่มแรกส่งคืนโหมดเดียวสิ่งนี้จะใช้ได้!)
สองวิธีที่เป็นไปได้สำหรับกรณีนี้คือ:
import scipy
x.groupby(['client_id', 'date']).agg(lambda x: scipy.stats.mode(x)[0])
และวิธีแก้ปัญหาที่มอบให้ฉันโดย cs95 ในความคิดเห็น ที่นี่ :
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)
อย่างไรก็ตามทั้งหมดนี้ช้าและไม่เหมาะกับชุดข้อมูลขนาดใหญ่ วิธีแก้ปัญหาที่ฉันใช้ซึ่ง a) สามารถจัดการกับกรณีเหล่านี้ได้และ b) เร็วกว่ามากคือคำตอบของ abw33 รุ่นที่ปรับเปลี่ยนเล็กน้อย (ซึ่งควรจะสูงกว่า):
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
โดยพื้นฐานแล้วเมธอดจะทำงานบนหนึ่ง col ในแต่ละครั้งและส่งออก df ดังนั้นแทนที่จะconcat
เป็นแบบเร่งรัดคุณถือว่าสิ่งแรกเป็น df จากนั้นเพิ่มอาร์เรย์เอาต์พุตซ้ำ ( values.flatten()
) เป็นคอลัมน์ใน df