Last active
August 23, 2016 10:25
-
-
Save darden1/dc886aa903b2eb98f9be604a21604e73 to your computer and use it in GitHub Desktop.
StudyMachineLearning_LogisticRegression.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import sys | |
import numpy as np | |
import pandas as pd | |
import matplotlib.pyplot as plt | |
from matplotlib.colors import ListedColormap | |
def main(): | |
# ---アヤメデータの取得 | |
df = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data", header=None) | |
y = df.iloc[0:100, 4].values | |
y = np.where(y == "Iris-setosa", 0, 1) | |
X = df.iloc[0:100, [0, 2]].values | |
# ---トレーニングサンプルの標準化 | |
Xstd = np.copy(X) | |
Xstd[:, 0] = (X[:, 0] - X[:, 0].mean()) / X[:, 0].std() | |
Xstd[:, 1] = (X[:, 1] - X[:, 1].mean()) / X[:, 1].std() | |
# ---学習実施(学習率:0.01 最大エポック数:20 (特徴量を標準化,シャッフルオン,バッチ勾配降下法)) | |
clf = LogisticRegression(eta=0.01, numEpoch=20, shuffle=True) | |
clf.fit(Xstd, y) | |
plotResult(clf,Xstd,y,"Standardization","On","BGD") | |
# ---学習実施(学習率:0.2 最大エポック数:20 (特徴量を標準化,シャッフルオン,バッチ勾配降下法)) | |
clf = LogisticRegression(eta=0.2, numEpoch=20, shuffle=True) | |
clf.fit(Xstd, y) | |
plotResult(clf,Xstd,y,"Standardization","On","BGD") | |
# ---学習実施(学習率:0.01 最大エポック数:20 (特徴量を標準化,シャッフルオン,確率的勾配降下法)) | |
clf = LogisticRegression(eta=0.01, numEpoch=20, shuffle=True) | |
clf.fitSGD(Xstd, y) | |
plotResult(clf, Xstd, y, "Standardization", "On", "SGD") | |
# ---学習実施(学習率:0.2 最大エポック数:20 (特徴量を標準化,シャッフルオン,確率的勾配降下法)) | |
clf = LogisticRegression(eta=0.2, numEpoch=20, shuffle=True) | |
clf.fitSGD(Xstd, y) | |
plotResult(clf, Xstd, y, "Standardization", "On", "SGD") | |
# ---学習実施(学習率:0.01 最大エポック数:20 (特徴量を標準化,シャッフルオン,一発解法)) | |
clf = LogisticRegression(eta=0.01, numEpoch=20, shuffle=True) | |
clf.fitLS(Xstd, y) | |
plotResult(clf, Xstd, y, "Standardization", "On", "LS") | |
def plotResult(clf,X,y,trainSampleState,shuffeled,fitAlgorism): | |
#---プロットのプロパティ | |
markers = ('s', 'o', 'x', '^', 'v') | |
colors = ('green', 'yellow','red', 'blue', 'lightgreen', 'gray', 'cyan') | |
cmap = ListedColormap(colors[:len(np.unique(y))]) | |
labels = ('setosa', 'versicolor') | |
fig = plt.figure(figsize=(18, 10)) | |
plt.clf() | |
ax1 = fig.add_subplot(231) | |
ax2 = fig.add_subplot(232) | |
ax3 = fig.add_subplot(233) | |
ax4 = fig.add_subplot(234) | |
ax5 = fig.add_subplot(235) | |
# ---エポック数と重みのプロット | |
epochTimes = np.array(range(0, clf.numEpoch + 1)) | |
clf.W_ = np.array(clf.W_) | |
ax1.plot(epochTimes, clf.W_[:, 0].T[0], color="blue", label="w0") | |
ax1.plot(epochTimes, clf.W_[:, 1].T[0], color="red", label="w2") | |
ax1.plot(epochTimes, clf.W_[:, 2].T[0], color="green", label="w1") | |
ax1.legend(loc="upper left") | |
ax1.set_xlabel('Epochs') | |
ax1.set_ylabel('Weight') | |
ax1.set_title("Epochs and weight") | |
ax1.set_xlim(0, clf.numEpoch) | |
# ---ax1.set_xticks(range(0,numEpoch+1,1)) | |
ax1.grid() | |
# ---エポック数と正答率のプロット | |
epochTimes = range(1, clf.numEpoch + 1) | |
ax2.plot(epochTimes, np.array(clf.correctAnswerRateEachEpoch_) * 100, color="blue", marker="o", | |
label="Correct answer rate") | |
# ---ax2.legend(loc="upper left") | |
ax2.set_title("Epochs and correct answer rate") | |
ax2.set_xlabel('Epochs') | |
ax2.set_ylabel('Correct answer rate[%]') | |
ax2.set_xlim(0, clf.numEpoch) | |
ax2.grid() | |
# ---教師データのクラスラベルが1(バージカラー)であるである確率 | |
numTrainSamples = len(y) | |
trainSampeleIndex=range(numTrainSamples) | |
ax3.plot(trainSampeleIndex, clf.probability(X)*100, color="blue", marker="o",label="Probability") | |
ax3.set_title("TrainSamples and probability(label=1)") | |
ax3.set_xlabel('TrainSamples') | |
ax3.set_ylabel('Probability[%]') | |
ax3.set_xlim(0, numTrainSamples) | |
ax3.grid() | |
# ---エポック数とコスト関数のプロット | |
epochTimes = range(1, clf.numEpoch + 1) | |
ax4.plot(epochTimes, np.array(clf.J_)[:, 0][:, 0], color="blue", marker="o", | |
label="Cost function values") | |
# ---ax3.legend(loc="upper left") | |
ax4.set_title("Epochs and cost function values") | |
ax4.set_xlabel('Epochs') | |
ax4.set_ylabel('Cost function values') | |
ax4.set_xlim(0, clf.numEpoch) | |
ax4.grid() | |
# ---ax3.set_xticks(range(0,numEpoch+1,1)) | |
# ---決定領域のプロット | |
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1 | |
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1 | |
dx = 0.02 | |
X1 = np.arange(x1_min, x1_max, dx) | |
X2 = np.arange(x2_min, x2_max, dx) | |
X1, X2 = np.meshgrid(X1, X2) | |
Z = clf.predict(np.array([X1.ravel(), X2.ravel()]).T) | |
Z = Z.reshape(X1.shape) | |
# ---決定領域 | |
ax5.contourf(X1, X2, Z, alpha=0.5, cmap=cmap) | |
ax5.set_xlim(X1.min(), X1.max()) | |
ax5.set_ylim(X2.min(), X2.max()) | |
# ---アヤメデータ | |
for idx, cl in enumerate(np.unique(y)): | |
ax5.scatter(x=X[y == cl, 0], y=X[y == cl, 1], | |
alpha=1.0, c=cmap(idx), | |
marker=markers[idx], label=labels[idx]) | |
ax5.set_title("Decision regions") | |
ax5.set_xlabel("Sepal length [cm]") # がく片の長さ | |
ax5.set_ylabel("Petal length [cm]") # 花びらの長さ | |
ax5.legend(loc="upper left") | |
ax5.grid() | |
pngFileName=u"ロジスティック回帰学習結果_トレーニングサンプル" +trainSampleState +u"_シャッフル"+shuffeled+u"_Fitアルゴリズム"+fitAlgorism+ u"_学習率"+str(clf.eta)+u"_最大エポック数"+str(clf.numEpoch)+ ".png" | |
plt.savefig(pngFileName, dpi=300) | |
class LogisticRegression(object): | |
def __init__(self, eta=0.01, numEpoch=10, shuffle=True, random_state=None): | |
self.eta = eta #学習率 | |
self.numEpoch = numEpoch #最大エポック数 | |
self.shuffle = shuffle #トレーニングサンプルをシャッフルする? | |
if random_state: | |
np.random.seed(random_state) | |
self.W_=[] #各エポックごとに重みを保存するリスト | |
self.J_=[] #各エポックごとにコスト関数を保存するリスト | |
self.correctAnswerRateEachEpoch_=[] #各エポックごとに正答率を保存するリスト | |
def __actFunc(self, z): | |
"""活性化関数(__でプライベート関数)""" | |
return 1.0 / (1.0 + np.exp(-z)) | |
def __quantizer(self, phi): | |
"""量子化器(__でプライベート関数)""" | |
return np.where(np.array(phi) >= 0.5, 1, 0) | |
def __shuffle(self, X, y): | |
"""トレーニングサンプルのシャッフル(__でプライベート関数)""" | |
r = np.random.permutation(len(y)) | |
return X[r], y[r] | |
def predict(self, X): | |
"""予測関数""" | |
X = np.matrix(X) | |
m, n = X.shape | |
X = np.c_[np.matrix(np.ones((m, 1))), X] | |
z=X*self.w_ | |
phi=self.__actFunc(z) | |
return self.__quantizer(phi) | |
def probability(self, X): | |
"""教師データのクラスラベルが1である確率を求める関数""" | |
X = np.matrix(X) | |
m, n = X.shape | |
X = np.c_[np.matrix(np.ones((m, 1))), X] | |
z=X*self.w_ | |
phi=self.__actFunc(z) | |
return phi | |
def fit(self, X, y): | |
"""バッチ勾配降下法による学習の実施""" | |
# ---トレーニングサンプルのシャッフル | |
if self.shuffle: | |
X, y = self.__shuffle(X, y) | |
# ---特徴行列 | |
X = np.matrix(X) | |
m, n = X.shape | |
# ---しきい値用に一番左側の列に1を追加 | |
X = np.c_[np.matrix(np.ones((m, 1))), X] | |
# ---教師データベクトル | |
y = np.matrix(y).T | |
# ---重みベクトル(初期化) | |
self.w_ =np.matrix(np.zeros((n+1,1))) | |
# 重みを学習回数ごとに保存 | |
self.W_.append(self.w_.tolist()) | |
for indexEpoch in range(1,self.numEpoch+1): #エポックループ | |
correctAnswer=[] #各トレーニングセットに対する教師データと予測値の正誤表をイニシャライズ | |
# ---特徴行列と重みベクトルの掛け合わせ | |
z = X * self.w_ | |
# ---活性化関数出力ベクトル | |
phi =self.__actFunc(z) | |
# ---コスト関数 | |
J = -y.T * np.log(phi) - (np.ones((m, 1)) - y).T * np.log(np.ones((m, 1)) - phi) | |
# ---コスト関数の勾配 | |
gradJ = -X.T * (y - phi) | |
# ---重み更新 | |
dw = - self.eta * gradJ | |
self.w_ = self.w_ + dw | |
# 重みをエポックごとに保存 | |
self.W_.append(self.w_.tolist()) | |
# コスト関数をエポックごとに保存 | |
self.J_.append(J.tolist()) | |
#--正答表 | |
correctAnswer = np.where(np.array(y == self.__quantizer(phi)) == True, 1, 0) | |
#各エポックごとに正誤表から正答率算出し保存 | |
self.correctAnswerRateEachEpoch_.append(float(sum(correctAnswer))/len(correctAnswer)) | |
def fitSGD(self, X, y): | |
"""確率的勾配降下法による学習の実施""" | |
# ---トレーニングサンプルのシャッフル | |
if self.shuffle: | |
X, y = self.__shuffle(X, y) | |
# ---特徴行列 | |
X = np.matrix(X) | |
m, n = X.shape | |
# ---しきい値用に一番左側の列に1を追加 | |
X = np.c_[np.matrix(np.ones((m, 1))), X] | |
# ---教師データベクトル | |
y = np.matrix(y).T | |
# ---重みベクトル(初期化) | |
self.w_ = np.matrix(np.zeros((n + 1, 1))) | |
# 重みを学習回数ごとに保存 | |
self.W_.append(self.w_.tolist()) | |
for indexEpoch in range(1, self.numEpoch + 1): # エポックループ | |
correctAnswer = [] # 各トレーニングセットに対する教師データと予測値の正誤表をイニシャライズ | |
for xi, yi in zip(X, y): # トレーニングセットループ | |
# ---特徴行列と重みベクトルの掛け合わせ | |
zi = xi * self.w_ | |
# ---活性化関数出力ベクトル | |
phii = self.__actFunc(zi) | |
# ---コスト関数の勾配 | |
gradJi = -xi.T * (yi - phii) | |
# ---重み更新 | |
dwi = - self.eta * gradJi | |
self.w_ = self.w_ + dwi | |
# ---特徴行列と重みベクトルの掛け合わせ | |
z = X * self.w_ | |
# ---活性化関数出力ベクトル | |
phi =self.__actFunc(z) | |
# ---コスト関数 | |
J = -y.T * np.log(phi) - (np.ones((m, 1)) - y).T * np.log(np.ones((m, 1)) - phi) | |
# 重みをエポックごとに保存 | |
self.W_.append(self.w_.tolist()) | |
# コスト関数をエポックごとに保存 | |
self.J_.append(J.tolist()) | |
# --正答表 | |
correctAnswer = np.where(np.array(y == self.__quantizer(phi)) == True, 1, 0) | |
# 各エポックごとに正誤表から正答率算出し保存 | |
self.correctAnswerRateEachEpoch_.append(float(sum(correctAnswer)) / len(correctAnswer)) | |
def fitLS(self, X, y): | |
"""一発学習の実施""" | |
# ---トレーニングサンプルのシャッフル | |
if self.shuffle: | |
X, y = self.__shuffle(X, y) | |
# ---特徴行列 | |
X = np.matrix(X) | |
m, n = X.shape | |
# ---しきい値用に一番左側の列に1を追加 | |
X = np.c_[np.matrix(np.ones((m, 1))), X] | |
# ---教師データベクトル | |
y = np.matrix(y).T | |
# ---重みベクトル(初期化) | |
self.w_ = np.matrix(np.zeros((n + 1, 1))) | |
# 重みを学習回数ごとに保存 | |
self.W_.append(self.w_.tolist()) | |
for indexEpoch in range(1, self.numEpoch + 1): # エポックループ | |
correctAnswer = [] # 各トレーニングセットに対する教師データと予測値の正誤表をイニシャライズ | |
# ---コスト関数を最小にする重みを一発で算出 | |
dy = 1e-10 | |
yHat = np.where(y == 1, 1 - dy, dy) #---log(0)が計算できないのでyをdyだけずらしてやる | |
self.w_ = np.linalg.inv(X.T*X)*X.T*(np.log(yHat)-np.log(np.ones((m, 1)) - yHat)) | |
# ---特徴行列と重みベクトルの掛け合わせ | |
z = X * self.w_ | |
# ---活性化関数出力ベクトル | |
phi = self.__actFunc(z) | |
# ---コスト関数 | |
J = -y.T * np.log(phi) - (np.ones((m, 1)) - y).T * np.log(np.ones((m, 1)) - phi) | |
# 重みをエポックごとに保存 | |
self.W_.append(self.w_.tolist()) | |
# コスト関数をエポックごとに保存 | |
self.J_.append(J.tolist()) | |
# --正答表 | |
correctAnswer = np.where(np.array(y == self.__quantizer(phi)) == True, 1, 0) | |
# 各エポックごとに正誤表から正答率算出し保存 | |
self.correctAnswerRateEachEpoch_.append(float(sum(correctAnswer)) / len(correctAnswer)) | |
if __name__ == "__main__": | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment