python - una - pandas: aplica función a DataFrame que puede devolver varias filas
seleccionar una fila de un dataframe pandas (4)
Puede usar groupby:
def f(group):
row = group.irow(0)
return DataFrame({''class'': [row[''class'']] * row[''count'']})
df.groupby(''class'', group_keys=False).apply(f)
entonces 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
Estoy tratando de transformar DataFrame, de modo que algunas de las filas se repliquen una determinada cantidad 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 a:
class
0 A
1 C
2 C
Esto es lo contrario de la agregación con la función de conteo. ¿Hay alguna manera fácil de lograrlo en pandas (sin utilizar para bucles o listas de comprensión)?
Una posibilidad podría ser permitir que la función DataFrame.applymap
devuelva varias filas (como el método de apply
de GroupBy
). Sin embargo, no creo que sea posible en pandas ahora.
repeated_items = [list(row[1]*row[2]) for row in df.itertuples()]
creará una lista anidada:
[[''A''], [], [''C'', ''C'']]
que luego puede repetir con listas de comprensión para crear un nuevo marco de datos:
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 lo desea:
new_df = pd.DataFrame({"class":[j for i in [list(row[1]*row[2]) for row in df.itertuples()] for j in i]})
Sé que esta es una vieja pregunta, pero estaba teniendo problemas para obtener la respuesta de Wes para trabajar en múltiples columnas en el marco de datos, así que hice su código un poco más genérico. Pensé que lo compartiría en caso de que alguien más tropiece con esta pregunta con el mismo problema.
Básicamente, especifique en qué columna tienen los recuentos y obtendrá a cambio un marco de datos expandido.
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 lleva ~ 7 segundos. No estoy seguro en este caso si la agrupación es necesaria o acertada ya que está tomando todas las columnas para agrupar la forma, pero oigan lo que sea solo 7 segundos.
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 DataFrame de cualquier tamaño.