当我使用StringIndexer和OneHot Encoder为我的矩阵做数据准备时,我现在怎样才能知道重要特征的名称/来源?
randomForest分类器只会给我索引,而我看不到原始数据的链接: - (
以下代码: https://github.com/spark-in-action/first-edition/blob/master/ch08/python/ch08-listings.py
在这个数据集上: https://github.com/spark-in-action/first-edition/blob/master/ch08/adult.names
我提取了这个代码子集:
$data.take(1)
[Row(age=39.0, occupation=u' State-gov', capital_gain=77516.0, education=u' Bachelors', marital_status=u' Never-married', workclass=u' Adm-clerical', relationship=u' Not-in-family', race=u' White', sex=u' Male', capital_loss=2174.0, fnlwgt=0.0, hours_per_week=40.0, native_country=u' United-States', income=u' <=50K')]
$data2 = indexStringColumns(data, typeString)
$data2.take(1)
>[Row(age=39.0, capital_gain=77516.0, capital_loss=2174.0, fnlwgt=0.0, hours_per_week=40.0, occupation=4.0, education=2.0, marital_status=1.0, workclass=3.0, relationship=1.0, race=0.0, sex=0.0, native_country=0.0, income=0.0)]
$data3 = oneHotEncodeColumns(data2, colString_without_Y)
$data3.take(1)
>[Row(age=39.0, capital_gain=77516.0, capital_loss=2174.0, fnlwgt=0.0, hours_per_week=40.0, income=0.0, occupation=SparseVector(9, {4: 1.0}), education=SparseVector(16, {2: 1.0}), marital_status=SparseVector(7, {1: 1.0}), workclass=SparseVector(15, {3: 1.0}), relationship=SparseVector(6, {1: 1.0}), race=SparseVector(5, {0: 1.0}), sex=SparseVector(2, {0: 1.0}), native_country=SparseVector(42, {0: 1.0}))]
$# modélisation :
$rf = RandomForestClassifier(labelCol=colY, numTrees=ntree, maxDepth=depth,)
$model = rf.fit(trainingData)
$predictions = model.transform(testData)
$model.featureImportances
>SparseVector(107, {0: 0.1016, 1: 0.0302, 2: 0.0995, 3: 0.0207, 4: 0.0517, 5: 0.007, 6: 0.0061, 7: 0.0033, 8: 0.0021, 9: 0.0041, 10: 0.0058, 11: 0.0036, 12: 0.0001, 14: 0.0162, 15: 0.0067, 16: 0.0199, 17: 0.0134, 18: 0.0026, 19: 0.0059, 20: 0.0025, 21: 0.0038, 22: 0.0053, 23: 0.0064, 24: 0.003, 25: 0.0014, 26: 0.007, 27: 0.0023, 28: 0.001, 29: 0.0002, 30: 0.1473, 31: 0.0609, 32: 0.0057, 33: 0.0024, 34: 0.0019, 35: 0.001, 36: 0.0002, 37: 0.0258, 38: 0.0054, 39: 0.0244, 40: 0.0045, 41: 0.0055, 42: 0.0186, 43: 0.0061, 44: 0.0021, 45: 0.0043, 46: 0.0029, 47: 0.0046, 48: 0.0024, 49: 0.0019, 50: 0.0001, 51: 0.0, 52: 0.0786, 53: 0.0354, 54: 0.0169, 55: 0.0117, 56: 0.015, 57: 0.0026, 58: 0.0046, 59: 0.0064, 60: 0.0025, 61: 0.0014, 62: 0.0011, 63: 0.007, 64: 0.0312, 65: 0.0048, 66: 0.005, 67: 0.0022, 68: 0.0008, 69: 0.0008, 70: 0.0006, 71: 0.0006, 72: 0.0003, 73: 0.0013, 74: 0.0006, 75: 0.0012, 76: 0.0004, 77: 0.0003, 78: 0.0002, 79: 0.0005, 80: 0.0002, 81: 0.0003, 82: 0.0002, 83: 0.0003, 84: 0.0004, 85: 0.0002, 86: 0.0001, 87: 0.0003, 88: 0.0004, 89: 0.0001, 90: 0.0, 91: 0.0005, 93: 0.0004, 94: 0.0002, 95: 0.0003, 96: 0.0, 97: 0.0001, 98: 0.0001, 99: 0.0001, 100: 0.0, 101: 0.0, 102: 0.0, 103: 0.0, 104: 0.0, 105: 0.0002})
我怎么知道每个indice在原始数据矩阵中链接回来的类别值?
答案 0 :(得分:0)
StringIndexerModel.labels
就是您所需要的。
例如,
from pyspark.ml.feature import StringIndexer
from pyspark.sql.types import Row
data = sc.parallelize([
Row(v="A"),
Row(v="B"),
]).toDF()
labels = StringIndexer(inputCol="v", outputCol="indexed").fit(data).labels
for idx, v in enumerate(labels):
print idx, v
OneHotEncoder
在这里不是什么大问题,因为它只是将数字转换为索引。注意
默认情况下不包括最后一个类别(可通过dropLast配置)
所以你需要确保价值&amp;指数是一致的。
答案 1 :(得分:0)
解决方案是将我从StringIndexer获得的标签映射到模型的特征重要性。标签最终将被映射。 下面的示例是scala,但方法是相同的。
创建DataFrame:
val df = spark.createDataFrame(Seq(
(0, "a",0),
(1, "b",1),
(2, "c",0),
(3, "a",0),
(4, "a",1),
(5, "c",1)
)).toDF("id", "category","y")
将类别编码为类别索引列并获取标签
import org.apache.spark.ml.feature.{OneHotEncoder, StringIndexer}
val indexer = new StringIndexer().setInputCol("category").setOutputCol("categoryIndex").fit(df)
val indexed = indexer.transform(df)
val labels = indexer.labels.map("Category=" + _)
这就是labels
看起来
scala> labels
res9: Array[String] = Array(Category=a, Category=c, Category=b)
使用OneHotEncoder将类别索引映射到二进制向量
val encoder = new OneHotEncoder().setInputCol("categoryIndex").setOutputCol("categoryVec")
val encoded = encoder.transform(indexed)
encoded.select("id", "categoryVec").show()
训练RandomForest模型
import org.apache.spark.ml.classification.{RandomForestClassificationModel, RandomForestClassifier}
val rf = new RandomForestClassifier().setLabelCol("y").setFeaturesCol("categoryVec").setNumTrees(10)
val rfmodel = rf.fit(encoded)
现在要将要素重要性映射到标签,我们需要压缩featureImportance索引和值,然后在地图中我们将获得该索引位置labels(x._1)
的标签,其中x._1
是索引值。
val featureImportance = rfmodel.featureImportances.toSparse
val topFeatures = featureImportance.indices.zip(featureImportance.values).sortBy( - _._2).map(x => (labels(x._1),x._2))
这是最终输出topFeatures
的外观:
Array[(String, Double)] = Array((Category=a,0.7998663887552777), (Category=c,0.20013361124472231))