Как повернуть фрейм данных?
- Что такое пивот?
- Как мне повернуться?
- Это стержень?
- Длинный формат в широкий формат?
Я видел много вопросов о сводных таблицах. Даже если они не знают, что спрашивают о сводных таблицах, обычно это так. Практически невозможно написать канонический вопрос и ответ, охватывающий все аспекты поворота ...
... Но я собираюсь попробовать.
Проблема с существующими вопросами и ответами заключается в том, что часто вопрос сосредоточен на нюансе, который ОП не может обобщить, чтобы использовать ряд существующих хороших ответов. Однако ни один из ответов не дает исчерпывающего объяснения (потому что это непростая задача).
Посмотрите несколько примеров из моего поиска в Google
- Хороший вопрос и ответ. Но ответ отвечает только на конкретный вопрос без особых пояснений.
- В этом вопросе OP связан с выходом поворота. А именно как выглядят колонки. OP хотел, чтобы он выглядел как R. Это не очень полезно для пользователей pandas.
- Еще один достойный вопрос, но ответ сосредоточен на одном методе, а именно
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
Вопросы)
Почему я получаю
ValueError: Index contains duplicate entries, cannot reshape
Как сделать поворот
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
Как сделать поворот
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
Могу ли я получить что-то еще, кроме
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
Могу ли я делать более одного агрегирования за раз?
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
Могу ли я агрегировать столбцы с несколькими значениями?
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
Можно ли разделить на несколько столбцов?
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
Или
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
Могу ли я агрегировать частоту, с которой столбец и строки встречаются вместе, то есть «перекрестная таблица»?
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
Как преобразовать 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
Как сгладить множественный индекс до единственного индекса после
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
Ответы
Начнем с ответа на первый вопрос:
Вопрос 1
Почему я получаю
ValueError: Index contains duplicate entries, cannot reshape
Это происходит из-за того, что pandas пытается переиндексировать объект 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()
Вот список идиом, которые мы можем использовать для поворота
pd.DataFrame.groupby
+pd.DataFrame.unstack
- Хороший общий подход для выполнения практически любого типа поворота.
- Вы указываете все столбцы, которые будут составлять сводные уровни строк и уровни столбцов в одной группе с помощью. Вы следуете этому, выбирая оставшиеся столбцы, которые вы хотите агрегировать, и функции, которые вы хотите выполнить агрегирование. Наконец, вы
unstack
выбираете уровни, которые хотите разместить в индексе столбца.
pd.DataFrame.pivot_table
- Прославленная версия
groupby
с более интуитивным API. Для многих это предпочтительный подход. И это предполагаемый подход разработчиков. - Укажите уровень строки, уровни столбца, значения для агрегирования и функции для выполнения агрегирования.
- Прославленная версия
pd.DataFrame.set_index
+pd.DataFrame.unstack
- Удобно и интуитивно понятно для некоторых (включая меня). Не может обрабатывать повторяющиеся сгруппированные ключи.
- Подобно
groupby
парадигме, мы указываем все столбцы, которые в конечном итоге будут уровнями строк или столбцов, и устанавливаем их в качестве индекса. Затемunstack
мы помещаем нужные уровни в столбцы. Если оставшиеся уровни индекса или уровни столбцов не уникальны, этот метод завершится ошибкой.
pd.DataFrame.pivot
- Очень похоже на
set_index
то, что имеет ограничение на дублирование ключа. API также очень ограничен. Он принимает только скалярные значенияindex
,columns
,values
. - Подобно этому
pivot_table
методу, мы выбираем строки, столбцы и значения для поворота. Однако мы не можем агрегировать, и если строки или столбцы не уникальны, этот метод завершится ошибкой.
- Очень похоже на
pd.crosstab
- Это специализированная версия
pivot_table
и в чистом виде представляет собой наиболее интуитивно понятный способ выполнения нескольких задач.
- Это специализированная версия
pd.factorize
+np.bincount
- Это очень продвинутая техника, которая очень непонятна, но очень быстра. Его нельзя использовать при любых обстоятельствах, но когда его можно использовать, и вам будет удобно пользоваться им, вы получите вознаграждение за производительность.
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 на другую версию вопроса 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)