Python PySpark行函数组合

Python PySpark行函数组合,python,apache-spark,pyspark,apache-spark-sql,Python,Apache Spark,Pyspark,Apache Spark Sql,作为一个简化的示例,我有一个数据帧“df”,列为“col1,col2”,我想在对每列应用函数后计算行最大值: def f(x): return (x+1) max_udf=udf(lambda x,y: max(x,y), IntegerType()) f_udf=udf(f, IntegerType()) df2=df.withColumn("result", max_udf(f_udf(df.col1),f_udf(df.col2))) 因此,如果df: col1 col2

作为一个简化的示例,我有一个数据帧“df”,列为“col1,col2”,我想在对每列应用函数后计算行最大值:

def f(x):
    return (x+1)

max_udf=udf(lambda x,y: max(x,y), IntegerType())
f_udf=udf(f, IntegerType())

df2=df.withColumn("result", max_udf(f_udf(df.col1),f_udf(df.col2)))
因此,如果df:

col1   col2
1      2
3      0
然后

df2:

上述方法似乎不起作用,并产生“无法计算表达式:PythonUDF#f…”

我绝对肯定“f_-udf”在我的桌子上效果很好,主要问题是max_-udf

在不创建额外列或不使用基本map/reduce的情况下,有没有一种方法可以完全使用数据帧和UDF来完成上述操作?我应该如何修改“max_udf”

我也试过:

max_udf=udf(max, IntegerType())
这会产生同样的错误

我还确认了以下工作:

df2=(df.withColumn("temp1", f_udf(df.col1))
       .withColumn("temp2", f_udf(df.col2))

df2=df2.withColumn("result", max_udf(df2.temp1,df2.temp2))
为什么我不能一次完成这些


我希望看到一个可以推广到任何函数“f_udf”和“max_udf”的答案。

用户定义函数在接受udf作为其参数时抛出错误

您可以修改max_udf,如下所示,使其正常工作

df = sc.parallelize([(1, 2), (3, 0)]).toDF(["col1", "col2"])

max_udf = udf(lambda x, y: max(x + 1, y + 1), IntegerType())

df2 = df.withColumn("result", max_udf(df.col1, df.col2))

注意

当且仅当内部函数(此处
f_udf
)生成有效的SQL表达式时,第二种方法才有效

它在这里工作是因为
f_udf(df.col1)
f_udf(df.col2)
在传递到
max_udf
之前分别作为
列和
列进行评估。它不适用于任意函数

例如,如果我们尝试这样的方法,它将不起作用:

from math import exp

df.withColumn("result", max_udf(exp(df.col1), exp(df.col2)))

我有一个类似的问题,并在答案中找到了解决办法

要将多列或整行传递给UDF,请使用:

从pyspark.sql.functions导入udf,struct
从pyspark.sql.types导入IntegerType
df=sqlContext.createDataFrame([(无,无),(1,无),(无,2)],(“a”,“b”))
count\u empty\u columns=udf(lambda行:len([x表示x,如果x==None]),IntegerType()
new_df=df.withColumn(“null_count”,count_empty_columns(struct([df[x]表示df.columns中的x]))
新_df.show()
返回:

+----+----+----------+
|a | b |空|计数|
+----+----+----------+
|空|空| 2|
|1 |空| 1|
|空| 2 | 1|
+----+----+----------+

下面是一段非常有用的代码,专门用来创建任何新专栏,只需调用顶级业务规则即可,完全与技术和heavy Spark的东西隔离开来(无需再花费美元,也无需再依赖Databricks库)。 我的建议是,在您的组织中,为了顶级数据用户的利益,尽量在生活中简单、干净地做事:

def createColumnFromRule(df,columnName,ruleClass,ruleName,inputColumns=None,inputValues=None,columnType=None):
从pyspark.sql导入函数为F
从pyspark.sql导入类型为T
def_getSparkClassType(shortType):
defaultSparkClassType=“StringType”
类型映射={
“bigint”:“LongType”,
“二进制”:“二进制类型”,
“布尔型”:“布尔型”,
“byte”:“ByteType”,
“日期”:“日期类型”,
“十进制”:“十进制类型”,
“double”:“DoubleType”,
“浮动”:“浮动类型”,
“int”:“IntegerType”,
“整型”:“整型”,
“long”:“LongType”,
“数字”:“数字类型”,
“字符串”:defaultSparkClassType,
“时间戳”:“时间戳类型”
}
sparkClassType=无
尝试:
sparkClassType=类型映射[shortType]
除:
sparkClassType=默认sparkClassType
返回sparkClassType
如果(columnType!=无):sparkClassType=\u getSparkClassType(columnType)
其他:sparkClassType=“StringType”
aUdf=eval(“F.udf(ruleClass.+ruleName+”,T.“+sparkClassType+”()))
列=无
值=无
if(inputColumns!=None):columns=F.struct([df[column]表示inputColumns中的列])
if(inputValues!=None):values=F.struct([F.lit(value)表示inputValues中的值])
#叫规矩
如果(inputColumns!=None和inputValues!=None):df=df.withColumn(columnName,aUdf(columns,values))
elif(inputColumns!=None):df=df.withColumn(columnName,aUdf(columns,F.lit(None)))
elif(inputValues!=None):df=df.withColumn(columnName,aUdf(F.lit(None),values))
#否则创建空列
其他:
如果(columnType!=无):
df=df.withColumn(columnName,F.lit(None).cast(columnType))
其他:
df=df.withColumn(columnName,F.lit(无))
#返回结果数据帧
返回df
用法示例:

#定义您的业务规则(您可以获取列和值)
类CustomerRick:
def风险(自身,列=无,值=无):
isChurnRisk=False
# ... 规则的实现从这里开始
如果(值!=无):
如果(值[0]=“FORCE\u chorn=true”):isChurnRisk=true
如果(isChurnRisk==False,列!=None):

if(columns[“AGE”])处理此问题的最佳方法是退出表示并使用via和
[pyspark.RDD.map()](https://spark.apache.org/docs/latest/api/python/reference/api/pyspark.RDD.map.html#pyspark.RDD.map)

导入键入
#省去你自己的麻烦,总是导入这些东西:函数作为F,类型作为T
导入pyspark.sql.F函数
将pyspark.sql.types导入为T
从pyspark.sql导入行、SparkSession、SQLContext
火花=(
SparkSession.builder.appName(“堆栈溢出示例”)
.getOrCreate()
)
sc=spark.sparkContext
#有时需要sqlContet来从RDD创建数据帧
sqlContext=sqlContext(sc)
df=sc.parallelize([Row(**{a:“hello”,“b:1”,“c:2}),Row(**{a:“再见”,“b:2”,“c:1})]).toDF([“a”,“b”,“c”]))
def to_字符串(记录:dict)->行:
“”“创建记录的可读字符串表示形式”“”
def f_udf(x):
    return (x + 1)

max_udf = udf(lambda x, y: max(x, y), IntegerType())
## f_udf=udf(f, IntegerType())

df2 = df.withColumn("result", max_udf(f_udf(df.col1), f_udf(df.col2)))
from math import exp

df.withColumn("result", max_udf(exp(df.col1), exp(df.col2)))