對鳶尾花數據集和月亮數據集,分別採用線性LDA、k-means和SVM算法進行二分類可視化分析
一、線性LDA算法
1.定義:線性判別分析(Linear Discriminant Analysis
簡稱LDA)是一種經典的線性學習方法,在二分類問題上因爲最早由【Fisher,1936年】提出,所以也稱爲“Fisher 判別分析!”
Fisher(費歇)判別思想是投影,使多維問題簡化爲一維問題來處理。選擇一個適當的投影軸,使所有的樣本點都投影到這個軸上得到一個投影值。對這個投影軸的方向的要求是:使每一類內的投影值所形成的類內離差儘可能小,而不同類間的投影值所形成的類間離差儘可能大。
2.鳶尾花數據集進行二分類
# 鳶尾花數據集LDA線性二分類
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets.samples_generator import make_classification
class LDA():
def Train(self, X, y):
"""X爲訓練數據集,y爲訓練label"""
X1 = np.array([X[i] for i in range(len(X)) if y[i] == 0])
X2 = np.array([X[i] for i in range(len(X)) if y[i] == 1])
# 求中心點
mju1 = np.mean(X1, axis=0) # mju1是ndrray類型
mju2 = np.mean(X2, axis=0)
# dot(a, b, out=None) 計算矩陣乘法
cov1 = np.dot((X1 - mju1).T, (X1 - mju1))
cov2 = np.dot((X2 - mju2).T, (X2 - mju2))
Sw = cov1 + cov2
# 計算w
w = np.dot(np.mat(Sw).I, (mju1 - mju2).reshape((len(mju1), 1)))
# 記錄訓練結果
self.mju1 = mju1 # 第1類的分類中心
self.cov1 = cov1
self.mju2 = mju2 # 第2類的分類中心
self.cov2 = cov2
self.Sw = Sw # 類內散度矩陣
self.w = w # 判別權重矩陣
def Test(self, X, y):
"""X爲測試數據集,y爲測試label"""
# 分類結果
y_new = np.dot((X), self.w)
# 計算fisher線性判別式
nums = len(y)
c1 = np.dot((self.mju1 - self.mju2).reshape(1, (len(self.mju1))), np.mat(self.Sw).I)
c2 = np.dot(c1, (self.mju1 + self.mju2).reshape((len(self.mju1), 1)))
c = 1/2 * c2 # 2個分類的中心
h = y_new - c
# 判別
y_hat = []
for i in range(nums):
if h[i] >= 0:
y_hat.append(0)
else:
y_hat.append(1)
# 計算分類精度
count = 0
for i in range(nums):
if y_hat[i] == y[i]:
count += 1
precise = count / nums
# 顯示信息
print("測試樣本數量:", nums)
print("預測正確樣本的數量:", count)
print("測試準確度:", precise)
return precise
if '__main__' == __name__:
# 產生分類數據
n_samples = 500
X, y = make_classification(n_samples=n_samples, n_features=2, n_redundant=0, n_classes=2,n_informative=1, n_clusters_per_class=1, class_sep=0.5, random_state=10)
# LDA線性判別分析(二分類)
lda = LDA()
# 60% 用作訓練,40%用作測試
Xtrain = X[:299, :]
Ytrain = y[:299]
Xtest = X[300:, :]
Ytest = y[300:]
lda.Train(Xtrain, Ytrain)
precise = lda.Test(Xtest, Ytest)
# 原始數據
plt.scatter(X[:, 0], X[:, 1], marker='o', c=y)
plt.xlabel("x1")
plt.ylabel("x2")
plt.title("Test precise:" + str(precise))
plt.show()
運行結果:
3.月亮數據集進行二分類
#月亮數據集二分類
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
class LDA():
def Train(self, X, y):
"""X爲訓練數據集,y爲訓練label"""
X1 = np.array([X[i] for i in range(len(X)) if y[i] == 0])
X2 = np.array([X[i] for i in range(len(X)) if y[i] == 1])
# 求中心點
mju1 = np.mean(X1, axis=0) # mju1是ndrray類型
mju2 = np.mean(X2, axis=0)
# dot(a, b, out=None) 計算矩陣乘法
cov1 = np.dot((X1 - mju1).T, (X1 - mju1))
cov2 = np.dot((X2 - mju2).T, (X2 - mju2))
Sw = cov1 + cov2
# 計算w
w = np.dot(np.mat(Sw).I, (mju1 - mju2).reshape((len(mju1), 1)))
# 記錄訓練結果
self.mju1 = mju1 # 第1類的分類中心
self.cov1 = cov1
self.mju2 = mju2 # 第1類的分類中心
self.cov2 = cov2
self.Sw = Sw # 類內散度矩陣
self.w = w # 判別權重矩陣
def Test(self, X, y):
"""X爲測試數據集,y爲測試label"""
# 分類結果
y_new = np.dot((X), self.w)
# 計算fisher線性判別式
nums = len(y)
c1 = np.dot((self.mju1 - self.mju2).reshape(1, (len(self.mju1))), np.mat(self.Sw).I)
c2 = np.dot(c1, (self.mju1 + self.mju2).reshape((len(self.mju1), 1)))
c = 1/2 * c2 # 2個分類的中心
h = y_new - c
# 判別
y_hat = []
for i in range(nums):
if h[i] >= 0:
y_hat.append(0)
else:
y_hat.append(1)
# 計算分類精度
count = 0
for i in range(nums):
if y_hat[i] == y[i]:
count += 1
precise = count / (nums+0.000001)
# 顯示信息
print("測試樣本數量:", nums)
print("預測正確樣本的數量:", count)
print("測試準確度:", precise)
return precise
if '__main__' == __name__:
# 產生分類數據
X, y = make_moons(n_samples=100, noise=0.15, random_state=42)
# LDA線性判別分析(二分類)
lda = LDA()
# 60% 用作訓練,40%用作測試
Xtrain = X[:60, :]
Ytrain = y[:60]
Xtest = X[40:, :]
Ytest = y[40:]
lda.Train(Xtrain, Ytrain)
precise = lda.Test(Xtest, Ytest)
# 原始數據
plt.scatter(X[:, 0], X[:, 1], marker='o', c=y)
plt.xlabel("x1")
plt.ylabel("x2")
plt.title("Test precise:" + str(precise))
plt.show()
運行結果:
二、k-means算法
1.定義
K-Means算法的思想很簡單,對於給定的樣本集,按照樣本之間的距離大小,將樣本集劃分爲K個簇。讓簇內的點儘量緊密的連在一起,而讓簇間的距離儘量的大。
在數據集中根據一定策略選擇K個點作爲每個簇的初始中心,然後觀察剩餘的數據,將數據劃分到距離這K個點最近的簇中,也就是說將數據劃分成K個簇完成一次劃分,但形成的新簇並不一定是最好的劃分,因此生成的新簇中,重新計算每個簇的中心點,然後在重新進行劃分,直到每次劃分的結果保持不變。在實際應用中往往經過很多次迭代仍然達不到每次劃分結果保持不變,甚至因爲數據的關係,根本就達不到這個終止條件,實際應用中往往採用變通的方法設置一個最大迭代次數,當達到最大迭代次數時,終止計算。
2.鳶尾花數據集進行二分類
#鳶尾花數據集二分類
import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans
from sklearn import datasets
from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data[:] ##表示我們只取特徵空間中的後兩個維度
estimator = KMeans(n_clusters=5)#構造聚類器
estimator.fit(X)#聚類
label_pred = estimator.labels_ #獲取聚類標籤
#繪製k-means結果
x0 = X[label_pred == 0]
x1 = X[label_pred == 1]
x2 = X[label_pred == 2]
x3 = X[label_pred == 3]
plt.scatter(x0[:, 0], x0[:, 1], c = "red", marker='o', label='label0')
plt.scatter(x1[:, 0], x1[:, 1], c = "green", marker='*', label='label1')
#plt.scatter(x2[:, 0], x2[:, 1], c = "blue", marker='+', label='label2')
#plt.scatter(x3[:, 0], x3[:, 1], c = "yellow", marker='o', label='label3')
plt.xlabel('petal length')
plt.ylabel('petal width')
plt.legend(loc=2)
plt.show()
運行結果:
3.月亮數據集進行二分類
#月亮數據集K-Means二分類
import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import make_moons
X, y = make_moons(n_samples=100, noise=0.15, random_state=42)
estimator = KMeans(n_clusters=5)#構造聚類器
estimator.fit(X)#聚類
label_pred = estimator.labels_ #獲取聚類標籤
#繪製k-means結果
x0 = X[label_pred == 0]
x1 = X[label_pred == 1]
x2 = X[label_pred == 2]
x3 = X[label_pred == 3]
plt.scatter(x0[:, 0], x0[:, 1], c = "red", marker='o', label='label0')
plt.scatter(x1[:, 0], x1[:, 1], c = "green", marker='*', label='label1')
#plt.scatter(x2[:, 0], x2[:, 1], c = "blue", marker='+', label='label2')
#plt.scatter(x3[:, 0], x3[:, 1], c = "yellow", marker='o', label='label3')
plt.xlabel('petal length')
plt.ylabel('petal width')
plt.legend(loc=2)
plt.show()
運行結果:
三、SVM算法
1.定義:
SVM的全稱是Support Vector Machine,即支持向量機,主要用於解決模式識別領域中的數據分類問題,屬於有監督學習算法的一種。SVM要解決的問題可以用一個經典的二分類問題加以描述。如圖1所示,紅色和藍色的二維數據點顯然是可以被一條直線分開的,在模式識別領域稱爲線性可分問題。然而將兩類數據點分開的直線顯然不止一條。圖1(b)和©分別給出了A、B兩種不同的分類方案,其中黑色實線爲分界線,術語稱爲“決策面”。每個決策面對應了一個線性分類器。雖然在目前的數據上看,這兩個分類器的分類結果是一樣的,但如果考慮潛在的其他數據,則兩者的分類性能是有差別的。
2.鳶尾花數據集進行二分類
# 鳶尾花數據集SVM算法二分類
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets, svm
import pandas as pd
from pylab import *
mpl.rcParams['font.sans-serif'] = ['SimHei']
iris = datasets.load_iris()
iris = datasets.load_iris()
X = iris.data
y = iris.target
X = X[y != 0, :2] # 選擇X的前兩個特性
y = y[y != 0]
n_sample = len(X)
np.random.seed(0)
order = np.random.permutation(n_sample) # 排列,置換
X = X[order]
y = y[order].astype(np.float)
X_train = X[:int(.9 * n_sample)]
y_train = y[:int(.9 * n_sample)]
X_test = X[int(.9 * n_sample):]
y_test = y[int(.9 * n_sample):]
#合適的模型
for fig_num, kernel in enumerate(('linear', 'rbf','poly')): # 徑向基函數 (Radial Basis Function 簡稱 RBF),常用的是高斯基函數
clf = svm.SVC(kernel=kernel, gamma=10) # gamma是“rbf”、“poly”和“sigmoid”的核係數。
clf.fit(X_train, y_train)
plt.figure(str(kernel))
plt.xlabel('x1')
plt.ylabel('x2')
plt.scatter(X[:, 0], X[:, 1], c=y, zorder=10, cmap=plt.cm.Paired, edgecolor='k', s=20)
# zorder: z方向上排列順序,數值越大,在上方顯示
# paired兩個色彩相近輸出(paired)
# 圈出測試數據
plt.scatter(X_test[:, 0], X_test[:, 1], s=80, facecolors='none',zorder=10, edgecolor='k')
plt.axis('tight') #更改 x 和 y 軸限制,以便顯示所有數據
x_min = X[:, 0].min()
x_max = X[:, 0].max()
y_min = X[:, 1].min()
y_max = X[:, 1].max()
XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j]
Z = clf.decision_function(np.c_[XX.ravel(), YY.ravel()]) # 樣本X到分離超平面的距離
Z = Z.reshape(XX.shape)
plt.contourf(XX,YY,Z>0,cmap=plt.cm.Paired)
plt.contour(XX, YY, Z, colors=['r', 'k', 'b'],
linestyles=['--', '-', '--'], levels=[-0.5, 0, 0.5]) # 範圍
plt.title(kernel)
plt.show()
運行結果:
3.月亮數據集進行二分類
# 月亮數據集SVM二分類
import matplotlib.pyplot as plt
from sklearn.pipeline import Pipeline
import numpy as np
import matplotlib as mpl
from sklearn.datasets import make_moons
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC
# 爲了顯示中文
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
X, y = make_moons(n_samples=100, noise=0.15, random_state=42)
def plot_dataset(X, y, axes):
plt.plot(X[:, 0][y==0], X[:, 1][y==0], "bs")
plt.plot(X[:, 0][y==1], X[:, 1][y==1], "g^")
plt.axis(axes)
plt.grid(True, which='both')
plt.xlabel(r"$x_1$", fontsize=20)
plt.ylabel(r"$x_2$", fontsize=20, rotation=0)
plt.title("月亮數據",fontsize=20)
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
polynomial_svm_clf = Pipeline([
# 將源數據 映射到 3階多項式
("poly_features", PolynomialFeatures(degree=3)),
# 標準化
("scaler", StandardScaler()),
# SVC線性分類器
("svm_clf", LinearSVC(C=10, loss="hinge", random_state=42))
])
polynomial_svm_clf.fit(X, y)
def plot_predictions(clf, axes):
# 打表
x0s = np.linspace(axes[0], axes[1], 100)
x1s = np.linspace(axes[2], axes[3], 100)
x0, x1 = np.meshgrid(x0s, x1s)
X = np.c_[x0.ravel(), x1.ravel()]
y_pred = clf.predict(X).reshape(x0.shape)
y_decision = clf.decision_function(X).reshape(x0.shape)
# print(y_pred)
# print(y_decision)
plt.contourf(x0, x1, y_pred, cmap=plt.cm.brg, alpha=0.2)
plt.contourf(x0, x1, y_decision, cmap=plt.cm.brg, alpha=0.1)
plot_predictions(polynomial_svm_clf, [-1.5, 2.5, -1, 1.5])
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
plt.show()
運行結果:
from sklearn.svm import SVC
gamma1, gamma2 = 0.1, 5
C1, C2 = 0.001, 1000
hyperparams = (gamma1, C1), (gamma1, C2)
svm_clfs = []
for gamma, C in hyperparams:
rbf_kernel_svm_clf = Pipeline([
("scaler", StandardScaler()),
("svm_clf", SVC(kernel="rbf", gamma=gamma, C=C))
])
rbf_kernel_svm_clf.fit(X, y)
svm_clfs.append(rbf_kernel_svm_clf)
plt.figure(figsize=(11, 7))
for i, svm_clf in enumerate(svm_clfs):
plt.subplot(221 + i)
plot_predictions(svm_clf, [-1.5, 2.5, -1, 1.5])
plot_dataset(X, y, [-1.5, 2.5, -1, 1.5])
gamma, C = hyperparams[i]
plt.title(r"$\gamma = {}, C = {}$".format(gamma, C), fontsize=16)
plt.tight_layout()
plt.show()
運行結果:
四、SVM算法的優缺點
優點
(1)使用核函數可以向高維空間進行映射
(2)使用核函數可以解決非線性的分類
(3)分類思想很簡單,就是將樣本與決策面的間隔最大化
(4)分類效果較好
缺點:
(1)SVM算法對大規模訓練樣本難以實施
(2)用SVM解決多分類問題存在困難
(3)對缺失數據敏感,對參數和核函數的選擇敏感
參考鏈接:https://www.cnblogs.com/lsm-boke/p/11761534.html
參考書:《機器學習》-周志華