基于spark dataframe scala中的列值筛选行
我有一个dataframespark:基于spark dataframe scala中的列值筛选行,scala,apache-spark,dataframe,apache-spark-sql,Scala,Apache Spark,Dataframe,Apache Spark Sql,我有一个dataframespark: id value 3 0 3 1 3 0 4 1 4 0 4 0 我想创建一个新的数据帧: 3 0 3 1 4 1 需要删除每个id的1value之后的所有行。我尝试了spark dateframeScala中的窗口函数。但无法找到解决方案。似乎我走错了方向 我正在寻找Scala的解决方案。谢谢 使用单调递增id的输出 scala> val data = Seq((3,0),(3,1),(3,
id value
3 0
3 1
3 0
4 1
4 0
4 0
我想创建一个新的数据帧:
3 0
3 1
4 1
需要删除每个id的1value之后的所有行。我尝试了spark dateframeScala中的窗口函数。但无法找到解决方案。似乎我走错了方向
我正在寻找Scala的解决方案。谢谢
使用单调递增id的输出
scala> val data = Seq((3,0),(3,1),(3,0),(4,1),(4,0),(4,0)).toDF("id", "value")
data: org.apache.spark.sql.DataFrame = [id: int, value: int]
scala> val minIdx = dataWithIndex.filter($"value" === 1).groupBy($"id").agg(min($"idx")).toDF("r_id", "min_idx")
minIdx: org.apache.spark.sql.DataFrame = [r_id: int, min_idx: bigint]
scala> dataWithIndex.join(minIdx,($"r_id" === $"id") && ($"idx" <= $"min_idx")).select($"id", $"value").show
+---+-----+
| id|value|
+---+-----+
| 3| 0|
| 3| 1|
| 4| 1|
+---+-----+
如果我们在原始数据帧中进行排序转换,那么解决方案将不起作用。这一次,单调递增的id是基于原始DF而不是排序的DF生成的。我以前错过了这个需求
欢迎所有建议 一种方法是使用单调递增的id和自联接:
val data = Seq((3,0),(3,1),(3,0),(4,1),(4,0),(4,0)).toDF("id", "value")
data.show
+---+-----+
| id|value|
+---+-----+
| 3| 0|
| 3| 1|
| 3| 0|
| 4| 1|
| 4| 0|
| 4| 0|
+---+-----+
现在,我们生成一个名为idx的列,其长度不断增加:
现在我们得到每个id的minidx,其中value=1:
现在,我们将minidx连接回原始数据帧:
嗨,我找到了使用窗口和自连接的解决方案
val data = Seq((3,0,2),(3,1,3),(3,0,1),(4,1,6),(4,0,5),(4,0,4),(1,0,7),(1,1,8),(1,0,9),(2,1,10),(2,0,11),(2,0,12)).toDF("id", "value","sorted")
data.show
scala> data.show
+---+-----+------+
| id|value|sorted|
+---+-----+------+
| 3| 0| 2|
| 3| 1| 3|
| 3| 0| 1|
| 4| 1| 6|
| 4| 0| 5|
| 4| 0| 4|
| 1| 0| 7|
| 1| 1| 8|
| 1| 0| 9|
| 2| 1| 10|
| 2| 0| 11|
| 2| 0| 12|
+---+-----+------+
val sort_df=data.sort($"sorted")
scala> sort_df.show
+---+-----+------+
| id|value|sorted|
+---+-----+------+
| 3| 0| 1|
| 3| 0| 2|
| 3| 1| 3|
| 4| 0| 4|
| 4| 0| 5|
| 4| 1| 6|
| 1| 0| 7|
| 1| 1| 8|
| 1| 0| 9|
| 2| 1| 10|
| 2| 0| 11|
| 2| 0| 12|
+---+-----+------+
var window=Window.partitionBy("id").orderBy("$sorted")
val sort_idx=sort_df.select($"*",rowNumber.over(window).as("count_index"))
val minIdx=sort_idx.filter($"value"===1).groupBy("id").agg(min("count_index")).toDF("idx","min_idx")
val result_id=sort_idx.join(minIdx,($"id"===$"idx") &&($"count_index" <= $"min_idx"))
result_id.show
+---+-----+------+-----------+---+-------+
| id|value|sorted|count_index|idx|min_idx|
+---+-----+------+-----------+---+-------+
| 1| 0| 7| 1| 1| 2|
| 1| 1| 8| 2| 1| 2|
| 2| 1| 10| 1| 2| 1|
| 3| 0| 1| 1| 3| 3|
| 3| 0| 2| 2| 3| 3|
| 3| 1| 3| 3| 3| 3|
| 4| 0| 4| 1| 4| 3|
| 4| 0| 5| 2| 4| 3|
| 4| 1| 6| 3| 4| 3|
+---+-----+------+-----------+---+-------+
仍在寻找更优化的解决方案。谢谢你可以像这样简单地使用groupBy
val df2 = df1.groupBy("id","value").count().select("id","value")
id value
3 0
3 1
4 1
4 0
这是您的df1
结果数据帧是df2,这是您预期的输出,如下所示
val df2 = df1.groupBy("id","value").count().select("id","value")
id value
3 0
3 1
4 1
4 0
“到目前为止你尝试了什么?”eliasah我尝试了一些基于答案的实验。但到目前为止,你的DF还没有成功吗?@TheArchetypalPaul是的,它是成功的。这是因为你每次都在给show打电话。在我下面的代码中,计算是惰性的-只有在调用我的最终显示后,才会计算原始的val dataWithIndex。但你每次都会打电话给show,强迫重新评估。停止调用show,或者在创建dataWithIndexYeah后立即调用cache,不要深入查看通过单调增加id生成的列-每次查看时可能会得到不同的值-您看到的数字基于分区方案。只需运行代码,不要查看中间值。如果出于理智考虑,希望每次都看到相同的值,请添加dataWithIndex.cache行。但它不会改变整体结果——它只是让你可以在显微镜下观察每一步,而不会觉得自己疯了。谢谢@davidGirffin。我没有正确获得输出,我检查了中间结果。我已经更新了问题本身的输出。请你看一看。回答。这是因为每次你打电话给show,它都会迫使你重新评估。这就像量子力学——你通过观察来改变它的值。如果你像我一样运行代码-只有最后一场-它会得到正确的结果。
val df2 = df1.groupBy("id","value").count().select("id","value")
id value
3 0
3 1
3 0
4 1
4 0
4 0
id value
3 0
3 1
4 1
4 0
use isin method and filter as below:
val data = Seq((3,0,2),(3,1,3),(3,0,1),(4,1,6),(4,0,5),(4,0,4),(1,0,7),(1,1,8),(1,0,9),(2,1,10),(2,0,11),(2,0,12)).toDF("id", "value","sorted")
val idFilter = List(1, 2)
data.filter($"id".isin(idFilter:_*)).show
+---+-----+------+
| id|value|sorted|
+---+-----+------+
| 1| 0| 7|
| 1| 1| 8|
| 1| 0| 9|
| 2| 1| 10|
| 2| 0| 11|
| 2| 0| 12|
+---+-----+------+
Ex: filter based on val
val valFilter = List(0)
data.filter($"value".isin(valFilter:_*)).show
+---+-----+------+
| id|value|sorted|
+---+-----+------+
| 3| 0| 2|
| 3| 0| 1|
| 4| 0| 5|
| 4| 0| 4|
| 1| 0| 7|
| 1| 0| 9|
| 2| 0| 11|
| 2| 0| 12|
+---+-----+------+