Сообщить об ошибке.

Методы pivot() и pivot_table() объекта DataFrame в pandas

Создание сводных таблиц в pandas

Содержание:


Обзор методов DataFrame.pivot() и DataFrame.pivot_table()

Визуализация понятия сводной таблицы в pandas

Применение DataFrame.pivot()

Заметка. DataFrame.pivot() может обрабатывать только уникальные строки, указанные индексом и столбцами. Если данные содержат дубликаты, то нужно использовать DataFrame.pivot_table().

Данные часто хранятся в так называемом "stacked" или "record" формате. В "record" формате обычно имеется одна строка для каждого объекта. В формате "stacked" (например log-файл сервера) для каждого объекта, где это применимо, имеется несколько строк.

>>> import pandas as pd

data = {
   "value": range(12),
   "variable": ["A"] * 3 + ["B"] * 3 + ["C"] * 3 + ["D"] * 3,
   "date": pd.to_datetime(["2020-01-03", "2020-01-04", "2020-01-05"] * 4)
}

>>> df = pd.DataFrame(data)

Для выполнения операций с временными рядами с каждой уникальной переменной лучшим представлением было бы, где columns являются уникальными переменными, а index даты идентифицирует отдельные наблюдения. Чтобы придать данным такую форму, используем метод DataFrame.pivot() (также реализованный в виде функции верхнего уровня pandas.pivot()):

>>> pivoted = df.pivot(index="date", columns="variable", values="value")
>>> pivoted
# variable    A  B  C   D
# date                   
# 2020-01-03  0  3  6   9
# 2020-01-04  1  4  7  10
# 2020-01-05  2  5  8  11

Если аргумент values опущен, а входной DataFrame имеет более одного столбца значений, которые не используются в качестве входных данных для columns или index в DataFrame.pivot(), то результирующий "сводный" DataFrame будет иметь иерархические столбцы, самый верхний уровень которых указывает на соответствующий столбец значений:

>>> df["value2"] = df["value"] * 2
>>> pivoted = df.pivot(index="date", columns="variable")
>>> pivoted
#            value           value2            
# variable       A  B  C   D      A   B   C   D
# date                                         
# 2020-01-03     0  3  6   9      0   6  12  18
# 2020-01-04     1  4  7  10      2   8  14  20
# 2020-01-05     2  5  8  11      4  10  16  22

Затем можно выбрать подмножества из сводного DataFrame:

>>> pivoted["value2"]
# variable    A   B   C   D
# date                     
# 2020-01-03  0   6  12  18
# 2020-01-04  2   8  14  20
# 2020-01-05  4  10  16  22

Обратите внимание, что возвращается представление базовых данных в случае, когда данные однородно типизированы.

Применение DataFrame.pivot_table()

В то время как DataFrame.pivot() обеспечивает сведение общего назначения с различными типами данных, библиотека pandas также предоставляет метод DataFrame.pivot_table() и функцию верхнего уровня pandas.pivot_table() для сводной таблицы с агрегированием числовых данных.

Метод DataFrame.pivot_table() можно использовать для создания сводных таблиц в стиле электронных таблиц Excel.

>>> import datetime
>>> import numpy as np

df = pd.DataFrame(
    {
        "A": ["one", "one", "two", "three"] * 6,
        "B": ["A", "B", "C"] * 8,
        "C": ["foo", "foo", "foo", "bar", "bar", "bar"] * 4,
        "D": np.random.randn(24),
        "E": np.random.randn(24),
        "F": [datetime.datetime(2013, i, 1) for i in range(1, 13)]
        + [datetime.datetime(2013, i, 15) for i in range(1, 13)],
    }
)

>>> df
#         A  B    C         D         E          F
# 0     one  A  foo -2.462103 -0.339259 2013-01-01
# 1     one  B  foo -2.246244  1.581998 2013-02-01
# 2     two  C  foo  1.460594  0.775635 2013-03-01
# 3   three  A  bar -0.634787  1.243068 2013-04-01
# ...
# 20    one  C  foo -0.388582  0.695563 2013-09-15
# 21    one  A  bar -1.047349  0.287958 2013-10-15
# 22    two  B  bar -0.354933  1.664564 2013-11-15
# 23  three  C  bar  2.073142 -0.195454 2013-12-15
# 
# [24 rows x 6 columns]
>>> pd.pivot_table(df, values="D", index=["A", "B"], columns=["C"])
# C             bar       foo
# A     B                    
# one   A -0.938132 -0.361404
#       B  1.011535 -1.257616
#       C  0.001240  0.078341
# three A -0.155351       NaN
#       B       NaN -0.093591
#       C  0.684645       NaN
# two   A       NaN -0.731589
#       B -0.588690       NaN
#       C       NaN  0.753767
>>> pd.pivot_table(df, values=["D", "E"], index=["B"], columns=["A", "C"], aggfunc="sum")
#           D                                ...         E                              
# A       one               three            ...     three                 two          
# C       bar       foo       bar       foo  ...       bar       foo       bar       foo
# B                                          ...                                        
# A -1.876265 -0.722809 -0.310703       NaN  ...  1.041608       NaN       NaN -0.719820
# B  2.023070 -2.515232       NaN -0.187183  ...       NaN  1.484646  2.053085       NaN
# C  0.002481  0.156682  1.369290       NaN  ... -0.410849       NaN       NaN -1.195039
# 
# [3 rows x 12 columns]
>>> pd.pivot_table(df, values="E", index=["B", "C"], columns=["A"], aggfunc=["sum", "mean"])
#             sum                          mean                    
# A           one     three       two       one     three       two
# B C                                                              
# A bar  1.200118  1.041608       NaN  0.600059  0.520804       NaN
#   foo  2.002847       NaN -0.719820  1.001423       NaN -0.359910
# B bar -0.363976       NaN  2.053085 -0.181988       NaN  1.026543
#   foo  0.738202  1.484646       NaN  0.369101  0.742323       NaN
# C bar -1.391516 -0.410849       NaN -0.695758 -0.205425       NaN
#   foo  1.025271       NaN -1.195039  0.512636       NaN -0.597519

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

>>> pd.pivot_table(df[["A", "B", "C", "D", "E"]], index=["A", "B"], columns=["C"])
#                 D                   E          
# C             bar       foo       bar       foo
# A     B                                        
# one   A -0.938132 -0.361404  0.600059  1.001423
#       B  1.011535 -1.257616 -0.181988  0.369101
#       C  0.001240  0.078341 -0.695758  0.512636
# three A -0.155351       NaN  0.520804       NaN
#       B       NaN -0.093591       NaN  0.742323
#       C  0.684645       NaN -0.205425       NaN
# two   A       NaN -0.731589       NaN -0.359910
#       B -0.588690       NaN  1.026543       NaN
#       C       NaN  0.753767       NaN -0.597519

Кроме того, можно использовать pandas.Grouper() для ключевых аргументов index и columns.

>>> pd.pivot_table(df, values="D", index=pd.Grouper(freq="M", key="F"), columns="C")
# C                bar       foo
# F                             
# 2013-01-31       NaN -0.361404
# 2013-02-28       NaN -1.257616
# 2013-03-31       NaN  0.753767
# 2013-04-30 -0.155351       NaN
# 2013-05-31  1.011535       NaN
# 2013-06-30  0.001240       NaN
# 2013-07-31       NaN -0.731589
# 2013-08-31       NaN -0.093591
# 2013-09-30       NaN  0.078341
# 2013-10-31 -0.938132       NaN
# 2013-11-30 -0.588690       NaN
# 2013-12-31  0.684645       NaN

Пример расчета частичных сумм и промежуточных итогов

df = pd.DataFrame(
    data={
        "Province": ["ON", "QC", "BC", "AL", "AL", "MN", "ON"],
        "City": [
            "Toronto",
            "Montreal",
            "Vancouver",
            "Calgary",
            "Edmonton",
            "Winnipeg",
            "Windsor",
        ],
        "Sales": [13, 6, 16, 8, 4, 3, 1],
    }
)

>>> df
#   Province       City  Sales
# 0       ON    Toronto     13
# 1       QC   Montreal      6
# 2       BC  Vancouver     16
# 3       AL    Calgary      8
# 4       AL   Edmonton      4
# 5       MN   Winnipeg      3
# 6       ON    Windsor      1
table = df.pivot_table(
    values=["Sales"],
    index=["Province"],
    columns=["City"],
    aggfunc="sum",
    margins=True,
)

>>> table.stack("City", future_stack=True)
#                     Sales
# Province City            
# AL       Calgary      8.0
#          Edmonton     4.0
#          Montreal     NaN
#          Toronto      NaN
#          Vancouver    NaN
# ...                   ...
# All      Toronto     13.0
#          Vancouver   16.0
#          Windsor      1.0
#          Winnipeg     3.0
#          All         51.0
# 
# [48 rows x 1 columns]

Пример построения DataFrame с годовыми данными

Чтобы создать перекрестную таблицу по годам и месяцам, необходимо выполнить следующие действия.

df = pd.DataFrame(
    {"value": np.random.randn(36)},
    index=pd.date_range("2011-01-01", freq="M", periods=36),
)


>>> df.pivot_table(
...     index=df.index.month, columns=df.index.year, values="value", aggfunc="sum"
... )
#         2011      2012      2013
# 1  -0.684229  0.407663  0.415221
# 2   0.590280  0.417917 -0.164821
# 3  -0.737578  0.406965 -1.893850
# 4   0.951886  1.272036  1.654187
# 5   0.123040 -1.425201 -0.258822
# 6  -1.501977  1.208778  0.782863
# 7  -1.087257 -0.411236 -0.135623
# 8  -0.326061 -0.935996 -0.945246
# 9   0.083486  0.930429  0.998789
# 10 -0.568210 -0.973238 -1.432825
# 11 -1.685772  0.457168 -0.411864
# 12 -1.345183 -1.696976 -1.095169

pandas.pivot(data, *, columns, index=no_default, values=no_default):

Pandas предоставляет эквивалентный метод DataFrame.pivot(), который принимает аналогичные аргументы за исключением аргумента data, т.к. сам является вызывающим (исходным) DataFrame.

Функция pandas.pivot() и метод DataFrame.pivot() изменяет форму данных (создание сводной таблицы) на основе значений столбцов. Использует уникальные значения из указанного индекса/столбцов для формирования осей результирующего DataFrame. Возвращает измененный DataFrame, организованный по заданным значениям индекса/столбца.

Эта функция не поддерживает агрегацию данных, несколько значений приведут к созданию MultiIndex в столбцах. Если необходимо использовать функции агрегирования данных, то нужно использовать функцию pandas.pivot_table() или метод DataFrame.pivot_table().

Поднимает исключение ValueError если есть любые комбинации индексов, столбцов с несколькими значениями.

Заметка. DataFrame.pivot() может обрабатывать только уникальные строки, указанные индексом и столбцами. Если данные содержат дубликаты, то нужно использовать DataFrame.pivot_table().

Принимаемые аргументы pandas.pivot():

  • data - исходный DataFrame;
  • columns - столбец, используемый для создания столбцов нового DataFrame. Принимает: строку или список строк.
  • index=no_default - столбец, используемый для создания индекса нового DataFrame. Если не указано, то будет использоваться существующий индекс. Принимает строку или список строк.
  • values=no_default - столбцы, используемые для заполнения значений нового DataFrame. Если не указано, то будут использованы все оставшиеся столбцы, а результат будет иметь иерархически индексированные столбцы. Принимает: строку или список строк.

Примеры использования pandas.pivot()

>>> import pandas as pd
df = pd.DataFrame({'foo': ['one', 'one', 'one', 'two', 'two',
                           'two'],
                   'bar': ['A', 'B', 'C', 'A', 'B', 'C'],
                   'baz': [1, 2, 3, 4, 5, 6],
                   'zoo': ['x', 'y', 'z', 'q', 'w', 't']})

>>> df
#     foo   bar  baz  zoo
# 0   one   A    1    x
# 1   one   B    2    y
# 2   one   C    3    z
# 3   two   A    4    q
# 4   two   B    5    w
# 5   two   C    6    t
>>> df.pivot(index='foo', columns='bar', values='baz')
# bar  A   B   C
# foo
# one  1   2   3
# two  4   5   6
>>> df.pivot(index='foo', columns='bar')['baz']
# bar  A   B   C
# foo
# one  1   2   3
# two  4   5   6
>>> df.pivot(index='foo', columns='bar', values=['baz', 'zoo'])
#       baz       zoo
# bar   A  B  C   A  B  C
# foo
# one   1  2  3   x  y  z
# two   4  5  6   q  w  t

Можно назначить список имен столбцов или список имен индексов.

df = pd.DataFrame({
       "lev1": [1, 1, 1, 2, 2, 2],
       "lev2": [1, 1, 2, 1, 1, 2],
       "lev3": [1, 2, 1, 2, 1, 2],
       "lev4": [1, 2, 3, 4, 5, 6],
       "values": [0, 1, 2, 3, 4, 5]})

>>>df
#     lev1 lev2 lev3 lev4 values
# 0   1    1    1    1    0
# 1   1    1    2    2    1
# 2   1    2    1    3    2
# 3   2    1    2    4    3
# 4   2    1    1    5    4
# 5   2    2    2    6    5
>>> df.pivot(index="lev1", columns=["lev2", "lev3"], values="values")
# lev2    1         2
# lev3    1    2    1    2
# lev1
# 1     0.0  1.0  2.0  NaN
# 2     4.0  3.0  NaN  5.0
>>> df.pivot(index=["lev1", "lev2"], columns=["lev3"], values="values")
#       lev3    1    2
# lev1  lev2
#    1     1  0.0  1.0
#          2  2.0  NaN
#    2     1  4.0  3.0
#          2  NaN  5.0

Если есть дубликаты - возникает исключение ValueError.

df = pd.DataFrame({"foo": ['one', 'one', 'two', 'two'],
                   "bar": ['A', 'A', 'B', 'C'],
                   "baz": [1, 2, 3, 4]})

>>> df
#    foo bar  baz
# 0  one   A    1
# 1  one   A    2
# 2  two   B    3
# 3  two   C    4

Обратите внимание, что первые две строки для аргумента index и columns одинаковы.

>>> df.pivot(index='foo', columns='bar', values='baz')
# Traceback (most recent call last):
#    ...
# ValueError: Index contains duplicate entries, cannot reshape

pandas.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All', observed=False, sort=True):

Pandas предоставляет эквивалентный метод DataFrame.pivot_table(), который принимает аналогичные аргументы за исключением data, т.к. сам является вызывающим (исходным) DataFrame.

Функция pandas.pivot_table() и метод DataFrame.pivot_table() создает сводную таблицу в стиле электронной таблицы Excel в виде DataFrame.

Уровни в сводной таблице будут храниться в объектах MultiIndex (иерархических индексах) индексе и столбцах результирующего DataFrame.

Принимаемые аргументы pivot_table():

  • data - исходный DataFrame;

  • values=None - столбец или столбцы для агрегирования. Принимает скалярное значение или список значений.

  • index=None - ключи для группировки по индексу сводной таблицы. Если передается список, он может содержать любой из принимаемых типов (кроме списка). Если передается массив, он должен быть той же длины, что и данные, и будет использоваться тем же образом, что и значения столбцов. Принимает: строку с меткой столбца, pandas.Grouper(), массив или список этих типов.

  • columns=None - ключи для группировки по столбцу сводной таблицы. Если передается список, он может содержать любой из принимаемых типов (кроме списка). Если передается массив, он должен быть той же длины, что и данные, и будет использоваться тем же образом, что и значения столбцов. Принимает: строку с меткой столбца, pandas.Grouper(), массив или список этих типов.

  • aggfunc='mean' - если передается список агрегирующих функций, то результирующая сводная таблица будет иметь иерархические столбцы, верхним уровнем которых являются имена функций. Если передается словарь dict, то ключом для агрегирования является столбец, а значением - агрегирующая функция или их список. Если margins=True, то aggfunc будет использоваться для вычисления частичных агрегированных значений. Принимает: строку с именем функции, список имен функции, словарь dict.

  • fill_value=None - значение для замены отсутствующих значений (в результирующей сводной таблице, после агрегирования).

  • margins=False - если margins=True, то в строках и столбцах будут добавлены специальные столбцы и строки All (смотри аргумент margins_name) с частичными групповыми статистическими выражениями по категориям.

  • dropna=True - не включает столбцы, все записи которых имеют значение NaN. Если задано значение True, то перед вычислением полей, строки со значением NaN в любом столбце будут опущены.

  • margins_name='All' - имя строки/столбца, которое будет содержать итоги при margins=True.

  • observed=False - применимо только в том случае, если кто-либо из Grouper является Categoricals.

    • Если True: отображает наблюдаемые значения только для категориальных Grouper.
    • Если False: отображает все значения для категориальных Grouper.

  • sort=True - следует ли сортировать результат.

Примеры использования pandas.pivot_table()

>>> import pandas as pd
df = pd.DataFrame({"A": ["foo", "foo", "foo", "foo", "foo",
                         "bar", "bar", "bar", "bar"],
                   "B": ["one", "one", "one", "two", "two",
                         "one", "one", "two", "two"],
                   "C": ["small", "large", "large", "small",
                         "small", "large", "small", "small",
                         "large"],
                   "D": [1, 2, 2, 3, 3, 4, 5, 6, 7],
                   "E": [2, 4, 5, 5, 6, 6, 8, 9, 9]})

>>> df
#      A    B      C  D  E
# 0  foo  one  small  1  2
# 1  foo  one  large  2  4
# 2  foo  one  large  2  5
# 3  foo  two  small  3  5
# 4  foo  two  small  3  6
# 5  bar  one  large  4  6
# 6  bar  one  small  5  8
# 7  bar  two  small  6  9
# 8  bar  two  large  7  9

В этом первом примере значения агрегируются путем получения суммы.

>>> table = pd.pivot_table(df, values='D', index=['A', 'B'],
...                        columns=['C'], aggfunc="sum")
>>> table
# C        large  small
# A   B
# bar one    4.0    5.0
#     two    7.0    6.0
# foo one    4.0    1.0
#     two    NaN    6.0

Можно заполнить недостающие значения, используя аргумент fill_value.

>>> table = pd.pivot_table(df, values='D', index=['A', 'B'],
...                        columns=['C'], aggfunc="sum", fill_value=0)
>>> table
# C        large  small
# A   B
# bar one      4      5
#     two      7      6
# foo one      4      1
#     two      0      6

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

>>> table = pd.pivot_table(df, values=['D', 'E'], index=['A', 'C'],
...                        aggfunc={'D': "mean", 'E': "mean"})
>>> table
#                 D         E
# A   C
# bar large  5.500000  7.500000
#     small  5.500000  8.500000
# foo large  2.000000  4.500000
#     small  2.333333  4.333333

Также можно рассчитать несколько типов агрегированных значений для любого заданного столбца значений.

>>> table = pd.pivot_table(df, values=['D', 'E'], index=['A', 'C'],
...                        aggfunc={'D': "mean",
...                                 'E': ["min", "max", "mean"]})
>>> table
#                   D   E
#                mean max      mean  min
# A   C
# bar large  5.500000   9  7.500000    6
#     small  5.500000   9  8.500000    8
# foo large  2.000000   5  4.500000    4
#     small  2.333333   6  4.333333    2