48

spark-ml を使用してカテゴリ データを処理するに はどうすればよいspark-mllibですか?

ドキュメンテーションはあまり明確ではありませんが、 、 などの分類器RandomForestClassifierLogisticRegressionは、featuresColの機能の列の名前を指定DataFrameするlabelCol引数と、 のラベル付きクラスの列の名前を指定する引数があるようDataFrameです。

明らかに、予測に複数の機能を使用したいので、 を使用して、VectorAssemblerすべての機能を の下の単一のベクトルに配置しようとしましたfeaturesCol

ただし、VectorAssembler数値型、ブール型、およびベクトル型 (Spark Web サイトによる) のみを受け入れるため、機能ベクトルに文字列を入れることはできません。

どのように進めればよいですか?

4

5 に答える 5

58

ホールデンの答えを完成させたかっただけです。

Spark 2.3.0以降、OneHotEncoderは非推奨となり、 で削除され3.0.0ます。OneHotEncoderEstimator代わりに使用してください。

スカラでは:

import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.feature.{OneHotEncoderEstimator, StringIndexer}

val df = Seq((0, "a", 1), (1, "b", 2), (2, "c", 3), (3, "a", 4), (4, "a", 4), (5, "c", 3)).toDF("id", "category1", "category2")

val indexer = new StringIndexer().setInputCol("category1").setOutputCol("category1Index")
val encoder = new OneHotEncoderEstimator()
  .setInputCols(Array(indexer.getOutputCol, "category2"))
  .setOutputCols(Array("category1Vec", "category2Vec"))

val pipeline = new Pipeline().setStages(Array(indexer, encoder))

pipeline.fit(df).transform(df).show
// +---+---------+---------+--------------+-------------+-------------+
// | id|category1|category2|category1Index| category1Vec| category2Vec|
// +---+---------+---------+--------------+-------------+-------------+
// |  0|        a|        1|           0.0|(2,[0],[1.0])|(4,[1],[1.0])|
// |  1|        b|        2|           2.0|    (2,[],[])|(4,[2],[1.0])|
// |  2|        c|        3|           1.0|(2,[1],[1.0])|(4,[3],[1.0])|
// |  3|        a|        4|           0.0|(2,[0],[1.0])|    (4,[],[])|
// |  4|        a|        4|           0.0|(2,[0],[1.0])|    (4,[],[])|
// |  5|        c|        3|           1.0|(2,[1],[1.0])|(4,[3],[1.0])|
// +---+---------+---------+--------------+-------------+-------------+

Pythonの場合:

from pyspark.ml import Pipeline
from pyspark.ml.feature import StringIndexer, OneHotEncoderEstimator

df = spark.createDataFrame([(0, "a", 1), (1, "b", 2), (2, "c", 3), (3, "a", 4), (4, "a", 4), (5, "c", 3)], ["id", "category1", "category2"])

indexer = StringIndexer(inputCol="category1", outputCol="category1Index")
inputs = [indexer.getOutputCol(), "category2"]
encoder = OneHotEncoderEstimator(inputCols=inputs, outputCols=["categoryVec1", "categoryVec2"])
pipeline = Pipeline(stages=[indexer, encoder])
pipeline.fit(df).transform(df).show()
# +---+---------+---------+--------------+-------------+-------------+
# | id|category1|category2|category1Index| categoryVec1| categoryVec2|
# +---+---------+---------+--------------+-------------+-------------+
# |  0|        a|        1|           0.0|(2,[0],[1.0])|(4,[1],[1.0])|
# |  1|        b|        2|           2.0|    (2,[],[])|(4,[2],[1.0])|
# |  2|        c|        3|           1.0|(2,[1],[1.0])|(4,[3],[1.0])|
# |  3|        a|        4|           0.0|(2,[0],[1.0])|    (4,[],[])|
# |  4|        a|        4|           0.0|(2,[0],[1.0])|    (4,[],[])|
# |  5|        c|        3|           1.0|(2,[1],[1.0])|(4,[3],[1.0])|
# +---+---------+---------+--------------+-------------+-------------+

Spark 1.4.0以降、MLLib はOneHotEncoder機能も提供します。これは、ラベル インデックスの列をバイナリ ベクトルの列にマップし、最大でも 1 つの値しか持たないものです。

このエンコーディングにより、ロジスティック回帰などの連続機能を期待するアルゴリズムがカテゴリ機能を使用できるようになります

次のことを考えてみましょうDataFrame:

val df = Seq((0, "a"),(1, "b"),(2, "c"),(3, "a"),(4, "a"),(5, "c"))
            .toDF("id", "category")

最初のステップは、次のインデックス付きを作成することDataFrameですStringIndexer

import org.apache.spark.ml.feature.StringIndexer

val indexer = new StringIndexer()
                   .setInputCol("category")
                   .setOutputCol("categoryIndex")
                   .fit(df)

val indexed = indexer.transform(df)

indexed.show
// +---+--------+-------------+                                                    
// | 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|
// +---+--------+-------------+

その後、次のようにエンコードできcategoryIndexますOneHotEncoder

import org.apache.spark.ml.feature.OneHotEncoder

val encoder = new OneHotEncoder()
                   .setInputCol("categoryIndex")
                   .setOutputCol("categoryVec")

val encoded = encoder.transform(indexed)

encoded.select("id", "categoryVec").show
// +---+-------------+
// | id|  categoryVec|
// +---+-------------+
// |  0|(2,[0],[1.0])|
// |  1|    (2,[],[])|
// |  2|(2,[1],[1.0])|
// |  3|(2,[0],[1.0])|
// |  4|(2,[0],[1.0])|
// |  5|(2,[1],[1.0])|
// +---+-------------+
于 2015-08-28T19:35:42.260 に答える
49

Spark ML (MLlib ではない) のツリーベースのモデルに関するカテゴリ機能についても疑問に思っていたため、別の観点から回答を提供します。ドキュメントでは、すべてがどのように機能するかが明確ではありません。

追加のメタデータを使用してデータフレームの列を変換するとpyspark.ml.feature.StringIndexer、変換された機能をカテゴリ機能として明確にマークするデータフレームに保存されます。

データフレームを印刷すると、数値 (カテゴリ値の 1 つに対応するインデックス) が表示されます。スキーマを見ると、新しい変換された列が型であることがわかりますdouble。ただし、作成したこの新しい列pyspark.ml.feature.StringIndexer.transformは、通常の二重列ではなく、非常に重要な追加のメタデータが関連付けられています。データフレームのスキーマの適切なフィールドのプロパティを調べることで、このメタデータを調べるmetadataことができます (yourdataframe.schema を調べることで、データフレームのスキーマ オブジェクトにアクセスできます)。

この余分なメタデータには、次の 2 つの重要な意味があります。

  1. ツリーベースのモデルを使用しているときに呼び出すと.fit()、データフレームのメタデータがスキャンされ、 などのトランスフォーマーでカテゴリとしてエンコードされたフィールドが認識されますpyspark.ml.feature.StringIndexer(上記のように、 などのこの効果を持つトランスフォーマーは他にもありますpyspark.ml.feature.VectorIndexer)。このため、spark ML でツリーベースのモデルを使用する場合は、StringIndxer で変換した後に機能をワンホット エンコードする必要はありません (ただし、機能を使用しない他のモデルを使用する場合は、ワンホット エンコードを実行する必要があります)。線形回帰などのカテゴリカルを自然に処理します)。

  2. このメタデータはデータ フレームに保存されるため、 を使用pyspark.ml.feature.IndexToStringしていつでも数値インデックスを元のカテゴリ値 (多くの場合文字列) に戻すことができます。

于 2016-11-15T16:56:44.663 に答える
7

StringIndexer文字列を適切な方法で Double に変換するために使用できるML パイプラインのコンポーネントがあります。http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.ml.feature.StringIndexerにはさらに多くのドキュメントがあり、http://spark.apache.org/docs/ latest/ml-guide.htmlは、パイプラインの構築方法を示しています。

于 2015-08-28T18:42:56.613 に答える
-2

cast 関数を使用して、spark データ フレームの文字列列の型を数値データ型にキャストできます。

from pyspark.sql import SQLContext
from pyspark.sql.types import DoubleType, IntegerType

sqlContext = SQLContext(sc)
dataset = sqlContext.read.format('com.databricks.spark.csv').options(header='true').load('./data/titanic.csv')   

dataset = dataset.withColumn("Age", dataset["Age"].cast(DoubleType()))
dataset = dataset.withColumn("Survived", dataset["Survived"].cast(IntegerType()))

上記の例では、csv ファイルをデータ フレームとして読み込み、デフォルトの文字列データ型を整数と倍精度にキャストし、元のデータ フレームを上書きします。次に、VectorAssembler を使用して機能を単一のベクトルにマージし、お気に入りの Spark ML アルゴリズムを適用できます。

于 2017-05-27T23:20:19.557 に答える