Преобразование формы и сводные таблицы
Преобразование формы путем поворота объектов DataFrame
Данные часто хранятся в так называемом «стековом» или «записочном» формате:
In [1]: df
Out[1]:
date variable value
0 2000-01-03 A 0.469112
1 2000-01-04 A -0.282863
2 2000-01-05 A -1.509059
3 2000-01-03 B -1.135632
4 2000-01-04 B 1.212112
5 2000-01-05 B -0.173215
6 2000-01-03 C 0.119209
7 2000-01-04 C -1.044236
8 2000-01-05 C -0.861849
9 2000-01-03 D -2.104569
10 2000-01-04 D -0.494929
11 2000-01-05 D 1.071804
Для любознательных, вот как было создано выше DataFrame:
import pandas.util.testing as tm
tm.N = 3
def unpivot(frame):
N, K = frame.shape
data = {'value': frame.to_numpy().ravel('F'),
'variable': np.asarray(frame.columns).repeat(N),
'date': np.tile(np.asarray(frame.index), K)}
return pd.DataFrame(data, columns=['date', 'variable', 'value'])
df = unpivot(tm.makeTimeDataFrame())
Чтобы выбрать все для переменной A, можно сделать так:
In [2]: df[df['variable'] == 'A']
Out[2]:
date variable value
0 2000-01-03 A 0.469112
1 2000-01-04 A -0.282863
2 2000-01-05 A -1.509059
Но предположим, что мы хотим выполнить операции с временными рядами по переменным. Лучшим представлением будет тот случай, когда columns — это уникальные переменные, а index дат определяет отдельные наблюдения. Чтобы преобразовать данные в этот формат, используем метод DataFrame.pivot() (также реализован как функция верхнего уровня pivot()):
In [3]: df.pivot(index='date', columns='variable', values='value') Out[3]: variable A B C D date 2000-01-03 0.469112 -1.135632 0.119209 -2.104569 2000-01-04 -0.282863 1.212112 -1.044236 -0.494929 2000-01-05 -1.509059 -0.173215 -0.861849 1.071804
Если аргумент values опущен, а входной DataFrame имеет более одной колонки значений, которые не используются в качестве колонок или индексов для ввода в pivot, то полученная «повернутая» DataFrame будет иметь многоуровневые колонки, верхний уровень которых указывает на соответствующую колонку значений:
In [4]: df['value2'] = df['value'] * 2
In [5]: pivoted = df.pivot(index='date', columns='variable')
In [6]: pivoted
Out[6]:
value value2
variable A B C D A B C D
date
2000-01-03 0.469112 -1.135632 0.119209 -2.104569 0.938225 -2.271265 0.238417 -4.209138
2000-01-04 -0.282863 1.212112 -1.044236 -0.494929 -0.565727 2.424224 -2.088472 -0.989859
2000-01-05 -1.509059 -0.173215 -0.861849 1.071804 -3.018117 -0.346429 -1.723698 2.143608
Затем можно выбрать подмножества из повернутой DataFrame:
In [7]: pivoted['value2'] Out[7]: variable A B C D date 2000-01-03 0.938225 -2.271265 0.238417 -4.209138 2000-01-04 -0.565727 2.424224 -2.088472 -0.989859 2000-01-05 -3.018117 -0.346429 -1.723698 2.143608
Обратите внимание, что в случае однородных типов данных это возвращает вид на исходные данные.
Примечание
pivot() вернёт ошибку ValueError: Index contains duplicate
entries, cannot reshape, если пара индекс/колонка не уникальна. В этом случае рассмотрите использование pivot_table(), являющегося обобщением pivot, которое может обрабатывать дублирующие значения для одной пары индекс/колонка.
Преобразование формы с помощью стека и расстековки
Тесно связаны с методом pivot() связанные методы stack() и unstack(), доступные для Series и DataFrame. Эти методы предназначены для совместной работы с объектами MultiIndex (см. раздел многоуровневого индексирования). Вот в чём суть этих методов:
-
stack: «повернуть» уровень меток колонок (возможно, многоуровневых), возвращаяDataFrameс индексом с новым внутренним уровнем меток строк. -
unstack: (обратная операция кstack) «повернуть» уровень строчного индекса (возможно, многоуровневого) на ось колонок, создавая преобразованныйDataFrameс новым внутренним уровнем меток колонок.
Самый понятный способ объяснения — на примере. Возьмем предыдущий пример набора данных из раздела многоуровневого индексирования:
In [8]: tuples = list(zip(*[['bar', 'bar', 'baz', 'baz',
...: 'foo', 'foo', 'qux', 'qux'],
...: ['one', 'two', 'one', 'two',
...: 'one', 'two', 'one', 'two']]))
...:
In [9]: index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
In [10]: df = pd.DataFrame(np.random.randn(8, 2), index=index, columns=['A', 'B'])
In [11]: df2 = df[:4]
In [12]: df2
Out[12]:
A B
first second
bar one 0.721555 -0.706771
two -1.039575 0.271860
baz one -0.424972 0.567020
two 0.276232 -1.087401
Функция stack «сжимает» уровень в колонках DataFrame для получения либо:
- A
Series, в случае простого индекса колонок. - A
DataFrame, в случае многоуровневого индекса в колонках.
Если колонки имеют MultiIndex, можно выбрать, какой уровень стекировать. Стекируемый уровень становится новым самым нижним уровнем в MultiIndex по колонкам:
In [13]: stacked = df2.stack()
In [14]: stacked
Out[14]:
first second
bar one A 0.721555
B -0.706771
two A -1.039575
B 0.271860
baz one A -0.424972
B 0.567020
two A 0.276232
B -1.087401
dtype: float64
При «стековом» DataFrame или Series (имеющем MultiIndex в качестве index), обратная операция к stack — это unstack, которая по умолчанию расстекивает последний уровень:
In [15]: stacked.unstack()
Out[15]:
A B
first second
bar one 0.721555 -0.706771
two -1.039575 0.271860
baz one -0.424972 0.567020
two 0.276232 -1.087401
In [16]: stacked.unstack(1)
© 2008–2012, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team
Licensed under the 3-clause BSD License.
https://pandas.pydata.org/pandas-docs/version/0.24.2/user_guide/reshaping.html