【问题标题】:How to add a new column with a constant DenseVector to a pyspark dataframe?如何将具有常量 DenseVector 的新列添加到 pyspark 数据帧?
【发布时间】:2022-01-21 19:14:09
【问题描述】:

我想向包含常量 DenseVector 的 pyspark 数据帧添加一个新列。

以下是我的尝试,但失败了:

from pyspark.sql import SparkSession

spark = SparkSession.builder.getOrCreate()

data = [(1,2),(3,4),(5,6),(7,8)]
df = spark.createDataFrame(data=data)

@udf(returnType=VectorUDT())
def add_cons_dense_col(val):
    return val

df.withColumn('ttt',add_cons_dense_col(DenseVector([1.,0.]))).show()

它失败了:

TypeError                                 Traceback (most recent call last)
/tmp/ipykernel_3894138/803146743.py in <module>
----> 1 df.withColumn('ttt',add_cons_dense_col(DenseVector([1.,0.]))).show()

~/miniconda3/envs/pyspark/lib/python3.9/site-packages/pyspark/sql/udf.py in wrapper(*args)
    197         @functools.wraps(self.func, assigned=assignments)
    198         def wrapper(*args):
--> 199             return self(*args)
    200 
    201         wrapper.__name__ = self._name

~/miniconda3/envs/pyspark/lib/python3.9/site-packages/pyspark/sql/udf.py in __call__(self, *cols)
    177         judf = self._judf
    178         sc = SparkContext._active_spark_context
--> 179         return Column(judf.apply(_to_seq(sc, cols, _to_java_column)))
    180 
    181     # This function is for improving the online help system in the interactive interpreter.

~/miniconda3/envs/pyspark/lib/python3.9/site-packages/pyspark/sql/column.py in _to_seq(sc, cols, converter)
     59     """
     60     if converter:
---> 61         cols = [converter(c) for c in cols]
     62     return sc._jvm.PythonUtils.toSeq(cols)
     63 

~/miniconda3/envs/pyspark/lib/python3.9/site-packages/pyspark/sql/column.py in <listcomp>(.0)
     59     """
     60     if converter:
---> 61         cols = [converter(c) for c in cols]
     62     return sc._jvm.PythonUtils.toSeq(cols)
     63 

~/miniconda3/envs/pyspark/lib/python3.9/site-packages/pyspark/sql/column.py in _to_java_column(col)
     43         jcol = _create_column_from_name(col)
     44     else:
---> 45         raise TypeError(
     46             "Invalid argument, not a string or column: "
     47             "{0} of type {1}. "

TypeError: Invalid argument, not a string or column: [1.0,0.0] of type <class 'pyspark.ml.linalg.DenseVector'>. For column literals, use 'lit', 'array', 'struct' or 'create_map' function.

你能帮我理解为什么会失败吗?

【问题讨论】:

    标签: apache-spark pyspark apache-spark-sql apache-spark-ml


    【解决方案1】:

    你可以试试

    add_cons_dense_col = F.udf(lambda: DenseVector([1., 0.]), VectorUDT())
    df = df.withColumn('ttt', add_cons_dense_col())
    df.show(truncate=False)
    

    【讨论】:

    【解决方案2】:

    当您调用 UDF 而不是 DenseVector 时,您需要传递 ArrayType 类型列。而且你还需要把add_cons_dense_col函数的返回改成DenseVector

    import pyspark.sql.functions as F
    
    @F.udf(returnType=VectorUDT())
    def add_cons_dense_col(val):
        return DenseVector(val)
    
    df.withColumn('ttt', add_cons_dense_col(F.array(F.lit(1.), F.lit(1.)))).show()
    
    #+---+---+---------+
    #| _1| _2|      ttt|
    #+---+---+---------+
    #|  1|  2|[1.0,0.0]|
    #|  3|  4|[1.0,0.0]|
    #|  5|  6|[1.0,0.0]|
    #|  7|  8|[1.0,0.0]|
    #+---+---+---------+
    

    从 python 列表创建数组列:

    F.array(*[F.lit(x) for x in [1., 0., 3., 5.]])
    

    【讨论】:

    • 感谢您提供的信息丰富的回答!我对什么都可以作为 udf 的输入有点困惑。我不能使用列表,但我可以使用数组。这背后有什么原因吗?
    • @MiloMinderbinder Spark UDF 始终将列类型作为输入。这里F.array(...)返回的是列类型而不是python列表。
    • 知道了!谢谢你:)
    • 抱歉,查询迟了,但您能帮我理解为什么F.array(F.lit(1.), F.lit(1.)) 也能正常工作吗?现在输入的不是col 类型而是list 类型
    • @MiloMinderbinder F.array 函数返回一个数据类型为ArrayType 的列,它不是你在python 中知道的列表[...]
    猜你喜欢
    • 2017-01-25
    • 2020-04-19
    • 2017-02-15
    • 2018-07-25
    • 2018-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多