Aplicar la función a Pandas DataFrame que puede devolver múltiples filas

Estoy tratando de transformar DataFrame, de manera que algunas de las filas se replicarán un número dado de veces. Por ejemplo:

df = pd.DataFrame({'class': ['A', 'B', 'C'], 'count':[1,0,2]}) class count 0 A 1 1 B 0 2 C 2 

debe transformarse en:

  class 0 A 1 C 2 C 

Este es el reverso de la agregación con la función de conteo. ¿Hay una manera fácil de lograrlo en pandas (sin usar para bucles o listas de comprensión)?

Una posibilidad podría ser permitir que la función DataFrame.applymap devuelva varias filas (método de apply similar a GroupBy ). Sin embargo, no creo que sea posible en pandas ahora.

Usted podría usar groupby:

 def f(group): row = group.irow(0) return DataFrame({'class': [row['class']] * row['count']}) df.groupby('class', group_keys=False).apply(f) 

así que obtienes

 In [25]: df.groupby('class', group_keys=False).apply(f) Out[25]: class 0 A 0 C 1 C 

Puedes arreglar el índice del resultado como quieras.

Sé que esta es una pregunta antigua, pero estaba teniendo problemas para que la respuesta de Wes funcionara para varias columnas en el dataframe, así que hice su código un poco más genérico. Pensé que compartiría en caso de que alguien más tropiece con esta pregunta con el mismo problema.

Básicamente, usted simplemente especifica en qué columna están los recuentos y obtiene a cambio un dataframe ampliado.

 import pandas as pd df = pd.DataFrame({'class 1': ['A','B','C','A'], 'class 2': [ 1, 2, 3, 1], 'count': [ 3, 3, 3, 1]}) print df,"\n" def f(group, *args): row = group.irow(0) Dict = {} row_dict = row.to_dict() for item in row_dict: Dict[item] = [row[item]] * row[args[0]] return pd.DataFrame(Dict) def ExpandRows(df,WeightsColumnName): df_expand = df.groupby(df.columns.tolist(), group_keys=False).apply(f,WeightsColumnName).reset_index(drop=True) return df_expand df_expanded = ExpandRows(df,'count') print df_expanded 

Devoluciones:

  class 1 class 2 count 0 A 1 3 1 B 2 3 2 C 3 3 3 A 1 1 class 1 class 2 count 0 A 1 1 1 A 1 3 2 A 1 3 3 A 1 3 4 B 2 3 5 B 2 3 6 B 2 3 7 C 3 3 8 C 3 3 9 C 3 3 

Con respecto a la velocidad, mi base df es de 10 columnas por ~ 6k filas y cuando se expande es ~ 100,000 filas toma ~ 7 segundos. No estoy seguro en este caso si la agrupación es necesaria o sensata, ya que está tomando todas las columnas para agruparlas, pero hey lo que sea solo 7 segundos.

 repeated_items = [list(row[1]*row[2]) for row in df.itertuples()] 

creará una lista anidada:

 [['A'], [], ['C', 'C']] 

que luego puede iterar una vez con las comprensiones de listas para crear un nuevo dataframe:

 new_df = pd.DataFrame({"class":[j for i in repeated_items for j in i]}) 

Por supuesto, también puede hacerlo en una sola línea si desea:

 new_df = pd.DataFrame({"class":[j for i in [list(row[1]*row[2]) for row in df.itertuples()] for j in i]}) 

Esta pregunta es muy antigua y las respuestas no reflejan las capacidades modernas de los pandas. Puede usar iterrows para recorrer cada fila y luego usar el constructor DataFrame para crear nuevos DataFrames con el número correcto de filas. Finalmente, use pd.concat para concatenar todas las filas juntas.

 pd.concat([pd.DataFrame(data=[row], index=range(row['count'])) for _, row in df.iterrows()], ignore_index=True) class count 0 A 1 1 C 2 2 C 2 

Esto tiene la ventaja de trabajar con cualquier DataFrame de cualquier tamaño.