Python 如何将向量拆分为列-使用PySpark
上下文:我有一个Python 如何将向量拆分为列-使用PySpark,python,apache-spark,pyspark,apache-spark-sql,apache-spark-ml,Python,Apache Spark,Pyspark,Apache Spark Sql,Apache Spark Ml,上下文:我有一个DataFrame,有两列:word和vector。其中“vector”的列类型为VectorUDT 例如: word | vector assert | [435,323,324,212...] 我想得到这个: word | v1 | v2 | v3 | v4 | v5 | v6 ...... assert | 435 | 5435| 698| 356|.... 问题: 如何使用PySpark将一列向量拆分为每个维度的几列 提前感谢Spark>=3.0.0
DataFrame
,有两列:word和vector。其中“vector”的列类型为VectorUDT
例如:
word | vector
assert | [435,323,324,212...]
我想得到这个:
word | v1 | v2 | v3 | v4 | v5 | v6 ......
assert | 435 | 5435| 698| 356|....
问题:
如何使用PySpark将一列向量拆分为每个维度的几列
提前感谢Spark>=3.0.0 由于Spark 3.0.0,这可以在不使用UDF的情况下完成
from pyspark.ml.functions import vector_to_array
(df
.withColumn("xs", vector_to_array("vector")))
.select(["word"] + [col("xs")[i] for i in range(3)]))
## +-------+-----+-----+-----+
## | word|xs[0]|xs[1]|xs[2]|
## +-------+-----+-----+-----+
## | assert| 1.0| 2.0| 3.0|
## |require| 0.0| 2.0| 0.0|
## +-------+-----+-----+-----+
火花<3.0.0
一种可能的方法是在RDD之间进行转换:
from pyspark.ml.linalg import Vectors
df = sc.parallelize([
("assert", Vectors.dense([1, 2, 3])),
("require", Vectors.sparse(3, {1: 2}))
]).toDF(["word", "vector"])
def extract(row):
return (row.word, ) + tuple(row.vector.toArray().tolist())
df.rdd.map(extract).toDF(["word"]) # Vector values will be named _2, _3, ...
## +-------+---+---+---+
## | word| _2| _3| _4|
## +-------+---+---+---+
## | assert|1.0|2.0|3.0|
## |require|0.0|2.0|0.0|
## +-------+---+---+---+
另一种解决方案是创建UDF:
from pyspark.sql.functions import udf, col
from pyspark.sql.types import ArrayType, DoubleType
def to_array(col):
def to_array_(v):
return v.toArray().tolist()
# Important: asNondeterministic requires Spark 2.3 or later
# It can be safely removed i.e.
# return udf(to_array_, ArrayType(DoubleType()))(col)
# but at the cost of decreased performance
return udf(to_array_, ArrayType(DoubleType())).asNondeterministic()(col)
(df
.withColumn("xs", to_array(col("vector")))
.select(["word"] + [col("xs")[i] for i in range(3)]))
## +-------+-----+-----+-----+
## | word|xs[0]|xs[1]|xs[2]|
## +-------+-----+-----+-----+
## | assert| 1.0| 2.0| 3.0|
## |require| 0.0| 2.0| 0.0|
## +-------+-----+-----+-----+
有关Scala等效项,请参见
该函数将特征向量列转换为单独的列从 上面zero323在解决方案中给出的提取函数使用toList,它创建一个Python列表对象,用Python浮点对象填充它,通过遍历列表找到所需的元素,然后需要将列表转换回JavaDouble;每行重复一次。使用rdd比to_数组udf慢得多,后者也调用toList,但两者都比让SparkSQL处理大部分工作的udf慢得多 将rdd extract和此处提出的阵列udf与以下udf进行比较的计时代码: 结果:
i_th 0.05964796099999958
flatten 0.4842299350000001
to_array 0.42978780299999997
extract 2.9254476840000017
对于试图将PySpark ML模型训练后生成的
rawPrediction
或probability
列拆分为Pandas列的任何人,可以按如下方式拆分:
your_pandas_df['probability'].apply(lambda x: pd.Series(x.toArray()))
your_pandas_df['probability'].apply(lambda x: pd.Series(x.toArray()))
要将PySpark ML模型训练后生成的
rawPrediction
或probability
列拆分为Pandas列,可以按如下方式拆分:
your_pandas_df['probability'].apply(lambda x: pd.Series(x.toArray()))
your_pandas_df['probability'].apply(lambda x: pd.Series(x.toArray()))
就性能而言,使用
.map/.toDF
函数要聪明得多,因为它们几乎总是比UDF实现更快。[除非您使用的是spark 2.2+中的矢量化udf
定义]谢谢您的评论。RDDAPI不会在某个时候被弃用吗?因此,我认为后者是推荐的,或者我正在编写?请注意,从spark 2.3开始,矢量化UDF
要求输入和输出coolumns都是java原语,因此,它不适用于此应用程序。相关JIRA票证对此进行了改进:@zero323-对我来说,UDF方式似乎已经奏效。如何将结果保存为DF?当我在最后做一个.show时,它会按照我想要的方式显示DF。似乎找不到命名/保存它的方法。请参阅,以获取性能更好的解决方案。(我在这两个方面都做了计时。如果我有声誉的话,我会将这一个标记为重复。)@hwrd你能分享一下你使用的基准测试代码吗?TIA.@user10465355作为“解决方案”添加到下面,因为它太大,无法发表评论。(这个组织有点古怪,因为我从Jupyter笔记本中取出了它,然后替换了%%timeit cell magic。)这是一些看起来很棒的代码,但它能做什么呢?你能解释一下使用的不同方法吗?@代码乘以此处接受的解决方案中Spark<3.0.0的两个函数和中提出的ith
函数,以表明后一种解决方案更优越。你是在比较DAG构造,而不是实际的转换。我得到了以下错误:TypeError:“Column”对象不可调用