Я ищу решение, в котором я выполняю GROUP BY, HAVING CLAUSE и ORDER BY вместе в коде Pyspark. По сути, нам нужно перенести некоторые данные из одного фрейма данных в другой с некоторыми условиями.
SQL-запрос выглядит так, что я пытаюсь изменить его на Pyspark.
SELECT TABLE1.NAME, Count(TABLE1.NAME) AS COUNTOFNAME,
Count(TABLE1.ATTENDANCE) AS COUNTOFATTENDANCE INTO SCHOOL_DATA_TABLE
FROM TABLE1
WHERE (((TABLE1.NAME) Is Not Null))
GROUP BY TABLE1.NAME
HAVING (((Count(TABLE1.NAME))>1) AND ((Count(TABLE1.ATTENDANCE))<>5))
ORDER BY Count(TABLE1.NAME) DESC;
Код Spark, который я пробовал и терпел неудачу: Что я сделал, я взял столбцы из df в df2, над которыми нужно выполнить операции:
df2= df.select('NAME','ATTENDANCE')
df2=df2.groupBy('NAME').agg(count('NAME').alias('name1').agg(count('ATTENDANCE').alias('NEW_ATTENDANCE'))).filter((col('name1')>1) & (col('NEW_ATTENDANCE') !=5))
ОБРАЗЕЦ ДАННЫХ
rdd = spark.sparkContext.parallelize([
('Aayush', 10),
('Aayush', 9),
('Shiva', 5 ),
('Alia', 6),
('Aayan', 11),
('Alia',9)])
df_1 = spark.createDataFrame(rdd, schema=['NAME','ATTENDANCE'])
На основе ответа, предоставленного @Emma, df2= df_1.select('NAME','ATTENDANCE') df2 = df2.groupBy('NAME').agg(count('NAME').alias('name1'),count('ATTENDANCE').alias('NEW_ATTENDANCE')).filter("name1 > 1 and NEW_ATTENDANCE !=5") df2.show(10,True)
Ваш код почти в порядке, после исправления нескольких синтаксических проблем он работает.
Кроме того, я думаю, что для «посещаемости» вы хотите использовать sum
, а не count
(иначе это всегда будет то же значение, что и количество имен).
Для сортировки просто добавьте orderBy
.
df.withColumn("NAME", lower("NAME"))
.groupBy('NAME')
.agg(count('NAME').alias('name1'),sum('ATTENDANCE').alias('NEW_ATTENDANCE'))
.filter((col('name1')>1) & (col('NEW_ATTENDANCE') !=5))
.orderBy(col("NAME"))
привет @Grisha Спасибо за ваш ответ, но есть одна проблема, с которой я столкнулся, на самом деле в столбце NAME есть два значения с именем «Virat» и «virat», из-за нижнего регистра во втором случае это значение не принимается в группе от
Я хочу выбрать тот вират после группы, условия которого удовлетворяют условиям фильтра
если вы хотите, чтобы имена не учитывали регистр, просто преобразуйте их в нижний регистр перед группой с помощью - df = df.withColumn("NAME", lower("NAME"))
Но нет ли другого способа, кроме снижения значений всего столбца
Может быть, я не понимаю, что вам нужно, на примере выше "Virat" и "virat", вы хотите, чтобы в результате были обе эти записи или вы хотите, чтобы они были объединены? или что-нибудь еще?
Если вы хотите, чтобы они были объединены, стандартный способ - использовать «нижний», если вы хотите сохранить их отдельно, вам не нужно ничего делать, так как они будут сгруппированы отдельно...
привет @Grisha Мой вопрос: если у нас есть оба значения как Virat и virat в именах столбцов, то после группировки по нему следует выбрать оба значения, но нам нужно только то значение, чье количество1> 1 и посещаемость! = 5
поэтому в основном после выполнения GROUP BY он должен правильно выбрать оба значения (Virat, virat), поскольку оба имеют одинаковое имя, и из этих двух значений мы выберем те значения, которые соответствуют нашим условиям фильтра.
так как я не хочу менять каждое значение в столбце NAME на нижний регистр
В вашем конечном результате для (Virat, virat) вы ожидаете иметь две строки или одну? Если вы собираетесь иметь один, то какой? Опять же, если вы логически рассматриваете эти имена как одно и то же имя, вы должны нормализовать их заранее (например, через «ниже»). Также обратите внимание, что lower
не увеличивает производительность, поскольку в любом случае выполняется во время чтения данных.
да, я изменил столбец на нижний регистр и взял его в отдельный df, он работает, спасибо за предложение
agg
может принимать несколько агрегаций. Попробуйте пройти 2 счета такagg(count().alias(), count().alias())