目录
分类模型
分类模型主要有
k近邻(KNN)
逻辑斯谛回归
决策树
核心思想
- 在监督学习中,如果输出变量Y取有限个离散值时,预测问题就变成了分类问题
- 监督学习从数据中学习一个分类模型或者分类决策函数,称为分类器,分类器对新的输入进行预测,称为分类
- 包含学习和分类两部分,用数据得到一个分类器,用分类器对新的输入分类
分类模型核心就是如何分类,然后这样分类好不好
精确率和召回率
一般用分类准确率(accuracy)评价分类器性能:测试集正确分类的样本数 / 总样本数
对于二类分类问题,一般用精确率(precision)和召回率(recall)评价
-
精确率:所有预测为正类的数据中,预测正确的比例
-
召回率:所有实际为正类的数据中,被正确预测找出的比例
对此,我们要明白几个概念 -
TP:将正类预测为正类
-
FN:将正类预测为负类
-
FP:将负类预测为正类
-
TN:将负类预测为负类
k近邻模型(KNN)
最初级的分类器,将所有的训练数据对应的类别记录下来,当测试对象的某个属性和训练对象的属性完全匹配时,对其进行分类
核心思想
KNN作为分类模型,核心其实就是如何分类:
- 计算测试数据和各个训练数据之间的距离
- 按照距离的递增关系进行排序
- 选取距离最小的 k 个点, 一般 k 不大于20
- 确定 k 个点所在类别的出现频率
- 返回 k 个点中出现频率最高的类别作为测试数据的预测分类
下面这个事例我们可以看到,KNN 的结果很大程度取决于 k 的取之,而且选择的邻居都要是被正确分类的对象
比如下列这个二维图形,绿色圆属于哪一类
k = 3 时,把离绿圆最近的 3 个点圈起来,有 2 红 1 蓝,那绿圆就被分类为红三角
k = 5 时,把离绿圆最近的 5 个点圈起来,有 2 红 3 蓝,那绿圆就被分类为蓝正方
同样的k = 11,还是蓝色正方形
距离函数
KNN中,通过计算对象间距离来作为各个对象之间的非相似性指标,避免了对象之间的匹配问题,我们一般使用欧氏距离或者曼哈顿距离
代码实现
- 引入依赖和数据
import numpy as np
import pandas as pd
#sklearn自带了入门学习用的数据集
from sklearn.datasets import load_iris
#sklearn划分训练集和测试集的模块
from sklearn.model_selection import train_test_split
#计算分类预测准确率的模块
from sklearn.metrics import accuracy_score
#iris 有核心的两部分数据 data 和 target
iris = load_iris()
x = iris.data
# reshape是讲python中的数组结构改变,比如一维改为二维数组
y = iris.target.reshape(-1,1)
print(x.shape)
print(y.shape)
#x.shape is: (150, 4) y.shape is: (150, 1)
#可以看到分别是4维数组 和 一维数组(只有0,1,2这样的类型值)
#所以应该是一堆 4维坐标点 和 坐标点对应的索引关联到对应的类型
2. 划分训练集和测试集
# train_data:x 待划分样本数据
# train_target:y 待划分样本数据的结果(标签)
# test_size:测试数据占样本数据的比例,若整数则样本数量
# random_state:设置随机数种子,保证每次都是同一个随机数。若为0或不填,则每次得到数据都不一样
# stratify参数,按照谁划分,可以处理数据不平衡问题
x_train, x_test, y_train, y_test = train_test_split(
x, y, test_size=0.3, random_state=35, stratify=y)
#python shape可以获取矩阵的形状
print('x_train is:',x_train.shape,' x_test is:',x_test.shape
,' y_train is:',y_train.shape,' y_test is:',y_test.shape,)
#x_train is: (105, 4) x_test is: (45, 4)
#y_train is: (105, 1) y_test is: (45, 1)
3.算法实现
# 第一步,定义距离
def l1_distance(a, b): # a是矩阵 ,b是向量
# np.sum(x)对输入参数中的所有元素进行求和,输入参数带有axis时,将按照指定axis进行对应求和
# 有 b 为 ([[ 0, 1, 2, 3, 4, 5],
# [ 6, 7, 8, 9, 10, 11]])
# 那么 np.sum(b) 为 666,np.sum(b,axis=1) 为 array([15, 51])
return np.sum( np.abs(a-b), axis=1 )
def l2_distance(a, b):
#sqrt 求平方根
return np.sqrt( np.sum( (a-b)**2, axis=1 ) )
# 继承式写法,代表KNN继承object
class KNN(object):
# 定义一个初始化方法,__init__ 是python的构造方法
# 函数编程特性,可以传入函数 l1_distance
# n_neighbors 就是 k ,给默认值1
def __init__(self, n_neighbors = 1, dist_func = l1_distance):
self.n_neighbors = n_neighbors
self.dist_func = dist_func
# 训练模型方法
# KNN实际上没有训练,只要有训练数据和要预测的数据
def fit(self, x, y):
self.x_train = x
self.y_train = y
# 模型预测方法
def predict(self, x):
# 初始化预测分类数组
# np.zeros( 形状(几行几列),类型(默认给的是float) ), 初始化一个 0 矩阵
y_pred = np.zeros( (x.shape[0],1), dtype=self.y_train.dtype )
# 遍历输入的 x 数据点,取出每一个数据点的序号 i 和数据 x_test
for i, x_test in enumerate(x):
# x_test跟所有训练数据计算距离
distances = self.dist_func( self.x_train, x_test )
#由近到远排序,然后按照索引值记录数值由小到大的顺序
# argsort
nn_index = np.argsort(distances)
#选取最近的 k 个点,保存他们分类的类别
#nn_index[:self.n_neighbors] 这个截取,ravel是用来将矩阵向量化
nn_y = self.y_train[ nn_index[:self.n_neighbors] ].ravel()
#统计每个类别出现的次数,找到最多的那个
# a = [0,1,0,3]
# np.bincount(a) 得到 array([2, 1, 0, 1])
#返回第一个出现的最大值的位置
# a = [1, 2, 9, 2, 5, 6, 9]
# np.argmax(a) 为 2, 9 的索引为 2
y_pred[i] = np.argmax( np.bincount(nn_y) )
return y_pred
4.测试
# 定义一个knn实例
knn = KNN(n_neighbors = 3)
# 训练模型
knn.fit(x_train, y_train)
# 传入测试数据,做预测
y_pred = knn.predict(x_test)
print(y_test.ravel())
print(y_pred.ravel())
# 求出预测准确率
accuracy = accuracy_score(y_test, y_pred)
print("预测准确率: ", accuracy)
5. 测试不同的 距离函数 和 K 值 的效果哪种最好
# 定义一个knn实例
knn = KNN()
# 训练模型
knn.fit(x_train, y_train)
# 保存结果list
result_list = []
# 针对不同的参数选取,做预测
for p in [1, 2]:
knn.dist_func = l1_distance if p == 1 else l2_distance
# 考虑不同的k取值,步长为2
for k in range(1, 10, 2):
knn.n_neighbors = k
# 传入测试数据,做预测
y_pred = knn.predict(x_test)
# 求出预测准确率
accuracy = accuracy_score(y_test, y_pred)
result_list.append([k, 'l1_distance' if p == 1 else 'l2_distance', accuracy])
df = pd.DataFrame(result_list, columns=['k', '距离函数', '预测准确率'])
df
逻辑斯谛回归(Logistic Regression)模型
和线性回归区别
这个和线性回归有点关系,但是他是分类模型
首先我们看一下线性回归预判肿瘤是否是恶性
一般是这样的直线,但是线性回归的健壮性不够,如果有噪声数据
我们随机选取一个噪点,我们看一下这个点的实际值是1,应该是恶性肿瘤,但是我们线性回归模型给出的是0.4,是更接近于良性吗,这肯定不行
此时我们需要用到逻辑斯谛回归,比如下面的这样去进行分类
sigmoid函数(压缩函数)
sigmoid函数是对数几率函数,sigmoid函数可以将输出压缩到0-1之内
但这样还是没有实现分类的效果,我们一般设置一个门槛,一般是 0.5 ,当大于 0.5 时,就将其结果判断为 1 ,反之判断为 0
案例一
我们用线性回归拟合出来的值用压缩函数进行压缩,压缩完成后用0.5做一个概率的判定边界,就能把样本分为两类,正样本和负样本
案例二
损失函数
如果我们和线性回归一样使用平方损失函数,会发现函数是下列这样,我们很可能只是找到一个局部最小值,而和实际最小值差距很大
我们想要的是一个凸函数
我们损失函数有一种是对数损失函数,而对数函数的特性如下
可以看到使用对数函数作为损失函数很合适,那么就有
当 y = 1 和 y = 0 时,其实就是
可以推导出
我们知道,为了防止过拟合,我们需要加一个正则化项,得到
这样,我们就得到一个凸函数,其中在上述公式中有
决策树
决策树是一种简单高效并且具有强解释性的模型,广泛用于数据分析领域,本质上是一个由上而下的由多个判断节点组成的树
核心思想
- 决策树是一个 if-then 规则的集合
- 由根节点到叶节点的每一条路径,构建一条规则,路径上内部节点的特征对应着规则的条件,叶节点对应规则的结论
- 决策树 if-then 规则的集合特性:互斥且完备,也就是每个实例都被一条规则(一条路径)所覆盖,并且只能被一条规则覆盖
案列
预测打球问题