1. VectorAssembler 做什么?
给定一组输入列 inputCols(每列类型必须是 数值 或 Vector ),把它们按顺序组合成一个新向量列 outputCol:
-
输入可以混合:
- 单个数值列(Number)
- DenseVector / SparseVector(Vector)
-
输出是一个 Vector(通常是稠密或稀疏表示,取决于内部实现与输入组合)
典型用途:
StringIndexer -> OneHotEncoder -> VectorAssembler -> LogisticRegression数值特征 + one-hot 稀疏特征 + embedding 向量 -> VectorAssembler -> 模型
2. 输入列与输出列
输入列(Input Columns)
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
inputCols |
Number / Vector | null | 待拼接的列(可多列) |
输出列(Output Columns)
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
outputCol |
Vector | "output" |
拼接后的向量列 |
3. 参数详解(Parameters)
| Key | 默认值 | 必填 | 说明 |
|---|---|---|---|
inputCols |
null | ✅ | 输入列名数组(顺序很重要) |
outputCol |
"output" |
否 | 输出列名 |
handleInvalid |
ERROR_INVALID |
否 | 遇到非法值如何处理(如空值/类型不对等) |
工程建议:
inputCols的顺序决定最终向量的维度排列,一旦上线最好固定,否则训练/预测会对不上。
4. Java 示例逐段解读
示例里把三列拼成一列:
vec:DenseVector(2.1, 3.1)(长度 2)num:数值 1.0(长度 1)sparseVec:SparseVector(size=5, ...)(长度 5)
最终拼出来的向量长度应该是:2 + 1 + 5 = 8
4.1 输入数据
java
DataStream<Row> inputStream =
env.fromElements(
Row.of(
Vectors.dense(2.1, 3.1),
1.0,
Vectors.sparse(5, new int[] {3}, new double[] {1.0})),
Row.of(
Vectors.dense(2.1, 3.1),
1.0,
Vectors.sparse(
5,
new int[] {4, 2, 3, 1},
new double[] {4.0, 2.0, 3.0, 1.0})));
Table inputTable = tEnv.fromDataStream(inputStream).as("vec", "num", "sparseVec");
这里 sparseVec 的 size=5,意味着它代表长度为 5 的向量,只不过用稀疏方式存储非零位置。
4.2 创建 VectorAssembler
java
VectorAssembler vectorAssembler =
new VectorAssembler()
.setInputCols("vec", "num", "sparseVec")
.setOutputCol("assembledVec");
拼接顺序就是:vec 在前,num 在中间,sparseVec 在最后。
最终向量的 layout 可以理解为:
assembledVec = [ vec(2 dims) | num(1 dim) | sparseVec(5 dims) ]
4.3 transform 并读取输出
java
Table outputTable = vectorAssembler.transform(inputTable)[0];
Vector outputValue = (Vector) row.getField(vectorAssembler.getOutputCol());
System.out.printf("... Output Value: %s\n", outputValue);
输出 Value 会是一个 Vector(可能打印成 dense 或 sparse),内容会把三列的信息组合到同一个向量里。
5. 实战注意点(很关键)
1)OneHotEncoder 输出通常是 SparseVector,Assembler 非常适配
这也是最常见链路:
- StringIndexer:
city -> cityIndex - OneHotEncoder:
cityIndex -> cityVec (SparseVector) - VectorAssembler:
[数值列, cityVec, 其它Vec] -> features - LogisticRegression:
features -> prediction
2)数值列不要忘记类型一致性
你的示例里 num 是 Double(1.0)。实际表里可能是 INT/LONG/FLOAT,建议统一成 Double 或确保能被识别为 Number。
3)维度稳定性是上线生命线
如果你在训练时 inputCols=["age","cityVec","deviceVec"],上线推理千万不要换成 ["cityVec","age","deviceVec"],否则模型输入维度语义全错。
4)handleInvalid 的选择
- 离线训练:可以
ERROR_INVALID让问题暴露 - 线上:更倾向"先做清洗",或者用能跳过/替代的策略(如果支持),避免任务被脏数据打挂
6. 小结
VectorAssembler 是 Flink ML 里把"多列特征形态"统一成 features 向量列的关键组件:
- 支持 Number + Vector 混合拼接
inputCols顺序决定最终向量维度布局- 常用于把 one-hot、embedding、数值特征拼成一个 features 列喂给模型