感知机
概念
感知机(Perceptron
)在1957年由Rosenblatt
提出,是神经网络
和支持向量机
的基础。
感知机是一种二类分类的线性分类模型,其输入为实例的特征向量,输出为实例的类别,+1
代表正类,-1
代表负类。感知机属于判别模型,它的目标是要将输入实例通过分离超平面将正负二类分离。
原理
对于分类任务,线性回归模型就无能为力了,但是可以在线性模型的函数进行后再加入一层激活函数,这个函数是非线性的,激活函数的反函数叫做链接函数。有两种线性分类的方式:
硬分类,直接需要输出观测对应的分类。这类模型的代表为:
线性判别分析(Fisher 判别)(Filsher Discriminant Analysis)
软分类,产生不同类别的概率,这类算法根据概率方法的不同分为两种
生成式(根据贝叶斯定理先计算参数后验,再进行推断)(概率生成模型):高斯判别分析(GDA)
和朴素贝叶斯等为代表
判别式(直接对条件概率进行建模)(概率判别模型):逻辑回归(Logistic Regression)
模型:
有:
\begin{align} sign(a)&= \left\{ \begin{array}{**lr**} +1, & a\ge0\\ -1, & a<0\\ \end{array} \right. \\ \end{align}
其中$w_0$就是b
这样可以将线性回归的结果映射到两分类的结果上。
定义损失函数为错误分类的数目,比较直观的方式是使用指示函数,但是指示函数不可导,因此可以定义:
但是如果样本非常多的情况下,计算复杂度较高,但是,实际上并不需要绝对的损失函数下降的方向,只需要损失函数的期望值下降,但是计算期望需要知道真实的概率分布,实际只能根据训练数据抽样来估算这个概率分布(经验风险):
\mathbb{E}_{\mathcal D}[\mathbb{E}_\hat{p}[\nabla_wL(w)]]=\mathbb{E}_{\mathcal D}[\frac{1}{N}\sum\limits_{i=1}^N\nabla_wL(w)]
是可以收敛的,同时使用单个观测更新也可以在一定程度上增加不确定度,从而减轻陷入局部最小的可能。在更大规模的数据上,常用的是小批量随机梯度下降法。
创建数据
复制 #%%
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
# 伪造数据
"""
* n_samples:样本数量
* n_features:维度,特征数=n_informative() + n_redundant + n_repeated
* n_classes:划分几类
* data:为
"""
data,target=make_classification(n_samples=200, n_features=2,n_classes=2,n_informative=1,n_redundant=0,n_repeated=0,n_clusters_per_class=1)
绘图
复制 """
* c:指定目标值,根据目标值,进行划分类
* n_features:维度
* n_classes:划分几类
"""
plt.scatter(data[:, 0], data[:, 1], c=target,s=50)
训练
复制 lambda_ = 0.1 # lambda值
epochs = 10 # 步长
n_samples, n_features = data.shape # 样本数量,维度
Y = target.reshape(-1,1) # 转换为二维矩阵nx1
Y[Y == 0] = -1
X= np.c_[data, np.ones(shape=(n_samples,))] # 添加常量 x0=1
w = np.random.random(size=(n_features+1,1)) # 维度+1
XY = np.c_[X,Y] # (x_i,y_i)
复制 for _ in range(epochs):
np.random.shuffle(XY)
for i in range(n_samples):
x_i = XY[i,:-1]
y_i = XY[i,-1:]
if (x_i.dot(w)*y_i)[0] < 0:
nw = (x_i * y_i).reshape(-1,1)
w = w + lambda_ * nw
复制 w1 = w[0,0]
w2 = w[1,0]
bias = w[2,0]
w1,w2,bias
#%%
x = np.arange(np.min(X), np.max(X), 0.1)
y = -w1 / w2 * x - bias / w2
复制 x = np.arange(np.min(X), np.max(X), 0.1)
y = -w1 / w2 * x - bias / w2
plt.scatter(X[:,0], X[:,1], c=target, s=50)
plt.plot(x, y, 'r')
plt.show()
sklearn 实现
复制 from sklearn.linear_model import Perceptron
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
X,Y = make_classification(n_samples=200, n_features=2,n_classes=2,n_informative=1,n_redundant=0,n_repeated=0,n_clusters_per_class=1)
per = Perceptron()
per.fit(X,Y)
# 绘制散点
plt.scatter(X[:,0], X[:,1], c=Y, s=50)
w = per.coef_ # 权重矩阵
b = per.intercept_ #超平面的截距
x = np.arange(np.min(X), np.max(X), 0.1)
y = x * (-w[0][0] / w[0][1]) - b
plt.plot(x,y)
线性判别分析-LDA(隐含狄利克雷分布)
原理
假设,
在 LDA 中,基本想法是选定一个方向,将试验样本顺着这个方向投影,投影后的数据需要满足两个条件,从而可以更好地分类:
投影后类内方差最小,类间方差最大
方差为:
注意协方差矩阵不是点乘...
所以类内距离可以记为:
对于第二点,可以用两类的均值表示这个距离:
综合这两点,由于协方差是一个矩阵,于是将这两个值相除来得到损失函数 ,并最大化这个值:
Fisher线性判别函数
此时,两个群的投影中心间的中点为:
此时,Filsher线性判别函数为:
h(x) = S_w^{-1}(\overline{x_{c1}}-\overline{x_{c2}})x-c\left\{ \begin{array}{**lr**} \ge0,x\in C1\\ <0,x\in C2\\ \end{array} \right. \\
创建数据
复制 import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets.samples_generator import make_classification
#%%
n_samples = 100
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)
"""
X:2维
"""
绘图
复制 # 原始数据
plt.scatter(X[:, 0], X[:, 1], marker='o', c=y)
plt.plot()
plt.xlabel("x1")
plt.ylabel("x2")
plt.show()
实现
复制 # 类别
labels = np.unique(y)
Sw = 0
for label in labels:
x = np.array([X[i] for i in range(len(X)) if y[i] == label])
mu = np.mean(x,axis=0)
cov = np.dot((x-mu).T,x-mu)
Sw += cov # Sw:pxp
mus = np.mean(X[y==0],axis=0) - np.mean(X[y==1],axis=0)
mua = np.mean(X[y==0],axis=0) + np.mean(X[y==1],axis=0)
w = np.dot(np.linalg.pinv(Sw),mus.reshape(-1,1))
复制 y_new = X.dot(w)
n_samples = X.shape[0]
# 两个投影中心间的中心
c = 1/2*np.dot(np.dot(mus.reshape(1,-1),np.linalg.pinv(Sw)),mua.reshape(-1,1))
# 线性判别
h = y_new - c
y1 = []
for i in range(n_samples):
if h[i] >= 0: # 属于类别1
y1.append(0)
else: # 属于类型2
y1.append(1)
count = 0
for a,b in zip(y1,y): # 与原类别进行比较
if a == b:
count += 1
accuracy = count / n_samples
print("accuracy:", accuracy)
plt.scatter(X[:, 0], X[:, 1], marker='o', c=y1)
plt.xlabel("x1")
plt.ylabel("x2")
plt.show()
绘制决策边界
复制 x1 = np.arange(np.min(X), np.max(X), 0.1)
x2 = -w[0][0] * x1 - w[1][0]
复制 plt.scatter(X[:, 0], X[:, 1], c=y1, s=50)
plt.plot(x1, x2, 'r')
plt.show()
sklearn实现
复制 from sklearn.datasets.samples_generator import make_classification
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
n_samples = 100
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(n_components=2)
x_new = lda.fit_transform(X, y)
lda.score(X,y)
概率判别模型-Logistic 回归
原理
即,
sigmod \ function:Sigmod(z) = \frac{1}{1+e^{-z}}, \left\{ \begin{array}{**lr**} 当z\rightarrow \infty , Sigmod(z) = 1 \\ 当z\rightarrow 0 , Sigmod(z) = \frac{1}{2} \\ 当z\rightarrow -\infty ,Sigmod(z) = 0 \\ \end{array} \right. \\
上面的式子叫 Logistic Sigmoid
函数,其参数表示了两类联合概率比值的对数。在判别式中,不关心这个参数的具体值,模型假设直接对 $a$ 进行。
复制 import numpy as np
import matplotlib.pyplot as plt
def Sigmod(x):
return 1/(1+np.exp(-x))
x = np.arange(-10,10,0.1)
y = Sigmod(x)
plt.plot(x,y)
Logistic
回归的模型假设是:
有,
于是,综合表达:
对这个函数求导数,注意到:
则:
由于概率值的非线性,放在求和符号中时,这个式子无法直接求解。于是在实际训练的时候,和感知机类似,也可以使用不同大小的批量随机梯度上升(对于最小化就是梯度下降)来获得这个函数的极大值。
创建数据
复制 import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
X,y=make_classification(n_samples=100, n_features=2,n_classes=2,n_informative=1,n_redundant=0,n_repeated=0,n_clusters_per_class=1)
X = np.c_[X,np.ones(100)]
n_samples,n_features = X.shape
w = np.zeros((n_features,1))
Y = y.reshape(-1,1)
实现
复制 def calc_w(x,y,w,epochs=10000,eta=0.0001,batch_size=16):
n_samples,n_features = x.shape
xy = np.c_[x,y]
for _ in range(epochs):
np.random.shuffle(xy)
for i in range(n_samples):
batch_xy = xy[batch_size * i:batch_size * (i + 1)]
x = batch_xy[:,:-1]
y = batch_xy[:,-1:]
p1 = Sigmod(x.dot(w))
w = w - (eta* (y-p1).T.dot(x)/ batch_size).T
return w
xy = np.c_[X,y]
w = calc_w(X,y,w)
绘制决策边界
复制 w1 = w[0][0]
w2 = w[1][0]
bias = w[2][0]
x1 = np.arange(np.min(X), np.max(X), 0.1)
x2 = -w1 / w2 * x1 - bias / w2
复制 plt.scatter(X[:, 0], X[:, 1], c=y,s=50)
plt.plot(x1, x2, 'r')
plt.show()
sklearn实现
复制 #%%
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
X,y=make_classification(n_samples=100, n_features=2,n_classes=2,n_informative=1,n_redundant=0,n_repeated=0,n_clusters_per_class=1)
lr = LogisticRegression()
lr.fit(X,y)
w1=lr.coef_[0][0]
w2=lr.coef_[0][1]
bias=lr.intercept_[0]
x1=np.arange(np.min(X),np.max(X),0.1)
x2=-w1/w2*x1-bias/w2
plt.scatter(X[:, 0], X[:, 1], c=y,s=50)
plt.plot(x1, x2, 'r')
plt.show()
#%%
#计算准确度
lr.score(X,y)
概率生成模型-高斯判别分析 GDA
模型定义
于是,生成模型为:
其中,
y\sim Bernoulli(\phi) => \left\{ \begin{array}{**lr**} \phi^y,y=1\\ (1-\phi)^{1-y},y=0\\ \end{array} \right.\\ =>p(y)=\phi^y \cdot (1-\phi)^{1-y}(伯努利)
那么e独立全同的数据集最大后验概率(MAP)可以表示为:
由上可知,
有,
模型求解
有,
求期望
有,
由于:
求协方差
因此综上,可得:
这里应用了类协方差矩阵的对称性。
于是就利用最大后验的方法求得了模型假设里面的所有参数,根据模型,可以得到联合分布,也就可以得到用于推断的条件分布了。
分类结果
求出结果后,那么分类结果为:
\begin{align} y|x&= \left\{ \begin{array}{**lr**} 1, & p(y=1|x)\ge p(y=0|x)\\ 0, & other\\ \end{array} \right. \\ \end{align}
创建数据
复制 import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
X,y=make_classification(n_samples=100, n_features=2,n_classes=2,n_informative=1,n_redundant=0,n_repeated=0,n_clusters_per_class=1)
实现
复制 def gda(x,y):
n_samples,n_features = x.shape
n1 = y[y==1].shape[0]
n2 = y[y==0].shape[0]
phi = n1 / n_samples
mu1 = np.sum([xi*yi for xi,yi in zip(x,y)])/n1
mu2 = np.sum([xi*(1-yi) for xi,yi in zip(x,y)])/n2
x1 = x[y==1]
x0 = x[y==0]
sigma = (n1*np.dot(x0.T,x0) + n2*np.dot(x1.T,x1)) / n_samples
return phi,mu1,mu2,sigma
phi,mu1,mu2,sigma = gda(X,y)
复制 def Gaussian(x, mean, cov):
"""
这是自定义的高斯分布概率密度函数
:param x: 输入数据
:param mean: 均值向量
:param cov: 协方差矩阵
:return: x的概率
"""
dim = np.shape(cov)[0]
# cov的行列式为零时的措施
covdet = np.linalg.det(cov + np.eye(dim) * 0.001)
covinv = np.linalg.inv(cov + np.eye(dim) * 0.001)
xdiff = (x - mean).reshape((1, dim))
# 概率密度
p = 1.0 / (np.power(np.power(2 * np.pi, dim) * np.abs(covdet), 0.5)) * \
np.exp(-0.5 * xdiff.dot(covinv).dot(xdiff.T))[0][0]
return p
复制 def predict(x,mu1,mu2,sigma):
y = []
for xi in x:
if Gaussian(xi, mu1, sigma) >= Gaussian(xi, mu2, sigma):
y.append(1)
else:
y.append(0)
return y
绘图
概率生成模型-朴素贝叶斯
思想:朴素贝叶斯假设(条件独立性假设),又是最简单的概率图(有向图)模型。
动机:为了简化运算。
朴素贝叶斯队数据的属性之间的关系作出了假设,一般地,有需要得到 $p(x|y)$ 这个概率值,由于 $x$ 有 $p$ 个维度,因此需要对这么多的维度的联合概率进行采样,但是知道这么高维度的空间中采样需要的样本数量非常大才能获得较为准确的概率近似。
在一般的有向概率图模型中,对各个属性维度之间的条件独立关系作出了不同的假设,其中最为简单的一个假设就是在朴素贝叶斯模型描述中的条件独立性假设。
即:
于是利用贝叶斯定理,对于单次观测:
对于单个维度的条件概率以及类先验作出进一步的假设:
采用MLE(似然)进行参数估计