pandas.melt()
и pandas.wide_to_long()
.pandas.melt()
отменяет поворот DataFrame
из широкого формата в длинный; pandas.wide_to_long()
похожа на pandas.melt()
, только с большей настраиваемостью сопоставления столбцов, но менее гибкая.pandas.melt()
и pandas.wide_to_long()
Функция pandas.melt()
и соответствующий метод DataFrame.melt()
полезны для преобразования DataFrame
в формат, где один или несколько столбцов являются переменными-идентификаторами, при этом все остальные столбцы, считающиеся измеряемыми переменными, "не привязаны" к оси строк, оставляя только два столбца без идентификаторов, "переменная" и "значение". Имена этих столбцов можно настроить, указав аргументы var_name
и value_name
.
>>> import pandas as pd cheese = pd.DataFrame( { "first": ["John", "Mary"], "last": ["Doe", "Bo"], "height": [5.5, 6.0], "weight": [130, 150], } ) >>> cheese # first last height weight # 0 John Doe 5.5 130 # 1 Mary Bo 6.0 150 >>> cheese.melt(id_vars=["first", "last"]) # first last variable value # 0 John Doe height 5.5 # 1 Mary Bo height 6.0 # 2 John Doe weight 130.0 # 3 Mary Bo weight 150.0 >>> cheese.melt(id_vars=["first", "last"], var_name="quantity") # first last quantity value # 0 John Doe height 5.5 # 1 Mary Bo height 6.0 # 2 John Doe weight 130.0 # 3 Mary Bo weight 150.0
При преобразовании DataFrame
с помощью pandas.melt()
индекс будет проигнорирован. Исходные значения индекса можно сохранить, установив для аргумента ignore_index=False
(по умолчанию True
). Аргумент ignore_index=False
будет дублировать значения индекса.
# создадим `MultiIndex` для предыдущего `DataFrame` >>> index = pd.MultiIndex.from_tuples([("person", "A"), ("person", "B")]) cheese = pd.DataFrame( { "first": ["John", "Mary"], "last": ["Doe", "Bo"], "height": [5.5, 6.0], "weight": [130, 150], }, index=index, ) >>> cheese # first last height weight # person A John Doe 5.5 130 # B Mary Bo 6.0 150 >>> cheese.melt(id_vars=["first", "last"]) # first last variable value # 0 John Doe height 5.5 # 1 Mary Bo height 6.0 # 2 John Doe weight 130.0 # 3 Mary Bo weight 150.0 >>> cheese.melt(id_vars=["first", "last"], ignore_index=False) # first last variable value # person A John Doe height 5.5 # B Mary Bo height 6.0 # A John Doe weight 130.0 # B Mary Bo weight 150.0
Функция pandas.wide_to_long()
похожа на функцию pandas.melt()
менее гибкая, но более удобная для пользователя с большей настраиваемостью сопоставления столбцов.
>>> import numpy as np dft = pd.DataFrame( { "A1970": {0: "a", 1: "b", 2: "c"}, "A1980": {0: "d", 1: "e", 2: "f"}, "B1970": {0: 2.5, 1: 1.2, 2: 0.7}, "B1980": {0: 3.2, 1: 1.3, 2: 0.1}, "X": dict(zip(range(3), np.random.randn(3))), } ) >>> dft["id"] = dft.index >>> dft # A1970 A1980 B1970 B1980 X id # 0 a d 2.5 3.2 0.534195 0 # 1 b e 1.2 1.3 -1.392514 1 # 2 c f 0.7 0.1 -1.372925 2 >>> pd.wide_to_long(dft, ["A", "B"], i="id", j="year") # X A B # id year # 0 1970 0.534195 a 2.5 # 1 1970 -1.392514 b 1.2 # 2 1970 -1.372925 c 0.7 # 0 1980 0.534195 d 3.2 # 1 1980 -1.392514 e 1.3 # 2 1980 -1.372925 f 0.1
pandas.melt(frame, id_vars=None, value_vars=None, var_name=None, value_name='value', col_level=None, ignore_index=True)
:Pandas предоставляет эквивалентный метод DataFrame.melt(), который принимает аналогичные аргументы за исключением
frame
, т.к. сам является вызывающим (исходным)DataFrame
.
Функция pandas.melt()
отменяет поворот DataFrame
из широкого формата в длинный, при необходимости оставив установленные идентификаторы.
Эта функция полезна для преобразования фрейма данных в формат, в котором один или несколько столбцов являются переменными-идентификаторами (id_vars
), в то время как все остальные столбцы, считаются измеряемыми переменными (value_vars
) - "не привязаны" к оси строк, оставляя только два столбца без идентификаторов, ‘variable’
и ‘value’
.
Принимаемые аргументы
frame
- исходный DataFrame
.id_vars=None
- столбцы, которые будут использоваться в качестве переменных-идентификаторов.value_vars=None
- столбцы, которые нужно отключить. Если не указано, то будут использоваться все столбцы, которые не заданы как id_vars
.var_name=None
- имя, используемое для столбца ‘variable’
. Если его нет, то используется frame.columns.name
или ‘variable’
.value_name='value'
- имя, которое будет использоваться для столбца ‘value’.col_level=None
- используйте этот уровень, если столбцы являются MultiIndex
.ignore_index=True
- если True
, то исходный индекс игнорируется. Если False
, исходный индекс сохраняется. Метки индексов будут повторяться по мере необходимости.pandas.melt()
:>>> import pandas as pd df = pd.DataFrame({'A': {0: 'a', 1: 'b', 2: 'c'}, 'B': {0: 1, 1: 3, 2: 5}, 'C': {0: 2, 1: 4, 2: 6}}) >>> df # A B C # 0 a 1 2 # 1 b 3 4 # 2 c 5 6 >>> pd.melt(df, id_vars=['A'], value_vars=['B']) # A variable value # 0 a B 1 # 1 b B 3 # 2 c B 5 >>> pd.melt(df, id_vars=['A'], value_vars=['B', 'C']) # A variable value # 0 a B 1 # 1 b B 3 # 2 c B 5 # 3 a C 2 # 4 b C 4 # 5 c C 6
Имена столбцов ‘variable’
и ‘value’
можно настроить:
>>> pd.melt(df, id_vars=['A'], value_vars=['B'], ... var_name='myVarname', value_name='myValname') # A myVarname myValname # 0 a B 1 # 1 b B 3 # 2 c B 5
Исходные значения индекса могут быть сохранены:
>>> pd.melt(df, id_vars=['A'], value_vars=['B', 'C'], ignore_index=False) # A variable value # 0 a B 1 # 1 b B 3 # 2 c B 5 # 0 a C 2 # 1 b C 4 # 2 c C 6
Если есть столбцы имеют MultiIndex
:
>>> df.columns = [list('ABC'), list('DEF')] >>> df # A B C # D E F # 0 a 1 2 # 1 b 3 4 # 2 c 5 6 >>> pd.melt(df, col_level=0, id_vars=['A'], value_vars=['B']) # A variable value # 0 a B 1 # 1 b B 3 # 2 c B 5 >>> pd.melt(df, id_vars=[('A', 'D')], value_vars=[('B', 'E')]) # (A, D) variable_0 variable_1 value # 0 a B E 1 # 1 b B E 3 # 2 c B E 5
pandas.wide_to_long(df, stubnames, i, j, sep='', suffix='\\d+')
:Функция pandas.wide_to_long()
похожа на функцию pandas.melt()
. Более удобная для пользователя (менее гибкая, но с большей настраиваемостью сопоставления столбцов).
С помощью stubnames=[‘A’, ‘B’]
эта функция ожидает найти одну или несколько групп столбцов формата A-suffix1
, A-suffix2
,..., B-suffix1
, B-suffix2
,… В результирующем формате с помощью аргумента j
(например, j=’year’
) указываем, как нужно назвать этот суффикс.
Предполагается, что каждая строка этих переменных однозначно идентифицируется символом, переданным аргументу i
(это может быть имя одного столбца или список имен столбцов)
Все остальные переменные остаются нетронутыми. Здесь под капотом просто используется pandas.melt()
, но жестко запрограммирован для "правильного действия" в типичном случае.
Принимаемые аргументы
df
- исходный DataFrame
.stubnames
- имя/имена префиксов. Предполагается, что столбцов с суффиксами начинаются с этих префиксов.i
- столбец/столбцы, которые будут использоваться в качестве идентификаторов переменных.j
- имя переменной поднаблюдения. Как нужно назвать объединенный столбец (аргумент i
) в новом формате данных.sep=''
- символ, обозначающий разделение имен переменных (с суффиксами), который должен быть удален из имен. Например, если имена столбцов A-suffix1
, A-suffix2
, то можно убрать дефис, указав sep=’-’.suffix='\d+'
- регулярное выражение, фиксирующее нужные суффиксы. Регулярное выражение '\d+'
фиксирует числовые суффиксы. Суффиксы без чисел могут быть указаны с помощью класса отрицаемых символов '\D+'
. Дополнительно можно устранить неоднозначность суффиксов, например, если переменные имеют вид A-one
, B-two
, .. , и есть несвязанный столбец A-rating
, то можно проигнорировать последний, указав suffix='(!?one|two)'
. Когда все суффиксы являются числовыми, они преобразуются в int64
/float64
.pandas.wide_to_long()
:>>> import pandas as pd >>> import numpy as np >>> np.random.seed(123) df = pd.DataFrame({"A1970" : {0 : "a", 1 : "b", 2 : "c"}, "A1980" : {0 : "d", 1 : "e", 2 : "f"}, "B1970" : {0 : 2.5, 1 : 1.2, 2 : .7}, "B1980" : {0 : 3.2, 1 : 1.3, 2 : .1}, "X" : dict(zip(range(3), np.random.randn(3))) }) >>> df["id"] = df.index >>> df # A1970 A1980 B1970 B1980 X id # 0 a d 2.5 3.2 -1.085631 0 # 1 b e 1.2 1.3 0.997345 1 # 2 c f 0.7 0.1 0.282978 2 >>> pd.wide_to_long(df, ["A", "B"], i="id", j="year") # X A B # id year # 0 1970 -1.085631 a 2.5 # 1 1970 0.997345 b 1.2 # 2 1970 0.282978 c 0.7 # 0 1980 -1.085631 d 3.2 # 1 1980 0.997345 e 1.3 # 2 1980 0.282978 f 0.1
С несколькими столбцами идентификаторов
df = pd.DataFrame({ 'famid': [1, 1, 1, 2, 2, 2, 3, 3, 3], 'birth': [1, 2, 3, 1, 2, 3, 1, 2, 3], 'ht1': [2.8, 2.9, 2.2, 2, 1.8, 1.9, 2.2, 2.3, 2.1], 'ht2': [3.4, 3.8, 2.9, 3.2, 2.8, 2.4, 3.3, 3.4, 2.9] }) >>> df # famid birth ht1 ht2 # 0 1 1 2.8 3.4 # 1 1 2 2.9 3.8 # 2 1 3 2.2 2.9 # 3 2 1 2.0 3.2 # 4 2 2 1.8 2.8 # 5 2 3 1.9 2.4 # 6 3 1 2.2 3.3 # 7 3 2 2.3 3.4 # 8 3 3 2.1 2.9 >>> l = pd.wide_to_long(df, stubnames='ht', i=['famid', 'birth'], j='age') >>> l # ht # famid birth age # 1 1 1 2.8 # 2 3.4 # 2 1 2.9 # 2 3.8 # 3 1 2.2 # 2 2.9 # 2 1 1 2.0 # 2 3.2 # 2 1 1.8 # 2 2.8 # 3 1 1.9 # 2 2.4 # 3 1 1 2.2 # 2 3.3 # 2 1 2.3 # 2 3.4 # 3 1 2.1 # 2 2.9
Переход от длинного DataFrame
к широкому требует некоторого творческого использования DataFrame.unstack()
>>> w = l.unstack() >>> w.columns = w.columns.map('{0[0]}{0[1]}'.format) >>> w.reset_index() # famid birth ht1 ht2 # 0 1 1 2.8 3.4 # 1 1 2 2.9 3.8 # 2 1 3 2.2 2.9 # 3 2 1 2.0 3.2 # 4 2 2 1.8 2.8 # 5 2 3 1.9 2.4 # 6 3 1 2.2 3.3 # 7 3 2 2.3 3.4 # 8 3 3 2.1 2.9
Также обрабатываются менее сложные имена столбцов
>>> np.random.seed(0) df = pd.DataFrame({'A(weekly)-2010': np.random.rand(3), 'A(weekly)-2011': np.random.rand(3), 'B(weekly)-2010': np.random.rand(3), 'B(weekly)-2011': np.random.rand(3), 'X' : np.random.randint(3, size=3)}) >>> df['id'] = df.index >>> df # A(weekly)-2010 A(weekly)-2011 B(weekly)-2010 B(weekly)-2011 X id # 0 0.548814 0.544883 0.437587 0.383442 0 0 # 1 0.715189 0.423655 0.891773 0.791725 1 1 # 2 0.602763 0.645894 0.963663 0.528895 1 2 >>> pd.wide_to_long(df, ['A(weekly)', 'B(weekly)'], i='id', j='year', sep='-') # X A(weekly) B(weekly) # id year # 0 2010 0 0.548814 0.437587 # 1 2010 1 0.715189 0.891773 # 2 2010 1 0.602763 0.963663 # 0 2011 0 0.544883 0.383442 # 1 2011 1 0.423655 0.791725 # 2 2011 1 0.645894 0.528895
Если фрейм содержит много столбцов, то можно использовать регулярное выражение для поиска имен-префиксов и передачи этого списка в pandas.wide_to_long()
stubnames = sorted( set([match[0] for match in df.columns.str.findall( r'[A-B]\(.*\)').values if match != []]) ) >>> list(stubnames) # ['A(weekly)', 'B(weekly)']
Во всех приведенных выше примерах в качестве суффиксов используются целые числа. В качестве суффиксов могут использоваться строки.
df = pd.DataFrame({ 'famid': [1, 1, 1, 2, 2, 2, 3, 3, 3], 'birth': [1, 2, 3, 1, 2, 3, 1, 2, 3], 'ht_one': [2.8, 2.9, 2.2, 2, 1.8, 1.9, 2.2, 2.3, 2.1], 'ht_two': [3.4, 3.8, 2.9, 3.2, 2.8, 2.4, 3.3, 3.4, 2.9] }) >>> df # famid birth ht_one ht_two # 0 1 1 2.8 3.4 # 1 1 2 2.9 3.8 # 2 1 3 2.2 2.9 # 3 2 1 2.0 3.2 # 4 2 2 1.8 2.8 # 5 2 3 1.9 2.4 # 6 3 1 2.2 3.3 # 7 3 2 2.3 3.4 # 8 3 3 2.1 2.9 >>> l = pd.wide_to_long(df, stubnames='ht', i=['famid', 'birth'], j='age', sep='_', suffix=r'\w+') >>> l # ht # famid birth age # 1 1 one 2.8 # two 3.4 # 2 one 2.9 # two 3.8 # 3 one 2.2 # two 2.9 # 2 1 one 2.0 # two 3.2 # 2 one 1.8 # two 2.8 # 3 one 1.9 # two 2.4 # 3 1 one 2.2 # two 3.3 # 2 one 2.3 # two 3.4 # 3 one 2.1 # two 2.9