Git 超入門

1.Gitを使おう

Git(ギット)とは、ソースコードなどの変更履歴を管理する分散型のバージョン管理システムのことです。

Gitでは開発者や開発目的(サイドバーの開発など)ごとに本流の開発から分岐して開発を進め、ある程度完成したら、本流の戻して、本流の開発を進めることが出来ます。
これにより、機能ごと・時系列ごとに開発のバージョン管理をすることができます。

通常の共有ファイルでは、どのタイミングで誰が変えたか分からなくなってしまったり、変更がバッティングすることがありますが、
問題が発生したときも、任意の時点に戻ったり、バッティングを適切に対処することができます。

こういったメリットが受けて、近年のバージョン管理システムの主流となっています

ここではwindows環境を前提として進めてみます。


1.1 リモートレポジトリとローカルレポジトリの概念

リポジトリとは、ファイルやディレクトリの状態を保存する場所です。変更履歴を管理したいディレクトリなどをリポジトリの管理下に置くことで、そのディレクトリ内のファイルなどの変更履歴を記録できます。

リポジトリは自分のローカル環境(つまり、自分のPC)にある「ローカルリポジトリ」とサーバなどネットワーク上にある「リモートリポジトリ」の2箇所にあります。基本的にローカルリポジトリで作業を行い、その作業内容をリモートポジトリへプッシュするという流れです。


1.2 Gitインストール

参考ページ https://qiita.com/toshi-click/items/dcf3dd48fdc74c91b409



1.3 自分のローカルレポジトリでバージョンを管理してみる

個人で開発を進める際、バージョン管理は一旦ローカルで進めます。まずはローカルでのgitの使い方にふれます。


1.3.1 Gitで管理するフォルダを作成

コマンドラインを使ってみましょう
スタートマークを押してcmdでコマンドプロンプトの開始

作業フォルダに移動します

cd Users\username\documents

適当な作業フォルダを作成しました。フォルダ作成mkdir→フォルダ移動cd→作成mkdir→移動cd

mkdir gitdocuments
cd gitdocuments
mkdir gittest
cd gittest

git initでこのフォルダをgit管理下に置きます。実行すると、フォルダには.gitが作成されます。

git init

それではここに適当なファイルを作成します。ここではREADME.mdを作ってみます。
フォルダのエクスプローラー上で作成しても良いですが、コマンドラインで作成してみます。
これは、”this is test local repository” という内容を README.mdを作成して書き込み、という指示です。

echo "this is test local repository" > README.md



コミットによるバージョン管理

これからgit add [ファイル名]してgit commit -m [”任意のコメント”]していきます。
任意のコメントは、バージョン管理をするときにコメントを参照していくので、この変更が何を意味しているかを簡潔に表しておくと開発の運用上便利です。

git add README.md
git commit -m "this is the first commit"

これで、最初の状態が「コミット」された状態になります。
この時フォルダを見てみると、緑のチェックマークが以下のようについていると思います。
これは、このファイルが現在の状態が最新として管理されている状態を意味します。

次に、ファイルを適当に編集して変更してしまいます
次のように変更しました。

“this is test local repository”
changed

保存すると、フォルダの状態が以下のように、変更されたファイルが赤くなっていると思います。これは、変更された現在の状態が、最新でないことを表します。

ここで、コミットなどの状態を見るのに使うgit statusを使ってみます。

git status

すると以下のように、README.mdが編集された(modified)状態となっていることが分かります。

On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   README.md

no changes added to commit (use "git add" and/or "git commit -a")

それでは、これでコミットします。

git add README.md
git commit -m "modified"

これをすると、また、README.mdが最新の状態になっていることが確認できると思います。

ここで、これまでどのような変更履歴があったのかをgit logで見てみます。

git log

  
すると、以下のように、最初のコミットと次のコミットのログが表示されています。

commit 447f23dc631ada2efaa396ff023dede11f6814f3 (HEAD -> master)
Author: xxxxxxx <xxxxxxx@gmail.com>
Date:   Sun Sep 30 17:06:37 2018 +0900

    modified

commit 20479817d2fe72195d463391e25a2b2a413b0b1b
Author: xxxxxxx <xxxxxxx@gmail.com>
Date:   Sun Sep 30 16:50:34 2018 +0900

    this is the first commit

git add と git commit の意味
git addは「ステージング」といいます。git addで選んだファイルをステージにあげ、そのファイルだけを選択的にコミットすることが出来ます。
これによって、全ての変更の内、変更の種類によってコミットを小分けにしながら、変更が理解しやすい単位でコミットしていくことが出来ます。


ブランチを切って開発する

ブランチを切ることで、開発者や開発の目的に合わせて新たな分岐(ブランチ)を作り、開発を進めることができます。
そして、ある程度完成したら本流のブランチに統合します。
これによって本流を汚すことなく、開発者・開発の目的毎に開発を分割して進めることが出来ます。
ここでは、本流のmaster branchからdevelop branchを作成します。

ブランチを以下で切ります。

git branch develop

これでブランチが作成されました。次にできたブランチ一覧を見てましょう

git branch -a

実行結果は以下のようになります。星がついているブランチが現在自分がいるブランチを表していて、今はmasterブランチに居ます。

  develop
* master

それでは、作成したdevelop ブランチに移動します。

git checkout develop

git branch -aで今のブランチがdevelop ブランチに居ることを確認しましょう。

次に、このブランチで新たなファイルを作成します。hello world というpython ファイルです。

echo print("hello world") > hello.py

上の例にならって、このファイルをコミットしましょう。

git add hello.py
git commit -m "added hello.py"

さて、ここでエクスプローラを見てみましょう。全て最新の状態です。

ここで、masterに移動してみます。

git checkout master

すると、エクスプローラからhello.pyが消えていると思います。この様に、ブランチを切り替えるとエクスプローラの見え方もそれに合わせて変わります。

次に、developブランチをmasterブランチに統合します。この操作をマージと言います。
masterブランチに居る状態で以下を実行します。

git merge develop

これで、エクスプローラの見え方も、develop ブランチで作成した通りになったと思います。



参考 .gitignore

.gitiginoreというファイルを作成し、中に読み込む必要のないファイル名を書き込んでおくと、gitはこのファイルを無視します。
データファイルなどを無視したい場合はこれが便利です。


2.リモートレポジトリで共有する(Githubを使う)



2.1 Githubの登録

公式サイトにて、アカウント登録をします。



2.2 新しいプロジェクトを作成し、ローカルの内容をpush

アカウントでログインした状態で、new repository で新しいレポジトリを作成します。
適当なレポジトリ名をつけ、publicを選択して、create new repositoryで新しいレポジトリが作成されます。

コマンドラインで、以下を実行します。http://xxxxxxは自分のレポジトリに読み替えて下さい
1行目はURLに”origin”という短縮名(ニックネーム)を付けるという意味で、任意の名前を付けられますが、監修的にoriginとつけます。
2行目は、originのmasterブランチにプッシュする、という意味です。

git add origin http://xxxxxx
git push -u origin master

これで、リモートにローカルで作成していたmasterブランチの内容がそのまま作成されていることかと思います。

このようにして、ローカルで開発した内容を、リモートレポジトリに上げることが出来ます。


3.リモートレポジトリで共有する(既存レポジトリをクローン)



3.1 他の人のリモートレポジトリをコピー(clone)

gitでは、Github上にある他の人のリモートレポジトリをコピー(クローン)することができます。

クローン用のディレクトリを作成し、そのディレクトリに移動します。(適当な場所でOK)

cd..
mkdir clonetest
cd clonetest

次に、コピーしたい公開されたGithubのページに行き、clone or downloadをクリックし、URLをコピーします。

そのURLをもって、コマンドプロンプトで以下を実行します。

git clone https://github.com/MassSkt/testrepository.git

すると現在のフォルダ直下に、testrepositoryが作成されます。ブランチもリモートレポジトリでの構造を保っており、そのままローカルでブランチを切ったりして開発を進めることができます。

Python Matplotlib グラフ描画のまとめ 

Python の グラフ描画ツールであるMatlib plot の基本的な使い方をまとめています。

✔インポート

一文、以下のように書くだけで、描画ライブラリをインポートできます。下記の描画例ではこのインポート文を頭に書いています。

import matplotlib.pyplot as plt

✔2次元散布図

2次元散布図を書いてみます。x,yは-1から1までのまでの乱数を生成してプロットしています。

#==================================================
#2D scattering

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(10)
N=300
x=np.random.rand(N)*2-1
y=np.random.rand(N)*2-1


fig0=plt.figure()
plt.scatter(x,y)

plt.title('sample plot')

plt.xlabel('x')
plt.ylabel('y')
#グリッド
plt.grid()
plt.show()

✔3次元散布図

x,yの乱数に対し、z=x^2+y^2を生成し、三次元プロットをしています。

c=’r’ で赤 、marker=’s’ 四角マーク でプロットしています。その他種々の色・マークが用意されています。

 

#==================================================
#3D
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

np.random.seed(10)
N=300
x=np.random.rand(N)*2-1
y=np.random.rand(N)*2-1

z=x*x+y*y

fig1 = plt.figure()
ax = Axes3D(fig1)
ax.scatter3D(x,y,z,c='r', marker='s')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.legend(loc='upper left')

✔カラーマップ2次元散布図

z=x^2+y^2の値を色で表現することも可能です。

#==================================================
#2D scattering

import matplotlib.pyplot as plt
import numpy as np

np.random.seed(10)
N=300
x=np.random.rand(N)*2-1
y=np.random.rand(N)*2-1

z=x*x+y*y

fig01=plt.figure()
plt.scatter(x,y,c=z,cmap='Reds' ,marker="o", linewidths="2", edgecolors="orange",s=200)
plt.colorbar()

plt.title('sample plot')

plt.xlabel('x')
plt.ylabel('y')
#グリッド
plt.grid()
plt.show()
#==================================================

✔メッシュグリッドによる3D図

z=x^2+y^2の曲面を描画したい場合は、メッシュグリッドでx,yのメッシュを作成してから描画します。

#==================================================
#3D

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import numpy as np


fig2 = plt.figure()
ax = fig2.gca(projection='3d')

# Make data.
X = np.arange(-1, 1, 0.005)
Y = np.arange(-1, 1, 0.005)
X, Y = np.meshgrid(X, Y)
#R = np.sqrt(X**2 + Y**2)
#Z = np.sin(R)
Z=X**2+Y**2
# Plot the surface.
surf = ax.plot_surface(X, Y, Z,cmap=cm.coolwarm,
                       linewidth=0, antialiased=False)

ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

#カラーバーを追加 
fig2.colorbar(surf, shrink=0.5, aspect=5)

plt.show()

#==================================================

✔コンター図

コンター図は 同様にメッシュグリッドを切って作成します。contourf と contourがあり、内部を塗りつぶすかどうかが異なります。

contourf

contour

#==================================================
#contour
fig3=plt.figure()
cont = plt.contour(X, Y, Z)
plt.colorbar()
 
plt.gca().set_aspect('equal')
plt.show()

#==================================================
#contourf
fig3=plt.figure()
cont = plt.contourf(X, Y, Z)
plt.colorbar()

 
plt.gca().set_aspect('equal')
plt.show()

#==================================================

主成分分析(PCA)実践 ~次元圧縮の手法として~ Python 機械学習 Scikit-learn

今回はScikit-learn のPCA分析を用いて、UCIの機械学習データセットであるwineのサンプルデータを次元圧縮したのちに、サポートベクターマシンで分類してみたいと思います。初学者向けに、サンプルプログラムをコピーペーストでまず動かせるようにしています。

※参考記事

Pythonの導入方法Pythonを使った機械学習(超入門)
SVMでの分類Python 機械学習 Scikit-learnによるサポートベクターマシン(SVM)による学習・分類の実践
主成分分析の基礎主成分分析(PCA)実践 ~主成分分析とは?~ Python 機械学習 Scikit-learn

 

※wineのデータ
・UCIのデータセット
https://archive.ics.uci.edu/ml/datasets/Wine

・CSVデータ ⇒ wine

✔主成分分析による次元圧縮とは

前回、主成分分析は「データの情報をできるだけ失わずにはデータを縮約する補法である」と述べました。すなわち、データの圧縮に使えるわけです。もう少し言えば、主たる情報以外の情報はそぎ落とされるので、学習データのノイズまで学習してしまい、未知のデータに対する予測精度が落ちる「過学習」の状態を防ぐことができます。

✔次元圧縮の実践

ワインのデータは13種類の成分を特徴量X、3種類のワインのクラスYを有したデータです。今回は、データを学習用データと検証用データに分けたのち、13次元という高次元データを主成分分析により3次、2次、1次と、低次元にデータを圧縮していきます。圧縮後に、サポートベクターマシンによる分類で、正答率がどのように変化するか見ていきます。サンプルコードは後述します。

・学習用データ:特徴量Xとそれに対応するクラスYのデータを与え、分類器を学習させるためのデータ
・検証用データ:特徴量Xとそれに対応するクラスYを持つデータに対し、学習済みの分類器でXに対するクラスの予測Y’を実際のクラスYを比較して予測があっていたか検証するためのデータ

◆主成分分析による可視化

3次元の主成分分析で、三次元のデータに縮約すると以下のようなプロットとなります。大まかに3種類の群に分かれていることが見て取れます。PC1,2,3はそれぞれ第1、第2、第3主成分というわけです。

2次元に縮約すると以下のようになります。第1、2主軸の張る平面に射影した図であることがわかります。

さらに1次元に縮約するとどうでしょうか。第1主軸に全データを射影した状態です。これでもまだ、3種類のワインデータの境界が大まかに引けそうです。

◆次元圧縮後の学習・分類

圧縮の次元を横軸にとって、その圧縮された空間でのSVMによる学習・分類後の正答率を示しています。5次元以上で正答率は飽和しますが、2次元・3次元でも、分類するに十分な情報量を持っていることがわかります。

 

 

✔サンプルコード

import numpy as np
import pandas as pd 

all_data = pd.read_csv('wine.csv') 


col_num=all_data.shape[1]

#データインポート
X=all_data.iloc[1:,0:col_num-1]
Y=all_data.iloc[1:,col_num-1]
#features name
X_name=all_data.iloc[0,0:col_num-1]



#学習結果検証用 ratingがあるデータを、トレーニングデータと検証データに分解して利用。
from sklearn import __version__ as sklearn_version
from distutils.version import LooseVersion as Version

if Version(sklearn_version) < '0.18':
    from sklearn.cross_validation import train_test_split
else:
    from sklearn.model_selection import train_test_split

X_train,X_test,Y_train,Y_test= train_test_split(
    X, Y, test_size=0.3, random_state=0)

#データの標準化
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()

X_train=np.array(X_train)
X_test=np.array(X_test)
Y_train=np.array(Y_train)

sc.fit(X_train)
X_train_std=sc.transform(X_train)
sc.fit(X_test)
X_test_std=sc.transform(X_test)


#PCA
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

pca = PCA()
X_train_pca = pca.fit_transform(X_train_std)
pca.explained_variance_ratio_

#==========================================================
#3 dimension
pca3 = PCA(n_components=3)
X_train_pca3 = pca3.fit_transform(X_train_std)
X_test_pca3 = pca3.transform(X_test_std)



from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt

fig3 = plt.figure()
ax = Axes3D(fig3)
ax.scatter3D(np.ravel(X_train_pca3[Y_train==1,0]),np.ravel(X_train_pca3[Y_train==1,1]),np.ravel(X_train_pca3[Y_train==1,2]),c='r', marker='s',label='1')
ax.scatter3D(np.ravel(X_train_pca3[Y_train==2,0]),np.ravel(X_train_pca3[Y_train==2,1]),np.ravel(X_train_pca3[Y_train==2,2]),c='b', marker='x',label='2')
ax.scatter3D(np.ravel(X_train_pca3[Y_train==3,0]),np.ravel(X_train_pca3[Y_train==3,1]),np.ravel(X_train_pca3[Y_train==3,2]),c='g', marker='o',label='3')
ax.set_xlabel('pc 1')
ax.set_ylabel('pc 2')
ax.set_zlabel('pc 3')
plt.legend(loc='upper left')

plt.show()
#========================================================
#===========================================================
# 2 dimension
pca2 = PCA(n_components=2)
X_train_pca2 = pca2.fit_transform(X_train_std)
X_test_pca2 = pca2.transform(X_test_std)

fig2=plt.figure()

## 主成分の空間(平面)に射影
colors = ['r', 'b', 'g']
markers = ['s', 'x', 'o']

for l, c, m in zip(np.unique(Y_train), colors, markers):
    plt.scatter(X_train_pca2[Y_train == l, 0], 
                X_train_pca2[Y_train == l, 1], 
                c=c, label=l, marker=m)

#plt.scatter(X_train_pca[:, 0], X_train_pca[:, 1])
plt.xlabel('pc 1')
plt.ylabel('pc 2')
plt.show()

#print('Covariance Matrix : %r' % pca.get_covariance())
print('Explained ratio : %r' % pca2.explained_variance_ratio_.round(2))
print('pc1 vector : %r' % pca2.components_[0].round(2))
print('pc2 vector : %r' % pca2.components_[1].round(2))
#==========================================================


#===========================================================
# 1 dimension
pca1 = PCA(n_components=1)
X_train_pca1 = pca1.fit_transform(X_train_std)
X_test_pca1 = pca1.transform(X_test_std)

fig0=plt.figure()

## 主成分の空間(平面)に射影
colors = ['r', 'b', 'g']
markers = ['s', 'x', 'o']

for l, c, m in zip(np.unique(Y_train), colors, markers):
    plt.scatter(X_train_pca1[Y_train == l], np.zeros(len(X_train_pca1[Y_train == l])),
                c=c, label=l, marker=m)

#plt.scatter(X_train_pca[:, 0], X_train_pca[:, 1])
plt.xlabel('pc 1')
plt.ylabel('')
plt.show()


#==========================================================
#SVMを用いて分類
from sklearn.svm import SVC

####### apply non-linear svm ###################
## use "radial Basis Functional kernel" 動径基底カーネルを使用する。
svm = SVC(kernel='rbf', random_state=0, gamma=0.1, C=1.0)
svm.fit(X_train_pca2, Y_train)
y_pred_svm=svm.predict(X_test_pca2)

result=y_pred_svm

 
from sklearn.metrics import accuracy_score
print('Accuracy : %.2f' % accuracy_score(np.rint(result), Y_test))

#==========================================================
#主成分分析の次元を変えて正答率を可視化
accuracy=[]
for i in range(1, 11):

    pca = PCA(n_components=i)
    X_train_pca = pca.fit_transform(X_train_std)
    X_test_pca = pca.transform(X_test_std)

    svm = SVC(kernel='rbf', random_state=0, gamma=0.1, C=1.0)
    svm.fit(X_train_pca, Y_train)
    y_pred_svm=svm.predict(X_test_pca)
 
    from sklearn.metrics import accuracy_score
    #print('Accuracy : %.2f' % accuracy_score(np.rint(result), Y_test))
    accuracy.append(accuracy_score(y_pred_svm,Y_test))

fign=plt.figure()
plt.plot(range(1, 11), accuracy, marker='o')
plt.xlabel('n components')
plt.ylabel('accuracy')
#plt.savefig('./figures/elbow.png', dpi=300)
plt.show()

 

 

主成分分析(PCA)実践 ~主成分分析とは?~ Python 機械学習 Scikit-learn

今回はScikit-learn のPCA分析を用いて、「高校生の5教科の成績」のサンプルの主成分分析を行いたいと思います。初心者向けに、サンプルプログラムをコピーペーストでまず動かせるようにしています。

※Pythonの導入方法http://costudyinfodatabase.nagoya/2017/01/05/%e3%81%82-2/

※高校生の5教科の成績データ
国語・英語・数学・物理・化学の5教科の50人程度のデータを用意します。
※成績のデータ(csvファイル”Seiseki.csv”)⇒ Seiseki

 

✔主成分分析とは できるだけわかりやすく解説

主成分分析とは高次の特徴量を持つサンプルデータ群について、データとしての特徴をできるだけ失わずに、低次元に縮約する手法です。換言すれば、データを説明するのに主たる成分を抽出する手法ともいえます。

・2次元を例に

主成分分析のイメージをつかむために、2次元データを2次元の主成分分析にかける例をベースに説明します。(2次元→2次元ではデータを縮約したことになりませんが、、笑)

主成分分析はデータの分散が大きい方向を順に第1主成分、第2主成分、、として軸を取り直す操作です。理由は後述しますが、分散が最も大きい方向がデータの主たる成分となるのです。

例を見ましょう。5教科のデータから英語・数学に限ってプロットしてみます。このとき、第一主成分(PC1)と第二主成分(PC2)の軸のイメージを併記しています。

 

主成分分析では、新しく取り直した軸の意味付けは自分でするしかありません。下図に、主成分分析の結果を載せています。数学の得点のカラーマップ(緑が濃いほど数学の点が高い)と英語の得点のカラーマップ(青が濃いほど英語の特典が高い)にしています。PC1は数学も英語も得点の高い方向であるため、「総合力」と解釈できそうです。PC2は数学力が若干高く、英語が若干低くなる方向のため、あえて言うなら「理系力」と言えそうです。

※軸のスケールは主成分分析の過程で標準化されているため、元の得点のスケールではなくなります。

・数学のカラーマップ

・英語のカラーマップ

 

・なぜ、分散が大きいと「主成分」なのか

3次元を例に考えてみましょう。データは「英語」「数学」「物理」の三つ。このデータをプロットします。英語と数学と物理には正の相関があります。(つまり、英語ができる人は数学も物理もできるし、逆も然り)

ここで、分散が大きいという意味では、第一主成分をとるならば以下の図のような方向になるでしょう。

第2主成分までの主成分分析の結果は以下のようになります。このとき、分散が大きい直交する2軸が張る平面に、3次元データを射影しているイメージです。繰り返すと、主成分分析とは、このように高次の特徴量を持つサンプルデータ群について、データとしての特徴をできるだけ失わずに、低次元に縮約する手法です

話を戻して、なぜ分散が大きい方向が主成分なのかを再考してみましょう。

例えば、PC1に直交する平面をPC1とPC2主成分分析の結果の面とした場合どうでしょうか。主成分分析は上述の通り、主軸の張る平面へのデータの射影ですから、PC1のベクトルの方向からこの散布図を見たときがそのイメージとなります。その図を以下に示しています。

※実際にプログラムを動かして、グラフを回してみるとわかります。(Spyderでぐりぐり回せるグラフの表示方法:http://wp.me/p8il3n-c3)

このように、分散が大きくない方向から見てしまうと、点群がまとまって見えてしまいます。最悪、点群がほとんど重なってしまうこともあるでしょう。その時、各点の差異がなくなってしまい、データとしての情報を失ってしまいます。以上のことから、分散が最大の方向から見ることによって、データの情報をできるだけ失わずに済むというわけです。

✔サンプルコード

2次元⇒2次元の主成分分析

import numpy as np
import pandas as pd 

#data read
all_data = pd.read_csv('Seiseki.csv',encoding = "ISO-8859-1") 
Japanese=np.array(all_data['Japanese'],dtype='float64')
English=np.array(all_data['English'],dtype='float64')
Math=np.array(all_data['Math'],dtype='float64')
Physics=np.array(all_data['Physics'],dtype='float64')
Chemistry=np.array(all_data['Chemistry'],dtype='float64')

#理系科目の得点と文系科目の得点
LiberalArts=Japanese+English
Science=Math+Physics+Chemistry
total=LiberalArts+Science


#data
X_train=np.vstack((English,Math)).T

#データの標準化
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()

sc.fit(X_train)
X_train_std=sc.transform(X_train)
X_train_std=X_train

from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

pca = PCA()
X_train_pca = pca.fit_transform(X_train_std)
pca.explained_variance_ratio_

# データのプロット
fig = plt.figure()
plt.scatter(X_train[:,0], X_train[:,1],edgecolors="orange",s=300)
plt.xlabel('English')
plt.ylabel('Math')


# 2 dimension
pca2 = PCA(n_components=2)
X_train_pca2 = pca2.fit_transform(X_train_std)

## projection to two new axes
fig0 = plt.figure()
plt.scatter(X_train_pca2[:,0], X_train_pca2[:,1],c=Math,cmap='Greens' ,marker="o", linewidths="2", edgecolors="orange",s=600)
plt.xlabel('pc 1')
plt.ylabel('pc 2')

fig1=plt.figure()
plt.scatter(X_train_pca2[:,0], X_train_pca2[:,1],c=English,cmap='Blues' ,marker="o", linewidths="2", edgecolors="orange",s=600)
plt.xlabel('pc 1')
plt.ylabel('pc 2')
plt.show()

#print('Covariance Matrix : %r' % pca.get_covariance())
print('Explained ratio : %r' % pca2.explained_variance_ratio_.round(2))
print('pc1 vector : %r' % pca2.components_[0].round(2))
print('pc2 vector : %r' % pca2.components_[1].round(2))

[/Python]

3次元⇒2次元の主成分分析


import numpy as np
import pandas as pd 

#data read
all_data = pd.read_csv('Seiseki.csv',encoding = "ISO-8859-1") 
Japanese=np.array(all_data['Japanese'],dtype='float64')
English=np.array(all_data['English'],dtype='float64')
Math=np.array(all_data['Math'],dtype='float64')
Physics=np.array(all_data['Physics'],dtype='float64')
Chemistry=np.array(all_data['Chemistry'],dtype='float64')

#理系科目の得点と文系科目の得点
LiberalArts=Japanese+English
Science=Math+Physics+Chemistry
total=LiberalArts+Science


#data
X_train=np.vstack((English,Math,Physics)).T

#データの標準化
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()

sc.fit(X_train)
X_train_std=sc.transform(X_train)
X_train_std=X_train

from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

pca = PCA()
X_train_pca = pca.fit_transform(X_train_std)
pca.explained_variance_ratio_

# データのプロット
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = Axes3D(fig)
#ax.plot_wireframe(X,Y,Z)
#ax.scatter3D(np.ravel(X1),np.ravel(X2),np.ravel(X3),c='b', marker='x',label='1')
ax.scatter3D(np.ravel(X_train[:,0]),np.ravel(X_train[:,1]),np.ravel(X_train[:,2]),c='r', marker='s')
ax.set_xlabel('English')
ax.set_ylabel('Math')
ax.set_zlabel('Physics')
plt.legend(loc='upper left')

plt.show()


# 2 dimension
pca2 = PCA(n_components=2)
X_train_pca2 = pca2.fit_transform(X_train_std)

## projection to two new axes
fig0 = plt.figure()

plt.scatter(X_train_pca2[:,0], X_train_pca2[:,1],s=100)

plt.xlabel('pc 1')
plt.ylabel('pc 2')
plt.show()

#print('Covariance Matrix : %r' % pca.get_covariance())
print('Explained ratio : %r' % pca2.explained_variance_ratio_.round(2))
print('pc1 vector : %r' % pca2.components_[0].round(2))
print('pc2 vector : %r' % pca2.components_[1].round(2))

 

✔5教科の成績について主成分分析

5教科すべてのデータについて5次元→2次元の主成分分析をしてみましょう。

主成分分析の結果と、総合点/文系科目の総点(国語+英語)/理系科目の総点l(数学+物理+化学)のカラーマップを示しています。この結果を解釈するならば、第一主成分は「総合力」、第二主成分は「理系力」(高いほうが理系科目ができて、低いほうが文系科目ができる)と、解釈できるのはないでしょうか。

・総合点

・文系科目

・理系科目

 

◆サンプルプログラム

結果表示には各主成分の寄与度と、主成分のベクトルの成分を表示するようにしています。※寄与度:その主成分でどれだけサンプルを説明できているかの指標。

 

#data read
all_data = pd.read_csv('Seiseki.csv',encoding = "ISO-8859-1") 
Japanese=np.array(all_data['Japanese'],dtype='float64')
English=np.array(all_data['English'],dtype='float64')
Math=np.array(all_data['Math'],dtype='float64')
Physics=np.array(all_data['Physics'],dtype='float64')
Chemistry=np.array(all_data['Chemistry'],dtype='float64')

#理系科目の得点と文系科目の得点
LiberalArts=Japanese+English
Science=Math+Physics+Chemistry
total=LiberalArts+Science


#data
#X_train=np.vstack((Japanese,English,Math,Physics,Chemistry)).T
X_train=np.vstack((English,Math)).T


#データの標準化
from sklearn.preprocessing import StandardScaler
sc = StandardScaler()

sc.fit(X_train)
X_train_std=sc.transform(X_train)
X_train_std=X_train

from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

pca = PCA()
X_train_pca = pca.fit_transform(X_train_std)
pca.explained_variance_ratio_

# データのプロット

fig = plt.figure()
plt.scatter(X_train[:,0], X_train[:,1],edgecolors="orange",s=300)
plt.xlabel('English')
plt.ylabel('Math')


# 2 dimension
pca2 = PCA(n_components=2)
X_train_pca2 = pca2.fit_transform(X_train_std)
#X_test_pca2 = pca2.transform(X_test_std)


fig0 = plt.figure()
plt.scatter(X_train_pca2[:,0], X_train_pca2[:,1],c=Science,cmap='Greens' ,marker="o", linewidths="2", edgecolors="orange",s=600)
plt.xlabel('pc 1')
plt.ylabel('pc 2')

fig1=plt.figure()
plt.scatter(X_train_pca2[:,0], X_train_pca2[:,1],c=LiberalArts,cmap='Blues' ,marker="o", linewidths="2", edgecolors="orange",s=600)
plt.xlabel('pc 1')
plt.ylabel('pc 2')

fig1=plt.figure()
plt.scatter(X_train_pca2[:,0], X_train_pca2[:,1],c=total,cmap='Reds' ,marker="o", linewidths="2", edgecolors="orange",s=600)
plt.xlabel('pc 1')
plt.ylabel('pc 2')

plt.show()

#print('Covariance Matrix : %r' % pca.get_covariance())
print('Explained ratio : %r' % pca2.explained_variance_ratio_.round(2))
print('pc1 vector : %r' % pca2.components_[0].round(2))
print('pc2 vector : %r' % pca2.components_[1].round(2))


Python Spyder グラフ描画

備忘録的なTipsです。

・インタラクティブな3Dプロットを表示するには

3Dプロットを別ウィンドウで開き、ぐりぐり動かすためのSpyderの設定方法です。

ツール → 設定 → IPythonコンソール → グラフィックスタブを開く。

グラフィクスのバックエンドを「自動」にする。

Python 機械学習 Scikit-learnによる決定木学習の実践

今回は決定木によるIrisの花のデータセットの分類を実践します。サンプルプログラムをまずは動かしてみることを念頭にしています。

※Pythonの導入方法http://costudyinfodatabase.nagoya/2017/01/05/%e3%81%82-2/

※Iris のデータセットとは
Irisのデータセットは「Iris setosa」「 Iris versicolor」「 Iris virginica 」の三種のアヤメの花について、sepal length(がくの長さ), sepal width(がくの幅), petal length (花弁の長さ)そして petal width(花弁の幅) の測定値が特徴量として格納されている150個 のデータセットです。機械学習用の標準データセットとして、下記のサンプルコードで簡単にインストールできます。

◆決定木とは

決定木は、分類器の一つ。n次元の特徴量からなるデータの多クラス分類が可能です。分類のための判断プロセスが可視化できるため、意思決定などに多く用いられます。

例を見てみましょう。「服を買うか否か」の分類問題で、特徴量は「ほしい服があるか(2値)」「店までの距離は何分か(連続値)」「天候が晴れか(2値)」であったとします。決定木は、分類が可能となる”質問”の仕方(フロー)であり、決定木学習ではこの質問の最適な仕方・順序を学習します。
最適な質問の仕方の決定には情報利得の最大化という考え方を用います。具体的には、ある特徴量について、境界線(ある値以上or以下、など)を引いてみたときに、分類が最もうまくいくものを探す、という手法です。分類がうまくいっているかどうかについては、分類されたものの純度の高さ、情報量の高さで評価します。
評価指標としては「ジニ不純度」・「エントロピー」・「分類誤差」などがありますが、ここでは詳細を割愛します。

決定木では、特徴量が、数値特徴量(距離など)でも、順序特徴量(大・中・小など)でも、名義特徴量(アメリカ・日本、、など)でも分類が可能です。

 

 

◆サンプルプログラムの大枠の流れ

Irisのデータセットから二つの特徴量、petal width, petal lengthを持つ3種類の花のデータセット

1.irisデータセットから二つの特徴量、petal width, petal lengthを持つ3種類の花のデータセットをインポートし、学習データと検証データに切り分けます。

2.学習データを用いて、scikit-learnにある決定木を適用し、分類器(質問を学習させます)を学習させます。ここでは純度の評価指標として「エントロピー」を用います。決定木の「深さ」も設定することができ、ここではmax_depth=3としています。深すぎるときに過学習に陥りやすくなるため注意が必要です。

3.検証用データを学習させた分類器で分類し、正答率を検証します。

4.「Graphviz」を用いて、学習させた決定木を可視化します。
※Graphvizの公式ダウンロードページhttp://www.graphviz.org/Download.php

 

 

#=========================================================
## data import
from distutils.version import LooseVersion as Version
from sklearn import __version__ as sklearn_version
from sklearn import datasets
import numpy as np

iris = datasets.load_iris()
X = iris.data[:, [2, 3]]
y = iris.target

#data plot
import matplotlib.pyplot as plt
fig = plt.figure()
plt.scatter(np.ravel(X[y==0,0]),np.ravel(X[y==0,1]),c='b', marker='o',label='1')
plt.scatter(np.ravel(X[y==1,0]),np.ravel(X[y==1,1]),c='r', marker='o',label='2')
plt.scatter(np.ravel(X[y==2,0]),np.ravel(X[y==2,1]),c='y', marker='o',label='3')

plt.xlabel('petal length [cm]')
plt.ylabel('petal width [cm]')
plt.legend(loc='upper left')
plt.tight_layout()
#=========================================================

#=========================================================
# split data into training data and test data
if Version(sklearn_version) < '0.18':
    from sklearn.cross_validation import train_test_split
else:
    from sklearn.model_selection import train_test_split

##Split the data into trainning data and test data at a certain ratio
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=0)
#=========================================================

#standardization
#from sklearn.preprocessing import StandardScaler

#sc = StandardScaler()
#sc.fit(X_train)
#X_train_std = sc.transform(X_train)
#X_test_std = sc.transform(X_test)


from sklearn.tree import DecisionTreeClassifier

tree = DecisionTreeClassifier(criterion='entropy', max_depth=3, random_state=0)
tree.fit(X_train, y_train)

y_pred_dt=tree.predict(X_test)

plt.figure(figsize=(8, 6), dpi=80)
# training data
plt.scatter(np.ravel(X_train[y_train==0,0]),np.ravel(X_train[y_train==0,1]),c='b', marker='o',label='train 1')
plt.scatter(np.ravel(X_train[y_train==1,0]),np.ravel(X_train[y_train==1,1]),c='r', marker='o',label='train2')
plt.scatter(np.ravel(X_train[y_train==2,0]),np.ravel(X_train[y_train==2,1]),c='y', marker='o',label='train3')
#predction data
plt.scatter(np.ravel(X_test[y_pred_dt==0,0]),np.ravel(X_test[y_pred_dt==0,1]),c='b', marker='o',label='prediction 1',s=60)
plt.scatter(np.ravel(X_test[y_pred_dt==1,0]),np.ravel(X_test[y_pred_dt==1,1]),c='r', marker='o',label='prediction 2',s=60)
plt.scatter(np.ravel(X_test[y_pred_dt==2,0]),np.ravel(X_test[y_pred_dt==2,1]),c='y', marker='o',label='prediction 3',s=60)
#test data
plt.scatter(np.ravel(X_test[y_test==0,0]),np.ravel(X_test[y_test==0,1]),c='b', marker='o',label='test 1')
plt.scatter(np.ravel(X_test[y_test==1,0]),np.ravel(X_test[y_test==1,1]),c='r', marker='o',label='test 2')
plt.scatter(np.ravel(X_test[y_test==2,0]),np.ravel(X_test[y_test==2,1]),c='y', marker='o',label='test 3')

plt.xlabel('petal length [cm]')
plt.ylabel('petal width [cm]')
plt.legend(loc=2)
plt.tight_layout()

plt.show()

# prediction accuracy
from sklearn.metrics import accuracy_score
print('Misclassified samples: %d' % (y_test != y_pred_dt).sum())
print('Accuracy : %.2f' % accuracy_score(np.rint(y_pred_dt), y_test))


## export dot file
from sklearn.tree import export_graphviz

export_graphviz(tree, 
                out_file='tree_result.dot', 
                feature_names=['petal length', 'petal width'])


## export dot file
#from sklearn.tree import export_graphviz


◆結果

Misclassified samples: 1
Accuracy : 0.98

すべてのデータとその花の種類、検証データに対する予測した花の種類(大きな〇印)をプロットしています。黄色印と赤印の境界に誤分類が発生しているのがわかります。
次に、決定木の構造を、出力データから読み取ってみましょう。
tree_result.dotというファイルが、作業ディレクトリに保存されています。
GVEdit.exeファイルを実行して、 File → Openからtree_result.dotを開いてください。
すると以下のような決定木の構造が表示されます。

分類のための質問に番号を赤字で振っています。(Question1,Question2,,,)
各質問の内容が書かれており、境界の値として何を使っているかが明示されています。

それぞれの質問の境界線を載せてみます。学習として、まずQuestion1:petal width で青を一気に分類できる境界線を引きます。次にQestion2: petal lengthで黄と赤をざっくり分けて行きます。決定木の末端であるQuestion 3,4で赤と黄をさらに分類していきます。

このように、この決定木学習の境界面は、多くの直線(平面)で分断した構造を持っています。

Python 機械学習 Scikit-learnによるサポートベクターマシン(SVM)による学習・分類の実践

今回はSVM(サポートベクターマシン)によるIrisの花のデータセットの分類を実践します。サンプルプログラムをコピーペーストでまずは動かしてみることを念頭にしています。

※Pythonの導入方法http://costudyinfodatabase.nagoya/2017/01/05/%e3%81%82-2/

※Iris のデータセットとは
Irisのデータセットは「Iris setosa」「 Iris versicolor」「 Iris virginica 」の三種のアヤメの花について、sepal length(がくの長さ), sepal width(がくの幅), petal length (花弁の長さ)そして petal width(花弁の幅) の測定値が特徴量として格納されている150個 のデータセットです。機械学習用の標準データセットとして、下記のサンプルコードで簡単にインストールできます。

◆SVMとは

SVMは、分類器の一つ。n次元の特徴量からなるデータ空間に、トレーニングデータで学習して、分類境界線を引きます。そして、その境界線を境にして、未知のデータがどのクラスに属するかを判定します。

線形SVM
特徴量が2次元、クラスが二つ(下では、青とオレンジで色分け)の場合のイメージを以下に示します。2つのクラスの間に境界面を引き、2つのクラスの内、この境界面に最も近いサンプルと境界との距離(マージン)が最も大きくなるようにな境界面を決定境界とするのが線形SVMです。

 

非線形SVM
上記のように、境界面が直線(平面)であるようなSVMを線形SVMと呼んでいます。それに対し、決定境界に曲面を用いる非線形SVMというものがあります。下のようなクラスの分布を持っている場合はどうでしょうか。青とオレンジの2つのクラスを直線で分離するのが困難であり、下図のような曲面の境界が有効であることがわかります。
(曲面の関数を引いてやる手法はここでは割愛。非線形SVMで検索すると大量にヒットします)

いずれの手法を用いるにしても、設定した特徴量空間でクラスが分類できるような集合を成しているか(集合がごちゃ混ぜで境界もなにも引けないような状態になっていないか)が高い識別率を左右します。

◆サンプルプログラムの大枠の流れ

1.irisのデータセットから3次元データ(3つの特徴量を有するデータ)をインポートし、学習データと検証データに切り分けます。

2.学習データを用いて、scikit-learnにある非線形SVMを適用し、分類器(どんな境界線を引くか)を学習させます。

3.検証用データを学習させた分類器で分類し、正答率を検証します。

 

 

irisのデータセットから3次元データ(3つの特徴量を有するデータ)をインポートし、学習データと検証データに切り分けます。切り分けたデータには標準化を行います。

※標準化:データの平均値=0、分散=1になるようにデータを整形すること。

#=========================================================
## data import
from distutils.version import LooseVersion as Version
from sklearn import __version__ as sklearn_version
from sklearn import datasets
import numpy as np

iris = datasets.load_iris()
data1=1
data2=2
data3=3

X = iris.data[:, [data1,data2,data3]]#sepal width/petal length/petal length
y = iris.target

print('Class labels:', np.unique(y))

if Version(sklearn_version) &lt; '0.18':
from sklearn.cross_validation import train_test_split
else:
from sklearn.model_selection import train_test_split

##Split the data into trainning data and test data at a certain ratio
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=0)

from sklearn.preprocessing import StandardScaler

sc = StandardScaler()
sc.fit(X_train)
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)
#==========================================================

#==========================================================
#data plot
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt

fig = plt.figure()
ax = Axes3D(fig)
#ax.plot_wireframe(X,Y,Z)
#ax.scatter3D(np.ravel(X1),np.ravel(X2),np.ravel(X3),c='b', marker='x',label='1')
ax.scatter3D(np.ravel(X[y==0,0]),np.ravel(X[y==0,1]),np.ravel(X[y==0,2]),c='b', marker='x',label='1')
ax.scatter3D(np.ravel(X[y==1,0]),np.ravel(X[y==1,1]),np.ravel(X[y==1,2]),c='r', marker='o',label='2')
ax.scatter3D(np.ravel(X[y==2,0]),np.ravel(X[y==2,1]),np.ravel(X[y==2,2]),c='y', marker='o',label='3')
ax.set_xlabel(iris.feature_names[data1])
ax.set_ylabel(iris.feature_names[data2])
ax.set_zlabel(iris.feature_names[data3])
plt.legend(loc='upper left')

plt.show()
#========================================================

実行結果

3次元の特徴量空間に3種類の花が色分けしてプロットされています。

 

次に、scikit-learnライブラリからSVMをインポートします。

SVMとして、非線形SVMを選択します。kernel=’rbf’ : 動径基底関数カーネルを用いた非線形SVM。’linear’を選択すると線形SVMを利用できます。ハイパーパラメータであるγを小さくするとサンプルデータの寄与が大きくなり、決定境界がより学習サンプルに追従するように学習されます。詳しくは割愛。

学習させた分類器にテストデータを分類させ、クラス(花の種類)を予測させます。実際の花の種類と、予測された種類を比較し、正答率を表示します。

次に、全データと、テストデータをその予測された花の種類の色で塗りつぶしたものを大きめの〇で囲ってプロットするようにしています。

from sklearn.svm import SVC

## apply non-linear svm to iris
svm = SVC(kernel='rbf', random_state=0, gamma=0.2, C=1.0)
svm.fit(X_train_std, y_train)
y_pred_svm=svm.predict(X_test_std)

# prediction accuracy
from sklearn.metrics import accuracy_score
print('Misclassified samples: %d' % (y_test != y_pred_svm).sum())
print('Accuracy : %.2f' % accuracy_score(np.rint(y_pred_svm), y_test))

#test data plot
fig1 = plt.figure()
ax1 = Axes3D(fig1)
ax1.scatter3D(np.ravel(X_test[y_pred_svm==0,0]),np.ravel(X_test[y_pred_svm==0,1]),np.ravel(X_test[y_pred_svm==0,2]),c='b', marker='x',label='1')
ax1.scatter3D(np.ravel(X_test[y_pred_svm==1,0]),np.ravel(X_test[y_pred_svm==1,1]),np.ravel(X_test[y_pred_svm==1,2]),c='r', marker='o',label='2')
ax1.scatter3D(np.ravel(X_test[y_pred_svm==2,0]),np.ravel(X_test[y_pred_svm==2,1]),np.ravel(X_test[y_pred_svm==2,2]),c='y', marker='o',label='3')
ax1.set_xlabel(iris.feature_names[data1])
ax1.set_ylabel(iris.feature_names[data2])
ax1.set_zlabel(iris.feature_names[data3])
plt.legend(loc='upper left')

#============================================================
#all data plot
fig = plt.figure()
ax2 = Axes3D(fig)
#train data
ax2.scatter3D(np.ravel(X[y==0,0]),np.ravel(X[y==0,1]),np.ravel(X[y==0,2]),c='b', marker='x',label='1')
ax2.scatter3D(np.ravel(X[y==1,0]),np.ravel(X[y==1,1]),np.ravel(X[y==1,2]),c='r', marker='o',label='2')
ax2.scatter3D(np.ravel(X[y==2,0]),np.ravel(X[y==2,1]),np.ravel(X[y==2,2]),c='y', marker='o',label='3')
#test data
ax2.scatter3D(np.ravel(X_test[y_pred_svm==0,0]),np.ravel(X_test[y_pred_svm==0,1]),np.ravel(X_test[y_pred_svm==0,2]),c='b', marker='x',label='1')
ax2.scatter3D(np.ravel(X_test[y_pred_svm==1,0]),np.ravel(X_test[y_pred_svm==1,1]),np.ravel(X_test[y_pred_svm==1,2]),c='r', marker='o',label='2')
ax2.scatter3D(np.ravel(X_test[y_pred_svm==2,0]),np.ravel(X_test[y_pred_svm==2,1]),np.ravel(X_test[y_pred_svm==2,2]),c='y', marker='o',label='3')
#highlight the test data
ax2.scatter3D(np.ravel(X_test[y_pred_svm==0,0]),np.ravel(X_test[y_pred_svm==0,1]),np.ravel(X_test[y_pred_svm==0,2]),c='', marker='o',label='1', s=60)
ax2.scatter3D(np.ravel(X_test[y_pred_svm==1,0]),np.ravel(X_test[y_pred_svm==1,1]),np.ravel(X_test[y_pred_svm==1,2]),c='', marker='o',label='2', s=60)
ax2.scatter3D(np.ravel(X_test[y_pred_svm==2,0]),np.ravel(X_test[y_pred_svm==2,1]),np.ravel(X_test[y_pred_svm==2,2]),c='', marker='o',label='3', s=60)

ax2.set_xlabel(iris.feature_names[data1])
ax2.set_ylabel(iris.feature_names[data2])
ax2.set_zlabel(iris.feature_names[data3])
#============================================================

実行結果

 

Misclassified samples: 1
Accuracy : 0.98

以上のように、98%の正答率で分類できています。おおむねうまく分類されていますが、クラスの集合の境目付近は誤分類が発生しています。