如何动态地在多个列上执行udfs

时间:2018-01-16 06:39:30

标签: scala apache-spark pyspark apache-spark-sql pyspark-sql

我有30列,如DPF_1,DPF_2,DPF_3 ...... DPF_30,我需要在其上应用数据帧。所有30列数据类型都是String。 我的要求是转换所有" Na"这些30列中出现的值为" null"

我试过下面的代码,但它不是动态的。

def udf_A(x:StringType()):
    if x == "Na": return "null"
    else:return x
udf_B = udf(udf_A, StringType())

df.withColumn("DPF_1" udf_B("DPF_1"))
df.withColumn("DPF_2" udf_B("DPF_2"))
.
.
repeated till DPF_30 

现在我想在pyspark / scala中动态地使用这个过程,因为后面的列可能会随着不同的列名而增加。

4 个答案:

答案 0 :(得分:2)

这是Scala中的解决方案:

// columns which you want to keep 
val colsToSelect : Seq[Column] = ???
// columns which are applied to UDF
val selectUDFs : Seq[Column] = (1 to 30).map(i => udf_B(col(s"DPF_$i")).as(s"DPF_$i"))

df.select((colsToSelect++selectUDFs):_*)

答案 1 :(得分:2)

您只需将 30列数据框转换为na dataframe并将replace方法应用为

df.na.replace(df.columns, Map("Na" -> "null"))

您已将所有Na字符串替换为null字符串。

答案 2 :(得分:1)

Scala中的一种方法是使用过滤器组合列列表并遍历列表以使用UDF转换DataFrame:

val cols = df.columns.filter(_.startsWith("DPF_"))

val df2 = cols.foldLeft( df )( (acc, c) => acc.withColumn(c, udf_B(df(c))) )

答案 3 :(得分:0)

请尝试以下代码,希望这有帮助。

def udf_A(x:StringType()):
    if x == "Na": return "null"
    else:return x
udf_B = udf(udf_A, StringType())

import pyspark.sql.functions as psf

for c in df.dtypes:
    if "string" in c[1]:
        df=df.withColumn(c[0],udf_B(psf.col(c[0])))
df.show()

下面, df.dtypes为您提供列名和数据类型

的元组数组
[('DPF_1', 'string'), ('DPF_2', 'string'), ('DPF_3', 'string')... ]

c[0]表示列名称,c[1]表示您的案例中string的数据类型。