白板推导系列Pytorch-线性判别分析(LDA)

白板推导系列Pytorch-线性判别分析(LDA)

导入所需的包

import torch
from sklearn.linear_model import Perceptron
import torch.nn.functional as F
import matplotlib.pyplot as plt

生成数据集

def create_dataset(n_samples=1000):
    x0 = torch.normal(2,1,size=(n_samples//2,2),dtype=torch.float32)
    y0 = torch.zeros(n_samples//2,dtype=torch.float32)
    x1 = torch.normal(-2,1,size=(n_samples-n_samples//2,2),dtype=torch.float32)
    y1 = torch.ones(n_samples-n_samples//2,dtype=torch.float32)

    #合并数据x,y
    x=torch.cat((x0,x1),0)
    y=torch.cat((y0,y1),0)
    return x,y

X,y = create_dataset(1000)
plt.scatter(X[:,0],X[:,1],c=y)

在这里插入图片描述

准备一个可视化w直线的函数

def plot_line(X,y,w):
    plt.scatter(X[:, 0], X[:, 1], c=y)
    x = torch.tensor([-4,4],dtype=torch.float32)
    y = w[1] / w[0] * x
    plt.plot(x, y, color='red')
    plt.show()

定义LDA类

class LDA:
    def __init__(self):
        pass
    def fit(self,X,y):
        # 分离样本
        X = X.numpy()
        X1 = torch.tensor([X[i] for i in range(len(X)) if y[i] == 0],dtype=torch.float32)
        X2 = torch.tensor([X[i] for i in range(len(X)) if y[i] == 1],dtype=torch.float32)

        # 分别求均值
        mju1 = torch.mean(X1, dim=0)#求中心点
        mju2 = torch.mean(X2, dim=0)

        # 分别求协方差
        cov1 = torch.zeros(size=(len(mju1),len(mju1)),dtype=torch.float32)
        cov2 = torch.zeros(size=(len(mju2),len(mju2)),dtype=torch.float32)

        # 注意,下面的view一定要加上,否则会出问题
        for i in range(len(X1)):
            cov1 += torch.matmul((X1[i]-mju1).view(len(mju1),-1),(X1[i]-mju1).T.view(-1,len(mju1)))
        for i in range(len(X2)):
            cov2 += torch.matmul((X2[i]-mju2).view(len(mju2),-1),(X2[i]-mju2).T.view(-1,len(mju2)))

        # 求和得到Sw
        Sw = cov1/len(X1) + cov2/len(X2)

        # Sw的逆乘以均值差,注意同样要加view,把向量转换成矩阵。为了应对Sw不可逆的情况,采用伪逆
        w = torch.matmul(torch.pinverse(Sw), (mju1 - mju2).view(len(mju1),-1))  # 计算w

        # w单位化
        w = F.normalize(w,p=2,dim=0)
        
    def transform(self,X):
        X = torch.tensor(X,dtype=torch.float32)
        X = torch.matmul(X,self.w)
        return X

降维,计算原数据的投影

lda = LDA()
# 计算w
lda.fit(X,y)
# 计算投影
X_new = lda.transform(X)

投影前

plot_line(X,y,lda.w)

在这里插入图片描述

投影后(y随机生成)

plt.scatter(X_new[:, 0], torch.randn(size=(X_new.shape[0],)),marker='o',c=y)
plt.show()

在这里插入图片描述

利用sklearn进行LDA降维

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
lda = LinearDiscriminantAnalysis(n_components=1)
lda.fit(X,y)
X_new = lda.transform(X)
plt.scatter(X_new[:, 0], torch.randn(size=(X_new.shape[0],)),marker='o',c=y)
plt.show()

在这里插入图片描述

使用sklearn的lda生成的投影跟自己实现的lda投影正好相反,但不影响分类

利用skearn进行感知机分类

# fit_intercept表示是否需要截距
clf = Perceptron(fit_intercept=True,n_iter_no_change=100,shuffle=False)
# 训练
clf.fit(X_new[:800],y[:800])
# 评估
clf.score(X_new[800:],y[800:])

猜你喜欢

转载自blog.csdn.net/qq_41335232/article/details/120929984