Я хочу умножить два столбца в pandas DataFrame и добавить результат в новый столбец
Я пытаюсь умножить два существующих столбца в pandas Dataframe (orders_df) - Цены (цена закрытия акций) и Сумма (количество запасов) и добавить вычисление в новый столбец под названием "Значение". По какой-то причине, когда я запускаю этот код, все строки в столбце "Значение" представляют собой положительные числа, а некоторые из строк должны быть отрицательными. В столбце "Действие" в DataFrame есть семь строк с строкой "Sell" и семь с строкой "Купить".
for i in orders_df.Action:
if i == 'Sell':
orders_df['Value'] = orders_df.Prices*orders_df.Amount
elif i == 'Buy':
orders_df['Value'] = -orders_df.Prices*orders_df.Amount)
Пожалуйста, дайте мне знать, что я делаю неправильно!
Ответы
Ответ 1
Если мы готовы пожертвовать кратким решением Хейдена, можно также сделать что-то вроде этого:
In [22]: orders_df['C'] = orders_df.Action.apply(
lambda x: (1 if x == 'Sell' else -1))
In [23]: orders_df # New column C represents the sign of the transaction
Out[23]:
Prices Amount Action C
0 3 57 Sell 1
1 89 42 Sell 1
2 45 70 Buy -1
3 6 43 Sell 1
4 60 47 Sell 1
5 19 16 Buy -1
6 56 89 Sell 1
7 3 28 Buy -1
8 56 69 Sell 1
9 90 49 Buy -1
Теперь мы устранили необходимость в выражении if
. Используя DataFrame.apply()
, мы также устраняем цикл for
. Как отметил Хейден, векторизованные операции всегда бывают быстрее.
In [24]: orders_df['Value'] = orders_df.Prices * orders_df.Amount * orders_df.C
In [25]: orders_df # The resulting dataframe
Out[25]:
Prices Amount Action C Value
0 3 57 Sell 1 171
1 89 42 Sell 1 3738
2 45 70 Buy -1 -3150
3 6 43 Sell 1 258
4 60 47 Sell 1 2820
5 19 16 Buy -1 -304
6 56 89 Sell 1 4984
7 3 28 Buy -1 -84
8 56 69 Sell 1 3864
9 90 49 Buy -1 -4410
Это решение принимает две строки кода вместо одного, но немного легче читать. Я подозреваю, что вычислительные затраты тоже схожи.
Ответ 2
Я думаю, что элегантным решением является использование метода where
(также см. API docs
):
In [37]: values = df.Prices * df.Amount
In [38]: df['Values'] = values.where(df.Action == 'Sell', other=-values)
In [39]: df
Out[39]:
Prices Amount Action Values
0 3 57 Sell 171
1 89 42 Sell 3738
2 45 70 Buy -3150
3 6 43 Sell 258
4 60 47 Sell 2820
5 19 16 Buy -304
6 56 89 Sell 4984
7 3 28 Buy -84
8 56 69 Sell 3864
9 90 49 Buy -4410
Далее это должно быть самым быстрым решением.
Ответ 3
Вы можете использовать метод DataFrame apply
:
order_df['Value'] = order_df.apply(lambda row: (row['Prices']*row['Amount']
if row['Action']=='Sell'
else -row['Prices']*row['Amount']),
axis=1)
Как правило, быстрее использовать эти методы, а не более для циклов.
Ответ 4
Поскольку этот вопрос снова возник, я думаю, что хороший чистый подход использует assign.
Код довольно выразительный и самоописательный:
df = df.assign(Value = lambda x: x.Prices * x.Amount * x.Action.replace({'Buy' : 1, 'Sell' : -1}))
Ответ 5
Для меня это самый ясный и самый интуитивный:
values = []
for action in ['Sell','Buy']:
amounts = orders_df['Amounts'][orders_df['Action'==action]].values
if action == 'Sell':
prices = orders_df['Prices'][orders_df['Action'==action]].values
else:
prices = -1*orders_df['Prices'][orders_df['Action'==action]].values
values += list(amounts*prices)
orders_df['Values'] = values
Метод .values
возвращает numpy array
, позволяющий легко размножать элементы, а затем вы можете скомпилировать список, добавив его к нему.