Tengo un marco de datos pyspark

Place   Month       Sector      Estimate    Profit  
USA     1/1/2020    Sector1     5944
Col     1/1/2020    Sector1     398
IND     1/1/2020    Sector1     25
USA     1/1/2020    Sector2                 6.9%
Col     1/1/2020    Sector2                 0.4%
China   1/1/2020    Sector2                 0.0%
Aus     1/1/2020    Sector2                 7.7%

Necesito calcular la suma de todas las columnas Estimate (incluye todos los valores) y el promedio de todas las columnas Profit (excluyendo el 0,0 %) agrupadas por Month y Sector.

Necesito un valor adicional en el campo Lugar como Every Places que tiene estos valores de suma y promedio. Entonces, mi marco de datos deseado debería verse así:

Place           Month       Sector      Estimate    Profit  
USA             1/1/2020    Sector1     5944
Col             1/1/2020    Sector1     398
IND             1/1/2020    Sector1     25
USA             1/1/2020    Sector2                 6.9%
Col             1/1/2020    Sector2                 0.4%
China           1/1/2020    Sector2                 0.0%
Aus             1/1/2020    Sector2                 7.7%
Every Places    1/1/2020    Sector1     6367
Every Places    1/1/2020    Sector2                 5%

Intenté con este código, pero obtengo:

TypeError: la columna no es un error iterable.

df1=df.withColumn('Place',lit('Every Places')) \
               .groupBy('Month','Sector') \
               .sum((col('Estimate'))),
               avg(F.col('Profit'))

¿Cómo puedo resolver esto?

1
user175025 10 ene. 2022 a las 13:27
Pruebe groupBy().agg(sum(col('Estimate').as('Estimate'), avg(col('Profit').as('Profit')) Luego puede unir este marco de datos con el marco de datos original después agregando una columna adicional Lugar para obtener la Salida requerida
 – 
Nikunj Kakadiya
10 ene. 2022 a las 13:57
¿Puede proporcionar un fragmento de este pls? @NikunjKakadiya
 – 
user175025
10 ene. 2022 a las 14:25

1 respuesta

La mejor respuesta

Primero puede agrupar por Month + Sector para calcular la suma de Estimate y el promedio de Profit y luego usar la unión con el marco de datos original para obtener el resultado esperado:

import pyspark.sql.functions as F

df = spark.createDataFrame([
    ("USA", "1/1/2020", "Sector1", 5944, None), ("Col", "1/1/2020", "Sector1", 398, None),
    ("IND", "1/1/2020", "Sector1", 25, None), ("USA", "1/1/2020", "Sector2", None, "6.9%"),
    ("Col", "1/1/2020", "Sector2", None, "0.4%"), ("China", "1/1/2020", "Sector2", None, "0.0%"),
    ("Aus", "1/1/2020", "Sector2", None, "7.7%")], ["Place", "Month", "Sector", "Estimate", "Profit"]
)

grouped_df = df.withColumn(
    "Profit",
    F.regexp_extract("Profit", "(.+)%", 1) # extract percentage from string
).groupBy("Month", "Sector").agg(
    F.sum(F.col("Estimate")).alias("Estimate"),
    F.concat(
        F.sum("Profit") / F.sum(F.when(F.col("Profit") > 0.0, 1)), # exclude 0% from calculation
        F.lit("%")
    ).alias("Profit")
).withColumn(
    "Place",
    F.lit("Every Places")
)

df1 = df.unionByName(grouped_df)

df1.show()
#+------------+--------+-------+--------+------+
#|       Place|   Month| Sector|Estimate|Profit|
#+------------+--------+-------+--------+------+
#|         USA|1/1/2020|Sector1|    5944|  null|
#|         Col|1/1/2020|Sector1|     398|  null|
#|         IND|1/1/2020|Sector1|      25|  null|
#|         USA|1/1/2020|Sector2|    null|  6.9%|
#|         Col|1/1/2020|Sector2|    null|  0.4%|
#|       China|1/1/2020|Sector2|    null|  0.0%|
#|         Aus|1/1/2020|Sector2|    null|  7.7%|
#|Every Places|1/1/2020|Sector2|    null|  5.0%|
#|Every Places|1/1/2020|Sector1|  6367.0|  null|
#+------------+--------+-------+--------+------+
1
blackbishop 10 ene. 2022 a las 15:50
Probé con este código, pero cuando uní NyName a los marcos de datos, obtengo: AnalysisException: Found duplicate column(s) in the right attributes: 'Estimate', 'Profit'
 – 
user175025
10 ene. 2022 a las 15:45
1
Esto es extraño ... ¿puedes intentar ejecutar el ejemplo de trabajo completo que agregué?
 – 
blackbishop
10 ene. 2022 a las 15:53