1、StringIndexer
標簽索引器,它將標簽的字符串列映射到標簽索引的ML列。
如果輸入列為數字,則將其強制轉換為字符串並為字符串值編制索引。
索引在[0,numLabels)中。
索引構建的順序為標簽的頻率,優先編碼頻率較大的標簽,所以出現頻率最高的標簽為0號
默認情況下,按標簽頻率排序,因此最常使用的標簽的索引為0。
StringIndexer轉換器可以把一列類別型的特征(或標簽)進行編碼,使其數值化,
索引的范圍從0開始,該過程可以使得相應的特征索引化,
使得某些無法接受類別型特征的算法可以使用,並提高諸如決策樹等機器學習算法的效率
//定義一個StringIndexerModel,將label轉換成indexedlabel
StringIndexerModel labelIndexerModel=new StringIndexer().
setInputCol("label")
.setOutputCol("indexedLabel")
.fit(rawData);
//加labelIndexerModel加入到Pipeline中
Pipeline pipeline=new Pipeline()
.setStages(new PipelineStage[]
{labelIndexerModel,
featureIndexerModel,
dtClassifier,
converter});
//查看結果
pipeline.fit(rawData).transform(rawData).select("label","indexedLabel").show(20,false);
按label出現的頻次,轉換成0~num numOfLabels-1(分類個數),頻次最高的轉換為0,以此類推:
label=3,出現次數最多,出現了4次,轉換(編號)為0
其次是label=2,出現了3次,編號為1,以此類推
+-----+------------+
|label|indexedLabel|
+-----+------------+
|3.0 |0.0 |
|4.0 |3.0 |
|1.0 |2.0 |
|3.0 |0.0 |
|2.0 |1.0 |
|3.0 |0.0 |
|2.0 |1.0 |
|3.0 |0.0 |
|2.0 |1.0 |
|1.0 |2.0 |
+-----+------------+
StringIndexer對String按頻次進行編號
id | category | categoryIndex
----|----------|---------------
0 | a | 0.0
1 | b | 2.0
2 | c | 1.0
3 | a | 0.0
4 | a | 0.0
5 | c | 1.0
如果轉換模型(關系)是基於上面數據得到的 (a,b,c)->(0.0,2.0,1.0),如果用此模型轉換category多於(a,b,c)的數據,比如多了d,e,就會遇到麻煩:
id | category | categoryIndex
----|----------|---------------
0 | a | 0.0
1 | b | 2.0
2 | d | ?
3 | e | ?
4 | a | 0.0
5 | c | 1.0
Spark提供了兩種處理方式:
StringIndexerModel labelIndexerModel=new StringIndexer().
setInputCol("label")
.setOutputCol("indexedLabel")
//.setHandleInvalid("error")
.setHandleInvalid("skip")
.fit(rawData);
(1)默認設置,也就是.setHandleInvalid("error"):會拋出異常
org.apache.spark.SparkException: Unseen label: d,e
(2).setHandleInvalid("skip") 忽略這些label所在行的數據,正常運行,將輸出如下結果:
id | category | categoryIndex
----|----------|---------------
0 | a | 0.0
1 | b | 2.0
4 | a | 0.0
5 | c | 1.0
2、IndexToString
是一個轉換器“ Transformer”,它將一列索引映射回對應字符串值的新列。
索引字符串映射既可以來自輸入列的ML屬性,也可以來自用戶提供的標簽(優先於ML屬性)。
相應的,有StringIndexer,就應該有IndexToString。
在應用StringIndexer對labels進行重新編號后,帶着這些編號后的label對數據進行了訓練,並接着對其他數據進行了預測,
得到預測結果,預測結果的label也是重新編號過的,因此需要轉換回來。
見下面例子,轉換回來的convetedPrediction才和原始的label對應。
IndexToString converter=new IndexToString()
.setInputCol("prediction")//Spark默認預測label行
.setOutputCol("convetedPrediction")//轉換回來的預測label
.setLabels(labelIndexerModel.labels());//需要指定前面建好模型
Pipeline pipeline=new Pipeline()
.setStages(new PipelineStage[]
{labelIndexerModel,
featureIndexerModel,
dtClassifier,
converter});
pipeline.fit(rawData).transform(rawData)
.select("label","prediction","convetedPrediction").show(20,false);
|label|prediction|convetedPrediction|
+-----+----------+------------------+
|3.0 |0.0 |3.0 |
|4.0 |1.0 |2.0 |
|1.0 |2.0 |1.0 |
|3.0 |0.0 |3.0 |
|2.0 |1.0 |2.0 |
|3.0 |0.0 |3.0 |
|2.0 |1.0 |2.0 |
|3.0 |0.0 |3.0 |
|2.0 |1.0 |2.0 |
|1.0 |2.0 |1.0 |
+-----+----------+------------------+
