Как установить и сгруппировать панды многоуровневых столбцов? - PullRequest
0 голосов
/ 13 января 2019

У меня есть датафрейм, который имеет такую ​​форму:

   PX_LAST PX_OPEN PX_CLOSE ticker source timestamp
0        1       2        3      A   LSE   20180101
1        4       5        6      A   LSE   20180102
1        7       8        9      B   LSE   20180101
1       10      11       12      B   LSE   20180102
....

Я хочу помассировать его в следующем формате:

                                     A                          B
                                   LSE                        LSE
            PX_LAST, PX_CLOSE, PX_OPEN PX_LAST, PX_CLOSE, PX_OPEN
timestamp 
20180101          1         2       3        7         8        9 
20180102          4         5       6       10        11       12
....

Сначала я попытался использовать set_index, чтобы установить для столбцов тикера и исходного столбца индекс строки, и использовать unstack, чтобы подтолкнуть их к оси столбцов, которая, кажется, работает

df.set_index(['timestamp', 'ticker', 'source'])
    .unstack(level=[1,2])
    .swaplevel(0,1,axis=1)
    .swaplevel(1,2,axis=1)

Это делает трюк, но имеет две проблемы: 1) это очень многословно, со всеми вызовами swaplevel, которые мы должны сделать, чтобы привести столбцы в правильную форму. 2) Кажется, это не делает группировку, которую я хотел бы, т.е. результат, который я получаю, выглядит следующим образом:

              LSE     LSE      LSE      LSE ...
          PX_LAST PX_LAST PX_CLOSE PX_CLOSE ...
timestamp 
20180101       1        7        2       8  ...
20180102       4        8        5      11  ...

Есть ли более чистый способ сделать это, чтобы я мог получить нужный мне формат?

Ответы [ 3 ]

0 голосов
/ 13 января 2019

Ваше решение должно быть немного изменено - с порядком столбцов в set_index, пропустите секунду swaplevel и добавьте sort_index:

df = (df.set_index(['timestamp', 'source', 'ticker'])
        .unstack(level=[1,2])
        .swaplevel(0,2,axis=1)
        .sort_index(axis=1)
)
print (df)
ticker           A                        B                
source         LSE                      LSE                
          PX_CLOSE PX_LAST PX_OPEN PX_CLOSE PX_LAST PX_OPEN
timestamp                                                  
20180101         3       1       2        9       7       8
20180102         6       4       5       12      10      11
0 голосов
/ 13 января 2019

Мое предложение состоит в том, чтобы изменить ваше решение следующим образом:

Шаг 1: df.set_index(['timestamp', 'ticker', 'source']).unstack([1, 2]), как ты.

Оставляет столбцы в следующей форме:

          PX_LAST     PX_OPEN     PX_CLOSE
ticker          A   B       A   B        A   B
source        LSE LSE     LSE LSE      LSE LSE

timestamp в качестве индекса).

Шаг 2: reorder_levels([1, 2, 0], axis=1) вместо ваших 2 swaplevel инструкции.

Оставляет столбцы как:

ticker          A       B       A       B        A        B
source        LSE     LSE     LSE     LSE      LSE      LSE
          PX_LAST PX_LAST PX_OPEN PX_OPEN PX_CLOSE PX_CLOSE

И последний шаг sort_index(axis=1, level=[0,1], sort_remaining=False)

Обратите внимание, что вы сортируете только уровень 0 и 1, поэтому порядок на последнем уровне остается без изменений (PX_LAST, PX_OPEN, PX_CLOSE).

Таким образом, весь сценарий (то есть одна инструкция):

df2 = df.set_index(['timestamp', 'ticker', 'source']).unstack([1, 2])\
    .reorder_levels([1, 2, 0], axis=1)\
    .sort_index(axis=1, level=[0,1], sort_remaining=False)

Когда вы напечатаете результат, вы получите:

ticker          A                        B
source        LSE                      LSE
          PX_LAST PX_OPEN PX_CLOSE PX_LAST PX_OPEN PX_CLOSE
timestamp
20180101        1       2        3       7       8        9
20180102        4       5        6      10      11       12
0 голосов
/ 13 января 2019

Один из вариантов: melt, set_index и unstack:

u = df.melt(['ticker', 'source', 'timestamp'])
(u.set_index(u.columns.difference({'value'}).tolist())['value']
  .unstack([1, 0, -1])
  .sort_index(axis=1))

ticker           A                        B                
source         LSE                      LSE                
variable  PX_CLOSE PX_LAST PX_OPEN PX_CLOSE PX_LAST PX_OPEN
timestamp                                                  
20180101         3       1       2        9       7       8
20180102         6       4       5       12      10      11

или melt и pivot_table:

u = df.melt(['ticker', 'source', 'timestamp'])
u.pivot_table(index='timestamp', 
              columns=['ticker','source','variable'], 
              values='value')

ticker           A                        B                
source         LSE                      LSE                
variable  PX_CLOSE PX_LAST PX_OPEN PX_CLOSE PX_LAST PX_OPEN
timestamp                                                  
20180101         3       1       2        9       7       8
20180102         6       4       5       12      10      11
...