python - "Desapilar" una columna de pandas que contiene listas en varias filas
dataframe (2)
Esta pregunta ya tiene una respuesta aquí:
Digamos que tengo el siguiente marco de datos de Pandas:
df = pd.DataFrame({"a" : [1,2,3], "b" : [[1,2],[2,3,4],[5]]})
a b
0 1 [1, 2]
1 2 [2, 3, 4]
2 3 [5]
¿Cómo "desapilaría" las listas en la columna "b" para transformarlas en el marco de datos:
a b
0 1 1
1 1 2
2 2 2
3 2 3
4 2 4
5 3 5
Aquí hay otro enfoque con
itertuples
:
df = pd.DataFrame({"a" : [1,2,3], "b" : [[1,2],[2,3,4],[5]]})
data = []
for i in df.itertuples():
lst = i[2]
for col2 in lst:
data.append([i[1], col2])
df_output = pd.DataFrame(data =data, columns=df.columns)
df_output
La salida es -
a b
0 1 1
1 1 2
2 2 2
3 2 3
4 2 4
5 3 5
Editar: también puede comprimir los bucles en un solo código y completar los
data
como:
data = [[i[1], col2] for i in df.itertuples() for col2 in i[2]]
ACTUALIZACIÓN: enfoque vectorizado genérico : funcionará también para múltiples columnas DF:
asumiendo que tenemos el siguiente DF:
In [159]: df
Out[159]:
a b c
0 1 [1, 2] 5
1 2 [2, 3, 4] 6
2 3 [5] 7
Solución:
In [160]: lst_col = ''b''
In [161]: pd.DataFrame({
...: col:np.repeat(df[col].values, df[lst_col].str.len())
...: for col in df.columns.difference([lst_col])
...: }).assign(**{lst_col:np.concatenate(df[lst_col].values)})[df.columns.tolist()]
...:
Out[161]:
a b c
0 1 1 5
1 1 2 5
2 2 2 6
3 2 3 6
4 2 4 6
5 3 5 7
Preparar:
df = pd.DataFrame({
"a" : [1,2,3],
"b" : [[1,2],[2,3,4],[5]],
"c" : [5,6,7]
})
Enfoque NumPy vectorizado:
In [124]: pd.DataFrame({''a'':np.repeat(df.a.values, df.b.str.len()),
''b'':np.concatenate(df.b.values)})
Out[124]:
a b
0 1 1
1 1 2
2 2 2
3 2 3
4 2 4
5 3 5
ANTIGUA respuesta:
Prueba esto:
In [89]: df.set_index(''a'', append=True).b.apply(pd.Series).stack().reset_index(level=[0, 2], drop=True).reset_index()
Out[89]:
a 0
0 1 1.0
1 1 2.0
2 2 2.0
3 2 3.0
4 2 4.0
5 3 5.0
O una solución un poco mejor proporcionada por @Boud :
In [110]: df.set_index(''a'').b.apply(pd.Series).stack().reset_index(level=-1, drop=True).astype(int).reset_index()
Out[110]:
a 0
0 1 1
1 1 2
2 2 2
3 2 3
4 2 4
5 3 5