【Pyspark】UDF函数的使用、UDF传入多个参数、UDF传出多个参数、传入特殊数据类型

目录

一、udf函数的使用基础

方式1:用@装饰器注册udf函数

方法2: 注册udf函数 

二、udf函数传入多个参数

三、udf函数传入固定参数/常数值/string

 方法1:利用 lit()函数

方法2:利用闭包

方法3:利用lambda匿名函数+闭包

四、传入字典/tuple等特殊数据类型

五、传出多个参数

六、参考文献


一、udf函数的使用基础
 

方式1:用@装饰器注册udf函数

特点:注册为udf函数的函数不能直接再被其他地方调用,使用不方便,我个人不建议这种形式

from pyspark.sql.functions import udf
from pyspark.sql.types import StringType
import numpy as np 
import math

@udf(returnType=StringType())
def caculateClusterBelongTo(inlist):
	try:
		#不用再进行for line in sys.stdin
		#直接对数据执行split,因为进来的就只有一行数据
		thing1,thing2,thing3,thing4 = inlist.strip().decode('utf-8').split('&&')
		…….. #省略中间过程
		out= '$$'.join([str(thing1),str(currentShortestDistance),str(thisPoiCurrentCluster)])
		return out
	except Exception,e:
	        return 'wrong'
	        pass
	

 

方法2: 注册udf函数 

特点: 可以单独注册一个新的udf函数,个人认为可以起一个别的名字,方便识别,又不与之前的函数冲突,方便各自独立使用


def func(data_col1):
    xxxx   #进行处理
    return str_out
func_udf = udf( func, StringType())

# 以下两者读取 col 列数据的方式不同 都可以用效果一样
# 1
df_out = df.withColumn("new_col", func_udf(df["col1"]))
# 2
df_out = df.withColumn("new_col", func_udf(df.col1))

 

 

二、udf函数传入多个参数

def func(data_col1,data_col2):
    xxxx   #进行处理
    return str_out
func_udf = udf( func, StringType())

# 以下两者读取 col 列数据的方式不同 都可以用效果一样
# 1

df_out = df.withColumn("new_col", func_udf(df["col1"],df["col2"]))

# 2

df_out = df.withColumn("new_col", func_udf(df.col1,df.col2))

 

三、udf函数传入固定参数/常数值/string

方法1:利用 lit()函数

用pyspark的lit函数,df增加一列每一行都为固定参数的列

再将多列传入普通的udf函数中

def func(col_var,businesstype, routeid, locale, languagetype, sentence):
    # 可以执行一些操作
    xyz = func_other(col_var,businesstype, routeid, locale, languagetype, sentence)
    return xyz
func_udf = udf( func, StringType())

# 先增加一列值为var的列 每一行数据都一样是var
df  = df.withColumn('col_var', F.lit(var))
# 再执行主要的计算步骤
df_out = df.withColumn("new_col", func_udf(df.businesstype, df.businessid, df.locale,df.languagetype, df.content, df.col_var)

 

方法2:利用闭包

函数套函数


def generate_udf(var1, var2):
    def func_inudf(businesstype, routeid, locale, languagetype, sentence):
        # func_inudf中可以将外部的固定变量当做全局变量使用
        var1_ = f1(var1)
        var2_ = f2(var2)

        # 也可以增加一些其他的操作
        xyz = f3(businesstype, routeid, locale, languagetype, sentence)
        return xyz

    return F.udf(func_inudf, StringType())

df_out  = df.withColumn('new_col',
                   generate_udf(var1, var2)(df.businesstype, df.businessid, df.locale,df.languagetype, df.content)
# df_out会增加一列叫new_col的,返回值是xyz

 

方法3:利用lambda匿名函数+闭包

外部调用udf时输入的列和内部的匿名函数的参数位置对应,

输入的固定参数和内部的大函数参数位置对应

内部的匿名函数可以使用内部的大函数的参数,从而保证内部函数的参数完整

# 功能:grid search

def NDCG_sort_process(weight):
    return udf(lambda expo,click:NDCG_sort(expo,click,weight))
def top_sort_process(weight):
    return udf(lambda expo,click:top_ratio_sort(expo,click,weight))

from tqdm import tqdm
for i in tqdm(range(1,100,)):
	   info_sort=info_top.withColumn("NDCG_sort",NDCG_sort_process(0.1*i)(info_top.expo,info_top.click))
    info_top_sort=info_sort.withColumn("top_ratio_sort",top_sort_process(0.1*i)(info_sort.expo,info_sort.click))
    print("weight:%f NDCG:%f" % (0.1*i,info_top_sort.agg({"NDCG_sort": "avg"}).toPandas()['avg(NDCG_sort)'].tolist()[0]))
    print("weight:%f top10 ratio:%f" % (0.1*i,info_top_sort.agg({"top_ratio_sort": "avg"}).toPandas()['avg(top_ratio_sort)'].tolist()[0]))
	

 

 

四、传入字典/tuple等特殊数据类型

利用json序列化一下数据,传参,使用的时候再解析


def generate_udf(json_dict, var1, var2):
    def func_inudf(businesstype, routeid, locale, languagetype, sentence):
        # func_inudf中可以将外部的固定变量当做全局变量使用
        
        # 内部函数中对其重新解析为字典使用
        dict_ = json.loads(json_dict)
        var1_ = f1(var1)
        var2_ = f2(var2)

        # 也可以增加一些其他的操作
        xyz = f3(dict_, businesstype, routeid, locale, languagetype, sentence)
        return xyz

    return F.udf(func_inudf, StringType())

# 利用json序列化一下数据,传参,使用的时候再解析
json_dict = json.dumps( dict_ )

df_out  = df.withColumn('new_col',
                   generate_udf(json_dict, var1, var2)(df.businesstype, df.businessid, df.locale,df.languagetype, df.content)
# df_out会增加一列叫new_col的,返回值是xyz

 

五、传出多个参数

将需要输出的固化为json或者字符串,用特殊符号作为分隔符将其相连

输出后再根据特殊符号的分隔符将其split开

再取对应位置的参数到新的列


def generate_udf(json_dict, var1, var2):
    def func_inudf(businesstype, routeid, locale, languagetype, sentence):
        # func_inudf中可以将外部的固定变量当做全局变量使用

        # 内部函数中对其重新解析为字典使用
        dict_ = json.loads(json_dict)
        var1_ = f1(var1)
        var2_ = f2(var2)

        # 也可以增加一些其他的操作
        x, y, z = f3(dict_, businesstype, routeid, locale, languagetype, sentence)
        return x+"@@"+y +"@@"+ z

    return F.udf(func_inudf, StringType())

# 利用json序列化一下数据,传参,使用的时候再解析
json_dict = json.dumps( dict_ )

df_out  = df.withColumn('new_col',
                   generate_udf(json_dict, var1, var2)(df.businesstype, df.businessid, df.locale,df.languagetype, df.content)
# df_out会增加一列叫new_col的,返回值是xyz

df_split = df_out.withColumn("s", F.split(df1['new_col'], "@@")) 

df_split = df_split.withColumn('Item0', df_split["s"].getItem(0)) 
df_split = df_split.withColumn('Item1', df_split["s"].getItem(1))
df_split = df_split.withColumn('Item2', df_split["s"].getItem(2))

df_out_final = df_split

 

 

六、参考文献

【Pyspark】 一列变多列 、分割 一行中的list分割转为多列 explode,多列变一列(可保持原顺序), 多行变一行

https://blog.csdn.net/sunflower_sara/article/details/104044252

pySpark udf函数传入常数值

https://www.pythonheidong.com/blog/article/275097/

pyspark中udf传参数(非列值参数)

https://blog.csdn.net/u011582757/article/details/102991347?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

Spark UDF使用详解及代码示例

https://www.jianshu.com/p/bded081b5350

你可能感兴趣的:(pyspark)