【DataCamp】29_Unsupervised Learning in Python③, ④

教師なし学習の後半です。

③Decorrelating your data and dimension reduction

次元削減の最も基本的なPCA(主成分分析)について。非相関と次元削減の2ステップ。

非相関

最初のステップは非相関。PCAはデータサンプルを軸に沿って回転させる。平均が0になるようにサンプルをシフトさせる。

扱うデータセットはwineとgrains。分かりやすいように特徴量は2つだけです。散布図に表せて、主成分も分かりやすい。


-wine

wineのデータセットです。'total_phenols', 'od280'の列をnumpy arrayにして、samplesという名前にします。

画像1

画像2

変換前

画像3

PCAで変換後

画像4

変換後は相関係数、平均値共に0に近くなっています。


-grains

grainsのデータセットです。今回、grainsはwidth, lengthの2列だけの (210, 2)のnumpy array。

widthとlengthはどの列か?元データを確認します。

UCI Machine Learning Repository seeds Data Set

スクロールすると、Attribute Informationに5. width of kernel, 4. length of kernelとあります。列が逆になっているのが少しめんどくさい…。

画像5

画像6

widthとlengthは正の相関があります。PCAを使って相関をなくします。

画像7

次に、主成分の2軸を矢印で表示しましょう。主成分は下記の通り。第1主成分は[ 0.63910027 0.76912343]、第2主成分は[-0.76912343 0.63910027]。

画像12

PCAの.mean_属性は、特徴量ごとの平均値

画像11

plt.arrow(x, y, dx, dy)は(x, y)から(x+dx, y+dy)まで矢印を表示します。

第1主成分は赤、第2主成分は緑の矢印で表しました。

画像16


次元削減

内在次元とは、データセットを近似するために必要な、分散が大きい特徴量の数。内在次元を調べて、内在次元以外の次元を削除します。

-iris

まず、irisからsepal length, sepal width, petal widthの3つの特徴量を取り出します。

画像8

3次元にプロット

画像9

z軸(petal length)方向への分散は小さく、sepal lengthとsepal widthの2つの特徴量のみで概算できそうです。

特徴量が2~3の場合、散布図で内在次元を特定できますが、それ以上の特徴量だとどうでしょう?

分散が大きいPCA特徴量を数えることで、内在次元を識別できます。

PCA特徴量の分散を調べます。

画像10

最初の2つの特徴量(sepal lengthとsepal width)の分散が大きく、petal lengthは無視して良さそうです。


次は4つの特徴量 'sepal length', 'sepal width', 'petal length', 'petal width'で行います。

画像16

特徴量が4つでも、内在次元は2つのようです。

PCAを使用して、次元を2つ減らします。

画像17

plt.scatter()の引数、cは文字列ではなく、数値のリストでなければなりません。

次元を4から2に減らしましたが、種を区別することができました。

-fish

こちらは特徴量が6つある6次元。こちらもPCA特徴量の分散をプロットしてみましょう。前半と同様に、標準化します。

画像14

あれ???他の分散が表示されない…。
→make_pipelineで引数をpca, scalerとしていました。逆。make_pipelineの引数は、ステップの順番でなければいけません。

画像15

fishの内在次元は2が良さそうです。

PCAを用いて、次元削減をします。

画像18

画像19

次元を6から2に減らしましたが、4種に区別できます。


-documents

documentsは文章のリストです。

documents=['cats say meow', 'dogs say woof', 'dogs chase cats']

これをTfidfVectorizerでcsr_matrix形式で表されるword frequency array(単語頻度配列)に変換します。

画像20


-wikipedia

コースのトップページからダウンロードしたWikipedia airticlesフォルダを解凍すると、3つのファイルがあります。

画像21

preprocessing.mdはMarkdown Documentationファイルで、メモ帳などのテキストエディタで開けます。開くと、wikipedia-vectors.csvの前処理の仕方が書いてあります。親切!

wikipedia-vocabulary-utf8には、単語がaaronからzooまで13125個あります。

wikipedia-vectors.csvをインポートします。行が単語、列が文書になっています(preprocessing.mdによると、行が文書、列が単語だと、列が長すぎてCSVで扱いづらいため)。

画像22

行と列を入れ替えて

画像23

csr_matrixに変換。airticlesができました。

画像24

titles:文書のタイトル一覧

画像25

上位50個の単語。PCAはn_components入力しないと、全ての要素が保持されます。しかし、TruncatedSVDはn_componentsのデフォルトは2。

画像26

あれ?第一成分の分散が低い??PCAとは違う??

あと、どの単語に対応しているか分からないかしら?



④Discovering interpretable features

NMFはNon-negative matrix factorizationの略で、日本語だと非負値行列因子分解。factorizeは「因数分解する」という意味。

・次元削減方法

・PCAと違い、解釈可能

・すべてのfeatures(特徴量)は非負(ゼロ以上)でなければならない。適用できるデータは、単語頻度配列や画像、audio spectrogram, e-コマースサイトでの購入履歴など。

・必要なcomponents(成分)の数を指定する

・csr_matrixとnumpy arrayの両方に使える

・PCAの主成分のように、サンプルから学習する成分がある。成分の次元はサンプルの次元と同じ。成分は常に非負。順番はない。

・NMF features(変換されたサンプル)と成分で、元のサンプルを再構築できる。


word frequency arrays(単語頻度配列)

・行が文書、列が単語

・入力値は、文書内でのそれぞれの単語の頻度。tf-idf (term frequency-inverse document frequency)を用いて表される。tfは文書内での単語の頻度。idfは、theなどの頻繁に出てくる単語の影響を減らす、重みづけの方法。


-wikipedia

wikipediaの記事の単語頻度配列を用いて、NMFを適用する。成分の数は6。

先程のcsr matrixのarticlesを用います。

articlesを変換したNMF featuresを、小数点第2位まで表す。

nmf_features.round(2)
→nmf_featuresはnumpy arrayで、numpy.ndarray.roundメソッドを使います。引数は小数位。

画像30

articlesを変換したNMF featuresに、文書のタイトルをつけて分かりやすくしましょう。

画像31

この中から、'Anne Hathaway'と'Denzel Washington'の行を取り出してみましょう。

画像32

df.loc['列名']は列をSeriesで取り出します。

画像33

画像34

この二人はどちらも、3番目のNMF featuresがかなり高い値です。これは、両方の記事は、主に3番目のNMF成分を用いて再構築される(※)ことを意味します。

※補足説明

NMF成分

画像35

画像36

NMF成分の3番目×NMF featuresの3番目となるため。


<NMF learns topics of documents>

まず、単語頻度配列(word frequency array)の列名のリストである、wordsを作成します。単語はaaronからzooまで13125個あります。

'wikipedia-vocabulary-utf8.txt' を読み込み

画像27

セパレータ(改行コード\n)で分割してリスト化してwordの完成。

画像28

先程、'Anne Hathaway'と'Denzel Washington'の両方の記事で、3番目のNMF featuresがかなり高い→主に3番目のNMF成分を用いて再構築されることが分かりました。3番目のNMF成分はどんなtopicsでしょう?

df.nlargest()メソッドは大きい方からn個選ぶ。デフォルトは5個。

画像29

これらのtopicsが、'Anne Hathaway'と'Denzel Washington'の両方の記事で共通であることが分かりました。

他の記事も見てみましょう。

画像37

0はBlack Sabbath(バンド)、1はRadamel Falcao(サッカー選手)、4はLeukemia(白血病)、5はAlexa Internetでした。

画像38

画像39


-digit

samplesは(100, 104)の2次元配列で表される、100個の画像。各行は13x8の単一の画像。

数値だけなので、np.loadtxtでインポートします。

画像40

samplesの0行目の画像を描画してみましょう。

画像41

「7」でした。

他の99個の画像も見たくてfor文に。%matplotlib notebookにすると図が重なって見えないので、%matplotlib inlineにしました。他は0-9の数字かと思いきや、意味をなさない画像が殆どでした。

画像44

画像45

次はNMFを用いて、このdigitsデータセットを分解します。成分数は7。

wikipediaと同じようにnmf_featuresを見てみましたが、スパースではないので、「○○の行は〇番目のnmf_featuresがすごく高いね~」という発見は特にありませんでした。どれも似た値。

画像44

7個の成分を画像にしてみましょう。

画像45

画像46

「8」を構成する7本の線になりました。だからn_components=7にしたのか~と納得。

ちなみに、n_components=4にすると、数本の線が現れました。

画像48

n_components=10にすると、7つは「8」を構成する7本の線に、残り3つは下図のようなグレーになりました。

画像47


-artists

<インポート>

まず、csr_matrixのartistsを作ります。

"Musical artists"フォルダを解凍すると、artists.csvとscrobbler-small-sample.csvの2つのファイルがあります。

scrobbler-small-sample.csvは2895x3。列は、user_offset, artist_offset, playcountの3つ。artist_offsetがcsr_matrixのrow, user_offsetがcolumn, playcountがdataのようです。

1行目は列名なので飛ばします。np.loadtxt()のdtypeのデフォルトはfloatなので、dtype='int64'にします。

画像49

csr_matrixに変換します。

画像50

artistsができました!

artists.csvから、artist_namesも作ります。

画像55

最後に空白があったので、削除しました。

画像56

<スケーリング>

全てのユーザーが同じ影響力を持つように、スケーリングします。

MaxAbsScaler:各feature(列)の最大絶対値が1を超えないようにするスケーリング。

画像52

画像53

確かに、最大値は1.0になっています。


スケーリングがややこしいので、表にまとめてみました。

画像51

<アーティストをオススメする>

画像55

norm_featuresは(111, 20)のnumpy array。アーティストが111名、ユーザーが20名です。

アーティスト名を入れて分かりやすく。

画像57

The Beatlesを聴く人は、他に何を聴いているでしょう?

画像58

The Beach Boysなどでした。

この記事が気に入ったらサポートをしてみませんか?