Как пересчитать значения построчно во фрейме данных pandas, когда необходимо несколько groupby () и shift ()? - PullRequest
1 голос
/ 03 мая 2019

У меня есть мультииндексный фрейм данных.В нем есть столбец - Shares - который должен вычисляться построчно на основе Equity значений столбца из предыдущего индекса.

Я попытался поиграть с определением функции, чтобы иметь возможность apply() к кадру данных построчно, но я понял, что не могу использовать ни groupby(), ни shift() с этим методом.

Я создал фрейм данных:

import pandas as pd
import numpy as np

date_index = pd.date_range(start='1/1/2019', end='1/10/2019')
symbol_index = ['AAPL','BOA','GE','MSFT']

idx = pd.MultiIndex.from_product([date_index, symbol_index], names=['Date', 'Symbol'])
col = ['Price', 'Shares', 'Profit','Total_Profit', 'Equity']

data = pd.DataFrame(index=idx,columns=col)

price_list = [46, 17, 56, 66, 54, 79, 33, 63, 60, 63, 39, 26]
data['Price'] = price_list

Мой начальныйфрейм данных выглядит так:

                   Price  Shares  Profit  Total_Profit   Equity
Date       Symbol                                              
2019-01-01 AAPL       46   NaN     NaN        NaN         NaN
           BOA        17   NaN     NaN        NaN         NaN
           GE         56   NaN     NaN        NaN         NaN
           MSFT       66   NaN     NaN        NaN         NaN
2019-01-02 AAPL       54   NaN     NaN        NaN         NaN
           BOA        79   NaN     NaN        NaN         NaN
           GE         33   NaN     NaN        NaN         NaN
           MSFT       63   NaN     NaN        NaN         NaN
2019-01-03 AAPL       60   NaN     NaN        NaN         NaN
           BOA        63   NaN     NaN        NaN         NaN
           GE         39   NaN     NaN        NaN         NaN
           MSFT       26   NaN     NaN        NaN         NaN

Мне нужны эти переменные:

starting_capital = 5000
risk_per_position = 0.1

И я определил столбцы:

data['Shares'] = data.groupby('Symbol')['Equity'].shift(1).fillna(starting_capital) * risk_per_position / data['Price']
data['Shares'] = round(data['Shares'],0)
data['Profit'] = data['Shares'] * data['Price']
data['Total_Profit'] = data.groupby(by=['Date','Symbol'])['Profit'].sum().groupby('Date').cumsum().groupby('Date').tail(1).cumsum()
data['Total_Profit'] = data['Total_Profit'].bfill()
data['Equity'] = starting_capital + data['Total_Profit']
data['previous equity'] = data.groupby('Symbol')['Equity'].shift(1).fillna(starting_capital)

Shares при date_index- и, следовательно, Profit, Total_Profit и Equity, а также - должны быть рассчитаны на основе значения Equity в previous_date_index.Тем не менее, теперь он всегда рассчитывается на основе starting_capital и вывод:

                   Price  Shares  Profit  Total_Profit   Equity
Date       Symbol                                              
2019-01-01 AAPL       46    11.0   506.0        2031.0   7031.0
           BOA        17    29.0   493.0        2031.0   7031.0
           GE         56     9.0   504.0        2031.0   7031.0
           MSFT       66     8.0   528.0        2031.0   7031.0
2019-01-02 AAPL       54     9.0   486.0        3990.0   8990.0
           BOA        79     6.0   474.0        3990.0   8990.0
           GE         33    15.0   495.0        3990.0   8990.0
           MSFT       63     8.0   504.0        3990.0   8990.0
2019-01-03 AAPL       60     8.0   480.0        5975.0  10975.0
           BOA        63     8.0   504.0        5975.0  10975.0
           GE         39    13.0   507.0        5975.0  10975.0
           MSFT       26    19.0   494.0        5975.0  10975.0

И вывод должен быть:

                   Price  Shares  Profit  Total_Profit   Equity
Date       Symbol                                              
2019-01-01 AAPL       46    11.0   506.0        2031.0   7031.0
           BOA        17    29.0   493.0        2031.0   7031.0
           GE         56     9.0   504.0        2031.0   7031.0
           MSFT       66     8.0   528.0        2031.0   7031.0
2019-01-02 AAPL       54    13.0   702.0        4830.0   9830.0
           BOA        79     9.0   711.0        4830.0   9830.0
           GE         33    21.0   693.0        4830.0   9830.0
           MSFT       63    11.0   693.0        4830.0   9830.0
2019-01-03 AAPL       60    16.0   960.0        8761.0  13761.0
           BOA        63    16.0  1008.0        8761.0  13761.0
           GE         39    25.0   975.0        8761.0  13761.0
           MSFT       26    38.0   988.0        8761.0  13761.0

Буду признателен за вашу помощь.Какова правильная формула для столбца Shares в этом случае?

Ответы [ 2 ]

0 голосов
/ 03 мая 2019

Я нашел решение своего вопроса. Это сделает свое дело:

def portfolio_calc(row):

    global starting_capital

    row['Shares'] = starting_capital * risk_per_position / row['Price']
    row['Shares'] = round(row['Shares'].astype(float), 0)
    row['Profit'] = row['Shares'] * row['Price']
    row['Total_Profit'] = row['Profit'].sum()
    row['Equity'] = starting_capital + row['Total_Profit']
    starting_capital += row['Profit'].sum()

    return row

data = data.groupby('Date').apply(portfolio_calc)

Единственное различие, которое мы имеем здесь, состоит в том, что выходные данные в Total_Profit будут включать сумму Profit для данной даты, но не совокупную сумму Profit s для всех дат.

0 голосов
/ 03 мая 2019
data['Shares'] = data.['Equity'].shift(-1).groupby('Symbol').fillna(starting_capital) * 
risk_per_position / data['Price']

Попробуйте сместить столбец 'Equity' на -1, а затем выполнить группирование по.

...