Scala 选择spark中每行的所有非空列名
假设我有一个如下所示的数据帧:Scala 选择spark中每行的所有非空列名,scala,dataframe,apache-spark,apache-spark-sql,Scala,Dataframe,Apache Spark,Apache Spark Sql,假设我有一个如下所示的数据帧: +-----+-----+-----+-----+ | A | B | C | D | +-----+-----+-----+-----+ | Y |null | Y |null | |null | N | N |null | | N | Y |null | N | +-----+-----+-----+-----+ val nonNullColsExpr = df.columns.map(c => when(c
+-----+-----+-----+-----+
| A | B | C | D |
+-----+-----+-----+-----+
| Y |null | Y |null |
|null | N | N |null |
| N | Y |null | N |
+-----+-----+-----+-----+
val nonNullColsExpr = df.columns.map(c => when(col(c).isNotNull, lit(c)))
df.withColumn("non_null", array(nonNullColsExpr:_*))
.withColumn("non_null", expr("array_join(non_null, ',')"))
.show()
//+----+----+----+----+--------+
//| A| B| C| D|non_null|
//+----+----+----+----+--------+
//| Y|null| Y|null| A,C|
//|null| N| N|null| B,C|
//| N| Y|null| N| A,B,D|
//+----+----+----+----+--------+
我想添加一个新列,它是每行所有非空列名称的串联
因此,对于上面的示例,它将添加一个新列
+--------+
|non-null|
+--------+
| A, C |
| B, C |
| A, B, D|
+--------+
有什么简单的方法可以做到这一点吗?我试图寻找一个反合并,如果不是null,它将使用提供的名称。例如,如果存在反聚结:
df.withColumn("non-null", antiCoalesce("A", "A,") + antiCoalesce("B", "B,") + antiCoalesce("C", "C,") + antiCoalesce("D", "D"))
遗憾的是,没有这样的函数,但它演示了我所寻找的内容。在SQL中,您可以使用
concat_ws()
来表达这一点:
这种方法怎么样?您可以使用新列
concat_ws
,这些新列包含列的名称(当列不为空时)
val df = Seq(("Y", null, "Y", null),
(null, "N", "N", null),
("N", "Y", null, "N")).toDF("A", "B", "C", "D")
val columns = df.columns
columns.foldLeft(df) {(df, name) => df.withColumn(name + "2", when(!col(name).isNull, lit(name)))}
.withColumn("non-null", concat_ws(",", columns.map(name => col(name + "2")): _*))
.drop(columns.map(name => name + "2"): _*)
.show(false)
那么
使用Spark 2.4+,您可以执行以下操作:
+-----+-----+-----+-----+
| A | B | C | D |
+-----+-----+-----+-----+
| Y |null | Y |null |
|null | N | N |null |
| N | Y |null | N |
+-----+-----+-----+-----+
val nonNullColsExpr = df.columns.map(c => when(col(c).isNotNull, lit(c)))
df.withColumn("non_null", array(nonNullColsExpr:_*))
.withColumn("non_null", expr("array_join(non_null, ',')"))
.show()
//+----+----+----+----+--------+
//| A| B| C| D|non_null|
//+----+----+----+----+--------+
//| Y|null| Y|null| A,C|
//|null| N| N|null| B,C|
//| N| Y|null| N| A,B,D|
//+----+----+----+----+--------+
首先,我们创建一个数组列,其中包含满足条件
isNotNull
的列名,不满足条件的列名将为null。然后使用,
分隔符(array\u join
在加入元素时过滤空值)将元素连接起来 这确实有效,但速度非常慢。还有更有效的方法吗?@Geoffreysaunds。我不知道这为什么会“非常慢”。它只是对每一行进行相对简单的计算。我真的想不出任何更快的事情。我有一个实现这样的事情,这真的需要很长的时间,所以我没有考虑它。我应该把它贴出来,作为我写问题时尝试的解决方案。我可以发布我在上面的问题,但它几乎完全是你在这里发布的。完美。哇,这真是跳出框框思考。太棒了我很抱歉问,但我已经挣扎了一整天。。。如何将此表达式转换为pyspark
?@GuidoCioni在pyspark中,您可以这样做:non\u null\u cols=[when(col(c).isNotNull,lit(c))for c in df.columns]
然后使用它:df.withColumn(“non\u null”,array(*non\u null\u cols))
。其余部分与Scala中的相同。我可以这样使用它:ds.withColumn(“missing_L”,F.array(*[F.when(F.isnull(c),F.lit(c)),ds.columns中的c为F.when(F.isnull(c),F.lit(c))。withColumn(“missing_L”,F.expr(“array_join(missing_L',,”))))。withColumn(“missing___L”,F.regexp(替换(F.coll)(“missing_L”),“on object”,”)。选择(“msn”、“缺失”)