условие кадра данных для нескольких столбцов в python - PullRequest
1 голос
/ 27 апреля 2020

dataframe:

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'

Если во втором столбце указано «да», принять новый_данный кадр к рассмотрению и проверить (подсчитать) значение первого столбца в новом_датном кадре. если число равно 1, тогда напишите yes в 3-м столбце (или обновите 2-й столбец с помощью «one_sg»), если количество больше 1, тогда напишите yes в 4-м столбце (или обновите 2-й столбец с помощью «more_sg»).

, пожалуйста, помогите

1 Ответ

0 голосов
/ 27 апреля 2020

элегантное решение с 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
...