Как применить функцию к пандам данных с множественным индексом элегантно, как на панели? - PullRequest
0 голосов
/ 30 августа 2018

Предположим, у меня есть такой фрейм данных:

ticker        MS                AAPL          
field      price    volume     price    volume
0      -0.861210 -0.319607 -0.855145  0.635594
1      -1.986693 -0.526885 -1.765813  1.696533
2      -0.154544 -1.152361 -1.391477 -2.016119
3       0.621641 -0.109499  0.143788 -0.050672

сгенерировано из следующих кодов, пожалуйста, игнорируйте числа, которые приведены в качестве примеров

columns = pd.MultiIndex.from_tuples([('MS', 'price'), ('MS', 'volume'), ('AAPL', 'price'), ('AAPL', 'volume')], names=['ticker', 'field'])
data = np.random.randn(4, 4)
df = pd.DataFrame(data, columns=columns)

Теперь я хотел бы вычислить pct_change () или любую функцию, определенную пользователем в каждом ценовом столбце, и добавить новый столбец на уровне поля, чтобы сохранить результат.

Я знаю, как сделать это элегантно, если данные представляют собой Panel, которая устарела начиная с версии 0.20. Предположим, что на оси 3 панели указаны дата, тикер и поле:

p[:,:, 'ret'] = p[:,:,'price'].pct_change()

Вот и все. Но я не нашел подобного элегантного способа сделать это с несколькими индексными фреймами данных.

Ответы [ 2 ]

0 голосов
/ 30 августа 2018
def cstm(s):
  return s.pct_change()

new = pd.concat(
    [df.xs('price', 1, 1).apply(cstm)],
    axis=1, keys=['new']
).swaplevel(0, 1, 1)

df.join(new).sort_index(1)

ticker      AAPL                            MS                    
field        new     price    volume       new     price    volume
0            NaN -0.855145  0.635594       NaN -0.861210 -0.319607
1       1.064928 -1.765813  1.696533  1.306863 -1.986693 -0.526885
2      -0.211991 -1.391477 -2.016119 -0.922211 -0.154544 -1.152361
3      -1.103335  0.143788 -0.050672 -5.022430  0.621641 -0.109499

Или

def cstm(s):
  return s.pct_change()

df.stack(0).assign(
    new=lambda d: d.groupby('ticker').price.apply(cstm)
).unstack().swaplevel(0, 1, 1).sort_index(1)
0 голосов
/ 30 августа 2018

Вы можете использовать IndexSlice

df.loc[:,pd.IndexSlice[:,'price']].apply(pd.Series.pct_change).rename(columns={'price':'ret'})
Out[1181]: 
ticker        MS      AAPL
field        ret       ret
0            NaN       NaN
1      -1.420166 -0.279805
2       3.011155  0.062529
3      -1.609004  0.759954
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...