#python #pandas #dataframe
В продолжение вопроса . Теперь пробую осветить проблему максимально широко. Исходный датафрейм: price qty side status tradeID date 71ZNeXwSQUqkxhKR9trvrQ 2018-09-03 17:00:00 7282.5 10.0 Buy filled 2018-09-05 11:00:00 7111.0 10.0 Sell filled WYgKLRv+Q9CuXic4FNEh0A 2018-09-08 10:00:00 6448.0 10.0 Buy filled 2018-09-08 18:00:00 6377.0 10.0 Sell filled /6WmcfJ1QcWWwPcwkXeoSw 2018-09-09 14:00:00 6376.5 10.0 Buy filled Я хочу применять различные формулы (например подсчет прибыли и пр.) и заполнять исходный датафрейм. Группируя обрабатываемые данные с помощью groupby('tradeID'). Например для подсчета профита были предложены два отличных варианта. 1 Вариант (от @MaxU): In [277]: df['profit'] = (df.sort_values(['tradeID','date', 'side']) .groupby('tradeID') ['price'].diff()) In [278]: df Out[278]: price qty side status profit tradeID date 71ZNeXwSQUqkxhKR9trvrQ 2018-09-03 17:00:00 7282.5 10.0 Buy filled NaN 2018-09-05 11:00:00 7111.0 10.0 Sell filled -171.5 WYgKLRv+Q9CuXic4FNEh0A 2018-09-08 10:00:00 6448.0 10.0 Buy filled NaN 2018-09-08 18:00:00 6377.0 10.0 Sell filled -71.0 /6WmcfJ1QcWWwPcwkXeoSw 2018-09-09 14:00:00 6376.5 10.0 Buy filled NaN 2 Вариант(От @strawdog): df['profit']= df.groupby(level=[0]).transform(lambda x: x.shift(-1) - x)['price'] print(df) price qty side status profit 71ZNeXwSQUqkxhKR9trvrQ 2018-09-03 17:00:00 7282.5 10.0 Buy filled -171.5 2018-09-05 11:00:00 7111.0 10.0 Sell filled NaN WYgKLRv+Q9CuXic4FNEh0A 2018-09-08 10:00:00 6448.0 10.0 Buy filled -71.0 2018-09-08 18:00:00 6377.0 10.0 Sell filled NaN Но такие способы не подходят, если мы имеем несколько строк, где side==Sell(или Buy). Я не понимаю как использовать выбор по значению столбца в таких условиях. Я пробовал, что то вроде self.df['profit'] = df.sort_values(['tradeID','date', 'side'])['price'].groupby('tradeID').apply(lambda x: x['price'][x['side']=='Sell'].mean() - x['price'][x['side']=='Buy'].mean()) Но получаю те или иные ошибки при подобных попытках, из-за не понимая принципа работы. Вопрос: Как провести подсчет прибыли внутри каждого tradeID на примере усложненного датафрейма (среднее арифметическое по Sell минус среднее арифметическое по Buy)? Столбцами qty, status, date можно пренебречь. Усложненный(новый) датафрейм: price qty side status tradeID date 71ZNeXwSQUqkxhKR9trvrQ 2018-09-03 17:00:00 7282.5 10.0 Buy filled 2018-09-05 11:00:00 7111.0 5.0 Sell filled 2018-09-05 11:30:00 7200.0 5.0 Sell filled WYgKLRv+Q9CuXic4FNEh0A 2018-09-08 10:00:00 6448.0 5.0 Buy filled 2018-09-08 10:02:00 6460.0 5.0 Buy filled 2018-09-08 18:00:00 6500.0 10.0 Sell filled
Ответы
Ответ 1
Если я правильно понял вопрос, то нужно сначала сгруппировать датафрейм по столбцам "tradeID" и "side" и применить mean() к столбцу "price": (df.groupby(['tradeID', 'side']) ['price'].mean()) Получим: tradeID side 71ZNeXwSQUqkxhKR9trvrQ Buy 7282.5 Sell 7155.5 WYgKLRv+Q9CuXic4FNEh0A Buy 6454.0 Sell 6500.0 И далее нужно сгруппировать этот результат по "tradeID" и посчитать разницу. С использованием предыдущего куска кода: (df.groupby(['tradeID', 'side']) ['price'].mean() .groupby('tradeID').diff() .to_frame() .rename(columns={'price': 'profit'})) Результат: profit tradeID side 71ZNeXwSQUqkxhKR9trvrQ Buy NaN Sell -127.0 WYgKLRv+Q9CuXic4FNEh0A Buy NaN Sell 46.0Ответ 2
Решение в стиле "PIVOT": res = (df.pivot_table(index='tradeID', columns='side', values='price', aggfunc='mean') .eval("profit = Sell - Buy")) Результат: In [397]: res Out[397]: side Buy Sell profit tradeID 71ZNeXwSQUqkxhKR9trvrQ 7282.5 7155.5 -127.0 WYgKLRv+Q9CuXic4FNEh0A 6454.0 6500.0 46.0Ответ 3
Если честно, то вариант моего коллеги мне больше нравится из-за своей наглядности. в вашем случае я бы предложил сделать так: 1 - меняем знак поля price в зависимости от значения side df.loc[df["side"] == 'Sell', 'price'] *= -1 price qty side status tradeID date 71ZNeXwSQUqkxhKR9trvrQ 2018-09-03 17:00:00 7282.5 10.0 Buy filled 2018-09-05 11:00:00 -7111.0 10.0 Sell filled 2018-09-05 11:00:00 -7050.0 10.0 Sell filled WYgKLRv+Q9CuXic4FNEh0A 2018-09-08 10:00:00 6448.0 10.0 Buy filled 2018-09-08 18:00:00 -6377.0 10.0 Sell filled 2018-09-08 18:00:00 -6200.0 10.0 Sell filled 2 - делаем кумулятивное суммирование по группам: df['profit'] = (df.sort_values(['tradeID','date', 'side']) .groupby('tradeID') ['price'].cumsum()) price qty side status profit tradeID date 71ZNeXwSQUqkxhKR9trvrQ 2018-09-03 17:00:00 7282.5 10.0 Buy filled 7282.5 2018-09-05 11:00:00 -7111.0 10.0 Sell filled 171.5 2018-09-05 11:00:00 -7050.0 10.0 Sell filled -6878.5 WYgKLRv+Q9CuXic4FNEh0A 2018-09-08 10:00:00 6448.0 10.0 Buy filled 6448.0 2018-09-08 18:00:00 -6377.0 10.0 Sell filled 71.0 2018-09-08 18:00:00 -6200.0 10.0 Sell filled -6129.0 Update забыл добавить - финальные значения по tradeID можно получить потом так: df.groupby('tradeID').nth(-1)["profit"] tradeID 71ZNeXwSQUqkxhKR9trvrQ -6878.5 WYgKLRv+Q9CuXic4FNEh0A -6129.0 Name: profit, dtype: float64
Комментариев нет:
Отправить комментарий