支持向量机
支持向量机(Support Vector Machines)是一种二分类模型,在机器学习、计算机视觉、数据挖掘中广泛应用,主要用于解决数据分类问题,它的目的是寻找一个超平面来对样本进行分割,分割的原则是间隔最大化(即数据集的边缘点到分界线的距离d最大,如下图),最终转化为一个凸二次规划问题来求解。通常SVM用于二元分类问题,对于多元分类可将其分解为多个二元分类问题,再进行分类。所谓“支持向量”,就是下图中虚线穿过的边缘点。支持向量机就对应着能将数据正确划分并且间隔最大的直线(下图中红色直线)
- 最优分类边界
如图中的A,B两个样本点,B点被预测为正类的确信度要大于A点,所以SVM的目标是寻找一个超平面,使得离超平面较近的异类点之间能有更大的间隔,即不必考虑所有样本点,只需让求得的超平面使得离它近的点间隔最大。超平面可以用如下线性方程来描述:
$$w^T x + b = 0$$
- 其中,\(x=(x_1;x_2;...;x_n)\),\(w=(w_1;w_2;...;w_n)\),\(b\)为偏置项. 可以从数学上证明,支持向量到超平面距离为:
$$\gamma = \frac{1}{||w||}$$
- 为了使距离最大,只需最小化\(||w||\)即可
SVM最优边界要求
SVM寻找最优边界时,需满足以下几个要求:
- 正确性:对大部分样本都可以正确划分类别;
- 安全性:支持向量,即离分类边界最近的样本之间的距离最远;
- 公平性:支持向量与分类边界的距离相等;
- 简单性:采用线性方程(直线、平面)表示分类边界,也称分割超平面。如果在原始维度中无法做线性划分,那么就通过升维变换,在更高维度空间寻求线性分割超平面. 从低纬度空间到高纬度空间的变换通过核函数进行。
线性可分与线性不可分
线性可分
- 如果一组样本能使用一个线性函数将样本正确分类,称这些数据样本是线性可分的。那么什么是线性函数呢?在二维空间中就是一条直线,在三维空间中就是一个平面,以此类推,如果不考虑空间维数,这样的线性函数统称为超平面。
如果一组样本,无法找到一个线性函数将样本正确分类,则称这些样本线性不可分。以下是一个一维线性不可分的示例:
以下是一个二维不可分的示例:
对于该类线性不可分问题,可以通过升维,将低纬度特征空间映射为高纬度特征空间,实现线性可分,如下图所示:
- 一维空间升至二维空间实现线性可分
- 二维空间升至三维空间实现线性可分,需要用到核函数
核函数
通过名为核函数的特征变换,增加新的特征,使得低维度线性不可分问题变为高维度线性可分问题。如果低维空间存在K(x,y),x,y∈Χ,使得K(x,y)=ϕ(x)·ϕ(y),则称K(x,y)为核函数,其中ϕ(x)·ϕ(y)为x,y映射到特征空间上的内积,ϕ(x)为X→H的映射函数。以下是几种常用的核函数
线性核函数
- 线性核函数(Linear)表示不通过核函数进行升维,仅在原始空间寻求线性分类边界,主要用于线性可分问题
- multiple2.txt
# 支持向量机示例
import numpy as np
import sklearn.model_selection as ms
import sklearn.svm as svm
import sklearn.metrics as sm
import matplotlib.pyplot as mp
x, y = [], []
with open("multiple2.txt", "r") as f:
for line in f.readlines():
data = [float(substr) for substr in line.split(",")]
x.append(data[:-1]) # 输入
y.append(data[-1]) # 输出
# 列表转数组
x = np.array(x)
y = np.array(y, dtype=int)
model = svm.SVC(kernel="linear") # 线性核函数
model.fit(x, y)
# 计算图形边界
l, r, h = x[:, 0].min() - 1, x[:, 0].max() + 1, 0.005
b, t, v = x[:, 1].min() - 1, x[:, 1].max() + 1, 0.005
# 生成网格矩阵
grid_x = np.meshgrid(np.arange(l, r, h), np.arange(b, t, v))
flat_x = np.c_[grid_x[0].ravel(), grid_x[1].ravel()] # 合并
flat_y = model.predict(flat_x) # 根据网格矩阵预测分类
grid_y = flat_y.reshape(grid_x[0].shape) # 还原形状
mp.figure("SVM Classifier", facecolor="lightgray")
mp.title("SVM Classifier", fontsize=14)
mp.xlabel("x", fontsize=14)
mp.ylabel("y", fontsize=14)
mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x[0], grid_x[1], grid_y, cmap="gray")
C0, C1 = (y == 0), (y == 1)
mp.scatter(x[C0][:, 0], x[C0][:, 1], c="orangered", s=80)
mp.scatter(x[C1][:, 0], x[C1][:, 1], c="limegreen", s=80)
mp.show()
练习代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import sklearn.model_selection as ms
import sklearn.svm as svm
import sklearn.metrics as sm
data = pd.read_csv('multiple2.txt',
header=None,
names=['x1','x2','y'])
data.plot.scatter(x='x1',y='x2',c='y',cmap='brg')
# plt.show()
#整理输入集和输出集
x = data.iloc[:,:-1]
y = data.iloc[:,-1]
train_x,\
test_x,\
train_y,\
test_y = ms.train_test_split(x,y,
test_size=0.1,
random_state=7)
model = svm.SVC(kernel='linear')
model.fit(train_x,train_y)
pred_test_y = model.predict(test_x)
print(sm.classification_report(test_y,pred_test_y))
#暴力绘制分类边界线
# 1.将x1的最小值,x1的最大值,拆成200个点
# 2.将x2的最小值,x2的最大值,拆成200个点
# 3.组合x1和x2的所有的点 4W个
# 4.将4w个点带入模型进行预测,得到预测类别
# 5.根据预测类别设置不同颜色
x1 = np.linspace(x['x1'].min(),x['x1'].max(),200)
x2 = np.linspace(x['x2'].min(),x['x2'].max(),200)
x = []
for i in x1:
for j in x2:
x.append([i,j])
x = np.array(x)
y = model.predict(x)
# data.plot.scatter(x=x[:,0],y=x[:,1],c=y,cmap='gray')
plt.scatter(x=x[:,0],y=x[:,1],c=y,cmap='gray')
plt.scatter(x=data['x1'],y=data['x2'],c=data['y'],cmap='brg')
plt.show()
输出结果
多项式核函数
多项式核函数(Polynomial Kernel)用增加高次项特征的方法做升维变换,当多项式阶数高时复杂度会很高,其表达式为:
$$K(x,y)=(α*(x^T*y)+c)^d$$
$$y = x_1 + x_2$$
$$y = x_1^2 + 2x_1x_2+x_2^2$$
$$y=x_1^3 + 3x_1^2x_2 + 3x_1x_2^2 + x_2^3$$
- 参数α用于缩放内积的结果,可以控制相似度的权重。
- 参数c是偏置项,用于调整映射后的特征空间的原点位置。
- 参数d是多项式核函数的次数,它定义了映射后特征空间中的多项式的阶数。
- multiple2.txt
# 支持向量机示例
import numpy as np
import sklearn.model_selection as ms
import sklearn.svm as svm
import sklearn.metrics as sm
import matplotlib.pyplot as mp
x, y = [], []
with open("multiple2.txt", "r") as f:
for line in f.readlines():
data = [float(substr) for substr in line.split(",")]
x.append(data[:-1]) # 输入
y.append(data[-1]) # 输出
# 列表转数组
x = np.array(x)
y = np.array(y, dtype=int)
# 线性核函数支持向量机分类器
model = svm.SVC(kernel="poly", degree=3) # 多项式核函数
# print("gamma:", model.gamma)
model.fit(x, y)
# 计算图形边界
l, r, h = x[:, 0].min() - 1, x[:, 0].max() + 1, 0.005
b, t, v = x[:, 1].min() - 1, x[:, 1].max() + 1, 0.005
# 生成网格矩阵
grid_x = np.meshgrid(np.arange(l, r, h), np.arange(b, t, v))
flat_x = np.c_[grid_x[0].ravel(), grid_x[1].ravel()] # 合并
flat_y = model.predict(flat_x) # 根据网格矩阵预测分类
grid_y = flat_y.reshape(grid_x[0].shape) # 还原形状
mp.figure("SVM Classifier", facecolor="lightgray")
mp.title("SVM Classifier", fontsize=14)
mp.xlabel("x", fontsize=14)
mp.ylabel("y", fontsize=14)
mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x[0], grid_x[1], grid_y, cmap="gray")
C0, C1 = (y == 0), (y == 1)
mp.scatter(x[C0][:, 0], x[C0][:, 1], c="orangered", s=80)
mp.scatter(x[C1][:, 0], x[C1][:, 1], c="limegreen", s=80)
mp.show()
练习代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import sklearn.model_selection as ms
import sklearn.svm as svm
import sklearn.metrics as sm
data = pd.read_csv('multiple2.txt',
header=None,
names=['x1','x2','y'])
data.plot.scatter(x='x1',y='x2',c='y',cmap='brg')
# plt.show()
#整理输入集和输出集
x = data.iloc[:,:-1]
y = data.iloc[:,-1]
train_x,\
test_x,\
train_y,\
test_y = ms.train_test_split(x,y,
test_size=0.1,
random_state=7)
model = svm.SVC(kernel='poly',degree=2)
model.fit(train_x,train_y)
pred_test_y = model.predict(test_x)
print(sm.classification_report(test_y,pred_test_y))
#暴力绘制分类边界线
# 1.将x1的最小值,x1的最大值,拆成200个点
# 2.将x2的最小值,x2的最大值,拆成200个点
# 3.组合x1和x2的所有的点 4W个
# 4.将4w个点带入模型进行预测,得到预测类别
# 5.根据预测类别设置不同颜色
x1 = np.linspace(x['x1'].min(),x['x1'].max(),200)
x2 = np.linspace(x['x2'].min(),x['x2'].max(),200)
x = []
for i in x1:
for j in x2:
x.append([i,j])
x = np.array(x)
y = model.predict(x)
# data.plot.scatter(x=x[:,0],y=x[:,1],c=y,cmap='gray')
plt.scatter(x=x[:,0],y=x[:,1],c=y,cmap='gray')
plt.scatter(x=data['x1'],y=data['x2'],c=data['y'],cmap='brg')
plt.show()
输出结果
径向基核函数
径向基核函数(Radial Basis Function Kernel)具有很强的灵活性,应用很广泛。与多项式核函数相比,它的参数少,因此大多数情况下,都有比较好的性能。在不确定用哪种核函数时,可优先验证高斯核函数。由于类似于高斯函数,所以也称其为高斯核函数。表达式如下:
$$K(x, y) = exp(-γ * ||x - y||^2)$$
- 其中,||x - y||表示欧氏距离,γ是径向基核函数的参数,控制了数据点对最终核函数值的影响程度。
- 在计算核函数值时,首先计算样本x和y之间的欧氏距离,然后将其乘以负的γ,再取指数,得到最终的核函数值。
- 径向基核函数在机器学习中常用于非线性分类和回归问题。它的作用是将样本映射到更高维的特征空间,通过衡量样本之间的相似度来进行分类或回归任务。通过调整γ的值,可以控制径向基核函数的平滑程度和决策边界的形状,从而适应不同类型的数据分布。
- multiple2.txt
# 支持向量机示例
import numpy as np
import sklearn.model_selection as ms
import sklearn.svm as svm
import sklearn.metrics as sm
import matplotlib.pyplot as mp
x, y = [], []
with open("multiple2.txt", "r") as f:
for line in f.readlines():
data = [float(substr) for substr in line.split(",")]
x.append(data[:-1]) # 输入
y.append(data[-1]) # 输出
# 列表转数组
x = np.array(x)
y = np.array(y, dtype=int)
# 径向基核函数支持向量机分类器
model = svm.SVC(kernel="rbf",
gamma=0.01, # 概率密度标准差
C=600) # 概率强度,该值越大对错误分类的容忍度越小,分类精度越高,但泛化能力越差;该值越小,对错误分类容忍度越大,但泛化能力强
model.fit(x, y)
# 计算图形边界
l, r, h = x[:, 0].min() - 1, x[:, 0].max() + 1, 0.005
b, t, v = x[:, 1].min() - 1, x[:, 1].max() + 1, 0.005
# 生成网格矩阵
grid_x = np.meshgrid(np.arange(l, r, h), np.arange(b, t, v))
flat_x = np.c_[grid_x[0].ravel(), grid_x[1].ravel()] # 合并
flat_y = model.predict(flat_x) # 根据网格矩阵预测分类
grid_y = flat_y.reshape(grid_x[0].shape) # 还原形状
mp.figure("SVM Classifier", facecolor="lightgray")
mp.title("SVM Classifier", fontsize=14)
mp.xlabel("x", fontsize=14)
mp.ylabel("y", fontsize=14)
mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x[0], grid_x[1], grid_y, cmap="gray")
C0, C1 = (y == 0), (y == 1)
mp.scatter(x[C0][:, 0], x[C0][:, 1], c="orangered", s=80)
mp.scatter(x[C1][:, 0], x[C1][:, 1], c="limegreen", s=80)
mp.show()
练习代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import sklearn.model_selection as ms
import sklearn.svm as svm
import sklearn.metrics as sm
data = pd.read_csv('multiple2.txt',
header=None,
names=['x1','x2','y'])
data.plot.scatter(x='x1',y='x2',c='y',cmap='brg')
# plt.show()
#整理输入集和输出集
x = data.iloc[:,:-1]
y = data.iloc[:,-1]
train_x,\
test_x,\
train_y,\
test_y = ms.train_test_split(x,y,
test_size=0.1,
random_state=7)
model = svm.SVC(kernel='rbf',gamma=0.1,C=10)
model.fit(train_x,train_y)
pred_test_y = model.predict(test_x)
print(sm.classification_report(test_y,pred_test_y))
#暴力绘制分类边界线
# 1.将x1的最小值,x1的最大值,拆成200个点
# 2.将x2的最小值,x2的最大值,拆成200个点
# 3.组合x1和x2的所有的点 4W个
# 4.将4w个点带入模型进行预测,得到预测类别
# 5.根据预测类别设置不同颜色
x1 = np.linspace(x['x1'].min(),x['x1'].max(),200)
x2 = np.linspace(x['x2'].min(),x['x2'].max(),200)
x = []
for i in x1:
for j in x2:
x.append([i,j])
x = np.array(x)
y = model.predict(x)
# data.plot.scatter(x=x[:,0],y=x[:,1],c=y,cmap='gray')
plt.scatter(x=x[:,0],y=x[:,1],c=y,cmap='gray')
plt.scatter(x=data['x1'],y=data['x2'],c=data['y'],cmap='brg')
plt.show()
输出结果
支持向量机总结
- 支持向量机是二分类模型
- 支持向量机通过寻找最优线性模型作为分类边界
- 边界要求:正确性、公平性、安全性、简单性
- 可以通过核函数将线性不可分转换为线性可分问题,核函数包括:线性核函数、多项式核函数、径向基核函数
- 支持向量机适合少量样本的分类
- 关于参数调优可以尝试网格搜索网格搜索
朴素贝叶斯
朴素贝叶斯是一组功能强大且易于训练的分类器,它使用贝叶斯定理来确定给定一组条件的结果的概率,“朴素”的含义是指所给定的条件都能独立存在和发生. 朴素贝叶斯是多用途分类器,能在很多不同的情景下找到它的应用,例如垃圾邮件过滤、自然语言处理等
概率
概率是反映随机事件出现的可能性大小. 随机事件是指在相同条件下,可能出现也可能不出现的事件. 例如:
- 我们可以将随机事件记为A或B,则P(A),P(B)表示事件A或B的概率
- 抛一枚硬币,可能正面朝上,可能反面朝上,这是随机事件. 正/反面朝上的可能性称为概率
- 掷骰子,掷出的点数为随机事件. 每个点数出现的可能性称为概率
- 一批商品包含良品、次品,随机抽取一件,抽得良品/次品为随机事件. 经过大量反复试验,抽得次品率越来越接近于某个常数,则该常数为概率
联合概率与条件概率
- 联合概率 : 联合概率表示多个事件同时发生的概率,记作\(P(A,B)\)或\(P(AB)\)或\(P(A \bigcap B)\).假设有事件A和事件B,那么它们的联合概率\(P(A \bigcap B)\)表示事件A和事件B同时发生的概率。这可以理解为两个事件的交集所占的比例。联合概率可以通过考察样本空间中同时满足事件A和事件B的样本点的概率来计算。
- 条件概率 : 条件概率表示在已知某一事件发生的条件下,另一个事件发生的概率,记作\(P(A|B)\).假设有事件A和事件B,条件概率P(A|B)表示在事件B发生的条件下,事件A发生的概率。它描述了对于已经发生的事件B,事件A发生的可能性。条件概率可以通过计算事件A和事件B的交集的概率除以事件B发生的概率来计算。
- 事件的独立性 : 事件A不影响事件B的发生,称这两个事件独立,记为:\(P(A \bigcap B)=P(A)*P(B)\)
- 可以理解为,给定或不给定B的条件下,A的概率都一样大
- 因为A和B不相互影响,则有:
$$P(A|B) = P(A)$$
先验概率与后验概率
- 先验概率 : 先验概率也是根据以往经验和分析得到的概率,例如:在没有任何信息前提的情况下,猜测对面来的陌生人姓氏,姓李的概率最大(因为全国李姓为占比最高的姓氏),这便是先验概率
- 后验概率 : 后验概率是指在接收了一定条件或信息的情况下的修正概率,例如:在知道对面的人来自“牛家村”的情况下,猜测他姓牛的概率最大,但不排除姓杨、李等等,这便是后验概率
- 两者的关系 : 事情还没有发生,求这件事情发生的可能性的大小,是先验概率(可以理解为由因求果). 事情已经发生,求这件事情发生的原因是由某个因素引起的可能性的大小,是后验概率(由果求因). 先验概率与后验概率有不可分割的联系,后验概率的计算要以先验概率为基础
先验概率与后验概率详细解释 - ChatGPT
- 于描述在观测到某些证据之前和观测到这些证据之后,关于某个事件发生的概率。
- 先验概率是指在观测到任何新的信息或证据之前,我们对事件发生概率的初始估计。它是基于以往的经验、领域知识或先前的观察而得出的概率。先验概率通常表示为 P(A),其中 A 表示某个事件。
- 后验概率是在观测到特定证据或信息之后,基于这些证据对事件发生概率进行更新后的概率。后验概率是通过贝叶斯定理计算得到的,它结合了先验概率和观测到的证据。后验概率通常表示为 P(A|B),其中 A 表示事件,B 表示观测到的证据。
贝叶斯定理
贝叶斯定理由英国数学家托马斯.贝叶斯(Thomas Bayes)提出,用来描述两个条件概率之间的关系,定理描述为:
$$P(A|B) = \frac{P(A)P(B|A)}{P(B)}$$
其中,\(P(A)\)和\(P(B)\)是A事件和B事件发生的概率. \(P(A|B)\)称为条件概率,表示B事件发生条件下,A事件发生的概率. 推导过程:
$$P(A,B) =P(B)P(A|B)$$
$$P(B,A) =P(A)P(B|A)$$
其中\(P(A,B)\)称为联合概率,指事件B发生的概率,乘以事件A在事件B发生的条件下发生的概率. 因为\(P(A,B)=P(B,A)\), 所以有:
$$P(B)P(A|B)=P(A)P(B|A)$$
两边同时除以\(P(B)\),则得到贝叶斯定理的表达式. 其中,\(P(A)\)是先验概率,\(P(A|B)\)是已知B发生后A的条件概率,也被称作后验概率
贝叶斯定理详细解释 - ChatGPT
贝叶斯定理表示为:
$$P(A|B) = (P(B|A) * P(A)) / P(B)$$
- 其中,P(A|B) 表示在观测到证据 B 的情况下事件 A 发生的概率,P(B|A) 表示在事件 A 发生的情况下观测到证据 B 的概率,P(A) 表示先验概率,P(B) 表示观测到证据 B 的概率。
- 通过贝叶斯定理,我们可以根据观测到的证据来更新我们对事件发生概率的估计,从而得到后验概率。先验概率和后验概率的关系可以帮助我们进行推断、决策和预测,特别在贝叶斯统计、机器学习和人工智能领域有广泛应用。
贝叶斯定理示例
计算诈骗短信的概率
事件 | 概率 | 表达式 |
---|---|---|
所有短信中,诈骗短信 | 5% | P(A) = 0.05 |
所有短信中,含有“中奖”两个字 | 4% | P(B) = 0.04 |
所有短信中,是诈骗短信,并且含有“中奖”两个字 | 50% | P(B|A) = 0.5 |
- 求:收到一条新信息,含有“中奖”两个字,是诈骗短信的概率?
$$P(A|B) = P(A) P(B|A) / P(B) = 0.05 * 0.5 / 0.04 = 0.625$$
计算喝酒驾车的概率
事件 | 概率 | 表达式 |
---|---|---|
所有客人中,驾车 | 20% | P(A)= 0.2 |
所有客人中,喝酒 | 10% | P(B)= 0.1 |
所有客人中,开车并且喝酒 | 5% | P(B|A)= 0.05 |
- 求:喝过酒仍然会开车的人的比例是多少?
$$P(A|B) = P(A) P(B|A) / P(B) = 0.2 * 0.05 / 0.1 = 0.1$$
假设一个学校中 60%的男生和40%的女生,女生穿裤子的人数和穿裙子的人数相等,所有的男生都穿裤子 一个人随机在远处眺望,看一个穿裤子的学生,请问这个学生是女生的概率
- p(女) = 0.4
- p(裤子|女) = 0.5
- p(裤子) = 0.8
- P(女|裤子) = 0.4 * 0.5 / 0.8 = 0.25
$$P(A|B) = \frac{P(A)P(B|A)}{P(B)}$$
朴素贝叶斯分类器
朴素贝叶斯分类器就是根据贝叶斯公式计算结果进行分类的模型,“朴素”指事件之间相互独立无影响. 例如:有如下数据集:
Text | Category |
---|---|
A great game(一个伟大的比赛) | Sports(体育运动) |
The election was over(选举结束) | Not sports(不是体育运动) |
Very clean match(没内幕的比赛) | Sports(体育运动) |
A clean but forgettable game(一场难以忘记的比赛) | Sports(体育运动) |
It was a close election(这是一场势均力敌的选举) | Not sports(不是体育运动) |
- 求:
A very close game
是体育运动的概率?数学上表示为\(P(Sports | a\ very\ close\ game)\). 根据贝叶斯定理,是运动的概率可以表示为:
$$P(Sports | a \ very \ close \ game)$$ $$= \frac{P(a \ very \ close \ game | sports) * P(sports)}{P(a \ very \ close \ game)}$$
- 不是运动概率可以表示为:
$$P(Not \ Sports | a \ very \ close \ game)$$ $$= \frac{P(a \ very \ close \ game | Not \ sports) * P(Not \ sports)}{P(a \ very \ close \ game)}$$
$$P(a \ very \ close \ game | sports) * P(sports)$$
$$P(a \ very \ close \ game | Not \ sports) * P(Not \ sports)$$
- 概率更大者即为分类结果. 由于分母相同,即比较分子谁更大即可. 我们只需统计
A very close game
多少次出现在Sports类别中,就可以计算出上述两个概率. 但是A very close game
并没有出现在数据集中,所以这个概率为0,要解决这个问题,就假设每个句子的单词出现都与其它单词无关(事件独立即朴素的含义),所以,\(P(a\ very\ close\ game)\)可以写成:
$$P(a \ very \ close \ game) $$ $$= P(a) * P(very) * P(close) * P(game)$$
$$P(a \ very \ close \ game|Sports)$$ $$= P(a|Sports)*P(very|Sports)*P(close|Sports)*P(game|Sports)$$
统计出
a
,ery
,close
,game
出现在Sports
类别中的概率,就能算出其所属的类别. 具体计算过程如下:
- 第一步:计算总词频:Sports类别词语总数14,Not Sports类别词语总数9
- 第二步:计算每个类别的先验概率,分子部分加1,是为了避免分子为0的情况;分母部分都加了词语总数14,是为了避免分子增大的情况下计算结果超过1的可能
# Sports和Not Sports概率
P(Sports) = 3 / 5 = 0.6
P(Not Sports) = 2 / 5 = 0.4
# Sports条件下各个词语概率
P(a | Sports) = (2 + 1) / (11 + 14) = 0.12
P(very | Sports) = (1 + 1) / (11 + 14) = 0.08
P(close | Sports) = (0 + 1) / (11 + 14) = 0.04
P(game | Sports) = (2 + 1) / (11 + 14) = 0.12
# Not Sports条件下各个词语概率
P(a | Not Sports) = (1 + 1) / (9 + 14) = 0.087
P(very | Not Sports) = (0 + 1) / (9 + 14) = 0.043
P(close | Not Sports) = (1 + 1) / (9 + 14) = = 0.087
P(game | Not Sports) = (0 + 1) / (9 + 14) = 0.043
- 第三步:将先验概率带入贝叶斯定理,计算概率:
- 是体育运动的概率:
$$P(a \ very \ close \ game|Sports)$$ $$= P(a|Sports)*P(very|Sports)*P(close|Sports)*P(game|Sports)$$ $$= 0.12 * 0.08 * 0.04 * 0.12 = 0.00004608$$
- 不是体育运动的概率:
$$P(a \ very \ close \ game|Not \ Sports)$$ $$= P(a|Not \ Sports)*P(very|Not \ Sports)*P(close|Not \ Sports)*P(game|Not \ Sports)$$ $$= 0.087 * 0.043 * 0.087 * 0.043 = 0.000013996$$
- 分类结果:P(Sports) = 0.00004608 , P(Not Sports) = 0.000013996, 是体育运动
实现朴素贝叶斯分类器
在sklearn中,提供了三个朴素贝叶斯分类器,分别是:
- GaussianNB(高斯朴素贝叶斯分类器):适合用于样本的值是连续的,数据呈正态分布的情况(比如人的身高、城市家庭收入、一次考试的成绩等等)
- MultinominalNB(多项式朴素贝叶斯分类器):适合用于大部分属性为离散值的数据集
- BernoulliNB(伯努利朴素贝叶斯分类器):适合用于特征值为二元离散值或是稀疏的多元离散值的数据集
该示例中,样本的值为连续值,且呈正态分布,所以采用GaussianNB模型. 代码如下:
# 朴素贝叶斯分类示例
import numpy as np
import sklearn.naive_bayes as nb
import matplotlib.pyplot as mp
# 输入,输出
x, y = [], []
# 读取数据文件
with open("multiple1.txt", "r") as f:
for line in f.readlines():
data = [float(substr) for substr in line.split(",")]
x.append(data[:-1]) # 输入样本:取从第一列到倒数第二列
y.append(data[-1]) # 输出样本:取最后一列
x = np.array(x)
y = np.array(y, dtype=int)
# 创建高斯朴素贝叶斯分类器对象
model = nb.GaussianNB()
model.fit(x, y) # 训练
# 计算显示范围
left = x[:, 0].min() - 1
right = x[:, 0].max() + 1
buttom = x[:, 1].min() - 1
top = x[:, 1].max() + 1
grid_x, grid_y = np.meshgrid(np.arange(left, right, 0.01),np.arange(buttom, top, 0.01))
mesh_x = np.column_stack((grid_x.ravel(), grid_y.ravel()))
mesh_z = model.predict(mesh_x)
mesh_z = mesh_z.reshape(grid_x.shape)
mp.figure('Naive Bayes Classification', facecolor='lightgray')
mp.title('Naive Bayes Classification', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x, grid_y, mesh_z, cmap='gray')
mp.scatter(x[:, 0], x[:, 1], c=y, cmap='brg', s=80)
mp.show()
输出结果
实验代码
import pandas as pd
import matplotlib.pyplot as plt
import sklearn.naive_bayes as nb
import sklearn.model_selection as ms
import sklearn.metrics as sm
import numpy as np
data = pd.read_csv('multiple1.txt',header=None,names=['x1','x2','y'])
# data.plot.scatter(x='x1',y='x2',c='y',cmap='brg')
# plt.show()
#整理输入集和输出集
x = data.iloc[:,:-1]
y = data.iloc[:,-1]
train_x,test_x,train_y,test_y = ms.train_test_split(x,y,test_size=0.1,random_state=7)
model = nb.GaussianNB()
# model = nb.MultinomialNB()
# model = nb.BernoulliNB()
model.fit(train_x,train_y)
pred_test_y = model.predict(test_x)
print(sm.classification_report(test_y,pred_test_y))
#暴力绘制分类边界线
# 1.将x1的最小值,x1的最大值,拆成200个点
# 2.将x2的最小值,x2的最大值,拆成200个点
# 3.组合x1和x2的所有的点 4W个
# 4.将4w个点带入模型进行预测,得到预测类别
# 5.根据预测类别设置不同颜色
x1 = np.linspace(x['x1'].min(),x['x1'].max(),200)
x2 = np.linspace(x['x2'].min(),x['x2'].max(),200)
x = []
for i in x1:
for j in x2:
x.append([i,j])
x = np.array(x)
y = model.predict(x)
plt.scatter(x=x[:,0],y=x[:,1],c=y,cmap='gray')
plt.scatter(x=data['x1'],y=data['x2'],c=data['y'],cmap='brg')
plt.show()
输出结果
朴素贝叶斯总结
什么是朴素贝叶斯
- 朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。“朴素”的含义为:假设问题的特征变量都是相互独立地作用于决策变量的,即问题的特征之间都是互不相关的。
优点
- 逻辑性简单
- 算法较为稳定。当数据呈现不同的特点时,朴素贝叶斯的分类性能不会有太大的差异。
- 当样本特征之间的关系相对比较独立时,朴素贝叶斯分类算法会有较好的效果。
缺点
- 特征的独立性在很多情况下是很难满足的,因为样本特征之间往往都存在着相互关联,如果在分类过程中出现这种问题,会导致分类的效果大大降低。
什么情况下使用朴素贝叶斯
- 根据先验概率计算后验概率的情况,且样本特征之间独立性较强
聚类
聚类(cluster)与分类(class)问题不同,聚类是属于无监督学习模型,而分类属于有监督学习。聚类使用一些算法把样本分为N个群落,群落内部相似度较高,群落之间相似度较低。在机器学习中,通常采用“距离”来度量样本间的相似度,距离越小,相似度越高;距离越大,相似度越低
相似度度量方式
欧氏距离
相似度使用欧氏距离来进行度量. 坐标轴上两点\(x_1, x_2\)之间的欧式距离可以表示为:
$$|x_1-x_2| = \sqrt{(x_1-x_2)^2}$$
平面坐标中两点\((x_1, y_1), (x_2, y_2)\)欧式距离可表示为:
$$|(x_1,y_1)-(x_2, y_2)| = \sqrt{(x_1-x_2)^2+(y_1-y_2)^2}$$
三维坐标系中\((x_1, y_1, z_1), (x_2, y_2, z_2)\)欧式距离可表示为:
$$|(x_1, y_1, z_1),(x_2, y_2, z_2)| = \sqrt{(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2}$$
以此类推,可以推广到N维空间.
$$|(x_1, y_1, z_1...,n_1),(x_2, y_2, z_2,...n_2)|$$ $$= \sqrt{(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2+...(n_1-n_2)^2}$$
曼哈顿距离
二维平面两点\(a(x_1, y_1)\)与\(b(x_2, y_2)\)两点间的曼哈顿距离为:
$$d(a, b) = |x_1 - x_2| + |y_1 - y_2|$$
推广到N维空间,\(x(x_1, x_2, ..., x_n)\)与\(y(y_1, y_2, ..., y_n)\)之间的曼哈顿距离为:
$$d(x,y) = |x_1 - y_1| + |x_2 - y_2| + ... + |x_n - y_n| = \sum_{i=1}^n|x_i - y_i|$$
- 在上图中,绿色线条表示的为欧式距离,红色线条表示的为曼哈顿距离,黄色线条和蓝色线条表示的为曼哈顿距离的等价长度
闵可夫斯基距离
闵可夫斯基距离(Minkowski distance)又称闵氏距离,其定义为:
$$D(x, y) = (\sum_{i=1}^n |x_i - y_i|^p)^{\frac{1}{p}}$$
- 当\(p=1\)时,即为曼哈顿距离
- 当\(p=2\)时,即为欧式距离
- 当\(p \rightarrow \infty\)时,即为切比雪夫距离
可见,曼哈顿距离、欧氏距离、切比雪夫距离都是闵可夫斯基的特殊形式
距离的性质
如果\(dist(x,y)\)度量标准为一个距离,它应该满足以下几个条件:
- 非负性:距离一般不能为负,即 \(dist(x, y) >= 0\)
- 同一性:\(dist(x_i, y_i) = 0\),当且仅当\(x_i = y_i\)
- 对称性:\(dist(x_i, y_i) = dist(y_i, x_i)\)
- 直递性:\(dist(x_i, x_j) <= dist(x_i, x_k) + dist(x_k, x_j)\)
聚类算法的划分
原型聚类
- 原型聚类也称“基于原型的聚类”(prototype-based clustering),此类算法假设聚类结构能通过一组原型刻画,在现实聚类任务中极为常用. 通常情况下,算法先对原型进行初始化,然后对原型进行迭代更新求解. 采用不同的原型表示、不同的求解方式,将产生不同的算法. 最著名的原型聚类算法有K-Means.
密度聚类
- 密度聚类也称“基于密度的聚类”(density-based clustering),此类算法假定聚类结构能通过样本分布的紧密程度确定. 通常情况下,密度聚类算法从样本密度的角度来考察样本之间的可连接性,并基于可连接样本不断扩展聚类簇以获得最终的聚类结果. 著名的密度聚类算法有DBSCAN.
层次聚类
- 层次聚类(hierarchical clustering)试图在不同层次对数据集进行划分,从而形成树形的聚类结构. 数据集的划分可以采用“自底向上”或“自顶向下”的策略. 常用的层次聚类有凝聚层次算法等.
常用聚类算法
K均值聚类
K均值聚类(k-means clustering)算法是一种常用的、基于原型的聚类算法,简单、直观、高效。其步骤为:
- 第一步:根据事先已知的聚类数,随机选择若干样本作为聚类中心,计算每个样本与每个聚类中心的欧式距离,离哪个聚类中心近,就算哪个聚类中心的聚类,完成一次聚类划分.
- 第二步:计算每个聚类的几何中心,如果几何中心与聚类中心不重合,再以几何中心作为新的聚类中心,重新划分聚类. 重复以上过程,直到某一次聚类划分后,所得到的各个几何中心与其所依据的聚类中心重合或足够接近为止. 聚类过程如下图所示:
- 聚类数(K)必须事先已知,来自业务逻辑的需求或性能指标.
- 最终的聚类结果会因初始中心的选择不同而异,初始中心尽量选择离中心最远的样本.
sklearn关于k-means算法API:
import sklearn.cluster as sc
# 创建模型
model = sc.KMeans(n_clusters) # n_cluster为聚类数量
# 获取聚类(几何)中心
centers = model.cluster_centers_
# 获取聚类标签(聚类结果)
pred_y = model.labels_
示例代码:
# k-means示例
import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp
import sklearn.metrics as sm
x = [] # 没有输出(无监督学习)
with open("multiple3.txt", "r") as f:
for line in f.readlines():
line = line.replace("\n", "")
data = [float(substr) for substr in line.split(",")]
x.append(data)
x = np.array(x)
# K均值聚类器
model = sc.KMeans(n_clusters=4) # n_cluster为聚类数量
model.fit(x) # 训练
pred_y = model.labels_ # 聚类标签(聚类结果)
centers = model.cluster_centers_ # 获取聚类(几何)中心
print("centers:", centers)
print("labels.shape:", pred_y.shape)
#print("labels:", pred_y)
# 计算并打印轮廓系数
score = sm.silhouette_score(x, pred_y,sample_size=len(x),metric="euclidean") # 欧式距离度量
print("silhouette_score:", score)
# 可视化
mp.figure("K-Means Cluster", facecolor="lightgray")
mp.title("K-Means Cluster")
mp.xlabel("x", fontsize=14)
mp.ylabel("y", fontsize=14)
mp.tick_params(labelsize=10)
mp.scatter(x[:, 0], x[:, 1], s=80, c=pred_y, cmap="brg")
mp.scatter(centers[:, 0], centers[:, 1], marker="+",c="black", s=200, linewidths=1)
mp.show()
输出结果
centers: [[7.07326531 5.61061224]
[1.831 1.9998 ]
[5.91196078 2.04980392]
[3.1428 5.2616 ]]
labels.shape: (200,)
silhouette_score: 0.5773232071896658
实验代码
import sklearn.cluster as sc
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv('multiple3.txt',header=None)
# plt.scatter(x=data[0],y=data[1])
# data.plot.scatter(x=0,y=1)
# plt.show()
model = sc.KMeans(4)
model.fit(data)
label = model.labels_
print(label)
plt.scatter(x=data[0],y=data[1],c=label,cmap='brg')
plt.colorbar()
plt.show()
输出结果
特点及使用
- 优点
- 原理简单,实现方便,收敛速度快;
- 聚类效果较优,模型的可解释性较强;
- 缺点
- 需要事先知道聚类数量;
- 聚类初始中心的选择对聚类结果有影响;
- 采用的是迭代的方法,只能得到局部最优解;
- 对于噪音和异常点比较敏感.
- 什么时候选择k-means
- 事先知道聚类数量
- 数据分布有明显的中心
噪声密度
噪声密度(Density-Based Spatial Clustering of Applications with Noise, 简写DBSCAN随机选择一个样本做圆心,以事先给定的半径做圆,凡被该圆圈中的样本都被划为与圆心样本同处一个聚类,再以这些被圈中的样本做圆心,以事先给定的半径继续做圆,不断加入新的样本,扩大聚类的规模,知道再无新的样本加入为止,即完成一个聚类的划分. 以同样的方法,在其余样本中继续划分新的聚类,直到样本空间被耗尽为止,即完成整个聚类划分过程. 示意图如下:
DBSCAN算法中,样本点被分为三类:
- 边界点(Border point):可以划分到某个聚类,但无法发展出新的样本
- 噪声点(Noise):无法划分到某个聚类中的点
- 核心点(Core point):除了孤立样本和外周样本以外的样本都是核心点
上图中,A和B为核心点,C为边界点,D为噪声点. 此外,DBSCAN还有两个重要参数:
- 邻域半径:设置邻域半径大小
- 最少样本数目:邻域内最小样本数量,某个样本邻域内的样本超过该数,才认为是核心点
sklearn提供了DBSCAN模型来实现噪声密度聚类,原型如下:
# eps 半径
# min_samples 最小样本数
model = sc.DBSCAN(eps,min_samples)
示例代码:
# 噪声密度聚类示例
import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp
import sklearn.metrics as sm
# 读取样本
x = []
with open("perf.txt", "r") as f:
for line in f.readlines():
line = line.replace("\n", "")
data = [float(substr) for substr in line.split(",")]
x.append(data)
x = np.array(x)
epsilon = 0.8 # 邻域半径
min_samples = 5 # 最小样本数
# 创建噪声密度聚类器
model = sc.DBSCAN(eps=epsilon, # 半径
min_samples=min_samples) # 最小样本数
model.fit(x)
score = sm.silhouette_score(x,
model.labels_,
sample_size=len(x),
metric='euclidean') # 计算轮廓系数
pred_y = model.labels_
print(pred_y) # 打印所有样本类别
# print(model.core_sample_indices_) # 打印所有核心样本索引
# 区分样本
core_mask = np.zeros(len(x), dtype=bool)
core_mask[model.core_sample_indices_] = True # 核心样本下标
offset_mask = (pred_y == -1) # 孤立样本
periphery_mask = ~(core_mask | offset_mask) # 核心样本、孤立样本之外的样本
# 可视化
mp.figure('DBSCAN Cluster', facecolor='lightgray')
mp.title('DBSCAN Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=14)
mp.grid(linestyle=':')
labels = set(pred_y)
print(labels)
cs = mp.get_cmap('brg', len(labels))(range(len(labels)))
print("cs:", cs)
# 核心点
mp.scatter(x[core_mask][:, 0], # x坐标值数组
x[core_mask][:, 1], # y坐标值数组
c=cs[pred_y[core_mask]],
s=80, label='Core')
# 边界点
mp.scatter(x[periphery_mask][:, 0],
x[periphery_mask][:, 1],
edgecolor=cs[pred_y[periphery_mask]],
facecolor='none', s=80, label='Periphery')
# 噪声点
mp.scatter(x[offset_mask][:, 0],
x[offset_mask][:, 1],
marker='D', c=cs[pred_y[offset_mask]],
s=80, label='Offset')
mp.legend()
mp.show()
执行图像:
实验代码
import sklearn.cluster as sc
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv('perf.txt',header=None)
# plt.scatter(x=data[0],y=data[1])
# data.plot.scatter(x=0,y=1)
# plt.show()
model = sc.DBSCAN(eps=0.55,min_samples=3)
model.fit(data)
label = model.labels_
print(label)
plt.scatter(x=data[0],y=data[1],c=label,cmap='brg')
plt.colorbar()
plt.show()
输出结果
- 算法优点
- 不用人为提前确定聚类类别数K
- 聚类速度快
- 能够有效处理噪声点(因为异常点不会被包含于任意一个簇,则认为是噪声)
- 能够应对任意形状的空间聚类
- 算法缺点
- 当数据量过大时,要求较大的内存支持I/O消耗很大
- 当空间聚类的密度不均匀、聚类间距差别很大时、聚类效果有偏差
- 邻域半径和最少样本数量两个参数对聚类结果影响较大
- 何时选择噪声密度
- 数据稠密、没有明显中心
- 噪声数据较多
- 未知聚簇的数量
凝聚层次聚类
凝聚层次(Agglomerative)算法,首先将每个样本看做独立的聚类,如果聚类数大于预期,则合并两个距离最近的样本作为一个新的聚类,如此反复迭代,不断扩大聚类规模的同时,减少聚类的总数,直到聚类数减少到预期值为止. 这里的关键问题是如何计算聚类之间的距离
依据对距离的不同定义,将Agglomerative Clustering的聚类方法分为三种:
- ward:默认选项,挑选两个簇来合并,是的所有簇中的方差增加最小。这通常会得到大小差不多相等的簇。
- average链接:将簇中所有点之间平均距离最小的两个簇合并。
- complete链接:也称为最大链接,将簇中点之间最大距离最小的两个簇合并。
ward适用于大多数数据集。如果簇中的成员个数非常不同(比如其中一个比其他所有都大得多),那么average或complete可能效果更好。
sklearn提供了AgglomerativeClustering聚类器来实现凝聚层次聚类,示例代码如下:
# 凝聚层次聚类示例
import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp
x = []
with open("multiple3.txt", "r") as f:
for line in f.readlines():
line = line.replace("\n", "")
data = [float(substr) for substr in line.split(",")]
x.append(data)
x = np.array(x)
# 凝聚聚类
model = sc.AgglomerativeClustering(n_clusters=4) # n_cluster为聚类数量
model.fit(x) # 训练
pred_y = model.labels_ # 聚类标签(聚类结果)
# 可视化
mp.figure("Agglomerative", facecolor="lightgray")
mp.title("Agglomerative")
mp.xlabel("x", fontsize=14)
mp.ylabel("y", fontsize=14)
mp.tick_params(labelsize=10)
mp.scatter(x[:, 0], x[:, 1], s=80, c=pred_y, cmap="brg")
mp.show()
输出结果
特点及使用
- 需要事先给定期望划分的聚类数(k),来自业务或指标优化
- 没有聚类中心,无法进行聚类预测,因为不依赖于中心的划分,所以对于中心特征不明显的样本,划分效果更佳稳定
- 适合于中心不明显的聚类
聚类的评价指标
理想的聚类可以用四个字概况:内密外疏,即同一聚类内部足够紧密,聚类之间足够疏远. 学科中使用“轮廓系数”来进行度量,见下图:
假设我们已经通过一定算法,将待分类数据进行了聚类,对于簇中的每个样本,分别计算它们的轮廓系数。对于其中的一个点 i 来说:
- a(i) = average(i向量到所有它属于的簇中其它点的距离)
- b(i) = min (i向量到各个非本身所在簇的所有点的平均距离)
那么 i 向量轮廓系数就为:
$$S(i)=\frac{b(i)-a(i)}{max(b(i), a(i))}$$
由公式可以得出:
- 当\(b(i)>>a(i)\)时,\(S(i)\)越接近于1,这种情况聚类效果最好
- 当\(b(i)<<a(i)\)时,\(S(i)\)越接近于-1,这种情况聚类效果最差
- 当\(b(i)=a(i)\)时,\(S(i)\)的值为0,这种情况分类出现了重叠
sklearn提供的计算轮廓系数API:
score = sm.silhouette_score(x, # 样本
pred_y, # 标签
sample_size=len(x), # 样本数量
metric="euclidean") # 欧式距离度量
聚类总结
- 聚类属于无监督学习;
- 聚类是根据数据的特征,将相似度最高的样本划分到一个聚簇中;
- 相似度的度量方式:曼哈顿距离、欧式距离、切比雪夫距离,都可以用闵式距离公式表示;
- 聚类算法
- 基于原型聚类:k-means算法
- 基于密度聚类:DBSCAN算法
- 基于层次聚类:凝聚算法
- 评价指标:轮廓系数
0 条评论