DataFrame.stack()
и DataFrame.unstack()
.DataFrame.stack()
- "сводит" уровень меток столбцов (возможно, иерархический) к оси индекса строк;DataFrame.unstack()
- "сводит" уровень индекса строки (возможно, иерархический) к оси столбца;DataFrame.stack()
и DataFrame.unstack()
С методом DataFrame.pivot()
тесно связаны методы DataFrame.stack()
и DataFrame.unstack()
, которые доступны для Series
и DataFrame
. Эти методы предназначены для совместной работы с объектами MultiIndex
.
метод DataFrame.stack()
: "сводит" уровень (возможно, иерархический) меток столбцов, возвращая a DataFrame
с новым, самым внутренним уровнем меток строк.
метод DataFrame.unstack()
: (обратная операция DataFrame.stack()
) "сводит" уровень индекса строки (возможно, иерархический) к оси столбца, создавая измененный DataFrame
с новым, самым внутренним уровнем меток столбцов.
tuples = [ ["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"], ["one", "two", "one", "two", "one", "two", "one", "two"], ] >>> import pandas as pd >>> import numpy as np >>> index = pd.MultiIndex.from_arrays(tuples, names=["first", "second"]) >>> df = pd.DataFrame(np.random.randn(8, 2), index=index, columns=["A", "B"]) >>> df2 = df[:4] >>> df2 df2 A B first second bar one -0.325765 -1.455506 two -0.909177 0.081546 baz one 0.128316 -0.435166 two -0.308656 2.402403
Метод DataFrame.stack()
"сжимает" уровень в столбцах DataFrame
, и получает одно из следующих значений:
Series
, в случае Index
в столбцах.DataFrame
, в случае MultiIndex
в столбцах.Если столбцы имеют MultiIndex
, то можно выбрать, какой уровень складывать. Уровень с накоплением становится новым самым низким уровнем в MultiIndex
по столбцам:
>>> stacked = df2.stack(future_stack=True) >>> stacked first second bar one A -0.325765 B -1.455506 two A -0.909177 B 0.081546 baz one A 0.128316 B -0.435166 two A -0.308656 B 2.402403 dtype: float64
С “многоуровневым” DataFrame или Series (имеющим MultiIndex
в качестве индекса строк) обратной операцией DataFrame.stack()
является DataFrame.unstack()
, которая по умолчанию разархивирует последний уровень:
>>> stacked.unstack() A B first second bar one -0.325765 -1.455506 two -0.909177 0.081546 baz one 0.128316 -0.435166 two -0.308656 2.402403 >>> stacked.unstack(1) second one two first bar A -0.325765 -0.909177 B -1.455506 0.081546 baz A 0.128316 -0.308656 B -0.435166 2.402403 >>> stacked.unstack(0) first bar baz second one A -0.325765 0.128316 B -1.455506 -0.435166 two A -0.909177 -0.308656 B 0.081546 2.402403
Если индексы имеют имена, то можно использовать имена меток уровней вместо номеров уровней:
>>> stacked.unstack("second") second one two first bar A -0.325765 -0.909177 B -1.455506 0.081546 baz A 0.128316 -0.308656 B -0.435166 2.402403
Обратите внимание, что методы DataFrame.stack()
и DataFrame.unstack()
неявно сортируют задействованные уровни индекса. Следовательно, вызов DataFrame.stack()
, а затем DataFrame.unstack()
, или наоборот, приведет к отсортированной копии исходного DataFrame
или Series
:
>>> index = pd.MultiIndex.from_product([[2, 1], ["a", "b"]]) >>> df = pd.DataFrame(np.random.randn(4), index=index, columns=["A"]) >>> df A 2 a 0.109137 b 0.104417 1 a -0.427419 b -0.976336 >>> all(df.unstack().stack(future_stack=True) == df.sort_index()) # True
columns = pd.MultiIndex.from_tuples( [ ("A", "cat", "long"), ("B", "cat", "long"), ("A", "dog", "short"), ("B", "dog", "short"), ], names=["exp", "animal", "hair_length"], ) >>> df = pd.DataFrame(np.random.randn(4, 4), columns=columns) >>> df exp A B A B animal cat cat dog dog hair_length long long short short 0 0.613395 0.069411 -0.843289 -0.935644 1 -0.556056 0.321497 0.742493 -1.329095 2 -0.828012 -0.477574 -0.208956 0.124899 3 1.674502 -0.127979 -0.204078 0.676785 >>> df.stack(level=["animal", "hair_length"], future_stack=True) exp A B animal hair_length 0 cat long 0.613395 0.069411 dog short -0.843289 -0.935644 1 cat long -0.556056 0.321497 dog short 0.742493 -1.329095 2 cat long -0.828012 -0.477574 dog short -0.208956 0.124899 3 cat long 1.674502 -0.127979 dog short -0.204078 0.676785
Список уровней может содержать либо имена, либо номера уровней, но не их сочетание.
# предыдущий пример эквивалентен: >>> df.stack(level=[1, 2], future_stack=True) exp A B animal hair_length 0 cat long 0.613395 0.069411 dog short -0.843289 -0.935644 1 cat long -0.556056 0.321497 dog short 0.742493 -1.329095 2 cat long -0.828012 -0.477574 dog short -0.208956 0.124899 3 cat long 1.674502 -0.127979 dog short -0.204078 0.676785
Распаковка может привести к пропущенным значениям, если подгруппы не имеют одинакового набора меток. По умолчанию пропущенные значения будут заменены значением по умолчанию для этого типа данных.
columns = pd.MultiIndex.from_tuples( [ ("A", "cat"), ("B", "dog"), ("B", "cat"), ("A", "dog"), ], names=["exp", "animal"], ) index = pd.MultiIndex.from_product( [("bar", "baz", "foo", "qux"), ("one", "two")], names=["first", "second"] ) >>> df = pd.DataFrame(np.random.randn(8, 4), index=index, columns=columns) >>> df3 = df.iloc[[0, 1, 4, 7], [1, 2]] >>> df3 exp B animal dog cat first second bar one -0.232130 -0.496571 two 0.184100 -0.553932 foo one 0.603123 -0.321162 qux two -0.626404 -0.434028
Отсутствующее значение может быть заполнено определенным значением с помощью аргумента fill_value
.
>>> df3.unstack(fill_value=-1e9) exp B animal dog cat second one two one two first bar -2.321301e-01 1.840997e-01 -4.965706e-01 -5.539317e-01 foo 6.031231e-01 -1.000000e+09 -3.211621e-01 -1.000000e+09 qux -1.000000e+09 -6.264035e-01 -1.000000e+09 -4.340277e-01
DataFrame.stack(level=-1, dropna=no_default, sort=no_default, future_stack=False)
:Метод DataFrame.stack()
"сводит" уровень меток столбцов (возможно, иерархический) к оси индекса строк, возвращая измененный DataFrame
с новым, самым внутренним уровнем меток строк.
Возвращает измененный DataFrame
или Series
, имеющий многоуровневый индекс с одним или несколькими новыми внутренними уровнями по сравнению с текущим DataFrame
. Новые самые внутренние уровни создаются путем поворота столбцов текущего DataFrame
:
Series
;DataFrame
.Метод назван по аналогии с коллекцией книг, которые реорганизуются из горизонтального положения (столбцы фрейма данных) в вертикальное расположение друг над другом (в индексе
DataFrame
).
Принимаемые аргументы
level=-1
- номер уровня (уровней как список значений) столбца для складывания к оси индекса. Можно передавать имя метки уровня.dropna=True
- следует ли удалять строки в результирующем DataFrame
/Series
с пропущенными значениями NA
. Наложение уровня столбца на ось индекса может создать комбинации значений индекса и столбца, которые отсутствуют в исходном DataFrame
.sort=True
- следует ли сортировать уровни результирующего MultiIndex
.future_stack=False
- следует ли использовать новую реализацию, которая заменит текущую реализацию в pandas
3.0. При значении True
dropna
и sort
не влияют на результат и должны оставаться неопределенными.DataFrame.stack()
Одноуровневые столбцы
>>> import pandas as pd df_single_level_cols = pd.DataFrame([[0, 1], [2, 3]], index=['cat', 'dog'], columns=['weight', 'height']) >>> df_single_level_cols weight height cat 0 1 dog 2 3
Сведение DataFrame
с осью столбца одного уровня, возвращает Series
:
>>> df_single_level_cols.stack(future_stack=True) cat weight 0 height 1 dog weight 2 height 3 dtype: int64
Многоуровневые столбцы: простой случай
df_multi_level_cols1multicol1 = pd.MultiIndex.from_tuples([('weight', 'kg'), ('weight', 'pounds')]) df_multi_level_cols1 = pd.DataFrame([[1, 2], [2, 4]], index=['cat', 'dog'], columns=multicol1) >>> df_multi_level_cols1 weight kg pounds cat 1 2 dog 2 4
Объединение DataFrame
с многоуровневой осью столбца:
>>> df_multi_level_cols1.stack(future_stack=True) weight cat kg 1 pounds 2 dog kg 2 pounds 4
Отсутствующие значения NA
multicol2 = pd.MultiIndex.from_tuples([('weight', 'kg'), ('height', 'm')]) df_multi_level_cols2 = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]], index=['cat', 'dog'], columns=multicol2) >>> df_multi_level_cols2 weight height kg m cat 1.0 2.0 dog 3.0 4.0
При объединении DataFrame
с многоуровневыми столбцами часто возникают пропущенные значения, т.к. составной фрейм данных обычно имеет больше значений, чем исходный фрейм данных. Пропущенные значения заполняются NaN
:
>>> df_multi_level_cols2.stack(future_stack=True) weight height cat kg 1.0 NaN m NaN 2.0 dog kg 3.0 NaN m NaN 4.0
Указание уровня(ей) для сведения
Первый аргумент ``level определяет, какой уровень или уровни складываются:
>>> df_multi_level_cols2.stack(0, future_stack=True) kg m cat weight 1.0 NaN height NaN 2.0 dog weight 3.0 NaN height NaN 4.0 >>> df_multi_level_cols2.stack([0, 1], future_stack=True) cat weight kg 1.0 height m 2.0 dog weight kg 3.0 height m 4.0 dtype: float64
Удаление пропущенных значений
df_multi_level_cols3 = pd.DataFrame([[None, 1.0], [2.0, 3.0]], index=['cat', 'dog'], columns=multicol2) >>> df_multi_level_cols3 weight height kg m cat NaN 1.0 dog 2.0 3.0
Обратите внимание, что строки, в которых отсутствуют все значения, по умолчанию удаляются, но этим поведением можно управлять с помощью ключевого аргумента dropna
:
>>> df_multi_level_cols3.stack(dropna=False) weight height cat kg NaN NaN m NaN 1.0 dog kg 2.0 NaN m NaN 3.0 >>> df_multi_level_cols3.stack(dropna=True) weight height cat m NaN 1.0 dog kg 2.0 NaN m NaN 3.0
DataFrame.unstack(level=-1, fill_value=None, sort=True)
:Метод DataFrame.unstack()
- обратная операция DataFrame.stack()
. "Сводит" уровень индекса строки (возможно, иерархический) к оси столбца, создавая измененный DataFrame
с новым, самым внутренним уровнем меток столбцов.
Метод возвращает DataFrame
, имеющий новый уровень меток столбцов, самый внутренний уровень которого состоит из меток сводного индекса.
Если индекс не является MultiIndex
, то результатом будет Series
(аналог стека, когда столбцы не являются многоиндексными).
Принимаемые аргументы
level=-1
- номер уровня (уровней как список значений) индекса для извлечения, можно передавать имя метки уровня.fill_value=None
- заменяет NaN
этим значением, если при извлечении из стека значения отсутствуют.sort=True
- следует ли сортировать уровни результирующего MultiIndex
.DataFrame.unstack()
>>> import pandas as pd index = pd.MultiIndex.from_tuples([('one', 'a'), ('one', 'b'), ('two', 'a'), ('two', 'b')]) >>> s = pd.Series(np.arange(1.0, 5.0), index=index) >>> s one a 1.0 b 2.0 two a 3.0 b 4.0 dtype: float64
>>> s.unstack(level=-1) a b one 1.0 2.0 two 3.0 4.0 >>> s.unstack(level=0) one two a 1.0 3.0 b 2.0 4.0 >>> df = s.unstack(level=0) >>> df.unstack() one a 1.0 b 2.0 two a 3.0 b 4.0 dtype: float64