Добавление нового столбца на основе существующих нескольких столбцов неожиданно создало столбец списка

#python #pandas

Вопрос:

У меня есть фрейм данных под названием df, и я хотел бы добавить столбец «прибыль» на основе существующих столбцов.

Используя эту логику:

 If decision == "buy":
    profit = 100/df["open"] * (df["close"] - df["open"])
If decision == "sell": 
    profit = 100/df["open"] * (df["open"] - df["close"])
If decision == "hold": 
    profit = 100/df["open"] * (df["open"]   df["close"])
 

Код:

 value = [[110, 95, 10, "buy"], [92, 90, -3.2, "sell"], [88, 85, -2.2, "sell"],
         [90, 95, 5.9, "hold"]]
df = pd.DataFrame(value, columns=['open', 'close', 'return', 'decision'])

df["profit"] = [(100 / df["open"] * (df["close"] - df["open"])) if x == "buy"
                else (100 / df["open"] * (df["open"] - df["close"])) for x in
                df["decision"]]
 

В результате для каждого значения в столбце прибыль было создано значение списка, а это не то, что я ожидал. Я хочу, чтобы столбец прибыли был создан следующим образом: [-13.63, 2.17, 3.41, 5.55] . Как это исправить?

Ответ №1:

Попробуйте с np.select :

 conditions = [df['decision'].eq('buy'),
              df['decision'].eq('sell'),
              df['decision'].eq('hold')]
values = [100 / df["open"] * (df["close"] - df["open"]),
          100 / df["open"] * (df["open"] - df["close"]),
          100 / df["open"] * (df["close"]   df["open"])]

df['profit'] = np.select(conditions, values)
 

df :

    open  close  return decision      profit
0   110     95    10.0      buy  -13.636364
1    92     90    -3.2     sell    2.173913
2    88     85    -2.2     sell    3.409091
3    90     95     5.9     hold  205.555556
 

Импорт и фрейм данных:

 import numpy as np
import pandas as pd

value = [[110, 95, 10, "buy"], [92, 90, -3.2, "sell"], [88, 85, -2.2, "sell"],
         [90, 95, 5.9, "hold"]]
df = pd.DataFrame(value, columns=['open', 'close', 'return', 'decision'])
 

Почему оригинал не сработал?

Потому что математические операции над рядами ведут себя следующим образом:

 100 / df["open"] * (df["close"] - df["open"])
 
 0   -13.636364
1    -2.173913
2    -3.409091
3     5.555556
dtype: float64
 

Таким образом, понимание списка создает список серий, основанный на том, где decision находится buy :

 [(100 / df["open"] * (df["close"] - df["open"]))
 if x == "buy" else
 (100 / df["open"] * (df["open"] - df["close"]))
 for x in df["decision"]]
 
 [0   -13.636364   <- Buy Calculation
1    -2.173913
2    -3.409091
3     5.555556
dtype: float64, 
0    13.636364   <- Sell Calculation
1     2.173913
2     3.409091
3    -5.555556
dtype: float64, 
0    13.636364   <- Sell Calculation
1     2.173913
2     3.409091
3    -5.555556
dtype: float64, 
0    13.636364   <- Sell (Not Buy) Calculation
1     2.173913
2     3.409091
3    -5.555556
dtype: float64]
 

Комментарии:

1. Большое тебе спасибо, Генри. Это сработало, как и ожидалось.

2. Давайте, если у меня есть другая опция «удерживать», могу ли я использовать np.где?

3. Какое значение вы хотите иметь для «удержания»?

4. Допустим, 100/df[«открыть»] * (df[«закрыть»] df[«открыть»]). Я добавил значение «удерживать».

5. np.select так будет лучше для этого.