2

如何将一组任意列转换为Mllib矢量? 基本上,我有我的DataFrame的第一列有一个固定的名称,然后是一些任意命名的列,每个列中都有Double值。将任意数量的列转换为矢量

像这样:

name | a | b | c | 
val1 | 0.0 | 1.0 | 1.0 | 
val2 | 2.0 | 1.0 | 5.0 | 

可以是任何数量的列。我需要获得以下数据集:

final case class ValuesRow(name: String, values: Vector) 

回答

2

这可以使用VectorAssembler以简单的方式完成。要合并到Vector中的列用作输入,在这种情况下,除第一列以外的所有列。

val df = spark.createDataFrame(Seq(("val1", 0, 1, 1), ("val2", 2, 1, 5))) 
    .toDF("name", "a", "b", "c") 

val columnNames = df.columns.drop(1) // drop the name column  
val assembler = new VectorAssembler() 
    .setInputCols(columnNames) 
    .setOutputCol("values") 

val df2 = assembler.transform(df).select("name", "values").as[ValuesRow] 

结果将包含名称的数据集和值列:

+----+-------------+ 
|name|  values| 
+----+-------------+ 
|val1|[0.0,1.0,1.0]| 
|val2|[2.0,1.0,5.0]| 
+----+-------------+ 
1

下面是做这件事:

import org.apache.spark.sql.functions._ 
import org.apache.spark.mllib.linalg.DenseVector 

val ds = Seq(
    ("val1", 0.0, 1.0, 1.0), 
    ("val2", 2.0, 1.0, 5.0) 
).toDF("name", "a", "b", "c"). 
as[(String, Double, Double, Double)] 

val colList = ds.columns 
val keyCol = colList(0) 
val valCols = colList.drop(1) 

def arrToVec = udf(
    (s: Seq[Double]) => new DenseVector(s.toArray) 
) 

ds.select(
    col(keyCol), arrToVec(array(valCols.map(x => col(x)): _*)).as("values") 
).show 
// +----+-------------+ 
// |name|  values| 
// +----+-------------+ 
// |val1|[0.0,1.0,1.0]| 
// |val2|[2.0,1.0,5.0]| 
// +----+-------------+ 
+0

谢谢。这是一个有用的答案。你能否为我解释这个部分 - (valCols.map(x => col(x)):_ *)?语法有点混乱。特别是:_ *部分。我在很多地方都看到过它,它似乎很有用,但我真的不明白。 –

+1

'valCols.map(x => col(x)):_ *'将valCols中的每个元素从String映射到Column类型。 splat运算符'_ *'将转换后的数组解包为由array()方法获取的参数序列。这里有一个[链接](https://alvinalexander.com/bookmarks/scala/scalas-missing-splat-operator)和一个说明性使用示例。 –

+0

谢谢!很有帮助 –