Я вижу, что ты там сделал! Это тонкая, хорошая ошибка.
Сначала я сделаю быструю очистку, чтобы мы могли видеть, что происходит:
# 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 будет лучший. Возьми его ответ. ;)