Pandas: изменить значение в столбце по условию со значением из того же столбца - PullRequest
0 голосов
/ 07 апреля 2020

Мне нужно заменить в одном столбце с именем 'month' значения на значения из того же столбца на основе другого столбца 'step_name'. Если df.step_name.str.contains('step1'), я хочу использовать значение 'month', где df.step_name.str.contains('step2'). Я использовал df.loc[], но он просто удаляет значения month с 'step1'.

for i in set(df['id']): df.loc[(df.id.str.contains(i))&(df.step_name.str.contains('step1')),'month'] = df.loc[(df.id.str.contains(i))&(df.step_name.str.contains('step2')),'month']

Ответы [ 2 ]

1 голос
/ 07 апреля 2020

Предположим, что исходный DataFrame содержит:

   id step_name     month
0  10     step1   January
1  10     step2     March
2  12     step1  February
3  12     step2     April
4  14     step1       May

, поэтому в строках с индексами 0 и 2 ( step_name == 'step1' ) month столбец должен быть обновлен значениями из следующей строки ( step_name == 'step2' , то же самое id ).

Для этого выполните:

df.set_index('id', inplace=True)
df.update(df[df.step_name == 'step2']['month'])
df.reset_index(inplace=True)

Результат:

   id step_name  month
0  10     step1  March
1  10     step2  March
2  12     step1  April
3  12     step2  April
4  14     step1    May

Обратите внимание, что update фактически обновляет обе строки с соответствующими id , но в случае строк с step_name == 'step2' ничего не меняется.

На мой взгляд, мое решение больше pandasoni c, чем ваше l oop с отдельными обновлениями для каждого id .

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

Я вижу, что ты там сделал! Это тонкая, хорошая ошибка.

Сначала я сделаю быструю очистку, чтобы мы могли видеть, что происходит:

# Your code.
is_step1 = new_df.step_name.str.contains('step1')
is_step2 = new_df.step_name.str.contains('step2')

for i in set(df['id']): 
  is_id = df.id.str.contains(i)
  df.loc[is_id & is_step1, 'month'] = df.loc[is_id & is_step2, 'month']

Вы используете две маски, которые взаимодействуют друг с другом .

'''
mask1 mask2  => df[mask1] df[mask2]
1     0         value1    NaN        -> value1 = NaN
0     1         NaN       value2
0     0         NaN       NaN
0     0         NaN       NaN
'''

Если вместо этого использовать массив, pandas отобразит массив со значениями для заполнения в левой части назначения ...

new_df.loc[is_id & is_step1, 'month'] = new_df.loc[is_id & is_step2, 'month'].values

.. и вот что происходит:

'''
mask1 mask2  => df[mask1] df[mask2].values
1     0         value1    value2            -> value1 = value2
0     1         NaN       
0     0         NaN       
0     0         NaN       
'''

Теперь, если вы хотите, например, поменять местами месяц step1 & step2 ...

# N.B. I don't say it is best practice, but it works!
new_df = df.sort_values('id')

is_step1 = new_df.step_name.str.contains('step1')
is_step2 = new_df.step_name.str.contains('step2')

c = df.loc[is_step1, 'month'].values
new_df.loc[is_step1, 'month'] = new_df.loc[is_step2, 'month'].values
new_df.loc[is_step2, 'month'] = c

Я считаю, что решение Valdi_Bo будет лучший. Возьми его ответ. ;)

...