Агрегирование столбцов условно с помощью pyspark?

#apache-spark #pyspark #apache-spark-sql #aggregation

#apache-spark #pyspark #apache-spark-sql #агрегация

Вопрос:

У меня есть следующий набор данных. Я хочу сгруппировать все переменные и разделить данные на основе приведенных ниже условий.

Тем не менее, я получаю сообщение об ошибке, когда я попробовал приведенный ниже код.

 CUST_ID NAME    GENDER  AGE
id_01   MONEY   F   43
id_02   BAKER   F   32
id_03   VOICE   M   31
id_04   TIME    M   56
id_05   TIME    F   24
id_06   TALENT  F   28
id_07   ISLAND  F   21
id_08   ISLAND  F   27
id_09   TUME    F   24
id_10   TIME    F   75
id_11   SKY M   35
id_12   VOICE   M   70



    from pyspark.sql.functions import *

    df.groupBy("CUST_ID", "NAME", "GENDER", "AGE").agg(
       CUST_ID.count AS TOTAL
       SUM(WHEN ((AGE >= 18 AND AGE <= 34) AND GENDER = 'M') THEN COUNT(CUST_ID) ELSE 0 END AS "M18-34")
       SUM(WHEN ((AGE >= 18 AND AGE <= 34) AND GENDER = 'F') THEN COUNT(CUST_ID) ELSE 0 END AS "F18-34")
       SUM(WHEN ((AGE >= 18 AND AGE <= 34 THEN COUNT(CUST_ID) ELSE 0 END AS "18-34")
       SUM(WHEN ((AGE >= 25 AND AGE <= 54 THEN COUNT(CUST_ID) ELSE 0 END AS "25-54")
       SUM(WHEN ((AGE >= 25 AND AGE <= 54) AND GENDER = 'F') THEN COUNT(CUST_ID) ELSE 0 END AS "F25-54")
       SUM(WHEN ((AGE >= 25 AND AGE <= 54) AND GENDER = 'M') THEN COUNT(CUST_ID) ELSE 0 END AS "M25-54")   
    )
 

Я был бы признателен за вашу помощь / предложения

Заранее спасибо

Ответ №1:

Ваш код не является ни допустимым pyspark, ни допустимым Spark SQL. Существует так много синтаксических проблем. Я попытался исправить их ниже, не уверен, что это то, что вы хотели. Если у вас так много SQL-подобных операторов, лучше использовать Spark SQL напрямую, а не pyspark API:

 df.createOrReplaceTempView('df')
result = spark.sql("""
SELECT NAME,
       COUNT(CUST_ID) AS TOTAL,
       SUM(CASE WHEN ((AGE >= 18 AND AGE <= 34) AND GENDER = 'M') THEN 1 ELSE 0 END) AS `M18-34`,
       SUM(CASE WHEN ((AGE >= 18 AND AGE <= 34) AND GENDER = 'F') THEN 1 ELSE 0 END) AS `F18-34`,
       SUM(CASE WHEN (AGE >= 18 AND AGE <= 34) THEN 1 ELSE 0 END) AS `18-34`,
       SUM(CASE WHEN (AGE >= 25 AND AGE <= 54) THEN 1 ELSE 0 END) AS `25-54`,
       SUM(CASE WHEN ((AGE >= 25 AND AGE <= 54) AND GENDER = 'F') THEN 1 ELSE 0 END) AS `F25-54`,
       SUM(CASE WHEN ((AGE >= 25 AND AGE <= 54) AND GENDER = 'M') THEN 1 ELSE 0 END) AS `M25-54` 
FROM df
GROUP BY NAME
""")

result.show()
 ------ ----- ------ ------ ----- ----- ------ ------ 
|  NAME|TOTAL|M18-34|F18-34|18-34|25-54|F25-54|M25-54|
 ------ ----- ------ ------ ----- ----- ------ ------ 
|ISLAND|    2|     0|     2|    2|    1|     1|     0|
| MONEY|    1|     0|     0|    0|    1|     1|     0|
|  TIME|    3|     0|     1|    1|    0|     0|     0|
| VOICE|    2|     1|     0|    1|    1|     0|     1|
|  TUME|    1|     0|     1|    1|    0|     0|     0|
| BAKER|    1|     0|     1|    1|    1|     1|     0|
|TALENT|    1|     0|     1|    1|    1|     1|     0|
|   SKY|    1|     0|     0|    0|    1|     0|     1|
 ------ ----- ------ ------ ----- ----- ------ ------ 
 

Если вам нужно решение pyspark, вот пример того, как это сделать для первого столбца. Остальное вы можете решить прямолинейно.

 import pyspark.sql.functions as F
result = df.groupBy('Name').agg(
    F.count('CUST_ID').alias('TOTAL'),
    F.count(F.when(F.expr("(AGE >= 18 AND AGE <= 34) AND GENDER = 'M'"), 1)).alias("M18-34")
)

result.show()
 ------ ----- ------ 
|  Name|TOTAL|M18-34|
 ------ ----- ------ 
|ISLAND|    2|     0|
| MONEY|    1|     0|
|  TIME|    3|     0|
| VOICE|    2|     1|
|  TUME|    1|     0|
| BAKER|    1|     0|
|TALENT|    1|     0|
|   SKY|    1|     0|
 ------ ----- ------ 
 

Комментарии:

1. извините, я переводил SQL-запрос в spark. но я также хочу их сгруппировать. итак, у меня должна быть сумма для каждого имени. извините, если слишком много вопросов, как я могу выполнить то же самое в pyspark

2. один короткий вопрос. можно ли группировать на основе нескольких столбцов

3. @JamesTaylor конечно, но в этом примере я думаю, что группировка по имени имеет больше смысла, чем группировка по всем столбцам.

4. @ mck Я пытался брать дроби, но вместо этого не работает общее количество 🙂

5. @ mck Я имею в виду, можем ли мы разделить все столбцы на общее количество, вот чего я пытаюсь достичь