¿Cómo dividir los valores de una celda en varias filas en el dataframe de pandas?

Tengo un dataframe siguiente, que se obtuvo utilizando el código:

df1=df.groupby('id')['x,y'].apply(lambda x: rdp(x.tolist(), 5.0)).reset_index() 

Refiera aqui

El dataframe resultante obtenido:

  id x,y 0 1 [(0, 0), (1, 2)] 1 2 [(1, 3), (1, 2)] 2 3 [(2, 5), (4, 6)] 

Es posible obtener algo como esto:

  id x,y 0 1 (0, 0) 1 1 (1, 2) 2 2 (1, 3) 3 2 (1, 2) 4 3 (2, 5) 5 3 (4, 6) 

Aquí, la lista de coordenadas obtenidas como resultado en df anterior se divide en nuevas filas contra sus respectivas ID.

Puedes usar el constructor DataFrame con la stack :

 df2 = pd.DataFrame(df1['x,y'].values.tolist(), index=df1['id']) .stack() .reset_index(level=1, drop=True) .reset_index(name='x,y') print (df2) id x,y 0 1 (0, 0) 1 1 (1, 2) 2 2 (1, 3) 3 2 (1, 2) 4 3 (2, 5) 5 3 (4, 6) 

solución numpy use numpy.repeat por lengths de valores por str.len , x,y column es flattenig por numpy.ndarray.sum :

 df2 = pd.DataFrame({'id': np.repeat(df1['id'].values, df1['x,y'].str.len()), 'x,y': df1['x,y'].values.sum()}) print (df2) id x,y 0 1 (0, 0) 0 1 (1, 2) 1 2 (1, 3) 1 2 (1, 2) 2 3 (2, 5) 2 3 (1, 9) 2 3 (4, 6) 

Tiempos :

 In [54]: %timeit pd.DataFrame(df1['x,y'].values.tolist(), index=df1['id']).stack().reset_index(level=1, drop=True).reset_index(name='x,y') 1000 loops, best of 3: 1.49 ms per loop In [55]: %timeit pd.DataFrame({'id': np.repeat(df1['id'].values, df1['x,y'].str.len()), 'x,y': df1['x,y'].values.sum()}) 1000 loops, best of 3: 562 µs per loop #piRSquared solution In [56]: %timeit pd.DataFrame({'id': df1['id'].repeat(df1['x,y'].str.len()), 'x,y': df1['x,y'].sum() }) 1000 loops, best of 3: 712 µs per loop 
  • Cálculo de la nueva columna 'id'
    • Podemos usar el método pandas str.len para contar rápidamente el número de elementos en la sub-lista de cada elemento. Esto es conveniente ya que podemos pasar directamente este resultado al método de repeat de df1['id'] que repetirá cada elemento en una cantidad correspondiente de las longitudes que pasamos.
  • Cálculo de la nueva columna 'x,y'
    • por lo general, me gusta usar np.concatenate para np.concatenate todas las sublistas. Sin embargo, en este caso, las sub-listas son listas de tuplas. np.concatenate no los tratará como listas de objetos. Entonces, en lugar de eso, uso el método de la sum y ese usará el método de la sum subyacente en las listas, que a su vez concatenará.

pandas

Si nos atenemos a los pandas podemos mantener el código más limpio.
Usar repeat con str.len y sum

 pd.DataFrame({ 'id': df1['id'].repeat(df1['x,y'].str.len()), 'x,y': df1['x,y'].sum() }) id x,y 0 1 (0, 0) 0 1 (1, 2) 1 2 (1, 3) 1 2 (1, 2) 2 3 (2, 5) 2 3 (4, 6) 

numpy

Podemos acelerar este enfoque mediante el uso de matrices numpy subyacentes y métodos numpy equivalentes
NOTA: esta es la lógica equivalente!

 pd.DataFrame({ 'id': df1['id'].values.repeat(df1['x,y'].str.len()), 'x,y': df1['x,y'].values.sum() }) 

Podemos acelerarlo aún más saltando el método str.len y calculando las longitudes con una lista de comprensión.

 pd.DataFrame({ 'id': df1['id'].values.repeat([len(w) for w in df1['x,y'].values.tolist()]), 'x,y': df1['x,y'].values.sum() }) 

Pruebas de tiempo

pequeños datos

 %%timeit pd.DataFrame({ 'id': df1['id'].values.repeat([len(w) for w in df1['x,y'].values.tolist()]), 'x,y': df1['x,y'].values.sum() }) 1000 loops, best of 3: 351 µs per loop %%timeit pd.DataFrame({ 'id': df1['id'].repeat(df1['x,y'].str.len()), 'x,y': df1['x,y'].sum() }) 1000 loops, best of 3: 590 µs per loop %%timeit pd.DataFrame({'id': np.repeat(df1['id'].values, df1['x,y'].str.len()), 'x,y': df1['x,y'].values.sum()})​ 1000 loops, best of 3: 498 µs per loop 

datos más grandes

 df1 = pd.concat([df1.head(3)] * 100, ignore_index=True) %%timeit pd.DataFrame({ 'id': df1['id'].values.repeat([len(w) for w in df1['x,y'].values.tolist()]), 'x,y': df1['x,y'].values.sum() }) 1000 loops, best of 3: 579 µs per loop %%timeit pd.DataFrame({ 'id': df1['id'].repeat(df1['x,y'].str.len()), 'x,y': df1['x,y'].sum() }) 1000 loops, best of 3: 841 µs per loop %%timeit pd.DataFrame({'id': np.repeat(df1['id'].values, df1['x,y'].str.len()), 'x,y': df1['x,y'].values.sum()})​ 1000 loops, best of 3: 704 µs per loop