Python 使用带参数的分组映射UDF
我想使用data.groupby.apply()将函数应用于每个组的Pyspark Dataframe的每一行 我使用了UDF的分组映射。但是,我不知道如何向函数中添加另一个参数 我尝试将参数用作全局变量,但函数无法识别它(我的参数是pyspark数据帧)Python 使用带参数的分组映射UDF,python,pyspark,pandas-groupby,Python,Pyspark,Pandas Groupby,我想使用data.groupby.apply()将函数应用于每个组的Pyspark Dataframe的每一行 我使用了UDF的分组映射。但是,我不知道如何向函数中添加另一个参数 我尝试将参数用作全局变量,但函数无法识别它(我的参数是pyspark数据帧) 我还尝试了这个问题中提出的解决方案(针对熊猫数据帧) @pandas\u udf(模式,PandasUDFType.GROUPED\u映射) def功能(键、数据、间隔): interval\u df=interval.filter(inte
我还尝试了这个问题中提出的解决方案(针对熊猫数据帧)
@pandas\u udf(模式,PandasUDFType.GROUPED\u映射)
def功能(键、数据、间隔):
interval\u df=interval.filter(interval[“var”]==key.toPandas()
对于间隔_df中的值:
#应用一些操作
返回数据.groupBy(“msn”).apply(计算差异,('arg1'))
或
@pandas\u udf(模式,PandasUDFType.GROUPED\u映射)
def功能(键、数据、间隔):
interval\u df=interval.filter(interval[“var”]==key.toPandas()
对于间隔_df中的值:
#应用一些操作
返回数据.groupBy(“msn”).apply(lambda x:calc_diff(x,'arg1'))
但我得到了一个错误:
ValueError:函数无效:函数类型为GROUPED_MAP的Panda_UDF必须采用一个参数(数据)或两个参数(键、数据)
有人能帮我解决上述问题吗
谢谢我想你可以这样做
def myfun(data, key, interval):
#Apply some operations
return something
@pandas_udf(schema, PandasUDFType.GROUPED_MAP)
def myfun_udf(data):
return myfun(data=data, key=mykey, interval=myinterval)
mykey=1
myinterval=2
Data.groupBy("msn").apply(myfun_udf)
您可以在函数中创建udf,以便在创建函数时知道函数参数。(或者您可以导入functools并使用部分函数求值来执行相同的操作。)以下是PySpark文档中的,经过修改以传入一些参数:
from pyspark.sql.functions import pandas_udf, PandasUDFType
df = spark.createDataFrame(
[(1, 1.0), (1, 2.0), (2, 3.0), (2, 5.0), (2, 10.0)],
("id", "v"))
def my_function(df, by="id", column="v", value=1.0):
schema = "{} long, {} double".format(by, column)
@pandas_udf(schema, PandasUDFType.GROUPED_MAP)
def subtract_value(pdf):
# pdf is a pandas.DataFrame
v = pdf[column]
g = pdf[by]
return pdf.assign(v = v - g * value)
return df.groupby(by).apply(subtract_value)
my_function(df, by="id", column="v", value=2.0).show()
我喜欢@hwrd的想法,但相反,它将使其成为一种生成器模式,以便于集成,如@Feng的示例中所示:
def function_generator(key):
@pandas_udf(schema,PandasUDFType.GROUPED_MAP)
def function(interval):
interval_df=interval.filter(interval["var"]==key).toPandas()
for value in interval_df:
#Apply some operations
return function
calc_diff = function_generator('arg1')
output = Data.groupBy("msn").apply(calc_diff)
所有的答案似乎都很有用,但没有对正在发生的事情进行正式描述。所以,我从所有人那里,特别是从@sifta那里,取了一些零碎的东西,试图解释为。也许这会对将来的人有所帮助 假设我有一个PySpark DF,如下所示
# test = pd.DataFrame({
# 'c1': ['a', 'a', 'b', 'b', 'b'],
# 'c2': ['a1', 'a2', 'b1', 'b1', 'b2']})
# test = spark.createDataFrame(test)
+---+---+
| c1| c2|
+---+---+
| a| a1|
| a| a2|
| b| b1|
| b| b1|
| b| b2|
+---+---+
我的目标是创建另一列c3
,它可以是组计数+一些固定值。好的,这肯定不是最好的例子,但是让我们试着用groupby来解决它。我们需要传递参数(固定值),这是一种不直接支持的参数
所以,根据答案,我们可以得出
schema = t.StructType([
t.StructField('c1', t.StringType()),
t.StructField('c2', t.StringType()),
t.StructField('c3', t.IntegerType()),
])
def fn_wrapper(df, val):
@f.pandas_udf(schema, f.PandasUDFType.GROUPED_MAP)
def fn(pdf):
pdf['c3'] = pdf.shape[0] + val
return pdf
return df.groupby('c1', 'c2').apply(fn)
fn_wrapper(test, 7).show()
但这到底意味着什么
我们有一个用于映射fn返回的DF的模式(returnpdf
)
那么,让我们来了解这个技巧是如何工作的。我们已经定义了一个名为fn_wrapper
的普通UDF,它接受Pyspark DF和要在核心pandas groupby中使用的参数。我们在fn\u包装器(test,7.show()
中调用它。现在,当我们在fn_包装器
中时,我们只是在其中有一个函数体,它将在此时被编译而不是执行
接下来,执行语句返回df.groupby('c1','c2').apply(fn)
。请参见,我们将函数fn
定义为一个UDF,它没有任何参数。然而,当fn被称为apply
并且定义了val
时,我们仍然在fn\u包装的范围内。因此,我们可以很容易地在pdf['c3']=pdf.shape[0]+val
中引用val,其中分组数据以数据帧的形式呈现
我想这有助于理解将函数包装为函数内部的函数,以及如何将UDF与参数结合起来。在我必须处理在某个阶段不为我所知的方案的情况下,这种模式也帮助了我;我也可以把它们当作一个论点来通过。我试过上面的方法,但它不起作用!因为udf不使用定义的全局变量mykey和myinterval,所以每次更改这两个参数时,我都必须重新运行分组映射udf定义,以便更新它们!