9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

N次元データを3次元にプロットする

Last updated at Posted at 2019-02-21

とりあえず

Pandasの勉強でCSVデータを取り込みデータ操作をやってみた。その結果として作成した多次元データを3次元で表現してみたい。ということで色々頑張ってみたのでその記事です。(くれぐれも・・・数学も機械学習もまだまだ初心者ですのであしからず・・・)

まずは

 やりたいことは、N次元を3次元になんとかできれば、プロットできる。ってことで”次元削減”。
 主成分分析やってみる。理論は結構ブログで書いている人もいるのでそれを読み漁ったみた。
 そして実践。流石に主成分分析をpythonで組む自信は無いので、sklearnのPCAを使ってみる事に。
 この記事を参考にしました。

print(target)

     user_id      date_x  all  p1  p2 ...    p76   p77   p78   score  flg
0   10404829   2017/6/28   33  35  36 ...   69.0  56.0  71.0  5819.0  2.0
1   10413677   2017/7/23   43  29  55 ...   53.0  50.0  58.0  4878.0  0.0
2   10377654   2017/5/15   32  32  37 ...   62.0  47.0  59.0  6290.0  0.0
3   10377655   2017/5/15   42  47  41 ...   44.0  59.0  46.0  4525.0  1.0
5   10479074   2017/12/4   42  47  40 ...   52.0  54.0  53.0  4643.0  1.0
6   10479075  2017/11/29   39  41  40 ...   46.0  40.0  46.0  4525.0  1.0
・・・

 まずは意味が無いんじゃないかな?と思うものを除外してみる。

target.drop(columns=['all', 'score', 'date_x', 'date_y', 'flg', 'user_id']) 

※ allとscoreはノリで除外しました。(date_x,date_y,flgは不要。user_idもindexで代用できる考え。)

必要なデータだけにして、sklearnのPCAで一気に3次元にしてみる。

    from sklearn.decomposition import PCA
    pca = PCA(n_components=3)
    pca.fit(target)

    print("--- explained_variance_ratio_ ---")
    print(pca.explained_variance_ratio_)
    print("--- components ---")
    print(pca.components_)
    print("--- mean ---")
    print(pca.mean_)
    print("--- covariance ---")
    print(pca.get_covariance())

 結果は色々でてくるけどとりあえずこれだけは理解。

--- explained_variance_ratio_ ---
[0.38644673 0.13264016 0.10981307]
・・・

 第1主成分は38%,第2主成分は13%,第3主成分は10%で説明できている。(ってことは、3次元に削ると60%しか精度が担保できていない?ってことかな?)
 今回は、データの可視化が目的なので、ひとまずは・・・無視!

 あとはその結果をDataFrame化してplotの元ネタにする。
 transformしても、並び順は変わらない。っぽいのでindexで結合しても良さそう。

    result = pca.transform(target)
    # fit_transform 呼出しで両方が同時に実行可能。
    result = pd.DataFrame(existing_2d)
    result.index = target.index
    result.columns = ['PC1', 'PC2', 'PC3']

 3次元散布図を描画するためにmatplotlibを使う。
 気にしたところは以下。

  • グラフを大きめに。
  • 3次元グラフに文字を印字(ラベル) ax.textちょー便利。
  • DataFrameの要約統計量を使ってグラフの描画角を決める。
    fig = plt.figure(num=None, figsize=(15, 15), dpi=150, facecolor='w', edgecolor='k') ←グラフをデカく
    ax = fig.gca(projection='3d')
  
    ax.plot(result['PC1'], result['PC2'], result['PC3'], marker="o", linestyle='None')
    for i in result.index:
        ax.text(result.iloc[i].PC1, result.iloc[i].PC2, result.iloc[i].PC3, i)

    ax.set_xlim(result.describe().at['min', 'PC1']-10, result.describe().at['max', 'PC1']+10)
    ax.set_ylim(result.describe().at['min', 'PC2']-10, result.describe().at['max', 'PC2']+10)
    ax.set_zlim(result.describe().at['min', 'PC3']-10, result.describe().at['max', 'PC3']+10)
    ax.set_xlabel('PC1')
    ax.set_ylabel('PC2')
    ax.set_zlabel('PC3')

    plt.show()

<結果>

スクリーンショット 2019-02-21 10.35.07.png

 ひとまず目的達成!

はい!そうです!欲が出ました。

折角前回 k-meansやったので、このベクトルをクラスタリングしてみたくなりました。

やりたい事

N個のクラスタに分類して色を変える。

 ここでふと疑問が・・・・ 主成分分析した結果の3次元ベクトルと元のN次元bベクトルでk-meansの結果は変わるのか?
 まぁとりあえず両方やってみる事に。

 まずはグラフ描画を以下のように変更。

  • 色用のlistを用意。
  • plotではなくscatterで描画(for文の中で)
  • k-meanの結果ラベルをDataFrameにjoin(今回はlabelとしてくっつけた)
    fig = plt.figure(num=None, figsize=(15, 15), dpi=150, facecolor='w', edgecolor='k')
    ax = fig.gca(projection='3d')

    color_ = ["r", "g", "b", "c", "m", "y", "k", "w"]

    for i in result.index:
        ax.scatter(result.iloc[i].PC1, result.iloc[i].PC2, result.iloc[i].PC3, marker="o", linestyle='None', color=color_[result.iloc[i].label])
        ax.text(result.iloc[i].PC1, result.iloc[i].PC2, result.iloc[i].PC3, result['name'][i])

    print(result.describe())

    ax.set_xlim(result.describe().at['min', 'PC1']-10, result.describe().at['max', 'PC1']+10)
    ax.set_ylim(result.describe().at['min', 'PC2']-10, result.describe().at['max', 'PC2']+10)
    ax.set_zlim(result.describe().at['min', 'PC3']-10, result.describe().at['max', 'PC3']+10)
    ax.set_xlabel('PC1')
    ax.set_ylabel('PC2')
    ax.set_zlabel('PC3')

    plt.show()

まずは主成分分析した結果の3次元ベクトルでクラスタリング
スクリーンショット 2019-02-21 10.50.54.png

こっちが元のベクトルでクラスタリング
スクリーンショット 2019-02-21 10.51.13.png

上と下で色の違いはありますが。。
 28と18の結果は違う事はわかる。。。うーん。。

まとめ

 よく出したけど、結局わからず。そりゃそうですよね。どうクラスタリングされるのが正解かわからない状態でやっているので・・・。
 けどなんか面白かったので記事にしてみました。
 色々勉強になりました。
 (もう少し、主成分分析とk-meansを数学的に理解すれば、この違いも説明できうる!?)

補足

 Macでmatplotlibで日本語出す時に困ったのでそのメモ。 Fontを追加した後は忘れずにキャッシュファイルを消す。

 rm ~/.matplotlib/fontlist-v300.json
9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?