机器学习基础

通常来说,我们认为统计学注重先验,要将一切准备工作就绪后才可以开始建模等后续步骤;而机器学习看重结果,因此机器学习中不会提前为线性回归排除共线性等可能会影响模型的因素,反而会先建立模型以查看效果。模型确立之后,如果效果不好,我们就根据统计学的指导来排除可能影响模型的因素。

摘要

本篇博客参考一些教程对机器学习基础进行总结,以便加深理解和记忆

1.KNN

K近邻(K Nearest Neighbors)是最简单、常用的分类算法之一,预测一个新的值X时,根据与它最近的K个点的类别(最多的)来判断X属于哪个类别

距离计算:欧氏距离、曼哈顿距离

K值选择:通过交叉验证(将样本数据按照一定比例,拆分出训练用的数据和验证用的数据,比如6:4拆分出部分训练数据和验证数据),从选取一个较小的 K 值开始,不断增加 K 的值,然后计算验证集合的方差,最终找到一个比较合适的 K 值。

Sklearn-KNN

  • 函数定义
def KNeighborsClassifier(n_neighbors = 5,	# n_neighbors:K
					   """weights(权重):计算两点距离时对距离进行加权
						uniform:不管远近权重都一样,就是最普通的 KNN 算法的形式
						distance:权重和距离成反比,距离预测目标越近具有越高的权重
						自定义函数:根据输入的坐标值返回对应的权重,达到自定义权重的目的
					    """
                       weights='uniform',
                       """KNN的构建方式
                       	brute:暴力法,直接计算距离存储比较
						kd_tree:KD 树实现 KNN
						ball_tree:球树实现 KNN 
						auto: 默认参数,自动选择合适的方法构建模型
						当数据较小或比较稀疏时,无论选择哪个最后都会使用 ‘brute’,暴力法适合数据较小的方式,否则效率会比较低。
						如果数据量比较大一般会选择用 Kd 树构建 KNN 模型,而当 Kd 树也比较慢的时候,则可以试试球树来构建 KNN
                       """
                       algorithm = '',
                       """
                       如果是选择暴力构建,这个值是可以忽略。当使用 Kd 树或球树,它就是停止建子树的叶子节点数量的阈值。
                       默认30,但如果数据量增多这个参数需要增大,否则速度过慢不说,还容易过拟合。
                       """
                       leaf_size = '30',
                       p = 2,	# 和 metric 结合使用,当 metric 参数是 “minkowski” 的时候,p=1 为曼哈顿距离, p=2 为欧式距离。默认为p=2
                       """指定距离度量方法
                       	euclidean:欧式距离;
						manhattan:曼哈顿距离;
						chebyshev:切比雪夫距离;
						minkowski: 闵可夫斯基距离,默认参数
                       """
                       metric = 'minkowski',
                       metric_params = None,
                       n_jobs = None	# 指定多少个CPU进行运算,默认是-1,也就是全部都使用
                       )
  • 选定K值
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier

# 读取鸢尾花数据集
iris = load_iris()
x = iris.data
y = iris.target
k_range = range(1, 31)
k_error = []
# 循环,取k=1到k=31,查看误差效果
for k in k_range:
    knn = KNeighborsClassifier(n_neighbors=k)
    # cv参数决定数据集划分比例,这里是按照5:1划分训练集和测试集
    scores = cross_val_score(knn, x, y, cv=6, scoring='accuracy')
    k_error.append(1 - scores.mean())

# 画图,x轴为k值,y值为误差值
plt.plot(k_range, k_error)
plt.xlabel('Value of K for KNN')
plt.ylabel('Error')
plt.show()
  • 进行推理
import matplotlib.pyplot as plt
from numpy import *
from matplotlib.colors import ListedColormap
from sklearn import neighbors, datasets

n_neighbors = 11

 # 导入一些要玩的数据
iris = datasets.load_iris()
x = iris.data[:, :2]  # 我们只采用前两个feature,方便画图在二维平面显示
y = iris.target

h = .02  # 网格中的步长

 # 创建彩色的图
cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF'])

# weights是KNN模型中的一个参数,上述参数介绍中有介绍,这里绘制两种权重参数下KNN的效果图
for weights in ['uniform', 'distance']:
    # 创建了一个knn分类器的实例,并拟合数据
    clf = neighbors.KNeighborsClassifier(n_neighbors, weights=weights)
    clf.fit(x, y)

    # 绘制决策边界,为此,我们将为每个分配一个颜色
    # 来绘制网格中的点 [x_min, x_max]x[y_min, y_max].
    x_min, x_max = x[:, 0].min() - 1, x[:, 0].max() + 1
    y_min, y_max = x[:, 1].min() - 1, x[:, 1].max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])

    # 将结果放入一个彩色图中
    Z = Z.reshape(xx.shape)
    plt.figure()
    plt.pcolormesh(xx, yy, Z, cmap=cmap_light)

    # 绘制训练点
    plt.scatter(x[:, 0], x[:, 1], c=y, cmap=cmap_bold)
    plt.xlim(xx.min(), xx.max())
    plt.ylim(yy.min(), yy.max())
    plt.title("3-Class classification (k = %i, weights = '%s')" % (n_neighbors, weights))

plt.show()
  • 算法特点
    • 非参的:模型不会对数据做出任何的假设,KNN 建立的模型结构是根据数据来决定的
    • 惰性:KNN算法不需要对数据进行训练,没有明确的训练过程
    • 优点:简单易用、训练速度快(无需训练)、对异常值不明显
    • 缺点:对内存要求较高,因为该算法存储了所有训练数据、预测阶段可能很慢、对不相关的功能和数据规模敏感

2.线性回归

  • 回归算法
    • 经典回归算法:线性回归(Linear Regression) 和 逻辑回归(分类)
    • 衍生:岭回归、Lasso、弹性网
    • 分类算法改进后的回归:回归树、随机森林的回归、支持向量回归、贝叶斯回归
    • 鲁棒的回归: RANSAC、Theil–sen估计、胡贝尔回归

损失函数:SSE误差平方和,RSS残差平方和

最小二乘法求解多元线性回归问题:通过最小化真实值和预测值之间的RSS来求解参数,推导时求损失函数的极值,注意需要两个假设:逆矩阵存在(特征矩阵不存在多重共线性);统计学中,使用最小二乘法来求解线性回归的方法是一种无偏估计的方法,这种无偏估计要求因变量,也就是标签的分布必须服从正态分布

  • sklearn.linear_model
class sklearn.linear_model.LinearRegression(*, fit_intercept=True, normalize=False, copy_X=True, n_jobs=None, positive=False)

①fit intercept:布尔值,可不填,默认为True。是否计算此模型的截距。如果设置为False,则不会计算截距。
②normalize:布尔值,可不填,默认为False。当fit_intercept设置为False时,将忽略此参数。如果为True,则特征矩阵X在进入回归之前将会被减去均值(中心化)并除以L2范式(缩放)。如果你希望进行标准化,请在fit数据之前使用preprocessing模块中的标准化专用类StandardScaler。
③copy_X:b布尔值,可不填,默认为True。如果为真,将在X.copy上进行操作,否则的话原本的特征矩阵X可能被线性回归影响并覆盖。
④n_jobs:指定多少个CPU进行运算,默认是-1,也就是全部都使用

  • 示例
from sklearn.linear_model import LinearRegression as LR  # 线性回归
from sklearn.model_selection import train_test_split, cross_val_score  # 划分训练测试集
from sklearn.datasets import fetch_california_housing as fch  # 加利福尼亚房屋价格数据集
import pandas as pd
if __name__ == '__main__':
    # 1.导入数据集
    # 1.1 实例化 --- 得到的是一个类似字典的数据集
    house_value = fch()
    keys = house_value.keys()  # dict_keys(['data', 'target', 'feature_names', 'DESCR'])
    # 1.2 通过data获取对应的数据集
    x = pd.DataFrame(house_value.data)
    print(x.shape)  # (20640, 8)
    # 1.3 通过target获取对应的标签 --- yhat
    y = house_value.target
    print(y.max())  # 5.00001
    print(y.min())  # 0.14999
    print(y.shape)  # (20640,)
    # 1.4 通过feature_names获取特证名称
    features = house_value.feature_names
    # ['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup', 'Latitude', 'Longitude']
    '''
    MedInc:该街区住户的收入中位数
    HouseAge:该街区房屋使用年代的中位数
    AveRooms:该街区平均的房间数目
    AveBedrms:该街区平均的卧室数目
    Population:街区人口
    AveOccup:平均入住率
    Latitude:街区的纬度
    Longitude:街区的经度
    '''
    # 1.5 将特征名称对应到x数据集
    x.columns = features

    # 2.划分训练集和测试集
    xtrain, xtest, ytrain, ytest = train_test_split(x, y, test_size=0.3, random_state=420)
    # 2.1 恢复抽取数据的索引
    for i in [xtrain, xtest]:
        i.index = range(i.shape[0])

    # 3.建模
    reg = LR().fit(xtrain, ytrain)
    yhat = reg.predict(xtest)
    print(yhat.min())  # -0.6528439725035966
    print(yhat.max())  # 7.146198214270875

    # 4.查看拟合函数
    # 4.1 查看w,回归系数向量
    coef = reg.coef_
    print(coef)
    # 4.1.1 将回归系数与特征对应
    compare = [*zip(xtrain.columns, reg.coef_)]
    # 4.2 获取截距
    intercept = reg.intercept_
    print(intercept)

    # 5.2交叉验证
    cross = cross_val_score(reg, x, y, cv=10, scoring="neg_mean_squared_error")
    print(cross)
    print(cross.mean())  # -0.550952429695658

    # 6.R2
    # 方式一
    from sklearn.metrics import r2_score
    r_score = r2_score(y_true=ytest, y_pred=yhat)  # 0.6043668160178817
    # 方式二
    score = reg.score(xtest, ytest)  # 0.6043668160178817
    # 方式三
    cross_score = cross_val_score(reg, x, y, cv=10, scoring="r2").mean()  # 0.5110068610524564
    
    # 绘图
    from matplotlib import pyplot as plt
    sorted(ytest)
    plt.plot(range(len(ytest)), sorted(ytest), c='black', label='Data')
    plt.plot(range(len(yhat)), sorted(yhat), c='red', label='Predict')
    plt.legend()
    plt.show()
  • 评估指标
    • 是否预测到了正确的数值

      • 均方误差
      • 绝对均值误差:其表达的概念与均方误差完全一致,不过在真实标签和预测值之间的差异外我们使用的是L1范式(绝对值)。现实使用中,MSE和MAE选一个来使用就好了
      • 交叉验证
      def cross_val_score(estimator, X, y=None, groups=None, scoring=None, cv=None,
                          n_jobs=None, verbose=0, fit_params=None,
                          pre_dispatch='2*n_jobs', error_score=np.nan):
      """
      estimator:估计方法对象(分类器)
      X:数据特征(Features)
      y:数据标签(Labels)
      soring:调用方法(包括accuracy和mean_squared_error等等)
      cv:几折交叉验证
      n_jobs:同时工作的cpu个数(-1代表全部)
      """
      
      # 使用,如上代码5.
      
      """
      虽然均方误差永远为正,但是sklearn中的参数soring下,均方误差作为评判标准时,却是计算”负均方误差”(neg_mean_squarederror)。这是因为sklearn在计算模型评估指标的时候,会考虑指标本身的性质,均方误差本身是一种误差,所以被sklearn划分为模型的一种损失(loss)。在sklearn当中,所有的损失都使用负数表示,因此均方误差也被显示为负数了。真正的均方误差MSE的数值,其实就是neg_mean_squared error去掉负号的数字。
      """
      
    • 是否拟合到了足够的信息

      红色线是我们的真实标签,而蓝色线是我们的拟合模型。这张图像上,前半部分的拟合非常成功,看上去我们的真实标签和我们的预测结果几乎重合,但后半部分的拟合却非常糟糕,模型向着与真实标签完全相反的方向去了。对于这样的一个拟合模型,如果我们使用MSE来对它进行判断,它的MSE会很小,因为大部分样体其实都被完美拟合了,少数样本的真实值和预测值的巨大差异在被均分到每个样本上后,MSE就会很小。但这样的拟合结果必然不是一个好结果,因为一旦我的新样本是处于拟合曲线的后半段的,我的预测结果必然会有巨大的偏差,而这不是我们希望看到的。所以,我们希望找到新的指标,除了判断预测的数值是否正确之外,还能够判断我们的模型是否拟合了足够多的、数值之外的信息。

      • R 2 R^2 R2

      使用方差来衡量数据上的信息量。如果方差越大,代表数据上的信息量越多,而这个信息量不仅包括了数值的大小,还包括了我们希望模型捕捉的那些规律。为了衡量模型对数据上的信息量的捕捉,我们定义了 R 2 R^2 R2来帮助我们:

其中y是我们的真实标签,y’是我们的预测结果,y_ave是我们的均值,yi - y’如果除以样本量m就是我们的方差。方差的本质是任意一个y值和样本均值的差异,差异越大,这些值所带的信息越多。在R^2中,分子是真实值和预测值之差的差值,也就是我们的模型没有捕获到的信息总量,分母是真实标签所带的信息量,所以其衡量的是我们的模型没有捕获到的信息量占真实标签中所带的信息量的比例,所以,R越接近1越好。

# R2的代码如上6.

R2为负值的情况:当R2显示为负的时候,这证明我们的模型对我们的数据的拟合非常糟糕,模型完全不能使用。所有,一个负的R2是存在的的。当然了,现实应用中,如果你发现你的线性回归模型出现了负的R2,不代表你就要接受他了,首先检查你的建模过程和数据处理过程是否正确,也许你已经伤害了数据本身,也许你的建模过程是存在bug的。如果是集成模型的回归,检查你的弱评估器的数量是否不足,随机森林,提升树这些模型在只有两三棵树的时候很容易出现负的R2。如果你检查了所有的代码,也确定了你的预处理没有问题,但你的R2也还是负的那这就证明,线性回归模型不适合你的数据,试试看其他的算法吧。

3.岭回归

1)标准线性回归回顾

最小化真实值和预测值(RSS残差平方和)的平方误差来训练模型,最小二乘法即为最小化残差平方和,将其转为矩阵形式,求解为: β = ( X T X ) X T y β=(X^TX)X^Ty β=(XTX)XTy。为求解β,需要假设 X T X X^TX XTX为满秩矩阵。

局限性:现实任务中, X T X X^TX XTX往往不是满秩矩阵,或某些列之间的线性相关性比较大,例如许多任务中,会出现变量数(属性数)远超过样例数,导致其列数多于行数,显然不满秩,即行列式接近于0,即接近于奇异,此时计算是误差会很大,可解出多个 β (有用的方程组数少于未知数的个数时,没有唯一解,即有无穷多个解),它们都能使均方误差最小化。即在多元回归中,特征之间会出现多重共线问题,使用最小二乘法估计系数会出现系数不稳定问题,缺乏稳定性和可靠性。

2)岭回归方法

岭回归即是在上述问题的基础上,提出的一种改良方案:

①在矩阵 X T X X^TX XTX的对角线元素上加入一个小常数值λ,然后取其逆得到系数: β r i d g e = ( X T x X + λ I n ) − 1 X T Y β_{ridge}=(X^TxX+λI_n)^{-1}X^TY βridge=(XTxX+λIn)1XTY,其中 I n I_n In为单位矩阵,类似于“山岭”;λ是岭系数,改变其数值可以改变单位矩阵对角线的值

②在损失函数RSS的基础上增加对系数(全体系数)的惩罚: L o s s = R S S + λ ∑ j = 0 n β j 2 = R S S + λ ∣ ∣ β ∣ ∣ 2 Loss=RSS+λ\sum^n_{j=0}β^2_j=RSS+λ||β||^2 Loss=RSS+λj=0nβj2=RSS+λ∣∣β2,矩阵形式为: L o s s = ∑ i = 1 p ( y i − X i β ) 2 + λ ∑ j = 0 n β j 2 = ∑ i = 1 p ( y i − X i β ) + λ ∣ ∣ β ∣ ∣ 2 Loss=\sum^p_{i=1}(y_i-X_iβ)^2+λ\sum^n_{j=0}β^2_j = \sum^p_{i=1}(y_i-X_iβ)+λ||β||^2 Loss=i=1p(yiXiβ)2+λj=0nβj2=i=1p(yiXiβ)+λ∣∣β2。λ是惩罚系数,越大模型就越简单。λ×β的二范数为收缩惩罚项,用其试图缩小模型,减小线性回归模型的方差。

3)分析

岭回归是一种改良的最小二乘估计法,通过放弃最小二乘法的无偏性,以损失部分信息、降低精度为代价获得回归系数,它是更为符合实际、更可靠的回归方法,对存在离群点的数据的拟合要强于最小二乘法。

不同与线性回归的无偏估计,岭回归的优势在于它的无偏估计,更趋向于将部分系数向0收缩。因此,它可以缓解多重共线问题,以及过拟合问题。但是由于岭回归中并没有将系数收缩到0,而是使得系数整体变小,因此,某些时候模型的解释性会大大降低,也无法从根本上解决多重共线问题。

4)sklearn API

# 1.带有 L2正则化的最小二乘法
class sklearn.linear_model.Ridge(alpha=1.0, *, fit_intercept=True, normalize=False, copy_X=True, max_iter=None, tol=0.001, solver='auto', random_state=None)
"""
@alpha:float, default=1.0:正则强度,必须是一个正浮点数。正则化改善了问题的条件,并减少了估计的方差。较大的值表示更强的正则化
@fit_intercept:bool, default=True;是否拟合该模型的截距。如果设置为false,则在计算中将不使用截距
@normalize:bool, default=False;归一化。fit_intercept设置为False时,将忽略此参数。如果为True,则将在回归之前通过减去均值并除以l2-范数来对回归变量X进行归一化。
@copy_X:bool, default=True;如果为True,将复制X;否则为X自身
@max_iter:int, default=None;共轭梯度求解器的最大迭代次数。
@tol:float, default=1e-3;结果的精度
@solver:{‘auto’, ‘svd’, ‘cholesky’, ‘lsqr’, ‘sparse_cg’, ‘sag’, ‘saga’}, default=‘auto’;用于计算例程的求解器
@random_state:int, default=None;随机种子
"""

# 2.内置交叉验证岭回归 - RidgeCV
# 在岭回归的基础上,内置了交叉验证。默认情况下,它执行有效的“留一法”交叉验证。RidgeCV不同于Ridge可以输入多个超参数Alpha,以方便得出最佳Alpha
"""
@alphas:float, default=(0.1, 1.0, 10.0);要尝试的Alpha值数组。同样表示正则强度,值必须是一个正浮点数。正则化改善了问题的条件,并减少了估计的方差。较大的值表示更强的正则化
@fit_intercept:bool, default=True;是否拟合该模型的截距。如果设置为false,则在计算中将不使用截距
@normalize:bool, default=False;归一化。fit_intercept设置为False时,将忽略此参数。如果为True,则将在回归之前通过减去均值并除以l2-范数来对回归变量X进行归一化。
@scoring:string, callable, default=None;带有scorer(estimator, X, y)签名的字符串或计分器可调用对象/函数 。如果为None,则当cv为’auto’或为None时(即,使用留一法交叉验证时)为负均方误差,否则为r2得分
@cv:int,default,交叉验证生成器或迭代器;确定交叉验证拆分策略
@gcv_mode:{‘auto’, ‘svd’, ‘eigen’}, default=‘auto’;指示执行“留一法”交叉验证时要使用的策略的标志
@store_cv_values:bool, default=False;指示是否应将与每个alpha对应的交叉验证值存储在cv_values_属性中的标志。该标志仅与cv=None(即使用“留一法”交叉验证)兼容
@alpha_per_target:bool, default=False;指示是否alphas分别针对每个目标(对于多输出设置:多个预测目标)分别优化α值(从参数列表中选取)的标志 。设置True为时,拟合后,该alpha_属性将包含每个目标的值。设置False为时,所有目标均使用单个alpha
"""

5)示例

# 导入库
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import Ridge
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline


# 生成训练集和测试集
def f(x):
    """ 使用多项式插值拟合的函数"""
    return x * np.sin(x)


# 为了画函数曲线生成的数据
x_plot = np.linspace(0, 10, 100)
# 生成训练集
x = np.linspace(0, 10, 100)
rng = np.random.RandomState(0)
rng.shuffle(x)
x = np.sort(x[:30])
y = f(x)
# 转换为矩阵形式
X = x[:, np.newaxis]
X_plot = x_plot[:, np.newaxis]

# 可视化
colors = ['teal', 'yellowgreen', 'gold']
linestyles = ["-", "--", ":"]
# lw = 2
fig = plt.figure(figsize=(12, 6))
plt.plot(x_plot, f(x_plot), color='cornflowerblue', linewidth=1, label="ground truth")
plt.scatter(x, y, color='navy', s=10, marker='o', label="training points")
for count, degree in enumerate([3, 4, 5]):
    model = make_pipeline(PolynomialFeatures(degree), Ridge())
    model.fit(X, y)
    y_plot = model.predict(X_plot)
    plt.plot(x_plot, y_plot, color=colors[count], linestyle=linestyles[count], linewidth=2,
             label="degree %d" % degree)
    plt.legend(loc='lower left')
plt.show()

4.LASSO回归

LASSO同岭回归类似,是处理具有复共线性数据的有偏估计,与岭回归的区别在于正则化,使用的是L1正则化。在scikit-learn库中LassoCV和LassoLarsCV是可选的两个模型

特点:Lasso回归使得一些系数变小,甚至还是一些绝对值较小的系数直接变为0,因此特别适用于参数数目缩减与参数的选择,因而用来估计稀疏参数的线性模型。

问题:Lasso回归有一个很大的问题,就是它的损失函数不是连续可导的,由于L1范数用的是绝对值之和,导致损失函数有不可导的点。也就是说,我们的最小二乘法,梯度下降法,牛顿法与拟牛顿法对它统统失效了。在求解时可以使用:坐标轴下降法(coordinate descent)和最小角回归法( Least Angle Regression, LARS)

5.逻辑斯蒂回归

# -*- coding: utf-8 -*-
import sys

from sklearn import datasets
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt


# 绘制决策边界
def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):
    # 设置标记点和颜色
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])

    # 绘制决策面
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution), np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())
    # 绘制所有样本
    X_test, y_test = X[test_idx, :], y[test_idx]
    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1], alpha=0.8, c=cmap(idx), marker=markers[idx], label=cl)
    # 高亮预测样本
    if test_idx:
        X_test, y_test = X[test_idx, :], y[test_idx]
        plt.scatter(X_test[:, 0], X_test[:, 1], alpha=1.0, linewidths=1, marker='o', s=55, label='test set')


if __name__ == '__main__':
    # 数据导入
    iris = datasets.load_iris()
    X = iris.data[:, [2, 3]]
    y = iris.target
    # 训练集和测试集划分
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
    # 标准化
    sc = StandardScaler()
    sc.fit(X_train)  # 计算样本的均值和标准差
    X_train_std = sc.transform(X_train)
    X_test_std = sc.transform(X_test)

    # 逻辑斯蒂回归
    lr = LogisticRegression(C=1000.0, random_state=0)
    lr.fit(X_train_std, y_train)
    # 模型预测
    y_pred = lr.predict_proba(X_test_std)
    # print(y_pred[:, 1])

    X_combined_std = np.vstack((X_train_std, X_test_std))
    y_combined = np.hstack((y_train, y_test))
    plot_decision_regions(X=X_combined_std, y=y_combined, classifier=lr, test_idx=range(105, 150))
    plt.xlabel('petal length[standardized]')
    plt.ylabel('petal width[standardized]')
    plt.legend(loc='upper left')
    plt.show()

    # 观察正则化参数C的作用:减少正则化参数C的值相当于增加正则化的强度
    # 观察:减小参数C值,增加正则化强度,导致权重系数逐渐收缩
    weights, params = [], []
    for c in np.arange(-5, 5, dtype=float):
        lr = LogisticRegression(C=10 ** c, random_state=0)
        lr.fit(X_train_std, y_train)
        weights.append(lr.coef_[1])
        params.append(10 ** c)
    weights = np.array(weights)
    plt.plot(params, weights[:, 0], label='petal length')
    plt.plot(params, weights[:, 1], label='petal width', linestyle='--')
    plt.ylabel('weight coefficient')
    plt.xlabel('C')
    plt.legend(loc='upper left')
    plt.xscale('log')
    plt.show()

6.贝叶斯算法

贝叶斯算法

7.决策树

非参数的有监督算法,能够从一组数据中总结出决策规则,用树结构呈现规则,以解决回归和分类问题。其决策过程可以看作通过问一系列的问题对数据进行分类。

1)两个核心问题
①如何寻找最佳属性:对分类树来说,衡量这个“最佳”的指标叫做**“不纯度”**。通常来说,不纯度越低,决策树对训练集的拟合越好。现在使用的决策树算法在分枝方法上的核心大多是围绕在对某个不纯度相关指标的最优化上。不纯度基于节点来计算,树中的每个节点都会有一个不纯度,并且子节点的不纯度一定是低于父节点的,也就是说,在同一棵决策树上,叶子节点的不纯度一定是最低的。

基本的指标有:信息熵(实际是信息增益,即父节点的信息熵和子节点的信息熵之差)、基尼系数

比起基尼系数,信息熵对不纯度更加敏感,对不纯度的惩罚最强。但是在实际使用中,信息熵和基尼系数的效果基本相同。信息熵的计算比基尼系数缓慢一些,因为基尼系数的计算不涉及对数。另外,因为信息熵对不纯度更加敏感,所以信息熵作为指标时,决策树的生长会更加“精细”,因此对于高维数据或者噪音很多的数据,信息熵很容易过拟合,基尼系数在这种情况下效果往往比较好。当模型拟合程度不足的时候,即当模型在训练集和测试集上都表现不太好的时候,使用信息熵。

②如何让决策树停止生长,防止过拟合:先剪枝、后剪枝、增加随机性

2)建树的过程

直到没有更多的特征可用,或整体的不纯度指标已经最优,决策树就会停止生长。

在建树过程中,属性选择时的数值会有所波动,引起建树不稳定,此时可以使用集成算法来解决,建立多棵树每次选出最优的。建立多棵树的方式为:在每次分枝时,不使用全部特征,而是随机选取一部分特征,从中选取不纯度相关指标最优的作为分枝用的节点。这样,每次生成的树也就不同了。

3)决策树的优缺点
①优点:易于理解、可解释性强、需要的数据预处理少、建树成本较低、可以处理连续型和离散型数据、可以使用统计测试验证
②缺点:容易过拟合、可能不稳定、属于局部最优、对一些问题难以学习、若标签中某些类占主导地位,决策树可能会偏向于主导类的树

4)scikit-learn决策树

决策树算法有:ID3、C4.5、C5.0、CART等版本,scikit-learn实现的是CART版本

scikit-learn中的决策树有5类:tree.DecisionTreeClassifier(分类树)、tree.DecisionTreeRegressor(回归树)、tree.ExtraTreeClassifier(高随机版本的分类树)、tree.ExtraTreeRegressor(高随机版本的回归树)、tree.export_graphviz(将生成的决策树导出为DOT格式,画图专用)

①分类树

"""分类树"""
class sklearn.tree.DecisionTreeClassifier (
    criterion=’gini’, splitter=’best’, max_depth=None,min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None,random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None,class_weight=None, presort=False
)
"""
@criterion:不纯度的计算方法:entropy:使用信息熵(Entropy);gini:使用基尼系数(Gini Impurity)
    @random_state:用来设置分枝中的随机模式的参数,默认None,在高维度时随机性会表现更明显,低维度的数据(比如鸢尾花数据集),随机性几乎不会显现。
    @splitter:控制决策树中的随机选项的:best:决策树在分枝时虽然随机,但是还是会优先选择更重要的特征进行分枝(重要性可以通过属性feature_importances_查看);random:决策树在分枝时会更加随机,树会因为含有更多的不必要信息而更深更大,并因这些不必要信息而降低对训练集的拟合。这也是防止过拟合的一种方式。
    @max_depth:树的最大深度:限制树的最大深度,超过设定深度的树枝全部剪掉,这是用得最广泛的剪枝参数,在高维度低样本量时非常有效。决策树多生长一层,对样本量的需求会增加一倍,所以限制树深度能够有效地限制过拟合。
    @min_samples_leaf:min_samples_leaf限定,一个节点在分枝后的每个子节点都必须包含至少min_samples_leaf个训练样本,否则分枝就不会发生,或者,分枝会朝着满足每个子节点都包含min_samples_leaf个样本的方向去发生。一般搭配max_depth使用,在回归树中有神奇的效果,可以让模型变得更加平滑。这个参数的数量设置得太小会引起过拟合,设置得太大就会阻止模型学习数据。
    @min_samples_split:min_samples_split限定,一个节点必须要包含至少min_samples_split个训练样本,这个节点才允许被分枝,否则分枝就不会发生。
    @max_features:用作树的”精修“。max_features限制分枝时考虑的特征个数,超过限制个数的特征都会被舍弃。和max_depth异曲同工,max_features是用来限制高维度数据的过拟合的剪枝参数,但其方法比较暴力
    @min_impurity_decrease:限制信息增益的大小,信息增益小于设定数值的分枝不会发生。
    @class_weight:完成样本标签平衡的参数。样本不平衡是指在一组数据集中,标签的一类天生占有很大的比例。使用class_weight参数对样本标签进行一定的均衡,给少量的标签更多的权重,让模型更偏向少类,向捕获少数类的方向建模。该参数默认None
    @min_weight_fraction_leaf:有了权重之后,样本量就不再是单纯地记录数目,而是受输入的权重影响了,因此这时候剪枝,就需要搭配min_weight_fraction_leaf这个基于权重的剪枝参数来使用。另请注意,基于权重的剪枝参数(例如min_weight_fraction_leaf)将比不知道样本权重的标准(比如min_samples_leaf)更少偏向主导类。如果样本是加权的,则使用基于权重的预修剪标准来更容易优化树结构,这确保叶节点至少包含样本权重的总和的一小部分。
 """
    
# 重要属性
# feature_importances_:能够查看各个特征对模型的重要性
    
# 重要方法:
# apply:输入测试集,返回每个测试样本所在的叶子节点的索引
# predict:输入测试集,返回每个测试样本的标签。
from sklearn import tree  # 树的模块
from sklearn.datasets import load_wine  # 导入红酒数据集
from sklearn.model_selection import train_test_split
import pandas as pd
import graphviz
import matplotlib.pyplot as plt
    
"""1.数据准备"""
wine = load_wine()
print(wine.data.shape)  # 数据有178个样本,13个特征
print(wine.target)  # 标签
pd.concat([pd.DataFrame(wine.data), pd.DataFrame(wine.target)], axis=1)
print(wine.feature_names, wine.target_names)  # 数据表格化
# 划分数据为训练集和测试集,test_size标示测试集数据占的百分比
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data, wine.target, test_size=0.3)
print(Xtrain.shape, Xtest.shape)

"""2.模型定义与训练"""
# 建立模型
clf = tree.DecisionTreeClassifier(criterion="entropy"
, random_state=30  # 保证模型稳定,每一次运行,所选取的特征不变
, splitter="random"
, max_depth=3
, min_samples_leaf=10  # 一个节点分支后,每一个子节点至少包含10个样本
, min_samples_split=10  # 一个节点至少包含10个样本才会分支
)

clf = clf.fit(Xtrain, Ytrain)  # 使用实例化好的模型进行拟合操作
score = clf.score(Xtest, Ytest)  # 返回预测的准确度
print(score)

"""3.可视化"""
# 对数据进行可视化
feature_name = ['酒精', '苹果酸', '灰', '灰的碱性', '镁', '总酚', '类黄酮', '非黄烷类酚类', '花青素', '颜色强度',
'色调', '稀释葡萄酒', '脯氨酸']

dot_data = tree.export_graphviz(clf  # 训练好的模型
, out_file=None
, feature_names=feature_name
, class_names=["琴酒", "雪莉", "贝尔摩德"]
, filled=True  # 进行颜色填充
, rounded=True  # 树节点的形状控制
)
graph = graphviz.Source(dot_data)

for feature_name, importance in [*zip(feature_name, clf.feature_importances_)]:
print(feature_name, importance)

"""4.确定最优参数"""
test = []
for i in range(10):
clf = tree.DecisionTreeClassifier(max_depth=i + 1
, criterion="entropy"
, random_state=30
, splitter="random"
)
clf = clf.fit(Xtrain, Ytrain)
score = clf.score(Xtest, Ytest)
test.append(score)
plt.plot(range(1, 11), test, color="red", label="max_depth")
plt.legend()
plt.show()

②回归树

class sklearn.tree.DecisionTreeRegressor (
criterion=’mse’, splitter=’best’, max_depth=None,min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None,random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, presort=False
)
"""
参数、重要属性、重要方法几乎相同
@criterion:mse:均方误差:父节点和叶子节点之间的均方误差的差额将被用来作为特征选择的标准;friedman_mse:费尔德曼均方误差;mae:绝对平均误差
"""
from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
import numpy as np
from sklearn.tree import DecisionTreeRegressor
import matplotlib.pyplot as plt

# 数据集导入
boston = load_boston()
# scoring 表示使用军方误差衡量模型、如果不写参数,对于回归模型,默认返回R平方,越接近1越好、均方误差越小越好
regressor = DecisionTreeRegressor(random_state=0)
# 交叉验证cross_val_score的用法(交叉验证用于验证模型的稳定性)
cross_val_score(regressor, boston.data, boston.target, cv=10, scoring="neg_mean_squared_error")

# 设置随机数种子,然后产生一个80*1的二维随机数数组,添加噪音
rng = np.random.RandomState(1)  # 设置随机数的种子
X = np.sort(5 * rng.rand(80, 1), axis=0)
y = np.sin(X).ravel()  # ravel()函数是降维函数
# 建立模型,并且进行拟合,建立回归树的深度不同
regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=5)
regr_1.fit(X, y)
regr_2.fit(X, y)
# np.arrange(开始,结束点,步长),生成有序数组的函数
# 产生一个序列,并且进行升维工作,np.newaxis是升维函数,然后进行预测
X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]
y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)
plt.figure()
plt.scatter(X, y, s=20, edgecolor="black", c="darkorange", label="data")
plt.plot(X_test, y_1, color="cornflowerblue", label="max_depth=2", linewidth=2)
plt.plot(X_test, y_2, color="yellowgreen", label="max_depth=5", linewidth=2)
plt.xlabel("data")
plt.ylabel("target")
plt.title("Decision Tree Regression")
plt.legend()
plt.show()

③多输出问题

多值输出问题是一个类似当 Y 是大小为 [n_samples, n_outputs] 的2d数组时,有多个输出值需要预测的监督学习问题。

当输出值之间没有关联时,一个很简单的处理该类型的方法是建立一个n独立模型,即每个模型对应一个输出,然后使用这些模型来独立地预测n个输出中的每一个。

然而,由于可能与相同输入相关的输出值本身是相关的,所以通常更好的方法是构建能够同时预测所有n个输出的单个模型。首先,因为仅仅是建立了一个模型所以训练时间会更短。第二,最终模型的泛化性能也会有所提升。

对于决策树,这一策略可以很容易地用于多输出问题。 这需要以下更改:在叶中存储n个输出值,而不是一个;通过计算所有n个输出的平均减少量来作为分裂标准。

# 多输出案例
import numpy as np
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeRegressor

# 生成测试数据集
# Z制作数据集
rng = np.random.RandomState(1)  # 设置随机数种子
X = np.sort(200 * rng.rand(100, 1) - 100, axis=0)
print(X.shape)  # 100*1

# y有两个标签
y = np.array([np.pi * np.sin(X).ravel(), np.pi * np.cos(X).ravel()]).T
# 给标签产生噪音
y[::5, :] += (0.5 - rng.rand(20, 2))

# 训练模型
regr_1 = DecisionTreeRegressor(max_depth=2)
regr_2 = DecisionTreeRegressor(max_depth=5)
regr_3 = DecisionTreeRegressor(max_depth=8)
regr_1.fit(X, y)
regr_2.fit(X, y)
regr_3.fit(X, y)

X_test = np.arange(-100.0, 100.0, 0.01)[:, np.newaxis]
y_1 = regr_1.predict(X_test)
y_2 = regr_2.predict(X_test)
y_3 = regr_3.predict(X_test)
y_1.shape  # (2000,2)

# max = 2
plt.figure()
s = 25
# 原始图像
plt.scatter(y[:, 0], y[:, 1], c="navy", s=s,
edgecolor="black", label="data")
plt.scatter(y_1[:, 0], y_1[:, 1], c="cornflowerblue", s=s,
edgecolor="red", label="max_depth=2")
plt.xlim([-6, 6])
plt.ylim([-6, 6])
plt.xlabel("target 1")
plt.ylabel("target 2")
plt.title("Multi-output Decision Tree Regression")
plt.legend(loc="best")
plt.show()

# max = 5
plt.figure()
s = 25
plt.scatter(y[:, 0], y[:, 1], c="navy", s=s,
edgecolor="black", label="data")
plt.scatter(y_2[:, 0], y_2[:, 1], c="red", s=s,
edgecolor="black", label="max_depth=5")
plt.xlim([-6, 6])
plt.ylim([-6, 6])
plt.xlabel("target 1")
plt.ylabel("target 2")
plt.title("Multi-output Decision Tree Regression")
plt.legend(loc="best")
plt.show()

# max = 8
plt.figure()
s = 25
plt.scatter(y[:, 0], y[:, 1], c="navy", s=s,
edgecolor="black", label="data")
plt.scatter(y_3[:, 0], y_3[:, 1], c="red", s=s,
edgecolor="black", label="max_depth=8")
plt.xlim([-6, 6])
plt.ylim([-6, 6])
plt.xlabel("target 1")
plt.ylabel("target 2")
plt.title("Multi-output Decision Tree Regression")
plt.legend(loc="best")
plt.show()

8.随机森林

1)随机森林就是通过集成学习的Bagging思想(将若干个弱分类器的分类结果进行投票,从而组成一个强分类器)将多棵树集成的一种算法,它的基本单元就是决策树。

2)森林中每棵树的随机生成过程
①设训练集的大小为N,则每棵树从训练集中随机且有放回的取出N个训练样本作为其训练集(每棵树的训练集不同,且可能包含重复样本)
②若存在M维特征,则每棵树在每个结点分裂时随机选择m维特征(m<M),使用这m维特征中的最佳特征来进行结点分裂。在森林生长过程中,m值保持不变

上述两个随机的引入对随机森林的性能至关重要,它们使得随机森林不易于过拟合,有较好的抗噪能力。

3)随机森林的分类性能

  • 分类性能:森林中任意两棵树的相关性越大,整体错误率也越大;每棵树的分类能力越强,错误率整体错误率越低(弱分类器应该好且不同)
  • OOB(袋外错误率 out-of-bag error):构建随机森林的关键是每次随机选取的m维特征,m参数主要依据OOB进行计算。

随机森林有一个重要的优点就是,没有必要对它进行交叉验证或者用一个独立的测试集来获得误差的一个无偏估计。它可以在内部进行评估,也就是说在生成的过程中就可以对误差建立一个无偏估计。oob误分率是随机森林泛化误差的一个无偏估计,它的结果近似于需要大量计算的k折交叉验证。这样,就可以通过比较oob误分率来选择一个最好的特征数m

计算方法:对每个样本作为oob样本,获取每棵树对它的分类情况,用投票法获得最终结果,用误分个数与样本总数的比例作为随机森林OOB的误分率

4)随机森林的特点

  • 能够处理具有高维特征的输入样本,而且不需要降维
  • 能够评估各个特征在分类问题上的重要性
  • 在生成过程中,能够获取到内部生成误差的一种无偏估计(OOB)
  • 对于缺省值问题也能够获得很好得结果

5)sklearn API

scikit-learn中,随机森林的分类器是RandomForestClassifier,回归器是RandomForestRegressor。其参数也包括两部分,第一部分是Bagging框架的参数,第二部分是一棵CART决策树的参数。

# 分类器
sklearn.ensemble.RandomForestClassifier(
n_estimators=10, criterion='gini',
max_depth=None,min_samples_split=2, 
min_samples_leaf=1, min_weight_fraction_leaf=0.0,
max_features='auto', max_leaf_nodes=None,
min_impurity_split=1e-07,bootstrap=True,
oob_score=False, n_jobs=1, 
random_state=None, verbose=0,
warm_start=False, class_weight=None)
"""Bagging框架参数
@n_estimators:弱学习器(决策树)的个数。一般来说n_estimators太小,容易欠拟合,n_estimators太大,计算量会太大,并且n_estimators到一定的数量后,再增大n_estimators获得的模型提升会很小,所以一般选择一个适中的数值。默认是100
@oob_score:即是否采用袋外样本来评估模型的好坏。默认False。推荐设置为True,因为袋外分数反应了一个模型拟合后的泛化能力
@criterion: CART树做划分时对特征的评价标准。分类模型和回归模型的损失函数是不一样的。分类RF对应的CART分类树默认是基尼系数gini,另一个可选择的标准是信息增益(information gain)。回归RF对应的CART回归树默认是均方差mse,另一个可以选择的标准是绝对值差mae。一般来说选择默认的标准就已经很好的
"""
"""决策树参数
@max_features:在每个节点处,从M中随机选择m个特征维度”中的那个m。默认是"auto",意味着每个节点在划分时随机考虑根号N个特征;如果是"log2"意味着划分时随机考虑log_2^N个特征;如果是整数,代表考虑的特征绝对数。如果是浮点数,代表考虑特征百分比,即考虑百分比*总特征维度数取整后的特征数。一般用默认的"auto"就可以了
@max_depth:决策树最大深度
@min_samples_split:内部节点再划分所需最小样本数
@min_samples_leaf:叶子节点最少样本数
@min_weight_fraction_leaf:叶子节点最小的样本权重
@max_leaf_nodes: 最大叶子节点数
@min_impurity_split: 节点划分最小不纯度
"""

9.集成学习

1)概念

集成学习就是组 合这里的多个弱监督模型以期得到一个更好更全面的强监督模型,集成学习潜在的思想是即便某一个弱分类器得到 了错误的预测,其他的弱分类器也可以将错误纠正回来。 集成方法是将几种机器学习技术组合成一个预测模型的元算法,以达到减小方差(bagging)、偏差(boosting) 或改进预测(stacking)的效果。 集成学习在各个规模的数据集上都有很好的策略:

  • 数据集大:划分成多个小数据集,学习多个模型进行组合
  • 数据集小:利用Bootstrap方法进行抽样,得到多个数据集,分别训练多个模型再进行组合

2)分类

  • 序列集成方法(Boosting) 其中参与训练的基础学习器按照顺序生成(例如 AdaBoost)。序列方法的原理是利用基础学习器之间的依赖关系。通过对之前训练中错误标记的样本赋值较高的权重,可以提高整体的预测效果

    过程:先在原数据集上构建一个分类器、把前一个分类器未能完美分类的数据重新weight、用新的赋权后的数据再训练一个分类器、最终的分类结果由加权投票决定

image-20231112183756626

代表算法:AdaBoost、GBDT

import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import AdaBoostClassifier
from sklearn.datasets import make_gaussian_quantiles
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier

if __name__ == '__main__':
    """1.构建二维数据"""
    X1, y1 = make_gaussian_quantiles(n_classes=2, n_samples=300, cov=2)  # 服从高斯分布
    X2, y2 = make_gaussian_quantiles(n_classes=2, n_samples=400, cov=1, mean=(3, 3))
    X = np.vstack((X1, X2))
    Y = np.hstack((y1, y2))
    plt.scatter(X[:, 0], X[:, 1], c=Y)
    plt.show()
    x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.2)
    """2.模型构建 AdaBoost
    AdaBoost 的核心思想是用反复修改的数据来训练一系列的弱学习器(一个弱学习器模型仅仅比随机猜测好一点, 
    比如一个简单的决策树,由这些弱学习器的预测结果通过加权投票(或加权求和)的方式组合, 得到我们最终的预测结果。在每一次所谓的提升(boosting)迭代中,
    数据的修改由应用于每一个训练样本的(新)的权重w1,w2,…,wN组成(即修改每一个训练样本应用于新一轮学习器的权重)
    初始化时,将所有弱学习器的权重都设置为1/N,因此第一次迭代仅仅是通过原始数据训练出一个弱学习器。
    在接下来的连续迭代中,样本的权重逐个地被修改,学习算法也因此要重新应用这些已经修改的权重。
    在给定的一个迭代中,那些在上一轮迭代中被预测为错误结果的样本的权重将会被增加,而那些被预测为正确结果的样本的权 重将会被降低。
    随着迭代次数的增加,那些难以预测的样例的影响将会越来越大,每一个随后的弱学习器都将 会被强迫更加关注那些在之前被错误预测的样例
    """
    abc = AdaBoostClassifier(
        base_estimator=DecisionTreeClassifier(max_depth=2, min_samples_split=4),  # base_estimator=None:基学习器,默认是决策树
        n_estimators=10,  # n_estimators=50:迭代次数
        learning_rate=1.0  # learning_rate=1.0
    )
    """3.训练得到结果"""
    abc.fit(x_train, y_train)
    print(abc.score(x_train, y_train))
    print(abc.feature_importances_)
    print(abc.estimator_errors_)  # 错误率
    print(abc.estimator_weights_)  # 权重
    """4.评估"""
    y_pred = abc.predict(x_test)
    print(abc.score(x_test, y_test))
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

if __name__ == '__main__':
    data, target = load_iris(return_X_y=True)
    x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.2)
    """创建模型GBDT
    DT-Decision Tree决策树,GB是Gradient Boosting,是一种学习策略,GBDT的含义就是用Gradient Boosting的策略训练出来的DT模型
    (使用GB+回归树组合的策略叫GBRT)。模型的结果是一组回归分类树组合(CART TreeEnsemble):T1,...,Tk 。
    其中Tj学习的是之前Tj-1棵树预测结果的残差,这种思想就像准备考试前的复习,先做一遍习题册,然后把做错的题目挑出来,在做一次,
    然后把做错题挑出来再做一次,经过反复多轮训练,取得最好的成绩。每一次的计算是为了减少上一次的残差,GBDT在残差减少(负梯度)的方向上建立一个新模型
    """
    gbdt = GradientBoostingClassifier(
        learning_rate=0.1,  # 学习率
        n_estimators=10  # 迭代次数
    )
    # 训练
    gbdt.fit(x_train, y_train)
    print(gbdt.score(x_test, y_test))  # 得分
    print(gbdt.estimators_)
    print(gbdt.feature_importances_)
    print(gbdt.train_score_)  # 表示在样本集上每次迭代以后的对应的损失函数值,损失越来越小
  • 并行集成方法(Bagging) 其中参与训练的基础学习器并行生成(例如 Random Forest)。并行方法的原理是利用基础学习器之间的独立性,通过平均可以显著降低错误

    代表算法:Bagging 元估计器、随机森林、极限随机树(ET或Extra-Trees(Extremely randomized trees)算法与随机森林算法十分相似,使用的所有的样本,只是特征是随机选取的,因为分裂是随机 的,所以在某种程度上比随机森林得到的结果更加好)

两者的区别:

  • 样本选择上
    • Bagging:训练集是在原始集中有放回选取的,从原始集中选出的各轮训练集之间是独立的
    • Boosting:每一轮的训练集不变,只是训练集中每个样例在分类器中的权重发生变化。而权值是根据上一轮的分类结果进行调整。
  • 样例权重
    • Bagging:使用均匀取样,每个样例的权重相等
    • Boosting:根据错误率不断调整样例的权值,错误率越大则权重越
  • 预测函数
    • Bagging:所有预测函数的权重相等
    • Boosting:每个弱分类器都有相应的权重,对于分类误差小的分类器会有更大的权重
  • 并行计算
    • Bagging:各个预测函数可以并行生成
    • Boosting:各个预测函数只能顺序生成,因为后一个模型参数需要前一轮模型的结果

4)Stacking

Stacking方法是指训练一个模型用于组合其他各个模型。首先我们先训练多个不同的模型,然后把之前训练的各 个模型的输出为输入来训练一个模型,以得到一个最终的输出。理论上,Stacking可以表示上面提到的两种 Ensemble方法,只要我们采用合适的模型组合策略即可。但在实际中,我们通常使用logistic回归作为组合策略

from sklearn.ensemble import StackingClassifier
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.datasets import load_breast_cancer
if __name__ == '__main__':
    estimators = [
        ('KNN', KNeighborsClassifier()),
        ('LR', LogisticRegression(solver='liblinear')),
        ('DT', DecisionTreeClassifier()),
        ('SVC', SVC()),
        ("RFC", RandomForestClassifier()),
        ('GBDT', GradientBoostingClassifier())
    ]
    stack = StackingClassifier(estimators=estimators)
    data, target = load_breast_cancer(return_X_y=True)
    x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.2)
    stack.fit(x_train, y_train)
    stack.predict(x_test)
    print(stack.score(x_test, y_test))

10.支持向量机SVM

1)Support Vector Machine,是通过支持向量和超平面(只使用部分数据)确定样本类别的分类器。其目标是在一个空间中找到一个最大间隔超平面能使得超平面将样本正确二分类,超平面两侧距离最大间隔超平面的样本被称为支持向量。它们到最大间隔超平面的距离最远。

2)推导

设n维空间中的点到该空间中超平面 w T x + b = 0 w^Tx+b=0 wTx+b=0的距离为: ∣ w T x + b ∣ ∣ ∣ w ∣ ∣ 2 \frac {|w^Tx+b|} {||w||_2} ∣∣w2wTx+b,设支持向量到超平面的距离为d,则其余点到超平面的距离大于d。则有:
∣ w T x + b ∣ ∣ ∣ w ∣ ∣ 2 ≥ d        y = 1 ; ∣ w T x + b ∣ ∣ ∣ w ∣ ∣ 2 ≤ d        y = − 1 即 ∣ w T x + b ∣ ∣ ∣ w ∣ ∣ 2 d ≥ 1        y = 1 ; , ∣ w T x + b ∣ ∣ ∣ w ∣ ∣ 2 d ≤ 1        y = − 1 令 ∣ ∣ w ∣ ∣ 2 d = 1 (对优化无影响),则有: ∣ w T x + b ∣ ≥ 1        y = 1 ; , ∣ w T x + b ∣ ≤ 1        y = − 1 整理得, y ( w T x + b ) ≥ 1 每个支持向量到超平面的距离为: d = ∣ w T x + b ∣ ∣ ∣ w ∣ ∣ 由 y ( w T x + b ) > 1 > 0 → y ( w T x + b ) = ∣ w T x + b ∣ 则 , d = y ( w T x + b ) ∣ ∣ w ∣ ∣ 最大化该距离得: 2 d m a x = m a x    2 y ( w T x + b ) ∣ ∣ w ∣ ∣ 由支持向量到超平面的距离为 1 ,则有: m a x    2 ∣ ∣ w ∣ ∣ 为方便优化则有: m i n 1 2 ∣ ∣ w ∣ ∣ 2      s . t . y i ( w T x i + b ) ≥ 1 \frac {|w^Tx+b|} {||w||_2} ≥ d \;\;\; y=1 ;\frac {|w^Tx+b|} {||w||_2} ≤ d \;\;\; y=-1 \\ 即 \frac {|w^Tx+b|} {||w||_2d} ≥ 1 \;\;\; y=1;,\frac {|w^Tx+b|} {||w||_2d} ≤ 1 \;\;\; y=-1 \\ 令||w||_2d=1(对优化无影响),则有: \\ |w^Tx+b| ≥ 1 \;\;\; y=1;,{|w^Tx+b|} ≤ 1 \;\;\; y=-1 \\ 整理得, y(w^Tx+b)≥1 \\ 每个支持向量到超平面的距离为:d = \frac {|w^Tx+b|} {||w||} \\ 由 y(w^Tx+b) > 1 > 0 → y(w^Tx+b) = |w^Tx+b| \\ 则,d = \frac {y(w^Tx+b)} {||w||} \\ 最大化该距离得: 2d_{max} = max \; 2 \frac {y(w^Tx+b)} {||w||} \\ 由支持向量到超平面的距离为1,则有: max \; \frac 2 {||w||} \\ 为方便优化则有:min \frac 1 2 ||w||^2 \;\; s.t. y_i(w^Tx_i+b)≥1 ∣∣w2wTx+bdy=1;∣∣w2wTx+bdy=1∣∣w2dwTx+b1y=1;∣∣w2dwTx+b1y=1∣∣w2d=1(对优化无影响),则有:wTx+b1y=1;wTx+b1y=1整理得,y(wTx+b)1每个支持向量到超平面的距离为:d=∣∣w∣∣wTx+by(wTx+b)>1>0y(wTx+b)=wTx+b,d=∣∣w∣∣y(wTx+b)最大化该距离得:2dmax=max2∣∣w∣∣y(wTx+b)由支持向量到超平面的距离为1,则有:max∣∣w∣∣2为方便优化则有:min21∣∣w2s.t.yi(wTxi+b)1

优化求解的方法:拉格朗日乘子法: L ( w , b , λ ) = 1 2 ∣ ∣ w ∣ ∣ 2 − ∑ i = 1 n λ i ( y i ( w T ⋅ Φ ( x i ) + b ) − 1 ) L(w,b,λ) = \frac 1 2 ||w||^2 - \sum_{i=1}^n λ_i(y_i(w^T·Φ(x_i)+b)-1) L(w,b,λ)=21∣∣w2i=1nλi(yi(wTΦ(xi)+b)1)

3)软间隔

之前寻找最大超平面的分法过于严格,可能导致模型不够健壮,为解决此问题,引入松弛因子,使得 y i ( w x i + b ) ≥ 1 − η i y_i(wx_i+b)≥1-η_i yi(wxi+b)1ηi

4)线性不可分与核函数

5)简单示例

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.svm import SVC, SVR
from sklearn.datasets import make_blobs
if __name__ == '__main__':

# 构造数据
data, target = make_blobs(centers=2)
plt.scatter(data[:, 0], data[:, 1], c=target)
# 定义模型并拟合
svc = SVC(C=1.0, kernel='linear')
"""
C=1.0:  C越大越严格, C越小越不严格(容忍度更高)
kernel='rbf'  核函数
'linear',  线性核函数
'poly',   多项式核函数
'rbf'    默认值,高斯核函数,基于半径核函数(radius based function), 常用
"""
svc.fit(data, target)
# 提取系数
w1, w2 = svc.coef_[0]
b = svc.intercept_[0]
print(w1, w2, b)
# 可视化
plt.scatter(data[:, 0], data[:, 1], c=target)
# 分割线
x = np.linspace(-6, 2, 10)
y = -(w1 * x + b) / w2
plt.plot(x, y)
# 获取支持向量
print(svc.support_vectors_)
# 画支持向量所在直线
plt.scatter(data[:, 0], data[:, 1], c=target)

# 分割线
x = np.linspace(-10, 10, 10)
y = -(w1 * x + b) / w2
plt.plot(x, y, c='r')

# 画支持向量的点
vectors = svc.support_vectors_
plt.scatter(vectors[:, 0], vectors[:, 1], s=200, alpha=0.5, cmap='rainbow')
plt.show()

6)多核示例

import numpy as np
from matplotlib import pyplot as plt
from sklearn.datasets import load_iris
from sklearn.svm import LinearSVC   # LinearSVC : 经过优化的线性核函数
from sklearn.svm import SVC
if __name__ == '__main__':
data, target = load_iris(return_X_y=True)
data2 = data[:, :2].copy()  # 仅使用两个维度
print(data2.shape, target.shape)
# 4种核函数
svcs = {
'linearSVC': LinearSVC(),
'linear': SVC(kernel='linear'),
'poly': SVC(kernel='poly'),
'rbf': SVC(kernel='rbf')
}

x = np.linspace(data2[:, 0].min(), data2[:, 0].max(), 1000)
y = np.linspace(data2[:, 1].min(), data2[:, 1].max(), 1000)
X, Y = np.meshgrid(x, y)
XY = np.c_[X.ravel(), Y.ravel()]

plt.figure(figsize=(2 * 5, 2 * 5))
for i, key in enumerate(svcs):
# 使用每一种svc模型训练
svc = svcs[key]
svc.fit(data2, target)
# 预测
y_pred = svc.predict(XY)
# 子图
axes = plt.subplot(2, 2, i + 1)
# 分界图
axes.pcolormesh(X, Y, y_pred.reshape(1000, 1000))
# 散点图
axes.scatter(data2[:, 0], data2[:, 1], c=target, cmap='rainbow')
# 标题
axes.set_title(key, fontsize=20)
plt.show()

11.K-means

K均值算法是一种聚类分析,通过不断地取离种子点最近均值。

算法思想:对于给定的样本集,按照样本之间的距离大小,将样本集划分为K个簇,让簇内的点尽量紧密连接,而让簇间的距离尽量的大

算法步骤:

  • 从数据中选择k个对象作初始聚类中心
  • 根据每个样本到聚类中心的距离来划分簇
  • 再次计算每个聚类中心
  • 计算标准测度函数,直到达到最大迭代次数则停止,否则重复上述过程
  • 确定最优的聚类中心
image-20231109101459061

算法优势:简单、快速、适合常规数据集

算法缺陷:

  • K值需事先给定:K值的选定是非常难以估计的。很多时候,事先并不知道给定的数据集应该分成多少个类别才最合适。(ISODATA算法通过类的自动合并和分裂,得到较为合理的类型数目K)
  • 初始聚类中心需随机选定:K-Means算法需要用初始随机种子点来搞,这个随机种子点太重要,不同的随机种子点会有得到完全不同的结果。(K-Means++算法可以用来解决这个问题,其可以有效地选择初始点)
  • 复杂度与样本数正相关、难以发现任意形状的簇

代码示例

# 简单示例
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs

if __name__ == '__main__':
data, target = make_blobs()
plt.scatter(data[:, 0], data[:, 1], c=target)
# cluster 聚类算法
from sklearn.cluster import KMeans

kmeans = KMeans(
# n_clusters=8 : K值,K个种子点,默认8个,也就是默认分成8组
n_clusters=3,
# init='k-means++' : K个种子点的初始位置算法
init='k-means++')
kmeans.fit(data)  # 训练,只需要给data,不需要提供target
print(kmeans.labels_)   # labels_: 分组结果
plt.scatter(data[:, 0], data[:, 1], c=kmeans.labels_)
centers = kmeans.cluster_centers_   # 聚类中心点
print(centers)
plt.scatter(centers[:, 0], centers[:, 1], s=200, alpha=0.5, c='r')
plt.show()
image-20231109104258579
# 图片颜色聚类
from io import BytesIO

import numpy as np
import requests
from PIL import Image
from matplotlib import pyplot as plt
from sklearn.cluster import KMeans
from sklearn.utils import shuffle

if __name__ == '__main__':
response = requests.get('https://th.bing.com/th/id/OIP.WR-OjfhkqHMT7FkJF9L1AgHaE7')
image_data = response.content
flower = Image.open(BytesIO(image_data))
flower = np.array(flower)
print(flower.shape)
plt.imshow(flower)
plt.show()
data = flower.reshape(-1, 3)
print(data.shape)
data_train = shuffle(data.copy())[:1000]  # 打乱顺序取1000个颜色点
print(data_train.shape)
"""保留主要的颜色聚成几类"""
for i in (64, 16, 4):
kmeans = KMeans(i)
kmeans.fit(data_train)
"""预测27万个颜色点所属的分类是哪一个"""
labels = kmeans.predict(data)
centers = kmeans.cluster_centers_
new_flower = centers[labels].reshape(flower.shape) / 255
plt.imshow(new_flower)
plt.show()

12.DBSCAN

Density-Based Spatial Clustering of Applications with Noise

基本概念:

  • 核心对象:若某个点的密度达到算法设定的阈值则其位核心点
  • e-邻域半径:密度半径r
  • 直接密度可达:若p在q的邻域内,且q是核心点,则p-q直接密度可达
  • 密度可达:若有一个点的序列q0、q1、…、qk,对任意qi-q(i-1)是密度可达的,则称q0到qk密度可达,这实际上是直接密度可达的传播
  • 边界点:属于某一类的非核心点,不能再密度连接了
  • 离群点(噪声点):不属于任何一个类簇的点,从任何一个核心点出发都是密度不可达的

A:核心对象;B、C:边界点;N:离群点

算法描述:

算法优势:

  • 不需要预先指定簇个数
  • 可以发现任意形状的簇
  • 擅长找到离群点(异常检测)

算法劣势:

  • 高维数据有点困难
  • 参数不好选择(参数对结果的影响大)
  • 效率较慢

程序示例:

import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_circles
if __name__ == '__main__':
data, target = make_circles(
n_samples=300,
noise=0.08,  # 噪声
factor=0.3  # 中间点的离散程度
)
plt.scatter(data[:, 0], data[:, 1], c=target)
plt.show()
dbscan = DBSCAN(
# eps=0.5, 半径
eps=0.2,
# min_samples=5, 形成簇所需的最小样本数
min_samples=3)
dbscan.fit(data)
labels = dbscan.labels_
plt.scatter(data[:, 0], data[:, 1], c=labels)
plt.show()

13.轮廓系数

轮廓系数 Silhouette Coefficient是聚类算法的评估指标

计算公式:

  • 簇内不相似度:计算样本i到同簇其他样本的平均距离ai。ai 越小,说明样本i越应该被聚类到该簇。将ai 称为样本i的簇内不相似度。

  • 簇间不相似度:计算样本i到其他某簇Cj 的所有样本的平均距离bij,称为样本i与簇Cj 的不相似度。定义为样本i的簇间不相似度:bi =min{bi1, bi2, …, bik}

  • si接近1,则说明样本i聚类合理;si接近-1,则说明样本i更应该分类到另外的簇;若si 近似为0,则说明样本i在两个簇的边界上

适用性:

  • 对于簇结构为凸的数据轮廓系数较高,对于簇结构非凸的轮廓系数较低。因此,轮廓系数不能在不同的算法之间比较优劣,如统一数据下,可能KMeans的结果就比DBSCAN要好。
  • 对于同种算法:轮廓系数越大越好

程序示例:

# 用轮廓系数评估DBSCAN
import sys
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_circles
from sklearn.metrics import silhouette_score

if __name__ == '__main__':
data, target = make_circles(
n_samples=300,
noise=0.2,
factor=0.3
)
plt.scatter(data[:, 0], data[:, 1], c=target)
plt.show()
scores = []
eps_init = 0.05
for i in range(10):
eps = eps_init + i * 0.01
dbscan = DBSCAN(eps=eps, min_samples=2)
labels = dbscan.fit(data).labels_
plt.scatter(data[:, 0], data[:, 1], c=labels)
# plt.show()
unique_labels = len(set(labels))  # Count the unique labels
# Check if there are at least 2 unique labels
if unique_labels >= 2:
score = silhouette_score(data, labels)
# print(score)
scores.append(score)
else:
scores.append(None)

# Plotting code remains the same
plt.plot(list(range(10)), scores)
plt.xticks(list(range(10)))
plt.grid()
plt.show()

14.主成分分析

主成分分析

15.评价指标

1)Precision、Recall、F-measure、Accuracy

image-20231112104630579
# 计算示例
"""
问题描述:假设有100个样本,其中有正样本70个,负样本30个,系统查出有50个正样本,其中有30个是真正的正样本
求:精准率precision, 召回率recall, F1值,准确率Accuracy?
"""
TP = 30
FP = 20
TN = 10
FN = 40
# 精准率precision(预测情况): 查准率
precision = TP / (TP + FP)
# 召回率recall (真实情况):查全率
recall = TP / (TP + FN)
# F1值:
F1 = 2 * precision * recall / (precision + recall)
# 准确率Accuracy
accuracy = (TP + TN) / (TP + TN + FP + FN)
print(precision, recall, F1, accuracy)

2)ROC和AUC

  • AUC:AUC是一个模型评价指标,用于二分类模型的评价。AUC是“Area under Curve(曲线下的面积)”的英文缩写,而这条“Curve(曲线)”就是ROC曲线。
  • ROC曲线:受试者工作特征曲线/接收者操作特征曲线(receiver operating characteristic curve)
    • True Positive Rate=TP/(TP+FN),代表将真实正样本划分为正样本的概率 真阳率
    • False Positive Rate=FP/(FP+TN),代表将真实负样本划分为正样本的概率 伪阳率
    • 以“True Positive Rate”作为纵轴,以“False Positive Rate”作为横轴,画出ROC曲线:
image-20231112104935775
import matplotlib.pyplot as plt
from sklearn.metrics import auc, roc_curve
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
"""绘制ROC曲线和计算AUC"""
data, target = load_iris(return_X_y=True)
# 只使用前2维
cond = target < 2
data2 = data[cond].copy()
target2 = target[cond].copy()
print(data2.shape, target2.shape)
x_train, x_test, y_train, y_test = train_test_split(data2, target2, test_size=0.2)
print(x_train.shape, x_test.shape)
# 逻辑斯蒂回归
lr = LogisticRegression()
lr.fit(x_train, y_train)
# 预测
y_pred = lr.predict(x_test)
# ROC曲线
fpr, tpr, _ = roc_curve(y_test, y_pred)
plt.plot(fpr, tpr, ls='--')
# 计算AUC值:ROC曲线下的面积
auc(fpr, tpr)
plt.show()
"""交叉验证下不同的数据,auc是多少, 平均auc是多少"""
# 数据集增加噪声:水平拼接了500列随机值
data3 = np.hstack((data2, np.random.randn(100, 500)))
# 5折,分成5份
skf = StratifiedKFold(n_splits=5)
# 遍历5次
for train, test in skf.split(data3, target2):
    # 训练数据,测试数据
    x_train = data3[train]
    x_test = data3[test]
    y_train = target2[train]
    y_test = target2[test]
    # LR
    lr = LogisticRegression()
    lr.fit(x_train, y_train)
    # 预测
    y_proba = lr.predict_proba(x_test)
    # ROC曲线
    fpr, tpr, _ = roc_curve(y_test, y_proba[:, -1])  # 将y_proba的最后一列传入
    # AUC值
    a = auc(fpr, tpr)
    print(f'auc: {a}')
    print(f'fpr: {fpr}')
    print(f'tpr: {tpr}')
    print('*' * 100)
    # 画ROC曲线
    plt.plot(fpr, tpr, label=f'auc:{np.round(a, 3)}')
    plt.legend()
    plt.show()

16.EDA探索性数据分析

1)概念

探索性数据分析(EDA)是由数据科学家用来分析和调查数据集,并总结其主要特征,通常采用数据可视化方法。它有助于确定如何最好地操作数据源以获得你所需要的答案,使数据科学家更容易发现模式,发现异常测试一个假设,或检查假设。

EDA的主要目的是做出任何假设之前帮助观察数据。它可以帮助识别明显的错误,以及更好地理解数据中的模式检测异常值或异常事件,找到变量间的有趣关系

2)为什么要进行EDA

  • 对数据集更深的理解(分布、缺失等统计信息)
  • 获得高质量的数据集(异常值、缺失值的基本处理)
  • 机器学习模型、实证假设构建的思路(灵感)

3)基本流程与方法

  • 基本前提:数据+问题/需求
  • 数据基本情况的了解:数据量、特征数量、数据类型;数据分布情况(标准差、分位数、最大最小值)
  • 数据的基本处理:缺失值、重复值、异常值处理
  • 数据可视化
    • 单变量可视化(数据分布直方图、箱线图)
    • 两个变量的可视化(相关性分析、折线图、散点图、热力图)
    • 时间维度的可视化:时间序列分析-折线图

17.Apriori算法

1)推荐系统

海量的数据产⽣也带来了信息过载和选择障碍的困扰,每个⽤户的时间和精⼒是有限的,怎样帮助⽤户 进⾏信息的过滤和选择,在当下是⾮常有价值的,此时推荐系统就应运⽽⽣了。

推荐算法是整个推荐系统中最核⼼、最关键的部分,很⼤程度上决定了推荐系统性能的优劣。⽬前,主要的推荐算法如下:

  • 基于内容的推荐
  • 协同过滤推荐
  • 基于关联规则的推荐
  • 基于知识的推荐
  • 混合推荐

2)关联分析

关联分析(association analysis)是⼀种在⼤规模数据集中寻找有趣关系的无监督学习算法。是利⽤⼀些有趣性的量度来识别数据库中的强规则。这种关系可以有两种形式:频繁项集或者关联规则

  • 频繁项集(frequent item sets)是经常一块出现的物品集合
  • 关联规则(association rules)暗示两种物品之间可能存在很强的关系

简单示例:

交易号码商品
001⾖奶,莴苣
002莴苣,尿布,啤酒,甜菜
003⾖奶,尿布,啤酒,橙汁
004莴苣,⾖奶,尿布,啤酒
005莴苣,⾖奶,尿布,橙汁
  • 事务:每⼀条交易称为⼀个事务。例如,在这个例⼦中包含了5个事务。
  • 项:交易的每⼀个物品称为⼀个项,例如⾖奶、尿布等。
  • 项集:包含零个或者多个项的集合叫做项集,例如 {⾖奶,莴苣}。
  • k-项集:包含k个项的项集叫做k-项集。例如 {⾖奶} 叫做1-项集,{⾖奶,尿布,啤酒} 叫做3-项 集。
  • 前件和后件:对于规则{尿布}→{啤酒},{尿布} 叫做前件,{啤酒} 叫做后件。

啤酒与尿布的故事

3)频繁项集的评估指标

频繁项集是经常出现在⼀块的物品的集合,那么问题就来了:

  • 当数据量⾮常⼤的时候,我们⽆法凭⾁眼找出经常出现在⼀起的物品,这就催⽣了关联规则挖掘算法,⽐如 Apriori、PrefixSpan、CBA 等。
  • 我们缺乏⼀个频繁项集的标准。

常用的频繁项集评估指标:

  • 支持度:⼏个关联的数据在数据集中出现的次数占总数据集的⽐重。或者说⼏个数据关联出现的概率。如果我们有两个想分析关联性的数据X和Y,则对应的⽀持度为:

    S u p p o r t ( X , Y ) = P ( X Y ) = n u m ( X Y ) n u m ( A l l S a m p l e s ) Support(X,Y)= P(XY) = \frac {num(XY)} {num(AllSamples)} Support(X,Y)=P(XY)=num(AllSamples)num(XY),e.g. S u p p o r t ( 啤酒,尿布 ) = 3 5 = 0.6 Support(啤酒,尿布) = \frac 3 5 = 0.6 Support(啤酒,尿布)=53=0.6

    以此类推,3个关联性数据X,Y,Z的支持度为:
    S u p p o r t ( X , Y , Z ) = P ( X Y Z ) = n u m ( X Y Z ) n u m ( A l l S a m p l e s ) Support(X,Y,Z)= P(XYZ) = \frac {num(XYZ)} {num(AllSamples)} Support(X,Y,Z)=P(XYZ)=num(AllSamples)num(XYZ)

    ⼀般来说,⽀持度⾼的数据不⼀定构成频繁项集,但是⽀持度太低的数据肯定不构成频繁项集。 另外, ⽀持度是针对项集来说的,因此,可以定义⼀个最⼩⽀持度,⽽只保留满⾜最⼩⽀持度的项集,起到⼀个项集过滤的作⽤。此外,⽀持度还具有⼀种期望的性质,可以⽤于关联规则的有效发现。

  • 置信度:体现了⼀个数据出现后,另⼀个数据出现的概率,或者说数据的条件概率。如果我们有两个想分 析关联性的数据X和Y,X对Y的置信度为:

    C o n f i d e n c e ( X → Y ) = P ( Y ∣ X ) = P ( X Y ) P ( X ) Confidence(X→Y) = P(Y|X) = \frac {P(XY)} {P(X)} Confidence(XY)=P(YX)=P(X)P(XY)
    e.g. C o n f i d e n c e ( 莴苣 → 豆奶 ) = P ( 豆奶 ∗ 莴苣 ) P ( 莴苣 ) = 3 5 4 5 = 0.6 0.8 = 0.75 Confidence(莴苣 → 豆奶) = \frac {P(豆奶 * 莴苣)} {P(莴苣)} = \frac {\frac 3 5} {\frac 4 5} = \frac {0.6} {0.8} = 0.75 Confidence(莴苣豆奶)=P(莴苣)P(豆奶莴苣)=5453=0.80.6=0.75

    依次类推到个关联性数据X,Y,Z: C o n f i d e n c e ( X Y → Z ) = P ( Z ∣ X Y ) = P ( X Y Z ) P ( X Y ) Confidence(XY→Z) = P(Z|XY) = \frac {P(XYZ)} {P(XY)} Confidence(XYZ)=P(ZXY)=P(XY)P(XYZ)

    置信度度量通过规则进⾏推理具有可靠性。对于给定的规则X→Y,置信度越⾼,Y在包含X的 事务中出现的可能性就越⼤。置信度也可以估计Y在给定X下的条件概率。

  • 提升度:提升度用于解决支持度和置信度的局限性(⽀持度的缺点在于许多潜在的有意义的模式由于包含⽀持度⼩的项⽽被删去,置信度的缺陷在于该度量忽略了规则后件中项集的⽀持度,⾼置信度的规则有时可 能出现误导)

    提升度表示X→Y的置信度与后件Y的支持度之比$lift(X→Y) = \frac {confidence(X→Y)} {support(Y)},提升度体现了X和Y之间的关联关系,提升度>1则X→Y是有效的强关联规则,<1是无效的强关联规则。一个特殊的情况是,=1,则X和Y独立

4)关联规则发现

给定事务的集合T,关联规则发现是指找出⽀持度⼤于等于 m i n S u p p o r t min_{Support} minSupport并且置信度⼤于等于 m i n C o n f i d e n c c e min_{Confidencce} minConfidencce的所有规则。

挖掘关联规则的⼀种原始⽅法是: 计算每个可能规则的⽀持度和置信度。但是这种⽅法的代价很⾼,令⼈望⽽却步,因为可以从数据集提 取的规则的数⽬达指数级。更具体地说,从包含d个项的数据集提取的可能规则的总数为: R = 3 d − 2 d + 1 + 1 R=3^d-2^{d+1} + 1 R=3d2d+1+1。其中,⼤部分计算是⽆⽤的开销。为了避免进⾏不必要的计 算,事先对规则剪枝,⽽⽆须计算它们的⽀持度和置信度的值将是有益的。 因此,⼤多数关联规则挖掘 算法通常采⽤的⼀种策略是,将关联规则挖掘任务分解为如下两个主要的⼦任务:

  • 频繁项集产⽣:其⽬标是发现满⾜最⼩⽀持度阈值的所有项集,这些项集称作频繁项集(frequent itemset)
  • 规则的产⽣:其⽬标是从上⼀步发现的频繁项集中提取所有⾼置信度的规则,这些规则称作强规则(strong rule)

通常,频繁项集产⽣所需的计算开销远⼤于产⽣规则所需的计算开销。那有没有办法可以减少这种⽆⽤ 的计算呢?有。下⾯这两种⽅法可以降低产⽣频繁项集的计算复杂度:

  • 减少候选项集的数目M
  • 减少比较次数:替代将每个候选项集与每个事务相匹配,可以使⽤更⾼级的数据结构,或者存储 候选项集或者压缩数据集,来减少⽐较次数

5)Apriori算法

  • 频繁项集筛选原理

先验原理: 如果⼀个项集是频繁的,则它的所有⼦集⼀定也是频繁的

推广:如果⼀个项集是⾮频繁项集, 那么它的所有超集也是非频繁的

{1,2,3}是频繁项集合 则其所有子集也一定是频繁的;若{2,3}是非频繁的,则其超集{0,2,3}、{1,2,3}、{0,1,2,3}也是非频繁的

image-20231113105544952
  • 频繁项集筛选过程
image-20231113105749332

C1,C2,…,Ck分别表示1-项集,2-项集,…,k-项集;L1,L2,…,Lk分别表示有k个数据项的频繁项集。

Scan表示数据集扫描函数。该函数起到的作⽤是⽀持度过滤,满⾜最⼩⽀持度的项集才留下,不满⾜最小⽀持度的项集直接舍掉。

  • 挖掘关联规则的流程:分级法

从⼀个频繁项集开始,创建⼀个规则列表,其中规则右部只包含⼀个元 素,然后计算这些规则的置信度。接下来合并所有剩余规则,创建⼀个新的规则列表,其中右部包含两 个元素,计算这些规则的置信度……如此循环,遍历所有的规则。

image-20231113110740463

18.推荐系统

1)推荐系统介绍

推荐建立在海量数据挖掘基础上,向用户提供个性化的信息服务 和决策支持。分为个性化推荐非个性化推荐

  • 个性化推荐:千人千面,精准到个人一面
  • 非个性化推荐:热门推荐、编辑精选、相似推荐

推荐系统需要考虑:用户的历史行为、社交关系、兴趣点、所处上下文、…(用户画像),去判断用户的当前需求/感兴趣的点

用户画像:

  • 静态维度:姓名、年龄、地区、手机号…
  • 动态维度:关注、浏览、收藏…

推荐系统的意义:解决信息过载、人总是期望计算机尽量多地服务

推荐系统评估:准确度(均方误差、平均绝对误差…)、新颖度(商品给用户的新鲜感)、惊喜度(推荐和用户历史不相似却满意的)、信任度(提供可靠的推荐理由)、实时性(实时更新程度)

2)协同过滤 Neighborhood-based algorithm

  • 基于内容的推荐:基于用户喜欢的物品的属性/内容进行推荐,分析内容,无需考虑用户之间的关联,通常在文本相关产品上进行推荐,物品通过内容(如关键词)进行关联(电影题材、标志特征、年代、关键词)

对于要推荐的内容需要建立一张二维表(TF-IDF),对用户也建立一张二维表,计算匹配度(用户和要推荐内容的相似度)

举例:基于书名(内容)进行书籍推荐

  • 协同过滤算法:是一种基于”邻近“的推荐算法,根据用户在物品上的行为找到物品或用户的”近邻“
image-20231113133623921

相似度/距离定义:欧氏距离、杰卡德相似度、余弦相似度、皮尔逊相似度

①基于用户的协同过滤(user-based CF):基于用户有共同行为的物品,计算用户相似度。找到”近邻“,对近邻在新物品的评价(打分)加权推荐

一个用户序列u1,u2,…,um;一个物品序列o1,o2,…,on。得到m×n得分矩阵,每个元素vij表示用户i对物品j的打分,计算用户之间的相似度/距离,找出与目标用户u最相似的k个用户,用S(u,K)表示,将S中用户喜欢的物品全部提取出来,并去除u已经喜欢的物品。对于每个候选物品i,计算用户u对它感兴趣的程度: p ( u , i ) = ∑ v ∈ S ( u , K ) ∩ N ( i ) w u v × r v i p(u,i) = \sum_{v∈S(u,K)∩N(i)} w_{uv} × r_{vi} p(u,i)=vS(u,K)N(i)wuv×rvi W u v W_{uv} Wuv是用户u和v的相似度, r v i r_{vi} rvi表示用户v对i的喜欢程度

②基于物品的协同过滤(item-based CF):对于有相同用户交互的物品,计算物品相似度。找到物品”近邻“,进行推荐

一个用户序列u1,u2,…,um;一个物品序列o1,o2,…,on。得到m×n得分矩阵,每个元素vij表示用户i对物品j的打分,计算物品i和j之间的相似度/距离,选取Top K推荐或加权预测打分

image-20231113140147967

协同过滤的优缺点:

优点:基于用户行为,对推荐内容无需先验知识,只需要用户和商品关联矩阵即可,在用户行为丰富的情况下,效果好

缺点:需要大量的显性/隐形用户行为,需要通过完全相同的商品关联(相似的不行),假定用户的兴趣完全取决于之前的行为和上下文无关,在数据系数的情况下受影响

3)隐语义模型

对于用户评分矩阵,部分商品是没有打分的,我们希望尽量正确地填满未打分的项。解决此问题的思路是:通过一些隐藏因素(如电影的演员、年代…或人为不可理解的隐藏因素)影响用户的打分

方法:通过用户特征矩阵的转置与商品特征矩阵相乘得到用户打分矩阵

image-20231113142338378

相比之下,CF更简单、直接、解释性更强,隐语义模型能更好的挖掘用户和商品的隐藏关联关系,覆盖度更好

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值