여기에 두 가지 주요 답변이 제안됩니다.
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])
yields IndexError
(group에서 반환 된 빈 Series 때문에 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
기본적으로이 메서드는 한 번에 하나의 열에서 작동하고 df를 출력하므로 concat
집중적 인 대신 첫 번째를 df로 처리 한 다음 출력 배열 ( values.flatten()
)을 df의 열로 반복적으로 추가합니다 .