對鳶尾花數據集和月亮數據集,分別採用LDA、k-means和SVM算法進行二分類可視化分析(python)

對鳶尾花數據集和月亮數據集,分別採用線性LDA、k-means和SVM算法進行二分類可視化分析(python)

一、線性判別分析LDA

1、LDA介紹

線性判別分析(linear discriminant analysis,LDA)是對費舍爾的線性鑑別方法的歸納,這種方法使用統計學,模式識別和機器學習方法,試圖找到兩類物體或事件的特徵的一個線性組合,以能夠特徵化或區分它們。所得的組合可用來作爲一個線性分類器,或者,更常見的是,爲後續的分類做降維處理。
線性判別分析是一種經典的線性學習方法,在二分類問題上最早由Fisher在1936年提出,亦稱Fisher線性判別。線性判別的思想非常樸素:給定訓練樣例集,設法將樣例投影到一條直線上,使得同類樣例的投影點儘可能接近,異樣樣例的投影點儘可能遠離;在對新樣本進行分類時,將其投影到同樣的直線上,再根據投影點的位置來確定新樣本的類別 。LDA與方差分析(ANOVA)和迴歸分析緊密相關,這兩種分析方法也試圖通過一些特徵或測量值的線性組合來表示一個因變量。然而,方差分析使用類別自變量和連續數因變量,而判別分析連續自變量和類別因變量(即類標籤)。邏輯迴歸和概率迴歸比方差分析更類似於LDA,因爲他們也是用連續自變量來解釋類別因變量的。LDA的基本假設是自變量是正態分佈的,當這一假設無法滿足時,在實際應用中更傾向於用上述的其他方法。LDA也與主成分分析(PCA)和因子分析緊密相關,它們都在尋找最佳解釋數據的變量線性組合。LDA明確的嘗試爲數據類之間不同建立模型。 另一方面,PCA不考慮類的任何不同,因子分析是根據不同點而不是相同點來建立特徵組合。判別的分析不同因子分析還在於,它不是一個相互依存技術:即必須區分出自變量和因變量(也稱爲準則變量)的不同。在對自變量每一次觀察測量值都是連續量的時候,LDA能有效的起作用。當處理類別自變量時,與LDA相對應的技術稱爲判別反應分析。

優點:
Fisher提出LDA距今已近七十年,仍然是降維和模式分類領域應用中最爲廣泛採用而且極 爲有效的方法之一,其典型應用包括人臉檢測、人臉識別、基於視覺飛行的地平線檢測、目標跟蹤和檢測、信用卡欺詐檢測和圖像檢索、語音識別等。之所以有如此廣泛的應用,其 主要原因是,LDA(包括其多類推廣)具有以下優點:可以直接求得基於廣義特徵值問題的解析解,從而避免了在一般非線性算法中,如多層感知器,構建中所常遇到的局部最小問題無需對模式的輸出類別進行人爲的編碼,從而使 LDA 對不平衡模式類的處理表現出尤其明顯的優勢。與神經網絡方法相比,LDA 不需要調整參數,因而也不存在學習參數和優化權重以及神經元激活函數的選擇等問題;對模式的歸一化或隨機化不敏感,而這在基於梯度 下降的各種算法中則顯得比較突出 [2] 。在某些實際情形中,LDA 具有與基於結構風險最小化原理的支持向量機(SVM)相當的甚至更優的推廣性能,但其計算效率則遠優於SVM。正則判別分析法(CDA)尋找最優區分類別的座標軸(k-1個正則座標,k爲類別的數量)。 這些線性函數是不相關的,實際上,它們通過n維數據雲定義了一個最優化的k-1個空間,能夠最優的區分k個類(通過其在空間的投影)。
多類LDA:當出現超過兩類的情況時,可以使用由費舍爾判別派生出的分析方法,它延伸爲尋找一個保留了所有類的變化性的子空間。這是由 C.R.Rao 總結出來的。假設,C個類中每一個類都有均值和相同的協方差。
要實現典型的LDA技術前提是所有的樣本都必須提前準備完畢。但有些情況下,沒有現成的完整數據集或者輸入觀察數據是流的形式。這樣,就要求LDA的特徵提取有能力隨着觀察新樣本的增加而更新LDA的特徵,而不是在整個數據集上運行算法。例如,在移動機器人或實時臉部識別等實時應用中,提取的LDA特徵能隨着新觀察值實時更新是非常重要的。這種能夠通過簡單觀察新樣本來更新LDA特徵的技術就叫做增量LDA算法,在過去二十年裏,它已經被廣泛的研究過。Catterjee和Roychowdhury提出了一種增量自組織LDA算法來更新LDA特徵。另外,Demir和Ozmehmet提出利用誤差改正和赫布學習規則的線上本地學習算法來更新LDA特徵。最後,Aliyari等人提供了快速增量LDA算法。

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  # 第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

        # 顯示信息
        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()


運行結果:

測試樣本數量: 200
預測正確樣本的數量: 196
測試準確度: 0.98

在這裏插入圖片描述

3、月亮數據集的線性判別分析

#月亮數據集的線性LDA分析
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()

運行結果:

測試樣本數量: 60
預測正確樣本的數量: 52
測試準確度: 0.8666666522222225

在這裏插入圖片描述

二、K-means

1、K-means介紹

k均值聚類算法(k-means clustering algorithm)是一種迭代求解的聚類分析算法,其步驟是,預將數據分爲K組,則隨機選取K個對象作爲初始的聚類中心,然後計算每個對象與各個種子聚類中心之間的距離,把每個對象分配給距離它最近的聚類中心。聚類中心以及分配給它們的對象就代表一個聚類。每分配一個樣本,聚類的聚類中心會根據聚類中現有的對象被重新計算。這個過程將不斷重複直到滿足某個終止條件。終止條件可以是沒有(或最小數目)對象被重新分配給不同的聚類,沒有(或最小數目)聚類中心再發生變化,誤差平方和局部最小。

聚類是一個將數據集中在某些方面相似的數據成員進行分類組織的過程,聚類就是一種發現這種內在結構的技術,聚類技術經常被稱爲無監督學習。
k均值聚類是最著名的劃分聚類算法,由於簡潔和效率使得他成爲所有聚類算法中最廣泛使用的。給定一個數據點集合和需要的聚類數目k,k由用戶指定,k均值算法根據某個距離函數反覆把數據分入k個聚類中。

算法:
先隨機選取K個對象作爲初始的聚類中心。然後計算每個對象與各個種子聚類中心之間的距離,把每個對象分配給距離它最近的聚類中心。聚類中心以及分配給它們的對象就代表一個聚類。一旦全部對象都被分配了,每個聚類的聚類中心會根據聚類中現有的對象被重新計算。這個過程將不斷重複直到滿足某個終止條件。終止條件可以是以下任何一個:
1)沒有(或最小數目)對象被重新分配給不同的聚類。
2)沒有(或最小數目)聚類中心再發生變化。
3)誤差平方和局部最小。

2、鳶尾花數據集的K-means聚類分析

#鳶尾花數據集的K-means分類
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聚類分析

#月亮數據集的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、介紹

支持向量機(Support Vector Machine, SVM)是一類按監督學習(supervised learning)方式對數據進行二元分類的廣義線性分類器(generalized linear classifier),其決策邊界是對學習樣本求解的最大邊距超平面(maximum-margin hyperplane) 。
SVM使用鉸鏈損失函數(hinge loss)計算經驗風險(empirical risk)並在求解系統中加入了正則化項以優化結構風險(structural risk),是一個具有稀疏性和穩健性的分類器 。SVM可以通過核方法(kernel method)進行非線性分類,是常見的核學習(kernel learning)方法之一 。
SVM被提出於1964年,在二十世紀90年代後得到快速發展並衍生出一系列改進和擴展算法,在人像識別、文本分類等模式識別(pattern recognition)問題中有得到應用 。

SVM是由模式識別中廣義肖像算法(generalized portrait algorithm)發展而來的分類器 ,其早期工作來自前蘇聯學者Vladimir N. Vapnik和Alexander Y. Lerner在1963年發表的研究 。1964年,Vapnik和Alexey Y. Chervonenkis對廣義肖像算法進行了進一步討論並建立了硬邊距的線性SVM 。此後在二十世紀70-80年代,隨着模式識別中最大邊距決策邊界的理論研究 、基於鬆弛變量(slack variable)的規劃問題求解技術的出現 ,和VC維(Vapnik-Chervonenkis dimension, VC dimension)的提出 ,SVM被逐步理論化併成爲統計學習理論的一部分 。1992年,Bernhard E. Boser、Isabelle M. Guyon和Vapnik通過核方法得到了非線性SVM 。1995年,Corinna Cortes和Vapnik提出了軟邊距的非線性SVM並將其應用於手寫字符識別問題 ,這份研究在發表後得到了關注和引用,爲SVM在各領域的應用提供了參考。

在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

2、鳶尾花數據集的SVM分析

#鳶尾花數據集的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分析

#月亮數據集的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])
plt.show()

在這裏插入圖片描述

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、優點

①SVM算法既可以解決線性問題,又可以解決非線性問題。
②非線性映射是SVM方法的理論基礎,SVM利用內積核函數代替向高維空間的非線性映射。
③對特徵空間劃分的最優超平面是SVM的目標,最大化分類邊際的思想是SVM方法的核心。
④支持向量是SVM的訓練結果,在SVM分類決策中起決定作用的是支持向量。
SVM理論提供了一種避開高維空間的複雜性,直接用此空間的內積函數(既是核函數),再利用在線性可分的情況下的求解方法直接求解對應的高維空間的決策問題.當核函數已知,可以簡化高維空間問題的求解難度.同時SVM是基於小樣本統計理論的基礎上的,這符合機器學習的目的.而且支持向量機比神經網絡具有較好的泛化推廣能力.

2、缺點

①對參數調節和核函數的選擇敏感。
②不易處理多分類問題。
③對大規模訓練樣本難以實施。
④SVM的可解釋性較差,無法給出決策樹那樣的規則。
對於每個高維空間在此空間的映射F,如何確定F也就是核函數,現在還沒有合適的方法,所以對於一般的問題,SVM只是把高維空間的複雜性的困難轉爲了求核函數的困難.而且即使確定核函數以後,在求解問題分類時,要求解函數的二次規劃,這就需要大量的存儲空間.這也是SVM的一個問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章