如何在Spark Scala数据帧中应用布尔索引?
我有两个Spark Scala数据帧,我需要使用一个数据帧中的一个布尔列来过滤第二个数据帧。两个数据帧的行数相同 在熊猫中,我希望它是这样的:如何在Spark Scala数据帧中应用布尔索引?,scala,apache-spark,apache-spark-sql,Scala,Apache Spark,Apache Spark Sql,我有两个Spark Scala数据帧,我需要使用一个数据帧中的一个布尔列来过滤第二个数据帧。两个数据帧的行数相同 在熊猫中,我希望它是这样的: import pandas as pd df1 = pd.DataFrame({"col1": ["A", "B", "A", "C"], "boolean_column": [True, False, True, False]})
import pandas as pd
df1 = pd.DataFrame({"col1": ["A", "B", "A", "C"], "boolean_column": [True, False, True, False]})
df2 = pd.DataFrame({"col1": ["Z", "X", "Y", "W"], "col2": [1, 2, 3, 4]})
filtered_df2 = df2[df1['boolean_column']]
// Expected filtered_df2 should be this:
// df2 = pd.DataFrame({"col1": ["Z", "Y"], "col2": [1, 3]})
如何以最节省时间的方式在Spark Scala中执行相同的操作
我目前的解决方案是将“boolean_column”从df1
添加到df2
,然后过滤df2
,只选择新添加列中具有true
值的行,最后从df2
中删除“boolean_column”
,但我不确定这是最佳解决方案
如有任何建议,我们将不胜感激
编辑:
- 预期输出是一个Spark Scala数据帧(不是列表或列),与第二个数据帧具有相同的模式,并且只有
df2
中满足df1
的的“布尔列”
中的布尔掩码的行子集
- 上面介绍的
df2
模式只是一个示例。我希望接收df2
作为参数,具有任意数量的不同(且不固定)模式的列
您可以压缩数据帧
并对这些元组进行过滤
val ints = sparkSession.sparkContext.parallelize(List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
val bools = sparkSession.sparkContext.parallelize(List(true, false, true, false, true, false, true, false, true, false))
val filtered = ints.zip(bools).filter { case (int, bool) => bool }.map { case (int, bool) => int }
println(filtered.collect().toList) //List(1, 3, 5, 7, 9)
我用以下代码解决了这个问题:
import org.apache.spark.sql.types.{LongType, StructField, StructType}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.{DataFrame, Row, SQLContext, SparkSession}
val spark = SparkSession.builder().appName(sc.appName).master(sc.master).getOrCreate()
val sqlContext = spark.sqlContext
def addColumnIndex(df: DataFrame, sqlContext: SQLContext) = sqlContext.createDataFrame(
// Add Column index
df.rdd.zipWithIndex.map{case (row, columnindex) => Row.fromSeq(row.toSeq :+ columnindex)},
// Create schema
StructType(df.schema.fields :+ StructField("columnindex", LongType, nullable = false))
)
import spark.implicits._
val DF1 = Seq(
("A", true),
("B", false),
("A", true),
("C", false)
).toDF("col1", "boolean_column")
val DF2 = Seq(
("Z", 1),
("X", 2),
("Y", 3),
("W", 4)
).toDF("col_1", "col_2")
// Add index
val DF1WithIndex = addColumnIndex(DF1, sqlContext)
val DF2WithIndex = addColumnIndex(DF2, sqlContext)
// Join
val joinDF = DF2WithIndex
.join(DF1WithIndex, Seq("columnindex"))
.drop("columnindex", "col1")
// Filter
val filteredDF2 = joinDF.filter(joinDF("boolean_column")).drop("boolean_column")
过滤后的数据帧将如下所示:
+-----+-----+
|col_1|col_2|
+-----+-----+
| Z| 1|
| Y| 3|
+-----+-----+
它们有共同的键连接在一起吗?否则,无法合并/加入数据帧。我建议过滤df1(仅保留true
),然后使用左半
连接我同意,如果没有连接条件,则无法保证两个表中的行将以相同的顺序连接否,数据集没有任何公共键,即使第一个数据集的每一行引用第二个数据集的每一行(第一行与第一行、第二行与第二行等),如果它们没有公共键,您如何知道df1[row1]
对应于df2[row1]
?每次加载两个数据集时,它们的顺序是否一致?一般来说,从一个数据集到另一个数据集使用/应用值的唯一方法是通过join,正如@RaphaelRoth已经提到的那样。如果两个数据集的顺序都是确定的,那么您可以使用类似于rowNumber
的方法向两个数据集添加一个公共id,并最终将它们连接起来。正如您所说的,顺序是确定的这可以通过ints.zip(bools)更简洁地完成。收集{case(int,bool)If bool=>int}
我对问题进行了编辑,对预期的输出和输入进行了一些额外的说明,因为建议的答案不会返回与df2