Как развернуть датафрейм

359
  • Что такое пивот?
  • Как мне повернуть?
  • Это стержень?
  • Длинный формат для широкого формата?

Я видел много вопросов о сводных таблицах. Даже если они не знают, что спрашивают о сводных таблицах, они обычно так и делают. Практически невозможно написать канонический вопрос и ответ, который охватывает все аспекты поворота ....

... Но я собираюсь попробовать.


Проблема с существующими вопросами и ответами состоит в том, что часто вопрос фокусируется на нюансе, который ОП затрудняет обобщение, чтобы использовать ряд существующих хороших ответов. Однако ни один из ответов не пытается дать исчерпывающее объяснение (потому что это сложная задача)

Посмотрите несколько примеров из моего поиска Google

  1. Как развернуть датафрейм в Pandas?
    • Хороший вопрос и ответ. Но ответ только отвечает на конкретный вопрос с небольшим объяснением.
  2. сводная таблица панд к фрейму данных
    • В этом вопросе OP касается вывода разворота. А именно, как выглядят колонны. ОП хотел, чтобы это выглядело как R. Это не очень полезно для пользователей панд.
  3. Панды, поворачивающие кадр данных, повторяющиеся строки
    • Еще один достойный вопрос, но ответ сосредоточен на одном методе, а именно pd.DataFrame.pivot

Поэтому всякий раз, когда кто-то ищет, pivotон получает спорадические результаты, которые, вероятно, не будут отвечать на его конкретный вопрос.


Настроить

Вы можете заметить, что я явно назвал свои столбцы и соответствующие значения столбцов в соответствии с тем, как я собираюсь поворачиваться в ответах ниже.

import numpy as np
import pandas as pd
from numpy.core.defchararray import add

np.random.seed([3,1415])
n = 20

cols = np.array(['key', 'row', 'item', 'col'])
arr1 = (np.random.randint(5, size=(n, 4)) // [2, 1, 2, 1]).astype(str)

df = pd.DataFrame(
    add(cols, arr1), columns=cols
).join(
    pd.DataFrame(np.random.rand(n, 2).round(2)).add_prefix('val')
)
print(df)

     key   row   item   col  val0  val1
0   key0  row3  item1  col3  0.81  0.04
1   key1  row2  item1  col2  0.44  0.07
2   key1  row0  item1  col0  0.77  0.01
3   key0  row4  item0  col2  0.15  0.59
4   key1  row0  item2  col1  0.81  0.64
5   key1  row2  item2  col4  0.13  0.88
6   key2  row4  item1  col3  0.88  0.39
7   key1  row4  item1  col1  0.10  0.07
8   key1  row0  item2  col4  0.65  0.02
9   key1  row2  item0  col2  0.35  0.61
10  key2  row0  item2  col1  0.40  0.85
11  key2  row4  item1  col2  0.64  0.25
12  key0  row2  item2  col3  0.50  0.44
13  key0  row4  item1  col4  0.24  0.46
14  key1  row3  item2  col3  0.28  0.11
15  key0  row3  item1  col1  0.31  0.23
16  key0  row0  item2  col3  0.86  0.01
17  key0  row4  item0  col3  0.64  0.21
18  key2  row2  item2  col0  0.13  0.45
19  key0  row2  item0  col4  0.37  0.70

Вопросов)

  1. Почему я получаю ValueError: Index contains duplicate entries, cannot reshape

  2. Как повернуть dfтак, чтобы colзначения были столбцами, rowзначения были индексом, а среднее значение val0- значениями?

    col   col0   col1   col2   col3  col4
    row                                  
    row0  0.77  0.605    NaN  0.860  0.65
    row2  0.13    NaN  0.395  0.500  0.25
    row3   NaN  0.310    NaN  0.545   NaN
    row4   NaN  0.100  0.395  0.760  0.24
  3. Как повернуть dfтак, чтобы colзначения были столбцами, rowзначения были индексом, средним значением val0были значения, а отсутствующими значениями были 0?

    col   col0   col1   col2   col3  col4
    row                                  
    row0  0.77  0.605  0.000  0.860  0.65
    row2  0.13  0.000  0.395  0.500  0.25
    row3  0.00  0.310  0.000  0.545  0.00
    row4  0.00  0.100  0.395  0.760  0.24
  4. Могу ли я получить что-то другое, чем mean, может быть, как sum?

    col   col0  col1  col2  col3  col4
    row                               
    row0  0.77  1.21  0.00  0.86  0.65
    row2  0.13  0.00  0.79  0.50  0.50
    row3  0.00  0.31  0.00  1.09  0.00
    row4  0.00  0.10  0.79  1.52  0.24
  5. Могу ли я сделать больше одной агрегации за раз?

           sum                          mean                           
    col   col0  col1  col2  col3  col4  col0   col1   col2   col3  col4
    row                                                                
    row0  0.77  1.21  0.00  0.86  0.65  0.77  0.605  0.000  0.860  0.65
    row2  0.13  0.00  0.79  0.50  0.50  0.13  0.000  0.395  0.500  0.25
    row3  0.00  0.31  0.00  1.09  0.00  0.00  0.310  0.000  0.545  0.00
    row4  0.00  0.10  0.79  1.52  0.24  0.00  0.100  0.395  0.760  0.24
  6. Могу ли я объединить несколько столбцов значений?

          val0                             val1                          
    col   col0   col1   col2   col3  col4  col0   col1  col2   col3  col4
    row                                                                  
    row0  0.77  0.605  0.000  0.860  0.65  0.01  0.745  0.00  0.010  0.02
    row2  0.13  0.000  0.395  0.500  0.25  0.45  0.000  0.34  0.440  0.79
    row3  0.00  0.310  0.000  0.545  0.00  0.00  0.230  0.00  0.075  0.00
    row4  0.00  0.100  0.395  0.760  0.24  0.00  0.070  0.42  0.300  0.46
  7. Можно разделить на несколько столбцов?

    item item0             item1                         item2                   
    col   col2  col3  col4  col0  col1  col2  col3  col4  col0   col1  col3  col4
    row                                                                          
    row0  0.00  0.00  0.00  0.77  0.00  0.00  0.00  0.00  0.00  0.605  0.86  0.65
    row2  0.35  0.00  0.37  0.00  0.00  0.44  0.00  0.00  0.13  0.000  0.50  0.13
    row3  0.00  0.00  0.00  0.00  0.31  0.00  0.81  0.00  0.00  0.000  0.28  0.00
    row4  0.15  0.64  0.00  0.00  0.10  0.64  0.88  0.24  0.00  0.000  0.00  0.00
  8. Или

    item      item0             item1                         item2                  
    col        col2  col3  col4  col0  col1  col2  col3  col4  col0  col1  col3  col4
    key  row                                                                         
    key0 row0  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.86  0.00
         row2  0.00  0.00  0.37  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.50  0.00
         row3  0.00  0.00  0.00  0.00  0.31  0.00  0.81  0.00  0.00  0.00  0.00  0.00
         row4  0.15  0.64  0.00  0.00  0.00  0.00  0.00  0.24  0.00  0.00  0.00  0.00
    key1 row0  0.00  0.00  0.00  0.77  0.00  0.00  0.00  0.00  0.00  0.81  0.00  0.65
         row2  0.35  0.00  0.00  0.00  0.00  0.44  0.00  0.00  0.00  0.00  0.00  0.13
         row3  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.28  0.00
         row4  0.00  0.00  0.00  0.00  0.10  0.00  0.00  0.00  0.00  0.00  0.00  0.00
    key2 row0  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.40  0.00  0.00
         row2  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.13  0.00  0.00  0.00
         row4  0.00  0.00  0.00  0.00  0.00  0.64  0.88  0.00  0.00  0.00  0.00  0.00
  9. Могу ли я объединить частоту, с которой столбец и строки встречаются вместе, то есть «кросс-табуляция»?

    col   col0  col1  col2  col3  col4
    row                               
    row0     1     2     0     1     1
    row2     1     0     2     1     2
    row3     0     1     0     2     0
    row4     0     1     2     2     1
  10. Как мне преобразовать DataFrame из длинного в широкий, поворачивая ТОЛЬКО на два столбца? Данный,

    np.random.seed([3, 1415])
    df2 = pd.DataFrame({'A': list('aaaabbbc'), 'B': np.random.choice(15, 8)})        
    df2        
       A   B
    0  a   0
    1  a  11
    2  a   2
    3  a  11
    4  b  10
    5  b  10
    6  b  14
    7  c   7

    Ожидаемый должен выглядеть примерно так

          a     b    c
    0   0.0  10.0  7.0
    1  11.0  10.0  NaN
    2   2.0  14.0  NaN
    3  11.0   NaN  NaN
  11. Как сгладить множественный индекс в единый индекс после pivot

    От

       1  2   
       1  1  2        
    a  2  1  1
    b  2  1  0
    c  1  0  0

    к

       1|1  2|1  2|2               
    a    2    1    1
    b    2    1    0
    c    1    0    0
piRSquared
источник

Ответы:

301

Начнем с ответа на первый вопрос:

Вопрос 1

Почему я получаю ValueError: Index contains duplicate entries, cannot reshape

Это происходит потому, что pandas пытается переиндексировать объект a columnsили indexобъект с повторяющимися записями. Существуют различные методы, которые могут использовать для разворота. Некоторые из них не очень подходят, когда есть дубликаты клавиш, в которых его просят повернуть. Например. Посмотрим pd.DataFrame.pivot. Я знаю , что есть повторяющиеся записи , которые разделяют rowи colзначение:

df.duplicated(['row', 'col']).any()

True

Поэтому, когда я pivotиспользую

df.pivot(index='row', columns='col', values='val0')

Я получаю ошибку, упомянутую выше. Фактически, я получаю ту же ошибку, когда пытаюсь выполнить ту же задачу с:

df.set_index(['row', 'col'])['val0'].unstack()

Вот список идиом, которые мы можем использовать для поворота

  1. pd.DataFrame.groupby + pd.DataFrame.unstack
    • Хороший общий подход для выполнения практически любого типа разворота
    • Вы указываете все столбцы, которые будут составлять поворотные уровни строк и уровни столбцов в одной группе. Вы следуете за этим, выбирая оставшиеся столбцы, которые вы хотите агрегировать, и функции, которые вы хотите выполнить агрегацию. Наконец, вы unstackуровни, которые вы хотите быть в индексе столбца.
  2. pd.DataFrame.pivot_table
    • Прославленная версия groupbyс более интуитивным API. Для многих это предпочтительный подход. И это намеченный подход со стороны разработчиков.
    • Укажите уровень строки, уровни столбцов, значения для агрегирования и функции для выполнения агрегации.
  3. pd.DataFrame.set_index + pd.DataFrame.unstack
    • Удобный и интуитивно понятный для некоторых (включая меня). Не удается обработать дублированные сгруппированные ключи.
    • Подобно groupbyпарадигме, мы указываем все столбцы, которые в конечном итоге будут уровнями строк или столбцов, и устанавливаем их в качестве индекса. Мы тогда unstackуровни, которые мы хотим в столбцах. Если оставшиеся уровни индекса или уровни столбца не являются уникальными, этот метод завершится ошибкой.
  4. pd.DataFrame.pivot
    • Очень похоже на set_indexто, что оно разделяет ограничение дубликата ключа. API также очень ограничен. Он принимает только скалярные значения index, columns, values.
    • Подобно pivot_tableметоду, в котором мы выбираем строки, столбцы и значения для поворота. Однако мы не можем агрегировать, и если строки или столбцы не являются уникальными, этот метод завершится ошибкой.
  5. pd.crosstab
    • Эта специализированная версия pivot_tableв чистом виде является наиболее интуитивным способом выполнения нескольких задач.
  6. pd.factorize + np.bincount
    • Это очень продвинутая техника, которая очень непонятна, но очень быстра. Его нельзя использовать при любых обстоятельствах, но когда его можно использовать, и вы можете его использовать, вы получите плоды производительности.
  7. pd.get_dummies + pd.DataFrame.dot
    • Я использую это для умного выполнения кросс-табуляции.

Примеры

Что я собираюсь сделать для каждого последующего ответа и вопроса, чтобы ответить на него, используя pd.DataFrame.pivot_table. Затем я предоставлю альтернативы для выполнения той же задачи.

Вопрос 3

Как повернуть dfтак, чтобы colзначения были столбцами, rowзначения были индексом, средним значением val0были значения, а отсутствующими значениями были 0?

  • pd.DataFrame.pivot_table

    • fill_valueне установлен по умолчанию. Я склонен устанавливать это соответствующим образом. В этом случае я установил его на 0. Обратите внимание, что я пропустил вопрос 2, так как он такой же, как этот ответ безfill_value
    • aggfunc='mean'по умолчанию, и мне не нужно было его устанавливать. Я включил это, чтобы быть явным.

      df.pivot_table(
          values='val0', index='row', columns='col',
          fill_value=0, aggfunc='mean')
      
      col   col0   col1   col2   col3  col4
      row                                  
      row0  0.77  0.605  0.000  0.860  0.65
      row2  0.13  0.000  0.395  0.500  0.25
      row3  0.00  0.310  0.000  0.545  0.00
      row4  0.00  0.100  0.395  0.760  0.24
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0'].mean().unstack(fill_value=0)
  • pd.crosstab

    pd.crosstab(
        index=df['row'], columns=df['col'],
        values=df['val0'], aggfunc='mean').fillna(0)

Вопрос 4

Могу ли я получить что-то другое, чем mean, может быть, как sum?

  • pd.DataFrame.pivot_table

    df.pivot_table(
        values='val0', index='row', columns='col',
        fill_value=0, aggfunc='sum')
    
    col   col0  col1  col2  col3  col4
    row                               
    row0  0.77  1.21  0.00  0.86  0.65
    row2  0.13  0.00  0.79  0.50  0.50
    row3  0.00  0.31  0.00  1.09  0.00
    row4  0.00  0.10  0.79  1.52  0.24
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0'].sum().unstack(fill_value=0)
  • pd.crosstab

    pd.crosstab(
        index=df['row'], columns=df['col'],
        values=df['val0'], aggfunc='sum').fillna(0)

Вопрос 5

Могу ли я сделать больше одной агрегации за раз?

Обратите внимание, что для pivot_tableи crosstabмне нужно было пройти список вызываемых. С другой стороны, groupby.aggспособен принимать строки для ограниченного числа специальных функций. groupby.aggтакже взял бы те же самые вызовы, которые мы передали другим, но часто более эффективно использовать имена строковых функций, поскольку есть эффективность, которую нужно получить.

  • pd.DataFrame.pivot_table

    df.pivot_table(
        values='val0', index='row', columns='col',
        fill_value=0, aggfunc=[np.size, np.mean])
    
         size                      mean                           
    col  col0 col1 col2 col3 col4  col0   col1   col2   col3  col4
    row                                                           
    row0    1    2    0    1    1  0.77  0.605  0.000  0.860  0.65
    row2    1    0    2    1    2  0.13  0.000  0.395  0.500  0.25
    row3    0    1    0    2    0  0.00  0.310  0.000  0.545  0.00
    row4    0    1    2    2    1  0.00  0.100  0.395  0.760  0.24
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0'].agg(['size', 'mean']).unstack(fill_value=0)
  • pd.crosstab

    pd.crosstab(
        index=df['row'], columns=df['col'],
        values=df['val0'], aggfunc=[np.size, np.mean]).fillna(0, downcast='infer')

Вопрос 6

Могу ли я объединить несколько столбцов значений?

  • pd.DataFrame.pivot_tableмы проходим, values=['val0', 'val1']но мы могли бы оставить это полностью

    df.pivot_table(
        values=['val0', 'val1'], index='row', columns='col',
        fill_value=0, aggfunc='mean')
    
          val0                             val1                          
    col   col0   col1   col2   col3  col4  col0   col1  col2   col3  col4
    row                                                                  
    row0  0.77  0.605  0.000  0.860  0.65  0.01  0.745  0.00  0.010  0.02
    row2  0.13  0.000  0.395  0.500  0.25  0.45  0.000  0.34  0.440  0.79
    row3  0.00  0.310  0.000  0.545  0.00  0.00  0.230  0.00  0.075  0.00
    row4  0.00  0.100  0.395  0.760  0.24  0.00  0.070  0.42  0.300  0.46
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0', 'val1'].mean().unstack(fill_value=0)

Вопрос 7

Можно разделить на несколько столбцов?

  • pd.DataFrame.pivot_table

    df.pivot_table(
        values='val0', index='row', columns=['item', 'col'],
        fill_value=0, aggfunc='mean')
    
    item item0             item1                         item2                   
    col   col2  col3  col4  col0  col1  col2  col3  col4  col0   col1  col3  col4
    row                                                                          
    row0  0.00  0.00  0.00  0.77  0.00  0.00  0.00  0.00  0.00  0.605  0.86  0.65
    row2  0.35  0.00  0.37  0.00  0.00  0.44  0.00  0.00  0.13  0.000  0.50  0.13
    row3  0.00  0.00  0.00  0.00  0.31  0.00  0.81  0.00  0.00  0.000  0.28  0.00
    row4  0.15  0.64  0.00  0.00  0.10  0.64  0.88  0.24  0.00  0.000  0.00  0.00
  • pd.DataFrame.groupby

    df.groupby(
        ['row', 'item', 'col']
    )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1)

Вопрос 8

Можно разделить на несколько столбцов?

  • pd.DataFrame.pivot_table

    df.pivot_table(
        values='val0', index=['key', 'row'], columns=['item', 'col'],
        fill_value=0, aggfunc='mean')
    
    item      item0             item1                         item2                  
    col        col2  col3  col4  col0  col1  col2  col3  col4  col0  col1  col3  col4
    key  row                                                                         
    key0 row0  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.86  0.00
         row2  0.00  0.00  0.37  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.50  0.00
         row3  0.00  0.00  0.00  0.00  0.31  0.00  0.81  0.00  0.00  0.00  0.00  0.00
         row4  0.15  0.64  0.00  0.00  0.00  0.00  0.00  0.24  0.00  0.00  0.00  0.00
    key1 row0  0.00  0.00  0.00  0.77  0.00  0.00  0.00  0.00  0.00  0.81  0.00  0.65
         row2  0.35  0.00  0.00  0.00  0.00  0.44  0.00  0.00  0.00  0.00  0.00  0.13
         row3  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.28  0.00
         row4  0.00  0.00  0.00  0.00  0.10  0.00  0.00  0.00  0.00  0.00  0.00  0.00
    key2 row0  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.40  0.00  0.00
         row2  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.00  0.13  0.00  0.00  0.00
         row4  0.00  0.00  0.00  0.00  0.00  0.64  0.88  0.00  0.00  0.00  0.00  0.00
  • pd.DataFrame.groupby

    df.groupby(
        ['key', 'row', 'item', 'col']
    )['val0'].mean().unstack(['item', 'col']).fillna(0).sort_index(1)
  • pd.DataFrame.set_index потому что набор ключей уникален как для строк, так и для столбцов

    df.set_index(
        ['key', 'row', 'item', 'col']
    )['val0'].unstack(['item', 'col']).fillna(0).sort_index(1)

Вопрос 9

Могу ли я объединить частоту, с которой столбец и строки встречаются вместе, то есть «кросс-табуляция»?

  • pd.DataFrame.pivot_table

    df.pivot_table(index='row', columns='col', fill_value=0, aggfunc='size')
    
        col   col0  col1  col2  col3  col4
    row                               
    row0     1     2     0     1     1
    row2     1     0     2     1     2
    row3     0     1     0     2     0
    row4     0     1     2     2     1
  • pd.DataFrame.groupby

    df.groupby(['row', 'col'])['val0'].size().unstack(fill_value=0)
  • pd.crosstab

    pd.crosstab(df['row'], df['col'])
  • pd.factorize + np.bincount

    # get integer factorization `i` and unique values `r`
    # for column `'row'`
    i, r = pd.factorize(df['row'].values)
    # get integer factorization `j` and unique values `c`
    # for column `'col'`
    j, c = pd.factorize(df['col'].values)
    # `n` will be the number of rows
    # `m` will be the number of columns
    n, m = r.size, c.size
    # `i * m + j` is a clever way of counting the 
    # factorization bins assuming a flat array of length
    # `n * m`.  Which is why we subsequently reshape as `(n, m)`
    b = np.bincount(i * m + j, minlength=n * m).reshape(n, m)
    # BTW, whenever I read this, I think 'Bean, Rice, and Cheese'
    pd.DataFrame(b, r, c)
    
          col3  col2  col0  col1  col4
    row3     2     0     0     1     0
    row2     1     2     1     0     2
    row0     1     0     1     2     1
    row4     2     2     0     1     1
  • pd.get_dummies

    pd.get_dummies(df['row']).T.dot(pd.get_dummies(df['col']))
    
          col0  col1  col2  col3  col4
    row0     1     2     0     1     1
    row2     1     0     2     1     2
    row3     0     1     0     2     0
    row4     0     1     2     2     1

Вопрос 10

Как мне преобразовать DataFrame из длинного в широкий, поворачивая ТОЛЬКО на два столбца?

Первым шагом является присвоение номера каждой строке - этот номер будет индексом строки этого значения в сводном результате. Это делается с помощью GroupBy.cumcount:

df2.insert(0, 'count', df.groupby('A').cumcount())
df2

   count  A   B
0      0  a   0
1      1  a  11
2      2  a   2
3      3  a  11
4      0  b  10
5      1  b  10
6      2  b  14
7      0  c   7

Второй шаг - использовать вновь созданный столбец в качестве индекса для вызова DataFrame.pivot.

df2.pivot(*df)
# df.pivot(index='count', columns='A', values='B')

A         a     b    c
count                 
0       0.0  10.0  7.0
1      11.0  10.0  NaN
2       2.0  14.0  NaN
3      11.0   NaN  NaN

Вопрос 11

Как сгладить множественный индекс в единый индекс после pivot

Если columns печатать objectсо строкойjoin

df.columns = df.columns.map('|'.join)

еще format

df.columns = df.columns.map('{0[0]}|{0[1]}'.format) 
piRSquared
источник
43
Не могли бы вы рассмотреть вопрос о расширении официальных документов ?
MaxU
что случилось с ответом на вопрос № 10? Я получаю KeyError: 'A'. Есть ли еще ответ?
Моника Хеднек
@MonicaHeddneck Я еще раз рассмотрю его и обновлю при необходимости. Однако 'A'предполагается, что 'A'в вашем фрейме данных есть столбец для группировки.
piRSquared
Могу ли я объединить несколько столбцов значений? Будет ли ответ для этого будет работать для столбцов другого типа данных. например: values ​​= ['val0', 'val1'], здесь val0 - это int, а val1 - строка
Анил Кумар
1
нет необходимости вставлять столбец в вопросе 10, его можно передать непосредственно в качестве аргумента в
сводную
4

Чтобы расширить ответ @ piRSquared на другую версию Вопроса 10

Вопрос 10.1

DataFrame:

d = data = {'A': {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 3, 6: 5},
 'B': {0: 'a', 1: 'b', 2: 'c', 3: 'a', 4: 'b', 5: 'a', 6: 'c'}}
df = pd.DataFrame(d)

   A  B
0  1  a
1  1  b
2  1  c
3  2  a
4  2  b
5  3  a
6  5  c

Вывод:

   0     1     2
A
1  a     b     c
2  a     b  None
3  a  None  None
5  c  None  None

Использование df.groupbyиpd.Series.tolist

t = df.groupby('A')['B'].apply(list)
out = pd.DataFrame(t.tolist(),index=t.index)
out
   0     1     2
A
1  a     b     c
2  a     b  None
3  a  None  None
5  c  None  None

Или Гораздо лучшая альтернатива использования pd.pivot_tableсdf.squeeze.

t = df.pivot_table(index='A',values='B',aggfunc=list).squeeze()
out = pd.DataFrame(t.tolist(),index=t.index)
Ch3steR
источник