Pyspark SQL Pandas UDF:返回数组

时间:2018-09-21 15:56:56

标签: python pandas pyspark pyspark-sql databricks

我正在尝试制作一个熊猫UDF,该熊猫UDF接受两列具有整数值,并基于这些值之间的差异返回一个十进制数组,其长度等于上述差异。

到目前为止,这是我的尝试,我一直在用很多不同的方法来尝试使此方法起作用,但这是一般的想法

Conv2D

这是我的用法示例

import pandas as pd

@pandas_udf(ArrayType(DecimalType()), PandasUDFType.SCALAR)
def zero_pad(x, y):
  buffer = []

  for i in range(0, (x - y)):
    buffer.append(0.0)

  return buffer #correction provided by Ali Yessili

最终结果为df = df.withColumn("zero_list", zero_pad(df.x, df.y)) ,其中一个名为df的新列是一个看起来像zero_list的ArrayType(DecimalType())列,其长度为(df.x-df .y)

该错误消息是如此普遍,几乎不值得发布,只是“由于阶段故障而导致作业中止”,并且仅追溯到我执行[0.0, 0.0, 0.0, ...]的代码部分,

df.show()

我希望有人可以向我指出正确的方向,制作出一个熊猫udf,该udf将返回可变长度的数组,或者只是告诉我为什么我的代码或方法错误。

我正在使用带有Spark 2.3.1的数据块来完成所有这些操作。

2 个答案:

答案 0 :(得分:0)

我不明白为什么您要从函数中返回熊猫系列值。对于每个输入,它将返回多行。

>>> import pandas as pd
>>> def zero_pad(x, y):
...     buffer = []
...     for i in range(0, (x - y)):
...             buffer.append(0.0)
...     return pd.Series(buffer)
... 
>>> zero_pad(5,1)
0    0.0
1    0.0
2    0.0
3    0.0
dtype: float64

因此,您不能添加具有多行结果的列。

另一方面,您不能在withColumn语句中直接使用udf。请在下面查看我的脚本,我认为结果正是您想要的

>>> from pyspark.sql.functions import udf
>>> 
>>> data = sc.parallelize([
...     (2,1),
...     (8,1),
...     (5,2),
...     (6,4)])
>>> columns = ['x','y']
>>> df = spark.createDataFrame(data, columns)
>>> df.show()
+---+---+
|  x|  y|
+---+---+
|  2|  1|
|  8|  1|
|  5|  2|
|  6|  4|
+---+---+

>>> def zero_pad(x, y):
...     buffer = []
...     for i in range(0, (x - y)):
...             buffer.append(0.0)
...     return buffer
... 
>>> my_udf = udf(zero_pad)
>>> df = df.withColumn("zero_list", my_udf(df.x, df.y))
>>> df.show()
+---+---+--------------------+
|  x|  y|           zero_list|
+---+---+--------------------+
|  2|  1|               [0.0]|
|  8|  1|[0.0, 0.0, 0.0, 0...|
|  5|  2|     [0.0, 0.0, 0.0]|
|  6|  4|          [0.0, 0.0]|
+---+---+--------------------+

答案 1 :(得分:0)

这个问题大约一年前,但是我遇到了同样的问题,这是我使用pandas_udf的解决方案:

import pandas as pd
from pyspark.sql.functions import pandas_udf, PandasUDFType
from pyspark.sql.types import *

@pandas_udf(ArrayType(IntegerType()), PandasUDFType.SCALAR)
def zero_pad(xs,ys):
    buffer = []
    for idx, x in enumerate(xs):
        buffer.append([0]*int(x-ys[idx]))

    return pd.Series(buffer)

df = df.withColumn("zero_list", zero_pad(df.x, df.y))