Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

180
Views
No está claro por qué groupby con un solo grupo produce fila DataFrame

Aquí hay dos operaciones groupby en un pandas.DataFrame :

 import pandas d = pandas.DataFrame({"a": [1, 2, 3, 4, 5, 6], "b": [1, 2, 4, 3, -1, 5]}) grp1 = pandas.Series([1, 1, 1, 1, 1, 1]) ans1 = d.groupby(grp1).apply(lambda x: xa * xbiloc[0]) grp2 = pandas.Series([1, 1, 1, 2, 2, 2]) ans2 = d.groupby(grp2).apply(lambda x: xa * xbiloc[0]) print(ans1.reset_index(drop=True)) # a 0 1 2 3 4 5 # 0 1 2 3 4 5 6 print(ans2.reset_index(drop=True)) # 0 1 # 1 2 # 2 3 # 3 12 # 4 15 # 5 18 # Name: a, dtype: int64

Quiero la salida en el formato de ans2 . Si la Serie de agrupación tiene más de un grupo (como en grp2 ), entonces no hay problema con el formato de salida. Sin embargo, cuando la agrupación Series tiene solo un grupo (como en grp1 ), la salida es un DataFrame con una sola fila. ¿Por qué es esto?

¿Cómo puedo asegurarme de que la salida siempre será como ans2 independientemente del número de grupos en la serie de agrupación? ¿Hay un enfoque más rápido/mejor que

  1. Comprobando si la salida es un DataFrame y coaccionando en una Serie
  2. Comprobando si la serie de agrupación tiene solo un grupo y evitando groupby si ese es el caso
over 4 years ago · Santiago Trujillo
4 answers
Answer question

0

Creo que lo más fácil es evitar .apply() que, de hecho, hace cosas raras cuando se recombina. Probablemente esto se deba a que la semántica de esta función es muy vaga. Puedes devolver cualquier cosa y los pandas harán todo lo posible para adivinar lo que quisiste decir.

Si desea resultados consistentes con funciones que se aplican a todo el sub-marco de datos, es mejor que ejecute la función usted mismo:

 >>> pd.concat({n: (lambda x: xa * xbiloc[0])(g) for n, g in d.groupby(grp1)}) 1 0 1 1 2 2 3 3 4 4 5 5 6 Name: a, dtype: int64 >>> pd.concat({n: (lambda x: xa * xbiloc[0])(g) for n, g in d.groupby(grp2)}) 1 0 1 1 2 2 3 2 3 12 4 15 5 18 Name: a, dtype: int64

Ahora, lo que recomendaría es usar una función con una forma de retorno bien definida. Aquí .transform() podría ser útil:

 >>> d.groupby(grp1)['b'].transform('first') 0 1 1 1 2 1 3 1 4 1 5 1 Name: b, dtype: int64 >>> d.groupby(grp2)['b'].transform('first') 0 1 1 1 2 1 3 3 4 3 5 3 Name: b, dtype: int64

Aquí hay un ejemplo de cómo podría usar para el mismo cálculo:

 >>> ans1 = d.copy() >>> ans1['a'] *= d.groupby(grp1)['b'].transform('first') >>> ans1 ab 0 1 1 1 2 2 2 3 4 3 4 3 4 5 -1 5 6 5 >>> ans2 = d.copy() >>> ans2['a'] *= d.groupby(grp2)['b'].transform('first') >>> ans2 ab 0 1 1 1 2 2 2 3 4 3 12 3 4 15 -1 5 18 5
over 4 years ago · Santiago Trujillo Report

0

Una solución simple es devolver un DataFrame desde apply :

 import pandas d = pandas.DataFrame({"a": [1, 2, 3, 4, 5, 6], "b": [1, 2, 4, 3, -1, 5]}) grp1 = pandas.Series([1, 1, 1, 1, 1, 1]) ans1 = d.groupby(grp1).apply(lambda x: x[['a']] * xbiloc[0]) grp2 = pandas.Series([1, 1, 1, 2, 2, 2]) ans2 = d.groupby(grp2).apply(lambda x: x[['a']] * xbiloc[0]) print(ans1.reset_index(drop=True)) # a # 0 1 # 1 2 # 2 3 # 3 4 # 4 5 # 5 6 print(ans2.reset_index(drop=True)) # a # 0 1 # 1 2 # 2 3 # 3 12 # 4 15 # 5 18

Para entender por qué, la documentación de la función de apply es útil. Cuando la función dada para apply devuelve una Series , se convierten en una fila y el resultado final es un DataFrame de datos con una fila por grupo. Entonces, el comportamiento de grp1 es el esperado.

Esto plantea la pregunta de por qué el segundo caso que usa grp2 devuelve una Series . Creo que se debe a que los dos grupos devuelven Series con diferentes valores de índice. Por lo tanto, los resultados de los dos grupos se agregan en una sola fila con indexación multinivel (como se ve a continuación).

 d = pandas.DataFrame({"a": [1, 2, 3, 4, 5, 6], "b": [1, 2, 4, 3, -1, 5]}) grp2 = pandas.Series([1, 1, 1, 2, 2, 2]) def func(x): z= xa * xbiloc[0] print(z.index) return z ans2 = d.groupby(grp2).apply(func) # Int64Index([0, 1, 2], dtype='int64') # Int64Index([3, 4, 5], dtype='int64') print(ans2) # 1 0 1 # 1 2 # 2 3 # 2 3 12 # 4 15 # 5 18 # Name: a, dtype: int64
over 4 years ago · Santiago Trujillo Report

0

Esto sucede porque, como solo tiene un grupo con grp1 , el intermedio se convierte primero como Serie y luego como DataFrame con el grupo como índice, en lugar de agregar un nivel de MultiIndex como con grp2 .

Para evitar esto, puede dividir sus datos como un marco de datos en su lambda y subestablecer la columna en Serie solo después de la agregación. Esto asegura que el resultado intermedio permanecerá en la dimensión correcta:

 >>> ans1 = d.groupby(grp1).apply(lambda x: x[['a']] * xbiloc[0])['a'] >>> ans1 0 1 1 2 2 3 3 4 4 5 5 6 Name: a, dtype: int64 >>> ans2 = d.groupby(grp2).apply(lambda x: x[['a']] * xbiloc[0])['a'] >>> ans2 0 1 1 2 2 3 3 12 4 15 5 18 Name: a, dtype: int64

Dicho esto, lo más fácil es usar transform :

 >>> d.groupby(grp1)['a'].transform(lambda x: x*d.loc[x.index[0], 'b']) 0 1 1 2 2 3 3 4 4 5 5 6 Name: a, dtype: int64 >>> d.groupby(grp2)['a'].transform(lambda x: x*d.loc[x.index[0], 'b']) 0 1 1 2 2 3 3 12 4 15 5 18 Name: a, dtype: int64
over 4 years ago · Santiago Trujillo Report

0

Otra forma, además de usar transform , para asegurarse de tener el mismo formato de salida es usar squeeze :

 >>> ans1.squeeze().reset_index(drop=True) 0 1 1 2 2 3 3 4 4 5 5 6 Name: 1, dtype: int64 >>> ans2.squeeze().reset_index(drop=True) 0 1 1 2 2 3 3 12 4 15 5 18 Name: a, dtype: int64

Puede usar squeeze=True en groupby pero generará un FutureWarning :

FutureWarning: el parámetro de squeeze está en desuso y se eliminará en una versión futura.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!