白板推导系列Pytorch-高斯判别分析(GDA)
不同于感知机和逻辑回归中由于得到的参数方程无法直接求解而只能采用随机梯度下降或上升的方式来求极值,LDA和GDA都可以直接求得参数,因而不需要通过逐步训练
导入需要的包
import torch
import matplotlib.pyplot as plt
import numpy as np
生成数据集
def create_dataset(n_samples=1000):
n_data = torch.ones(n_samples//2, 2)
x0 = torch.normal(2 * n_data, 1) # 生成均值为2.标准差为1的随机数组成的矩阵 shape=(100, 2)
y0 = torch.zeros(n_samples//2)
x1 = torch.normal(-2 * n_data, 1) # 生成均值为-2.标准差为1的随机数组成的矩阵 shape=(100, 2)
y1 = torch.ones(n_samples//2)
#合并数据x,y
x=torch.cat((x0,x1),0).type(torch.FloatTensor)
y=torch.cat((y0,y1),0).type(torch.FloatTensor)
return x,y
定义高斯函数
def Gauss(x,miu,sigma):
x_diff = (x-miu).view(sigma.shape[0],-1)
sigma_inv = torch.inverse(sigma+torch.eye(sigma.shape[0])*0.001)
sigma_det = torch.det(sigma+torch.eye(sigma.shape[0])*0.001)
a = 1/(np.power(2*np.pi,sigma.shape[0]/2)*np.sqrt(sigma_det))
return a*torch.exp(-0.5*torch.chain_matmul(x_diff.T,sigma_inv,x_diff))
定义模型
class GDA:
def __init__(self) -> None:
pass
def fit(self,X_data,y_data):
# 我们需要在fit函数中利用数据求得四个参数
# 首先,求 fi
self.fi = y_data.sum()/len(y_data)
# 其次,求u0,u1
self.u1 = torch.zeros(size=(X_data.shape[1],),dtype=torch.float)
self.u0 = torch.zeros(size=(X_data.shape[1],),dtype=torch.float)
for i in range(X_data.shape[0]):
self.u1 += X_data[i]*y_data[i]
self.u0 += X_data[i]*(1-y_data[i])
self.u1 = self.u1/y_data.sum()
self.u0 = self.u0/(len(y_data)-y_data.sum())
# 再次,求Sigma,但在求Sigma之前需要先求得正负样本的协方差
self.s1 = torch.zeros(size=(X_data.shape[1],X_data.shape[1]),dtype=torch.float)
self.s0 = torch.zeros(size=(X_data.shape[1],X_data.shape[1]),dtype=torch.float)
for i in range(X_data.shape[0]):
x1_diff = (X_data[i]-self.u1).view(self.u1.shape[0],-1)
x0_diff = (X_data[i]-self.u0).view(self.u0.shape[0],-1)
self.s1 += y[i]*torch.matmul(x1_diff,x1_diff.T)
self.s0 += (1-y[i])*torch.matmul(x0_diff,x0_diff.T)
# 注意,前面求得的s1,s0都已经乘上了各自的样本数,所以后面求sigma的时候直接相加即可
# 最后求得sigma
self.sigma = (self.s1+self.s0)/X_data.shape[0]
def predict(self,X_data):
pred = []
for x in X_data:
pred1 = Gauss(x,self.u1,self.sigma)*self.fi
pred0 = Gauss(x,self.u0,self.sigma)*(1-self.fi)
if pred1>pred0:
pred.append(1)
else:
pred.append(0)
return torch.tensor(pred,dtype=float)
def score(self,X_data,y_data):
y_pred = self.predict(X_data)
return (y_pred==y_data).sum()/len(y_data)
测试
X,y = create_dataset(1000)
plt.scatter(X[:,0],X[:,1],c=y)
gda = GDA()
gda.fit(X[:800],y[:800])
gda.score(X[800:],y[800:])