У меня есть фрейм данных с иерархическим индексом по оси 1 (столбцы) (из groupby.agg
операции):
USAF WBAN year month day s_PC s_CL s_CD s_CNT tempf
sum sum sum sum amax amin
0 702730 26451 1993 1 1 1 0 12 13 30.92 24.98
1 702730 26451 1993 1 2 0 0 13 13 32.00 24.98
2 702730 26451 1993 1 3 1 10 2 13 23.00 6.98
3 702730 26451 1993 1 4 1 0 12 13 10.04 3.92
4 702730 26451 1993 1 5 3 0 10 13 19.94 10.94
Я хочу сгладить его, чтобы он выглядел следующим образом (имена не имеют решающего значения - я мог бы переименовать):
USAF WBAN year month day s_PC s_CL s_CD s_CNT tempf_amax tmpf_amin
0 702730 26451 1993 1 1 1 0 12 13 30.92 24.98
1 702730 26451 1993 1 2 0 0 13 13 32.00 24.98
2 702730 26451 1993 1 3 1 10 2 13 23.00 6.98
3 702730 26451 1993 1 4 1 0 12 13 10.04 3.92
4 702730 26451 1993 1 5 3 0 10 13 19.94 10.94
Как мне это сделать? (Я много пробовал, но безрезультатно.)
Согласно предложению, вот голова в диктовке
{('USAF', ''): {0: '702730',
1: '702730',
2: '702730',
3: '702730',
4: '702730'},
('WBAN', ''): {0: '26451', 1: '26451', 2: '26451', 3: '26451', 4: '26451'},
('day', ''): {0: 1, 1: 2, 2: 3, 3: 4, 4: 5},
('month', ''): {0: 1, 1: 1, 2: 1, 3: 1, 4: 1},
('s_CD', 'sum'): {0: 12.0, 1: 13.0, 2: 2.0, 3: 12.0, 4: 10.0},
('s_CL', 'sum'): {0: 0.0, 1: 0.0, 2: 10.0, 3: 0.0, 4: 0.0},
('s_CNT', 'sum'): {0: 13.0, 1: 13.0, 2: 13.0, 3: 13.0, 4: 13.0},
('s_PC', 'sum'): {0: 1.0, 1: 0.0, 2: 1.0, 3: 1.0, 4: 3.0},
('tempf', 'amax'): {0: 30.920000000000002,
1: 32.0,
2: 23.0,
3: 10.039999999999999,
4: 19.939999999999998},
('tempf', 'amin'): {0: 24.98,
1: 24.98,
2: 6.9799999999999969,
3: 3.9199999999999982,
4: 10.940000000000001},
('year', ''): {0: 1993, 1: 1993, 2: 1993, 3: 1993, 4: 1993}}
df[:5].to_dict()
в качестве примера для других, чтобы прочитать в вашем наборе данных?pandas
реализовать специальный метод для этого.dat.columns = dat.columns.to_flat_index()
. Встроенная функция панд.Ответы:
Я думаю, что самый простой способ сделать это - установить столбцы на верхний уровень:
Примечание: если у уровня to есть имя, вы также можете получить к нему доступ, а не 0.
,
Если вы хотите объединить /
join
ваш MultiIndex в один индекс (при условии, что в ваших столбцах есть только строковые записи), вы можете:Примечание: мы должны
strip
использовать пробел, когда нет второго индекса.источник
['_'.join(col).rstrip('_') for col in df.columns.values]
sum s_CD
вместоs_CD sum
, можно сделатьdf.columns = ['_'.join(col).rstrip('_') for col in [c[::-1] for c in df.columns.values]]
.источник
pd.DataFrame(df.to_records(), columns=df.index.names + list(df.columns))
pd.DataFrame(df_volume.to_records(), index=df_volume.index).drop('index', axis=1)
Все текущие ответы в этой теме должны быть немного устаревшими. Начиная с
pandas
версии 0.24.0, то.to_flat_index()
, что вам нужно.Из собственной документации панды :
Простой пример из своей документации:
Применяя
to_flat_index()
:Использование его для замены существующего
pandas
столбцаПример того, как вы используете его
dat
, это DataFrame соMultiIndex
столбцом:источник
Ответ Энди Хейдена, безусловно, самый простой - если вы хотите избежать дублирования меток столбцов, вам нужно немного подправить
источник
источник
И если вы хотите сохранить какую-либо информацию об агрегации со второго уровня мультииндекса, вы можете попробовать это:
источник
new_cols
не определеноСамый питонический способ сделать это, чтобы использовать
map
функцию.Выход
print(df.columns)
:Обновите с помощью Python 3.6+ с помощью строки f:
Вывод:
источник
Самым простым и интуитивным решением для меня было объединить имена столбцов с помощью get_level_values . Это предотвращает дублирование имен столбцов, когда вы выполняете несколько агрегаций в одном столбце:
Если вы хотите разделитель между столбцами, вы можете сделать это. Это вернет то же самое, что и комментарий Сейджи Армстронга о принятом ответе, который включает только подчеркивания для столбцов со значениями на обоих уровнях индекса:
Я знаю, что это делает то же самое, что и отличный ответ Энди Хейдена выше, но я думаю, что это немного более интуитивно понятно и его легче запомнить (поэтому мне не нужно постоянно ссылаться на эту ветку), особенно для начинающих пользователей панд. ,
Этот метод также более расширяем в случае, когда у вас может быть 3 уровня столбца.
источник
Прочитав все ответы, я придумал это:
Использование:
Учитывая фрейм данных:
Одиночный метод агрегации : результирующие переменные имеют то же имя, что и источник :
df.groupby(by="grouper",
as_index = False)
или.agg(...)
.reset_index ()Одна исходная переменная, несколько агрегатов : результирующие переменные, названные в соответствии со статистикой :
a = df.groupby(..).agg(..); a.columns = a.columns.droplevel(0); a.reset_index()
.Несколько переменных, несколько агрегаций : результирующие переменные с именем (varname) _ (statname) :
a.columns = ["_".join(filter(None, map(str, levels))) for levels in a.columns.values]
под капотом (так как эта формаagg()
приводитMultiIndex
к столбцам).my_flatten_cols
помощника, возможно, будет проще ввести решение, предложенное @Seigi :,a.columns = ["_".join(t).rstrip("_") for t in a.columns.values]
которое работает аналогично в этом случае (но не работает, если у вас есть числовые метки на столбцах)a.columns = ["_".join(tuple(map(str, t))).rstrip("_") for t in a.columns.values]
), но я не понимаю, зачемtuple()
нужен вызов, и считаю, чтоrstrip()
это необходимо только в том случае, если в некоторых столбцах есть дескриптор типа("colname", "")
( что может случиться, если выreset_index()
раньше пытались наладить.columns
)Вы хотите назвать получившиеся переменные вручную (это не рекомендуется , так как панды 0.20.0 с не адекватной альтернативы , как 0,23 )
res.columns = ['A_sum', 'B_sum', 'count']
или создание.join()
несколькихgroupby
операторов.Случаи, обрабатываемые вспомогательной функцией
map(str, ..)
filter(None, ..)
columns.values
возвращает имена (аstr
не кортежи).agg()
вам может понадобиться сохранить самый нижний ярлык для столбца или объединить несколько ярлыковreset_index()
иметь возможность работать со столбцами группировки обычным способом, поэтому он делает это по умолчаниюисточник
tuple()
это нужно, вы можете прокомментировать сообщение jxstanford. В противном случае, это может быть полезно для осмотра.columns.values
в указанном примере:[('val1', 'min'), (2, 'sum'), (2, 'size')]
. 1)for t in a.columns.values
зацикливается на столбцах, для второго столбцаt == (2, 'sum')
; 2)map(str, t)
применяетсяstr()
к каждому «уровню», в результате чего('2', 'sum')
; 3)"_".join(('2','sum'))
результаты в "2_суме",Общее решение, которое обрабатывает несколько уровней и смешанных типов:
источник
df.columns = ['_'.join(tuple(map(str, t))).rstrip('_') for t in df.columns.values]
Возможно, немного поздно, но если вы не беспокоитесь о повторяющихся именах столбцов:
источник
(year, )
и(tempf, amax)
Если вы хотите иметь разделитель в имени между уровнями, эта функция работает хорошо.
источник
df.columns = ["_".join(filter(None, c)) for c in df.columns]
После @jxstanford и @ tvt173 я написал быструю функцию, которая должна делать свое дело, независимо от имен столбцов string / int:
источник
Вы также можете сделать, как показано ниже. Считайте,
df
что ваш фрейм данных, и предположите двухуровневый индекс (как в вашем примере)источник
Я поделюсь прямым путем, который работал для меня.
источник
Чтобы сгладить MultiIndex внутри цепочки других методов DataFrame, определите функцию следующим образом:
Затем используйте
pipe
метод, чтобы применить эту функцию в цепочке методов DataFrame, послеgroupby
иagg
перед любыми другими методами в цепочке:источник
Еще одна простая рутина.
источник