элегантное решение с DataFrame.pivot_table
:
new_df = df.join(df.pivot_table(columns = (df.groupby('i_id')['i_id']
.transform('size')
.gt(1)),
values='sg_yes_or_no',
index=df.index,
aggfunc='first')
.rename(columns={False : 'sg_only_one',
True : 'sg_morethan_one'})
.mask(lambda x: x.eq('no'))
.sort_index(axis=1, ascending=False))
print(new_df)
i_id sg_yes_or_no sg_only_one sg_morethan_one
0 i-123 yes NaN yes
1 i-123 yes NaN yes
2 i-456 no NaN NaN
3 i-678 yes yes NaN
4 i-1y6 yes NaN yes
5 i-1y6 yes NaN yes
Мы также можем использовать:
m1 = df.groupby('i_id')['i_id'].transform('size').gt(1)
m2 = df['sg_yes_or_no'].ne('no')
df['sg_morethan_one'] = df['sg_yes_or_no'].where(m & m2)
df['sg_only_one'] = df['sg_yes_or_no'].where(~m & m2)
Возможно, это много более эффективно, когда есть только две категории, но для n категорий опция pivot_table
лучше, кроме того, pivot_table
избегает применения n раз Series.where
EDIT
new_df = df.join(df.pivot_table(columns = (df.groupby('i_id')['i_id']
.transform('size')
.gt(1)
.astype(int)
.mask(df['sg_yes_or_no'].eq('no'), 2)),
values='sg_yes_or_no',
index=df.index,
aggfunc='first')
.rename(columns={0 : "one_sg",
1 : "more_sg",
2 : "no_sg"})
.sort_index(axis=1, ascending=False))
print(new_df)
i_id sg_yes_or_no one_sg no_sg more_sg
0 i-123 yes NaN NaN yes
1 i-123 yes NaN NaN yes
2 i-456 no NaN no NaN
3 i-678 yes yes NaN NaN
4 i-1y6 yes NaN NaN yes
5 i-1y6 yes NaN NaN yes