2016-09-02 2 views
3

Когда я делаю подготовку данных к моей матрице с помощью StringIndexer и OneHot Encoder, как я могу теперь узнать, что является именем/источником важных функций?Spark (OneHotEncoder + StringIndexer) = FeatureImportance как?

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}) 

Как я могу узнать, к какому категориальному значению относятся каждый индекс, связанный обратно в исходном матрице данных?

ответ

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)

Таким образом, вы должны убедиться, что значение & показатели выравниваются.

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") 

Encode категорию в колонке категории индексов и получить этикетки

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)) 
Смежные вопросы