给出SparseVector对象的两个DataFrame列,如何将这两个列加在一起(即矢量加法)以创建新列?
类似
df.columns
df: org.apache.spark.sql.DataFrame = [v1: SparseVector, v2: SparseVector]
df.withColumn("v3", ADD_COL_FUNCTION(col(v1), col(v2)))
答案 0 :(得分:0)
Spark中的SparseVectors没有内置的附加功能。 DenseVector
对象可以通过将它们变成数组来处理,但是对于SparseVector
来说,这可能是内存杀手。您可以将SparseVectors解释为地图,然后将地图“添加”在一起。
import org.apache.spark.mllib.linalg.{SparseVector, Vectors, Vector}
def addVecCols(v1: SparseVector, v2: SparseVector): Vector = {
val map1: Map[Int, Double] = (v1.indices zip v1.values).toMap
Vectors.sparse(v1. size,
(map1 ++ (v2.indices zip v2.values).toMap)
.map{ case (k, v) => k -> (v + map1.getOrElse(k, 0d))}
.toList
)
val addVecUDF = udf((v1: SparseVector, v2: SparseVector) => addVecCols(v1, v2))
请注意,在Spark 1.6中,Vectors.sparse
的返回类型为Vector
,而在Spark 2.X中,其返回类型为SparseVector
,因此请调整{{1} }。另外,在2.X版本中,您可以使用addVecCols
库而不是ml
库。
将其用于数据框
mllib
答案 1 :(得分:0)
这是我们解决此问题的最终方法。
首先,我们实现了this post中提供的Spark和Breeze向量之间的隐式转换(请注意注释中的错误修复)。这提供了以下代码中使用的asBreeze
和fromBreeze
转换。
然后,我们定义了一个允许添加稀疏向量列的函数:
def addVectors(v1Col: String, v2Col: String, outputCol: String)
: DataFrame => DataFrame = {
df: DataFrame => {
def add(v1: SparkVector, v2: SparkVector): SparkVector =
(v1.asBreeze + v2.asBreeze).fromBreeze
val func = udf((v1: SparkVector, v2: SparkVector) => add(v1, v2))
df.withColumn(outputCol, func(col(v1Col), col(v2Col)))
}
}
此函数的调用方式为:
df.transform(addVectors(col1Name, col2name, colOutName))
当然,您可能希望包括一些检查列名是否存在的方法,并确保输出列不会覆盖您不希望的任何内容。