Apache spark Pyspark:将UDF的结果迭代地写回dataframe不会产生预期的结果

Apache spark Pyspark:将UDF的结果迭代地写回dataframe不会产生预期的结果,apache-spark,pyspark,spark-dataframe,pyspark-sql,apache-spark-2.0,Apache Spark,Pyspark,Spark Dataframe,Pyspark Sql,Apache Spark 2.0,我仍然是pyspark的新手,我试图在UDF的帮助下对函数求值并迭代创建列。功能如下: def get_temp(df): l=['temp1','temp2','temp3'] s=[0] pt=[0] 开始=[0] 结束=[0] 累积统计=[0] 对于X范围内的p(1,4): def func(p): 如果p==1: 通过 如果p>1: 开始[0]=结束[0] s[0]=2 pt[0]=4 结束[0]=开始[0]+pt[0]-s[0] 返回端[0] func_udf=udf(func,Int

我仍然是pyspark的新手,我试图在UDF的帮助下对函数求值并迭代创建列。功能如下:

def get_temp(df):
l=['temp1','temp2','temp3']
s=[0]
pt=[0]
开始=[0]
结束=[0]
累积统计=[0]
对于X范围内的p(1,4):
def func(p):
如果p==1:
通过
如果p>1:
开始[0]=结束[0]
s[0]=2
pt[0]=4
结束[0]=开始[0]+pt[0]-s[0]
返回端[0]
func_udf=udf(func,IntegerType())
df=df.带列(l[p-1],func_udf(lit(p)))
返回df
df=获取温度(df)
df.show()
上述结果如下:

+---+---+---+-----+-----+-----+
|a | b | c | temp1 | temp2 | temp3|
+---+---+---+-----+-----+-----+
|  2| 12|  5|    0|    2|    2|
|  8|  5|  7|    0|    4|    4|
|  9|  4|  3|    0|    2|    2|
|  3|  8|  2|    0|    4|    4|
+---+---+---+-----+-----+-----+
预期结果是:

+---+---+---+-----+-----+-----+
|a | b | c | temp1 | temp2 | temp3|
+---+---+---+-----+-----+-----+
|  2| 12|  5|    0|    2|    4|
|  8|  5|  7|    0|    2|    4|
|  9|  4|  3|    0|    2|    4|
|  3|  8|  2|    0|    2|    4|
+---+---+---+-----+-----+-----+
如果仅查看内部函数的输出,结果与预期一致,即:

s=[0]
pt=[0]
开始=[0]
结束=[0]
累积统计=[0]
对于X范围内的p(1,4):
def func():
如果p==1:
通过
如果p>1:
开始[0]=结束[0]
s[0]=2
pt[0]=4
结束[0]=开始[0]+pt[0]-s[0]
返回端[0]
e=func()
打印e
输出:
0
2.
4.
不确定将这些结果从UDF写回df的正确方法是什么。发布的dataframe只是一个示例dataframe,我需要使用for循环,因为在我的原始代码中,我调用了for循环中的其他函数(谁的输出取决于迭代器的值)。例如,请参阅下面的示例:

def get_temp(df):
l=['temp1','temp2','temp3']
s=[0]
pt=[0]
开始=[0]
结束=[0]
q=[]
累积统计=[0]
对于X范围内的p(1,4):
def func(p):
如果p=a:
如果p==1:
通过
如果p>1:
开始[0]=结束[0]
s[0]=2
pt[0]=4
如果累积统计和p>1:
var1=func2(p,3000)
var2=func3(var1)
累积统计=np.nan
其他:
var1=func2(p,3000)
var2=func3(var1)
结束[0]=开始[0]+pt[0]-s[0]
q、 追加(结束[0],变量1,变量2)
返回q
func_udf=udf(func,ArrayType(ArrayType(IntegerType()))
df=df.带列(l[p-1],func_udf(lit(p)))
返回df
df=获取温度(df)
df.show()
我正在使用pyspark 2.2。非常感谢您的帮助。 要创建此数据帧,请执行以下操作:

rdd=sc.parallelize([(2,12,5),(8,5,7),
(9,4,3),
(3,8,2)])
df=sqlContext.createDataFrame(rdd,('a','b','c'))
df.show()

根据我对代码的理解,下一列的值取决于上一列的值。如果我的理解是正确的,那么我可以判断您的udf函数定义放在了错误的位置。你需要对你的代码做一些小的修改才能让它正常工作

让我们一步一步走

你已经有了

+---+---+---+
|  a|  b|  c|
+---+---+---+
|  2| 12|  5|
|  8|  5|  7|
|  9|  4|  3|
|  3|  8|  2|
+---+---+---+
我们需要一个初始值设定项列,我看到它是0

应该是哪一个

+---+---+---+-----+
|  a|  b|  c|temp0|
+---+---+---+-----+
|  2| 12|  5|    0|
|  8|  5|  7|    0|
|  9|  4|  3|    0|
|  3|  8|  2|    0|
+---+---+---+-----+
我们应该将
udf
函数作为

并在循环中调用
udf
函数

最后删除初始值设定项列

这将为您提供所需的输出

+---+---+---+-----+-----+-----+
|  a|  b|  c|temp1|temp2|temp3|
+---+---+---+-----+-----+-----+
|  2| 12|  5|    0|    2|    4|
|  8|  5|  7|    0|    2|    4|
|  9|  4|  3|    0|    2|    4|
|  3|  8|  2|    0|    2|    4|
+---+---+---+-----+-----+-----+

我希望答案是有帮助的

为什么要使用udf?这可能是一个问题吗?你想干什么?可能有一种更简单的方法。@pault我用示例代码更新了问题。我想使用udf,因为我确实在其中进行了其他函数调用,并最终对调用的函数进行了一些数学运算并返回了一个输出。上面显示的函数:func对其他函数调用进行计算由于不同列的函数不同,我建议您为每列编写不同的函数,并分别调用它们。请您进一步说明这一点好吗?我不确定如何将其解耦为单独的函数,因为累积_stat是根据在上一次迭代中获得的值进行计算的。谢谢
def func(p, end):
    start = 0
    s = 0
    pt = 0
    if p==1:
        pass
    elif p >1:
        start = end
        s=2
        pt =4
    end = start + pt - s
    return end

func_udf=F.udf(func, T.IntegerType())
def get_temp(df):
    l=['temp1','temp2','temp3']
    for p in xrange(1,4):
        df=df.withColumn(l[p-1],func_udf(F.lit(p), F.col('temp'+str(p-1))))
    return df

df=get_temp(df)
df=df.drop('temp0')
+---+---+---+-----+-----+-----+
|  a|  b|  c|temp1|temp2|temp3|
+---+---+---+-----+-----+-----+
|  2| 12|  5|    0|    2|    4|
|  8|  5|  7|    0|    2|    4|
|  9|  4|  3|    0|    2|    4|
|  3|  8|  2|    0|    2|    4|
+---+---+---+-----+-----+-----+