Eu tenho um quadro de dados com um índice hierárquico no eixo 1 (colunas) (de uma groupby.agg
operação):
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
Quero aplainá-lo, para que fique assim (os nomes não são críticos - eu poderia renomear):
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
Como eu faço isso? (Eu tentei muito, sem sucesso.)
Por sugestão, aqui está a cabeça em forma de ditado
{('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()
como um exemplo para outras pessoas lerem no seu conjunto de dados?pandas
rastreador de problemas para implementar um método dedicado para isso.dat.columns = dat.columns.to_flat_index()
. Função de pandas incorporada.Respostas:
Eu acho que a maneira mais fácil de fazer isso seria definir as colunas para o nível superior:
Nota: se o nível to tiver um nome, você também poderá acessá-lo por este, em vez de 0.
.
Se você deseja combinar /
join
seu MultiIndex em um índice (supondo que você tenha apenas entradas de string em suas colunas), você pode:Nota: precisamos
strip
o espaço em branco para quando não houver um segundo índice.fonte
['_'.join(col).rstrip('_') for col in df.columns.values]
sum s_CD
vez des_CD sum
, pode-se fazerdf.columns = ['_'.join(col).rstrip('_') for col in [c[::-1] for c in df.columns.values]]
.fonte
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)
Todas as respostas atuais neste tópico devem ter sido um pouco datadas. A partir da
pandas
versão 0.24.0, o.to_flat_index()
que você precisa.Da documentação do panda :
Um exemplo simples de sua documentação:
Aplicando
to_flat_index()
:Utilizando-o para substituir os existentes
pandas
colunaUm exemplo de como você o utilizaria
dat
, que é um DataFrame com umaMultiIndex
coluna:fonte
A resposta de Andy Hayden é certamente a maneira mais fácil - se você quiser evitar rótulos de coluna duplicados, precisará ajustar um pouco
fonte
fonte
E se você deseja reter alguma das informações de agregação do segundo nível do multi-índice, você pode tentar o seguinte:
fonte
new_cols
não está definido.A maneira mais pitônica de fazer isso para usar a
map
funçãoSaída
print(df.columns)
:Atualize usando Python 3.6+ com a string f:
Resultado:
fonte
A solução mais fácil e intuitiva para mim foi combinar os nomes das colunas usando get_level_values . Isso evita nomes de colunas duplicados quando você faz mais de uma agregação na mesma coluna:
Se você deseja um separador entre colunas, você pode fazer isso. Isso retornará o mesmo que o comentário de Seiji Armstrong na resposta aceita, que inclui apenas sublinhados para colunas com valores nos dois níveis de índice:
Eu sei que isso faz o mesmo que a ótima resposta de Andy Hayden acima, mas acho que é um pouco mais intuitivo e fácil de lembrar (por isso não preciso continuar me referindo a esse tópico), especialmente para usuários iniciantes de pandas .
Esse método também é mais extensível no caso em que você pode ter três níveis de coluna.
fonte
Depois de ler todas as respostas, vim com isso:
Uso:
Dado um quadro de dados:
Método de agregação único : variáveis resultantes nomeadas da mesma forma que fonte :
df.groupby(by="grouper",
a_index = False)
ou.agg(...)
.reset_index ()Variável de origem única, várias agregações : variáveis resultantes nomeadas após estatísticas :
a = df.groupby(..).agg(..); a.columns = a.columns.droplevel(0); a.reset_index()
.Várias variáveis, várias agregações : variáveis resultantes nomeadas (varname) _ (statname) :
a.columns = ["_".join(filter(None, map(str, levels))) for levels in a.columns.values]
sob o capô (já que essa forma deagg()
resultado emMultiIndex
colunas).my_flatten_cols
ajudante, que poderia ser mais fácil de digitar a solução sugerida por @Seigi :a.columns = ["_".join(t).rstrip("_") for t in a.columns.values]
, que funciona de forma semelhante, neste caso (mas não se você tem rótulos numéricos em colunas)a.columns = ["_".join(tuple(map(str, t))).rstrip("_") for t in a.columns.values]
), mas não entendo por que atuple()
chamada é necessária e acredito querstrip()
só será necessária se algumas colunas tiverem um descritor como("colname", "")
( o que pode acontecer se vocêreset_index()
antes de tentar consertar.columns
)Você deseja nomear as variáveis resultantes manualmente: (isso é obsoleto desde pandas 0.20.0 com qualquer alternativa adequada a partir de 0,23 )
res.columns = ['A_sum', 'B_sum', 'count']
ou.join()
ing váriasgroupby
instruções.Casos tratados pela função auxiliar
map(str, ..)
filter(None, ..)
columns.values
retorna os nomes (str
e não as tuplas).agg()
pode ser necessário manter o rótulo mais baixo de uma coluna ou concatenar vários rótulosreset_index()
poder trabalhar com as colunas agrupar de maneira regular, por isso é o padrãofonte
tuple()
é necessário comentar a publicação de jxstanford. Caso contrário, ele pode ser útil para inspecionar o.columns.values
no exemplo fornecido:[('val1', 'min'), (2, 'sum'), (2, 'size')]
. 1)for t in a.columns.values
loops sobre as colunas, para a segunda colunat == (2, 'sum')
; 2)map(str, t)
se aplicastr()
a cada "nível", resultando em('2', 'sum')
; 3)"_".join(('2','sum'))
resulta em "2_sum",Uma solução geral que lida com vários níveis e tipos mistos:
fonte
df.columns = ['_'.join(tuple(map(str, t))).rstrip('_') for t in df.columns.values]
Um pouco tarde, talvez, mas se você não estiver preocupado com nomes de colunas duplicados:
fonte
(year, )
e(tempf, amax)
Caso você queira ter um separador no nome entre os níveis, essa função funcionará bem.
fonte
df.columns = ["_".join(filter(None, c)) for c in df.columns]
Seguindo @jxstanford e @ tvt173, escrevi uma função rápida que deveria resolver o problema, independentemente dos nomes das colunas string / int:
fonte
Você também pode fazer o seguinte. Considere
df
ser o seu dataframe e assuma um índice de dois níveis (como é o caso no seu exemplo)fonte
Vou compartilhar uma maneira direta que funcionou para mim.
fonte
Para nivelar um MultiIndex dentro de uma cadeia de outros métodos DataFrame, defina uma função como esta:
Em seguida, use o
pipe
método para aplicar esta função na cadeia de métodos DataFrame, antesgroupby
e depois deagg
qualquer outro método na cadeia:fonte
Outra rotina simples.
fonte