python 中多列的数据帧条件

dataframe condition on multiple columns in python

数据框:

i_id    sg_yes_or_no
i-123   yes
i-123   yes
i-456   no
i-678   yes
i-1y6   yes
i-1y6   yes

预期输出应为:

i_id    sg_yes_or_no    sg_only_one sg_morethan_one
i-123   yes                         yes
i-123   yes                         yes
i-456   no      
i-678   yes             yes 
i-1y6   yes                         yes
i-1y6   yes                         yes

i_id    sg_yes_or_no    
i-123   more_sg         
i-123   more_sg           
i-456   no      
i-678   one_sg             
i-1y6   more_sg             
i-1y6   more_sg                      

尝试使用以下语法但不起作用:

for df['sg_yes_or_no'] in 'yes':
    if df['i_id'].nunique() == 1:
        df['sg_only_one'] = 'yes'
    elif df['i_id'].nunique() >= 1:
        df['sg_morethan_one'] = 'yes'

如果第 2 列是 "yes",请考虑 new_dataframe 并检查(计算)new_dataframe 中的第 1 列值。如果计数为 1,则在第 3 列中写入 yes(或使用 "one_sg" 更新第 2 列),如果计数大于 1,则在第 4 列中写入 yes(或使用 "more_sg" 更新第 2 列).

请协助

一个优雅的解决方案 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

编辑

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