VectorAssembler行为解析及稀疏向量与元数据聚合方法问询
关于VectorAssembler的行为解释及稀疏输出保持方案
咱们拆解你的两个问题,逐一解答:
1. 为什么show()和take()返回的VectorAssembler结果看起来不同?
其实这两种输出本质上是同一个稀疏向量,只是不同方法的字符串展示格式有区别:
show()方法用的是Spark MLlib稀疏向量的标准序列化字符串格式:(总维度, [非零元素的索引列表], [非零元素的值列表])。你看到的(262147,[0,1,2,57344,...],[2.0,1.0,1.0,...])就是这种紧凑的批量展示写法。take()方法返回的是Row对象的Python原生字符串表示,里面的SparseVector会以{索引: 值}的字典格式展示非零元素,也就是你看到的SparseVector(262147, {0: 2.0, 1: 1.0, ...})。
两种格式完全等价,你可以通过调用向量的toArray()方法验证,结果是完全一致的。
2. 如何让VectorAssembler保持稀疏输出以适配LSH算法?
默认情况下,你的输入列里包含CategoryID这类普通数值列,VectorAssembler会把它们视为长度为1的稠密向量。当稠密向量和稀疏向量(比如你的tf列)拼接时,结果会自动转为稠密向量——这是因为稠密向量会存储所有元素(包括零值),拼接后整个向量就变成了稠密格式,既不高效也不符合LSH的需求。
解决核心是把所有输入列都转换成稀疏向量,这样VectorAssembler拼接后就会输出稀疏向量。具体步骤如下:
步骤1:定义UDF将数值列转为单维度稀疏向量
from pyspark.sql.functions import udf from pyspark.ml.linalg import SparseVector, VectorUDT # 把单个数值转成单维度稀疏向量的UDF def num_to_sparse(x): return SparseVector(1, {0: x}) # 注册UDF,指定返回类型为Spark向量类型 num_to_sparse_udf = udf(num_to_sparse, VectorUDT())
步骤2:将所有数值列转换为稀疏向量列
# 为每个数值列生成对应的稀疏向量列 tf = tf.withColumn("CategoryID_sparse", num_to_sparse_udf(tf["CategoryID"])) tf = tf.withColumn("CountryID_sparse", num_to_sparse_udf(tf["CountryID"])) tf = tf.withColumn("CityID_sparse", num_to_sparse_udf(tf["CityID"]))
步骤3:用稀疏向量列作为VectorAssembler的输入
from pyspark.ml.feature import VectorAssembler assembler = VectorAssembler( inputCols=['CategoryID_sparse', 'CountryID_sparse', 'CityID_sparse', 'tf'], outputCol="features") output = assembler.transform(tf)
这样处理后,output里的features列就是稀疏向量了,完全适配LSH算法的输入要求,你可以用take()或show()验证输出格式。
内容的提问来源于stack exchange,提问作者Ivan Shelonik
相关产品推荐
相关产品推荐

