使用spark scala中的其他数据帧过滤一个数据帧
我将使用以下两个数据框演示我的问题使用spark scala中的其他数据帧过滤一个数据帧,scala,apache-spark,filter,Scala,Apache Spark,Filter,我将使用以下两个数据框演示我的问题 val datF1= Seq((1,"everlasting",1.39),(1,"game", 2.7),(1,"life",0.69),(1,"learning",0.69), (2,"living",1.38),(2,"worth",1.38),(2,"life",0.69),(3,"learning",0.69),(3,"never",1.38)).toDF("ID","token","value") dat
val datF1= Seq((1,"everlasting",1.39),(1,"game", 2.7),(1,"life",0.69),(1,"learning",0.69),
(2,"living",1.38),(2,"worth",1.38),(2,"life",0.69),(3,"learning",0.69),(3,"never",1.38)).toDF("ID","token","value")
datF1.show()
+---+-----------+-----+
| ID| token|value|
+---+-----------+-----+
| 1|everlasting| 1.39|
| 1| game| 2.7|
| 1| life| 0.69|
| 1| learning| 0.69|
| 2| living| 1.38|
| 2| worth| 1.38|
| 2| life| 0.69|
| 3| learning| 0.69|
| 3| never| 1.38|
+---+-----------+-----+
val dataF2= Seq(("life ",0.71),("learning",0.75)).toDF("token1","val2")
dataF2.show()
+--------+----+
| token1|val2|
+--------+----+
| life |0.71|
|learning|0.75|
+--------+----+
我想根据dataF2的token1筛选dataF1的ID和值。对于dataF2的token1中的每个单词,如果有单词标记,则值应等于dataF1的值,否则值应为零。
换句话说,我期望的输出应该是这样的
由于ID=2中没有表示学习,因此val等于零。同样地,因为生命不存在,ID等于3,val2等于零
我手工做的如下:
val newQ61=datF1.filter($"token"==="learning")
val newQ7 =Seq(1,2,3).toDF("ID")
val newQ81 =newQ7.join(newQ61, Seq("ID"), "left")
val tf2=newQ81.select($"ID" ,when(col("value").isNull ,0).otherwise(col("value")) as "val" )
val newQ62=datF1.filter($"token"==="life")
val newQ71 =Seq(1,2,3).toDF("ID")
val newQ82 =newQ71.join(newQ62, Seq("ID"), "left")
val tf3=newQ82.select($"ID" ,when(col("value").isNull ,0).otherwise(col("value")) as "val2" )
val tf4 =tf2.join(tf3 ,Seq("ID"), "left")
tf4.show()
+---+----+----+
| ID| val|val2|
+---+----+----+
| 1|0.69|0.69|
| 2| 0.0|0.69|
| 3|0.69| 0.0|
+---+----+----+
有没有办法通过访问另一个数据帧中一个数据帧的索引来更高效地执行此操作,而不是手动执行此操作?因为在现实生活中,可能有两个以上的单词,所以手动访问每个单词可能非常困难
多谢各位
更新
当我使用leftsemi-join时,我的输出如下:
datF1.join(dataF2, $"token"===$"token1", "leftsemi").show()
+---+--------+-----+
| ID| token|value|
+---+--------+-----+
| 1|learning| 0.69|
| 3|learning| 0.69|
+---+--------+-----+
看起来你需要左半连接。它将根据另一个数据帧过滤一个数据帧。 试着像这样使用它
datF1.join(datF2, $"token"===$"token2", "leftsemi")
您可以在此处找到更多信息-我相信左外连接然后在令牌上旋转可以在此处工作:
val ans = df1.join(df2, $"token" === $"token1", "LEFT_OUTER")
.filter($"token1".isNotNull)
.select("ID","token","value")
.groupBy("ID")
.pivot("token")
.agg(first("value"))
.na.fill(0)
没有空处理的结果:
ans.show
+---+--------+----+
| ID|learning|life|
+---+--------+----+
| 1| 0.69|0.69|
| 3| 0.69|0.0 |
| 2| 0.0 |0.69|
+---+--------+----+
更新:正如Lamanus的回答所建议的,内部连接可能比外部连接+过滤器更好。我认为内部连接就足够了。顺便说一句,我在你的测试用例中发现了拼写错误,这使得结果是错误的
val dataF1=序列1,永久,1.39,
1,游戏,2.7,
1,生命,0.69,
1,学习,0.69,
2,生活,1.38,
2,沃思,1.38,
2,生命,0.69,
3,学习,0.69,
3,从不,1.38。toDFID,标记,值
dataF1.show
// +--+------+---+
//| ID |标记|值|
// +--+------+---+
//| 1 |永恒| 1.39|
//| 1 |游戏| 2.7|
//| 1 |生活| 0.69|
//| 1 |学习| 0.69|
//| 2 |生活| 1.38|
//| 2 |沃思| 1.38|
//| 2 |生活| 0.69|
//| 3 |学习| 0.69|
//| 3 |从不| 1.38|
// +--+------+---+
val dataF2=Seqlife,0.71,//life->life
学习,0.75。托夫多克1,瓦尔2
dataF2.show
// +----+--+
//|代币1 |代币2|
// +----+--+
//|生活| 0.71|
//|学习| 0.75|
// +----+--+
val resultDF=dataF1.joindataF2,$token===$token1,内部
结果显示
// +--+----+---+----+--+
//| ID |标记|值|标记1 |值2|
// +--+----+---+----+--+
//| 1 |生活| 0.69 |生活| 0.71|
//| 1 |学习| 0.69 |学习| 0.75|
//| 2 |生活| 0.69 |生活| 0.71|
//| 3 |学习| 0.69 |学习| 0.75|
// +--+----+---+----+--+
resultDF.groupByID.pivottoken.aggfirstvalue
.na.fill0.orderByID.show
这将为您提供以下结果:
+---+--------+----+
| ID|learning|life|
+---+--------+----+
| 1| 0.69|0.69|
| 2| 0.0|0.69|
| 3| 0.69| 0.0|
+---+--------+----+
谢谢你的回答。但leftsemi-joing可能无法完全解决我的问题。我已经用leftsemi join得到的输出更新了我的问题。再次感谢,谢谢。您能建议如何将这些空值转换为零吗?@Sam88 Plz请参阅更新的答案。。同样相关的还有:
+---+--------+----+
| ID|learning|life|
+---+--------+----+
| 1| 0.69|0.69|
| 2| 0.0|0.69|
| 3| 0.69| 0.0|
+---+--------+----+