我几乎肯定以前曾经问过,但是a search through stackoverflow没有回答我的问题。不是[2]的重复,因为我想要最大值,而不是最频繁的项目。我是pyspark的新手,并且尝试做一些非常简单的事情:我想将groupBy列“A”分组,然后只保留每个组中具有“B”列中最大值的行。像这样:
df_cleaned = df.groupBy("A").agg(F.max("B"))
不幸的是,这会抛弃所有其他列 - df_cleaned只包含列“A”和B的最大值。如何保留行? (“A”,“B”,“C”......)
答案 0 :(得分:18)
您可以在PCCERT_CONTEXT
使用udf
的情况下执行此操作。
考虑以下示例:
Window
按列import pyspark.sql.functions as f
data = [
('a', 5),
('a', 8),
('a', 7),
('b', 1),
('b', 3)
]
df = sqlCtx.createDataFrame(data, ["A", "B"])
df.show()
#+---+---+
#| A| B|
#+---+---+
#| a| 5|
#| a| 8|
#| a| 7|
#| b| 1|
#| b| 3|
#+---+---+
创建Window
分区,并使用此值计算每个组的最大值。然后过滤掉行,使A
列中的值等于最大值。
B
或等效使用from pyspark.sql import Window
w = Window.partitionBy('A')
df.withColumn('maxB', f.max('B').over(w))\
.where(f.col('B') == f.col('maxB'))\
.drop('maxB')\
.show()
#+---+---+
#| A| B|
#+---+---+
#| a| 8|
#| b| 3|
#+---+---+
:
pyspark-sql
答案 1 :(得分:2)
另一种可能的方法是应用指定“ leftsemi”本身的联接数据框。 这种连接包括左侧数据框的所有列,右侧不包含任何列。
例如:
import pyspark.sql.functions as f
data = [
('a', 5, 'c'),
('a', 8, 'd'),
('a', 7, 'e'),
('b', 1, 'f'),
('b', 3, 'g')
]
df = sqlContext.createDataFrame(data, ["A", "B", "C"])
df.show()
+---+---+---+
| A| B| C|
+---+---+---+
| a| 5| c|
| a| 8| d|
| a| 7| e|
| b| 1| f|
| b| 3| g|
+---+---+---+
可以按以下方式选择B列按A列的最大值:
df.groupBy('A').agg(f.max('B')
+---+---+
| A| B|
+---+---+
| a| 8|
| b| 3|
+---+---+
使用此表达式作为左半联接的右侧,并将获得的列max(B)
重命名为其原始名称B
,我们可以获得所需的结果:
df.join(df.groupBy('A').agg(f.max('B').alias('B')),on='B',how='leftsemi').show()
+---+---+---+
| B| A| C|
+---+---+---+
| 3| b| g|
| 8| a| d|
+---+---+---+
此解决方案背后的物理计划与被接受的答案中的一个是不同的,我仍然不清楚哪一个在大型数据帧上的性能更好。
使用spark SQL语法可以获得相同的结果:
df.registerTempTable('table')
q = '''SELECT *
FROM table a LEFT SEMI
JOIN (
SELECT
A,
max(B) as max_B
FROM table
GROUP BY A
) t
ON a.A=t.A AND a.B=t.max_B
'''
sqlContext.sql(q).show()
+---+---+---+
| A| B| C|
+---+---+---+
| b| 3| g|
| a| 8| d|
+---+---+---+
答案 2 :(得分:0)
只想添加 @ndricca 答案的 Scala Spark 版本,以防有人需要它:
val data = Seq(("a", 5,"c"), ("a",8,"d"),("a",7,"e"),("b",1,"f"),("b",3,"g"))
val df = data.toDF("A","B","C")
df.show()
+---+---+---+
| A| B| C|
+---+---+---+
| a| 5| c|
| a| 8| d|
| a| 7| e|
| b| 1| f|
| b| 3| g|
+---+---+---+
val rightdf = df.groupBy("A").max("B")
rightdf.show()
+---+------+
| A|max(B)|
+---+------+
| b| 3|
| a| 8|
+---+------+
val resdf = df.join(rightdf, df("B") === rightdf("max(B)"), "leftsemi")
resdf.show()
+---+---+---+
| A| B| C|
+---+---+---+
| a| 8| d|
| b| 3| g|
+---+---+---+