質問するログイン新規登録

Q&A

解決済

1回答

3617閲覧

sklearnのFeatureHasherの挙動について

drken35

総合スコア16

深層学習

深層学習は、多数のレイヤのニューラルネットワークによる機械学習手法。人工知能研究の一つでディープラーニングとも呼ばれています。コンピューター自体がデータの潜在的な特徴を汲み取り、効率的で的確な判断を実現することができます。

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2018/02/12 07:55

0

0

機械学習に用いる学習データの作成中なのですが,カテゴリ変数をFeature Hashingによって次元削減してみようと思いました.
ためしに,「月」のカテゴリ変数を12次元→8次元化することを考えました.

python

1from sklearn.feature_extraction import FeatureHasher 2import pandas as pd ; import numpy as np 3#テストデータ 4test=["1","2","3","4","5","6","7","8","9","10","11","12"] 5test=pd.Series(test)#本番ではdfからスライスしたseriesを使用するため 6#ハッシュトリック 7FH=FeatureHasher(n_features=8,input_type="string") 8hashed = FH.fit_transform(test) ; hashed=hashed.toarray() 9#衝突検出 10arr = len(hashed) 11uniqs = len(np.unique(hashed, axis=0)) 12print(arr,uniqs) #-->(12,10)

↑の例だと衝突してしまうのですが,テストデータが↓のような例だとうまくいきます.

python

1test=["one1","222","three3","444","five5","666","seven7","888","nine9","1010","eleven11","1212"] 2test=pd.Series(test) 3#中略# 4print(arr,uniqs) #-->(12,12)

原因はなんなのでしょうか?
入力文字が短すぎ,形状が他の入力文字と似ているためにハッシュ関数?がうまく働いていないのでしょうか…?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

guest

回答1

0

ベストアンサー

ハッシュを使う限り衝突のリスクはいつもあるのではないでしょうか?
ソースコード見ている限り、衝突回避のための既出の記録や変換などはないようですし、たまたまだと思います。

辞書で隣り合うキーがハッシュ計算後衝突するのも直感的には合わないので運のような…

速さなどを得ることが目的の犠牲なので、衝突が困るのであればOneHotEncodingすれば良い気がします。


例えば以下のような文字列で試してみるとわかりやすいです。

python

1from sklearn.feature_extraction import FeatureHasher 2 3conv = FeatureHasher(n_features=2, input_type='string', alternate_sign=False) 4 5print(conv.transform(['f'])) 6print('-') 7print(conv.transform(['ff'])) 8print('-') 9print(conv.transform(['f'*5])) 10print('-') 11print(conv.transform(['fo'])) 12print('-') 13print(conv.transform(['fou'])) 14print('-') 15print(conv.transform(['four']))

投稿2018/02/12 11:34

編集2018/02/13 04:04
mkgrei

総合スコア8562

drken35

2018/02/13 01:26

うーん…ハッシュの衝突可能性を否定するつもりはもちろんないんですが、32bit符号にそうそう簡単にぶつかられる筋合いもないんですよね やはり自分の使い方が間違ってるのかとか、関数自体にクセがあるのかとかを考えてしまいます 色々試しているのですが 1 : STR型の数字ではなく普通の単語のような文字列を入力する 2 : 要素数とサンプル数が多い 3 : 変換前の要素次元と変換後の次元に無理がない(12→2とか) だとほぼ衝突せず、安定的に運用できるような感じがしてきました が、経験則的な答えではなく、ここが○○だから☓☓、回避するには△△というような技術的な解答が欲しいところです 内蔵されている符号化関数(murmurhash3)に起因するのかなあ…
mkgrei

2018/02/13 03:54

おっしゃるとおりですね。 この程度のサイズでハッシュの衝突を考える前に、ハッシュ計算後の処理に注目すべきでした。 https://github.com/scikit-learn/scikit-learn/blob/a24c8b46/sklearn/feature_extraction/hashing.py#L19 https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/feature_extraction/_hashing.pyx 以上二点お読みになればすべてに納得行くかと思います。 ハッシュ計算後にそれを用いて疎行列のインデックスと値を生成しています。 ただ、その際にインプットの文字列の長さに応じて値がバラけていきます。 長さが1の文字列を使うと、1つのハッシュ値に対してその後の操作が行われます。 その際にインデックスと値の衝突がおきやすくなります。 結論から言うと、文字列長さが一番重要で、十分に長い文字列に対しては衝突の確率が大きく下がることになります。
drken35

2018/02/13 15:25

なるほど,よく分かりました. わざわざソースコードまで読んでいただいて,お手数おかけしました いただいた解説とあわせて,自分もコードを読みながら理解を深めていきたいと思います どうもありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.25%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問