#python #arrays #pandas #dataframe #numpy
Вопрос:
У меня есть следующий фрейм данных:
data = {'Column A':[400, 522, 633, 744, 150, 140, 119, 744, 150, 400, 390, 315, 744, 150, 400, 522, 500, 633, 744, 204, 215, 150],
'Column B':[400, 0, 0, 0, -150, 0, 0, 744, 0, -400, 0, 0, -744, 0, -400, 0, 0, -633, 0, 0, 0, 150]}
df = pd.DataFrame(data)
Что я хочу сделать, так это сказать программе, чтобы она шла строка за строкой и сравнивала абсолютное значение последнего отрицательного значения в столбце B со значением столбца A для текущей строки, и если оно на 20% ниже, скопируйте его в столбец B. Вот как будет выглядеть фрейм данных с измененным столбцом B:
data = {'Column A':[400, 522, 633, 744, 150, 140, 119, 744, 150, 400, 390, 315, 744, 150, 400, 522, 500, 633, 744, 204, 215, 150],
'Column B':[400, 0, 0, 0, -150, 0, 119, 744, 0, -400, 0, 315, -744, 150, -400, 0, 0, -633, 0, 204, 215, 150],
}
Так, например, в 6-й строке последнее отрицательное значение в столбце B равно -150, поэтому его абсолютное значение будет равно 150, когда вы сравните это значение со значением 140 в столбце A, тогда значение не копируется, так как 140 все еще находится внутри порога 20%, однако в 7-й строке 119 более чем на 20% ниже 150, поэтому копируется в столбец B. В 10-й строке последний минус становится -400, поэтому он начнет использовать это значение для сравнения, затем снова пропустит 390, но скопирует 315.
Я надеюсь, что это достаточно ясно, и заранее благодарю вас за ваши ответы.
Ответ №1:
Вы можете попробовать что-то в этом роде :
last_value = 0
for i, n in df.iterrows():
if n["Column B"] < 0:
last_value = abs(n["Column B"])
if n["Column A"] < last_value*0.8:
df.loc[df.index == i, 'Column B'] = n["Column A"]
Комментарии:
1. Это решает проблему, но поскольку мой исходный набор данных содержит тысячи строк, нет ли более эффективного способа без использования операторов If или циклов for?
2. ..честно говоря, у меня нет возможности отказаться от использования условных операторов и цикла, по крайней мере, для повторения вашего фрейма данных…
Ответ №2:
Попробуй:
df['New Column B'] = np.where(df['Column B'].ge(0), np.nan, df['Column B'])
df['New Column B'].ffill(inplace=True)
condition = df['Column A'] < abs(df['New Column B']*0.8))
df['New Column B'].mask(condition, df['Column A'], inplace=True)
condition = df['Column B'].ne(df['New Column B']) amp; df['New Column B'].ne(df['Column A'])
df['New Column B'].mask(condition, df['Column B'], inplace=True)
df['New Column B'] = df['New Column B'].astype(int)
Комментарии:
1. Мухаммад спасибо вам за это, ваше решение намного эффективнее, однако, поскольку мне нужно заменить «Столбец B» на «Новый столбец B», я хотел спросить вас, есть ли способ избежать использования вспомогательного столбца, такого как «Новый столбец B», и просто перезаписать столбец B на месте, чтобы «Новый столбец B» стал фактическим столбцом B с изменениями.
Ответ №3:
Вот одна строка с np.where
ffill
последним отрицательным значением в столбце B. и после него.
df['newColB'] = ( # you can reassign directly to Column B
np.where(df['Column A']<0.8*df['Column B'].where(df['Column B']<0).ffill().abs(),
df['Column A'], df['Column B'])
)
print(df)
Column A Column B New Column B newColB
0 400 400 400 400
1 522 0 0 0
2 633 0 0 0
3 744 0 0 0
4 150 -150 -150 -150
5 140 0 0 0
6 119 0 119 119
7 744 744 744 744
8 150 0 0 0
9 400 -400 -400 -400
10 390 0 0 0
11 315 0 315 315
12 744 -744 -744 -744
13 150 0 150 150
14 400 -400 -400 -400
15 522 0 0 0
16 500 0 0 0
17 633 -633 -633 -633
...