python pandas dataframe

python - Dividir la célula en varias filas en el marco de datos de pandas



dataframe (4)

Tengo un marco de datos que contiene datos de pedidos, cada pedido tiene varios paquetes almacenados como columnas de cadena separadas por comas [ package y package_code package ]

Quiero dividir los datos de los paquetes y crear una fila para cada paquete, incluidos los detalles de su pedido

Aquí hay un ejemplo de marco de datos de entrada:

import pandas as pd df = pd.DataFrame({"order_id":[1,3,7],"order_date":["20/5/2018","22/5/2018","23/5/2018"], "package":["p1,p2,p3","p4","p5,p6"],"package_code":["#111,#222,#333","#444","#555,#666"]})

Y esto es lo que estoy tratando de lograr como resultado:

¿Cómo puedo hacer eso con los pandas?


Aquí hay una forma de usar numpy.repeat e itertools.chain . Conceptualmente, esto es exactamente lo que quiere hacer: repetir algunos valores, encadenar otros. Recomendado para pequeñas cantidades de columnas, de lo contrario stack métodos basados ​​en stack pueden ser mejores.

import numpy as np from itertools import chain # return list from series of comma-separated strings def chainer(s): return list(chain.from_iterable(s.str.split('',''))) # calculate lengths of splits lens = df[''package''].str.split('','').map(len) # create new dataframe, repeating or chaining as appropriate res = pd.DataFrame({''order_id'': np.repeat(df[''order_id''], lens), ''order_date'': np.repeat(df[''order_date''], lens), ''package'': chainer(df[''package'']), ''package_code'': chainer(df[''package_code''])}) print(res) order_id order_date package package_code 0 1 20/5/2018 p1 #111 0 1 20/5/2018 p2 #222 0 1 20/5/2018 p3 #333 1 3 22/5/2018 p4 #444 2 7 23/5/2018 p5 #555 2 7 23/5/2018 p6 #666


Cerca del método del frío :-)

df.set_index([''order_date'',''order_id'']).apply(lambda x : x.str.split('','')).stack().apply(pd.Series).stack().unstack(level=2).reset_index(level=[0,1]) Out[538]: order_date order_id package package_code 0 20/5/2018 1 p1 #111 1 20/5/2018 1 p2 #222 2 20/5/2018 1 p3 #333 0 22/5/2018 3 p4 #444 0 23/5/2018 7 p5 #555 1 23/5/2018 7 p6 #666



Esto debería funcionar para cualquier número de columnas como esta. La esencia es un poco de magia de apilar pila con str.split .

(df.set_index([''order_date'', ''order_id'']) .stack() .str.split('','', expand=True) .stack() .unstack(-2) .reset_index(-1, drop=True) .reset_index() ) order_date order_id package package_code 0 20/5/2018 1 p1 #111 1 20/5/2018 1 p2 #222 2 20/5/2018 1 p3 #333 3 22/5/2018 3 p4 #444 4 23/5/2018 7 p5 #555 5 23/5/2018 7 p6 #666

Hay otra alternativa de rendimiento que involucra la chain , pero necesitaría encadenar y repetir explícitamente cada columna (un pequeño problema con muchas columnas). Elija lo que mejor se adapte a la descripción de su problema, ya que no hay una respuesta única.

Detalles

Primero, establezca las columnas que no se tocarán como el índice.

df.set_index([''order_date'', ''order_id'']) package package_code order_date order_id 20/5/2018 1 p1,p2,p3 #111,#222,#333 22/5/2018 3 p4 #444 23/5/2018 7 p5,p6 #555,#666

A continuación, stack las filas.

_.stack() order_date order_id 20/5/2018 1 package p1,p2,p3 package_code #111,#222,#333 22/5/2018 3 package p4 package_code #444 23/5/2018 7 package p5,p6 package_code #555,#666 dtype: object

Tenemos una serie ahora. Así que llame a str.split en coma.

_.str.split('','', expand=True) 0 1 2 order_date order_id 20/5/2018 1 package p1 p2 p3 package_code #111 #222 #333 22/5/2018 3 package p4 None None package_code #444 None None 23/5/2018 7 package p5 p6 None package_code #555 #666 None

Necesitamos deshacernos de los valores NULL, así que vuelve a llamar a la stack .

_.stack() order_date order_id 20/5/2018 1 package 0 p1 1 p2 2 p3 package_code 0 #111 1 #222 2 #333 22/5/2018 3 package 0 p4 package_code 0 #444 23/5/2018 7 package 0 p5 1 p6 package_code 0 #555 1 #666 dtype: object

Casi estámos allí. Ahora queremos que el segundo último nivel del índice se convierta en nuestras columnas, así que desapíllelo usando unstack(-2) ( unstack en el segundo último nivel)

_.unstack(-2) package package_code order_date order_id 20/5/2018 1 0 p1 #111 1 p2 #222 2 p3 #333 22/5/2018 3 0 p4 #444 23/5/2018 7 0 p5 #555 1 p6 #666

Deshazte del último nivel superfluo usando reset_index :

_.reset_index(-1, drop=True) package package_code order_date order_id 20/5/2018 1 p1 #111 1 p2 #222 1 p3 #333 22/5/2018 3 p4 #444 23/5/2018 7 p5 #555 7 p6 #666

Y finalmente,

_.reset_index() order_date order_id package package_code 0 20/5/2018 1 p1 #111 1 20/5/2018 1 p2 #222 2 20/5/2018 1 p3 #333 3 22/5/2018 3 p4 #444 4 23/5/2018 7 p5 #555 5 23/5/2018 7 p6 #666