Eu tenho um quadro de dados em que algumas células contêm listas de vários valores. Em vez de armazenar vários valores em uma célula, eu gostaria de expandir o quadro de dados para que cada item da lista obtenha sua própria linha (com os mesmos valores em todas as outras colunas). Então, se eu tiver:
import pandas as pd
import numpy as np
df = pd.DataFrame(
{'trial_num': [1, 2, 3, 1, 2, 3],
'subject': [1, 1, 1, 2, 2, 2],
'samples': [list(np.random.randn(3).round(2)) for i in range(6)]
}
)
df
Out[10]:
samples subject trial_num
0 [0.57, -0.83, 1.44] 1 1
1 [-0.01, 1.13, 0.36] 1 2
2 [1.18, -1.46, -0.94] 1 3
3 [-0.08, -4.22, -2.05] 2 1
4 [0.72, 0.79, 0.53] 2 2
5 [0.4, -0.32, -0.13] 2 3
Como faço para converter para formato longo, por exemplo:
subject trial_num sample sample_num
0 1 1 0.57 0
1 1 1 -0.83 1
2 1 1 1.44 2
3 1 2 -0.01 0
4 1 2 1.13 1
5 1 2 0.36 2
6 1 3 1.18 0
# etc.
O índice não é importante, não há problema em definir colunas existentes como o índice e a ordem final não é importante.
df.explode('samples')
para resolver isso.explode
só pode suportar a explosão de uma coluna por enquanto.Respostas:
Resultado:
PS aqui você pode encontrar uma solução um pouco mais genérica
UPDATE: algumas explicações: A IMO, a maneira mais fácil de entender esse código, é tentar executá-lo passo a passo:
na linha seguinte, estamos repetindo valores em uma coluna
N
vezes ondeN
- é o comprimento da lista correspondente:isso pode ser generalizado para todas as colunas, contendo valores escalares:
usando
np.concatenate()
podemos achatar todos os valores nalist
coluna (samples
) e obter um vetor 1D:colocando tudo isso junto:
usando
pd.DataFrame()[df.columns]
garantirá que estamos selecionando colunas na ordem original ...fonte
lst_col
inteiramente as linhas que possuem uma lista vazia ; para manter essas linhas e preencher sualst_col
comnp.nan
, você pode apenas fazerdf[lst_col] = df[lst_col].apply(lambda x: x if len(x) > 0 else [np.nan])
antes de usar este método. Evidentemente.mask
não retornará listas, daí o.apply
.Um pouco mais do que eu esperava:
Se você deseja um índice seqüencial, pode aplicar
reset_index(drop=True)
- se ao resultado.update :
fonte
df.apply(lambda x: pd.Series(x['samples']),axis=1)
pordf.samples.apply(pd.Series)
.df.explode()
como mostrado aqui.Pandas> = 0,25
Os métodos Series e DataFrame definem um
.explode()
método que explode listas em linhas separadas. Consulte a seção de documentos em Explodindo uma coluna do tipo lista .Observe que isso também lida com colunas mistas de listas e escalares, bem como listas vazias e NaNs adequadamente (essa é uma desvantagem de
repeat
soluções baseadas em).No entanto, observe que
explode
só funciona em uma única coluna (por enquanto).PS: se você estiver procurando explodir uma coluna de strings , primeiro precisará dividir em um separador e depois usar
explode
. Veja esta (muito) resposta relacionada por mim.fonte
você também pode usar
pd.concat
epd.melt
para isso:por último, se você precisar, pode classificar a base nas primeiras três primeiras colunas.
fonte
Tentando trabalhar com a solução de Roman Pekar passo a passo para entendê-la melhor, criei minha própria solução, usada
melt
para evitar parte do empilhamento confuso e da redefinição do índice. Não posso dizer que é obviamente uma solução mais clara:Saída (obviamente, podemos soltar a coluna de amostras originais agora):
fonte
Para aqueles que procuram uma versão da resposta de Roman Pekar que evita a nomeação manual de colunas:
fonte
Eu achei a maneira mais fácil de:
samples
coluna em um DataFrameMostrado aqui:
Vale ressaltar que isso pode ter funcionado apenas porque cada tentativa tem o mesmo número de amostras (3). Algo mais inteligente pode ser necessário para ensaios com diferentes tamanhos de amostra.
fonte
Resposta muito tardia, mas quero acrescentar isso:
Uma solução rápida usando Python baunilha que também cuida da
sample_num
coluna no exemplo do OP. No meu próprio conjunto de dados grande, com mais de 10 milhões de linhas e um resultado com 28 milhões de linhas, isso leva apenas cerca de 38 segundos. A solução aceita se decompõe completamente com essa quantidade de dados e leva a ummemory error
sistema que possui 128 GB de RAM.fonte
Também muito tarde, mas aqui está uma resposta de Karvy1 que funcionou bem para mim se você não tiver pandas> = 0,25 versão: https://stackoverflow.com/a/52511166/10740287
Para o exemplo acima, você pode escrever:
Teste rápido:
1,33 ms ± 74,8 µs por loop (média ± desvio padrão de 7 corridas, 1000 loops cada)
4,9 ms ± 189 µs por loop (média ± desvio padrão de 7 corridas, 100 loops cada)
1,38 ms ± 25 µs por loop (média ± desvio padrão de 7 corridas, 1000 loops cada)
fonte
Tente isso em pandas> = 0,25 versão
fonte
.str.split(',')
porquePrices
já é uma lista.