2016-04-04 5 views
0

私は同じ列の2つのDataFramesを持っています。 をOne-Hot-Encodingを使ってベクトルに変換したいと思います。問題は です。例えば、トレーニングセットで3つの固有の値が発生する可能性がありますが、 ではそれよりも小さいかもしれません。スパーク:複数のデータフレームで同じOneHotEncoderを使用

Training Set:  Test Set: 

+------------+  +------------+ 
| Type |  | Type | 
+------------+  +------------+ 
|  0  |  |  0  | 
|  1  |  |  1  | 
|  1  |  |  1  | 
|  3  |  |  1  | 
+------------+  +------------+ 

この場合OneHotEncoderは、トレーニングおよびテストセット(ベクトルの各要素は、一意の値の存在を表すため)に、異なる長さのベクトルを作成します。

複数のDataFramesに同じOneHotEncoderを使用することはできますか? fit機能がないので、どうすればそれを行うことができるのかわかりません。おかげさまで

答えて

4

OneHotEncoderは単独で使用することを意図していません。代わりに、列メタデータを利用できるPipelineの一部である必要があります。たとえば次のよう考えてみましょう:あなたはエンコーダーを使用する場合

training = sc.parallelize([(0.,), (1.,), (1.,), (3.,)]).toDF(["type"]) 
testing = sc.parallelize([(0.,), (1.,), (1.,), (1.,)]).toDF(["type"]) 

は、直接それがコンテキストに関する知識がない:

from pyspark.ml.feature import OneHotEncoder 

encoder = OneHotEncoder().setOutputCol("encoded").setDropLast(False) 


encoder.setInputCol("type").transform(training).show() 
## +----+-------------+ 
## |type|  encoded| 
## +----+-------------+ 
## | 0.0|(4,[0],[1.0])| 
## | 1.0|(4,[1],[1.0])| 
## | 1.0|(4,[1],[1.0])| 
## | 3.0|(4,[3],[1.0])| 
## +----+-------------+ 


encoder.setInputCol("type").transform(testing).show() 
## +----+-------------+ 
## |type|  encoded| 
## +----+-------------+ 
## | 0.0|(2,[0],[1.0])| 
## | 1.0|(2,[1],[1.0])| 
## | 1.0|(2,[1],[1.0])| 
## | 1.0|(2,[1],[1.0])| 
## +----+-------------+ 

は今すぐ必要なメタデータを追加することができます。それはStringIndexerを使用することによって、たとえばことができます。

indexer = (StringIndexer() 
    .setInputCol("type") 
    .setOutputCol("type_idx") 
    .fit(training)) 

あなたは、インデックス付きの列にエンコーダを適用する場合は、両方のデータセットに一貫性のエンコーディングを取得します:

(encoder.setInputCol("type_idx") 
    .transform(indexer.transform(training)) 
    .show()) 

## +----+--------+-------------+ 
## |type|type_idx|  encoded| 
## +----+--------+-------------+ 
## | 0.0|  1.0|(3,[1],[1.0])| 
## | 1.0|  0.0|(3,[0],[1.0])| 
## | 1.0|  0.0|(3,[0],[1.0])| 
## | 3.0|  2.0|(3,[2],[1.0])| 
## +----+--------+-------------+ 

(エンコーダ .setInputCol(「type_idx 「) .transform(indexer.transform(テスト)) .SHOW())

## +----+--------+-------------+ 
## |type|type_idx|  encoded| 
## +----+--------+-------------+ 
## | 0.0|  1.0|(3,[1],[1.0])| 
## | 1.0|  0.0|(3,[0],[1.0])| 
## | 1.0|  0.0|(3,[0],[1.0])| 
## | 1.0|  0.0|(3,[0],[1.0])| 
## +----+--------+-------------+ 

ことに注意してくださいこの方法で取得したラベルは、入力データの値を反映しません。一貫性のあるエンコードが困難な要件である場合は、手動でスキーマを提供する必要があります:

from pyspark.sql.types import StructType, StructField, DoubleType 

meta = {"ml_attr": { 
    "name": "type", 
    "type": "nominal", 
    "vals": ["0.0", "1.0", "3.0"] 
}} 

schema = StructType([StructField("type", DoubleType(), False, meta)]) 

training = sc.parallelize([(0.,), (1.,), (1.,), (3.,)]).toDF(schema) 
testing = sc.parallelize([(0.,), (1.,), (1.,), (1.,)]).toDF(schema) 

assert (
    encoder.setInputCol("type").transform(training).first()[-1].size == 
    encoder.setInputCol("type").transform(testing).first()[-1].size 
) 
0

私たちは、メタ行列を作成し、複数のOneHotEncodersを作成することで、複数の柱状のデータセットにこれを拡張することができます。 これらの手順は、パイプラインでステージングできます。

関連する問題