版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第2章监督学习3.1K近邻算法3.2线性回归3.3岭回归3.4LASSON回归3.5逻辑回归3.6朴素贝叶斯算法3.7决策树3.8随机森林3.9核支持向量机3.10神经网络3.11分类器的不确定性3.12小结3.1K近邻算法
K近邻(K-NearestNeighbor,KNN)算法是分类算法中最简单的算法,也是一种理论很成熟的机器学习算法,算法的核心思想是“近朱者赤,近墨者黑”。即KNN算法会根据训练集的数据构建一个模型,然后对于输入的新数据,算法会将新数据的特征与训练集中对应的特征进行比对匹配,在训练集中找到与之相对较为相似的k个数据,判断未知样本的标签。如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个标签,则该样本也属于这个类别,并具有这个类别上样本的特性。
那么问题来了,这k个临近的样本是如何计算出来的,当样本中一半属于A标签,一半属于B标签的情况下如何处理呢?
KNN算法有多个参数,但算法中主要有三个参数比较重要,分别是算法中的k值n_neighbors,权重weights,度量距离方法的选择p、metric,只要这三个要素确定了,算法的预测方式也就确定了。分类决策
算法的分类决策规则通常采用多数表决法,即由样本中k个邻近最多的类别决定输入数据的类别。如果存在恰好临近多种类别的个数相同,这时权重weights就起到了作用,通过给临近距离加权从中选择一个,这也是算法风险较小的原因。由于一般不改变,遇到相同的情况比较小或者可以改变k值再次预测,所以我们把重点放在距离度量方式和k值选择上。距离度量
在KNN算法中,常用的距离度量方式有三种,分别为曼哈顿距离、欧式距离和闵可夫斯基距离,默认使用欧氏距离,最常用的也是欧式距离。下面是三种距离度量的公式,其中x1,x2,……,xn,y1,y2,……,yn分别是两个数据点的特征值。
距离的选择有两个参数控制,一个是p值,一个是metric。当metric=“minkowski”,p为2时是欧氏距离,p是1时,是曼哈顿距离,p为其他值时是闵可夫斯基距离,从公式可以看出,欧氏距离、曼哈顿距离是闵可夫斯基的特例。k值选择
k值大小的选择是非常重要的要素之一。当k=1时,称算法为最近邻算法。
当选择的k值较小时,就相当于用较小的领域中的训练实例进行预测,训练误差近似误差小,泛化误差会增大。预测结果对近邻的实例点非常敏感,若此时近邻的实例点是噪声,预测就会出错。换句话说,k值较小就意味着整体模型变得复杂,容易发生过拟合。
k值较大,就相当于用较大领域中的训练实例进行预测,泛化误差小,但缺点是近似误差大。一个极端是k等于样本数m,则完全没有分类,此时无论输入实例是什么,都只是简单的预测它属于在训练实例中最多的类,模型过于简单。换句话说,K值较大就意味着整体模型变得简单,容易发生欠拟合。工作原理k=1k=3鸢尾花数据集
鸢尾花数据集是一个三分类问题,返回类型的是一个bunch对象,类似于Python中的字典,所以可以实现Python中字典的功能,例如利用键来查看相应的值。数据集内包含3个种类共150条数据,每类各50个数据。数据集有4项特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度,可以通过这4个特征预测鸢尾花卉属于setosa,versicolour,virginica中的哪一个标签,即类别。fromsklearn.datasetsimportload_irisiris=load_iris()print(iris.keys())filename的功能是输出数据集所在位置。DESCR中是该数据集的详细解释,里面说明了数据,特征的数目,特征信息,分类信息等。feature_names里是鸢尾花数据集的所有特征名。data里面包括了数据集中的数据。target_names保存了目标名。target里面保存了目标值。#利用KKNN算法的简单实例#导入相关包fromsklearn.datasetsimportload_irisfromsklearn.model_selectionimporttrain_test_splitfromsklearn.neighborsimportKNeighborsClassifier#加载数据集iris=load_iris()#划分数据集X_train,X_test,y_train,y_test=train_test_split(iris.data,iris.target,random_state=0)#加载算法knn=KNeighborsClassifier(n_neighbors=1)#训练数据集knn.fit(X_train,y_train)score=knn.score(X_test,y_test)print("预测结果:{}".format(knn.predict(X_test)))print("预测精度={}".format(score))#KNN算法用于二分类importnumpyasnpfromsklearn.neighborsimportKNeighborsClassifierfromsklearn.model_selectionimporttrain_test_splitdata=[[-3,-4],[-2,-2],[-5,-4],[-4,-2],[-1,-3],[1,3],[2,3],[1,2],[2,5],[3,4]]target=[0,0,0,0,0,1,1,1,1,1]X=np.array(data)y=np.array(target)X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=1)knn=KNeighborsClassifier(n_neighbors=1)knn.fit(X_train,y_train)score=knn.score(X_test,y_test)print("knn.score={}".format(score))对二分类数据可视化决策边界可视化importmglearnimportnumpyasnpfromsklearn.model_selectionimporttrain_test_splitfromsklearn.neighborsimportKNeighborsClassifierimportmatplotlib.pyplotaspltdata=[[-3,-4],[-2,-2],[-5,-4],[-4,-2],[-1,-3],[1,3],[2,3],[1,2],[2,5],[3,4]]target=[0,0,0,0,0,1,1,1,1,1]X=np.array(data)y=np.array(target)X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=1)knn=KNeighborsClassifier(n_neighbors=1)fit=knn.fit(X,y)fig,axes=plt.subplots(figsize=(6,6))mglearn.plots.plot_2d_separator(fit,X,fill=True,eps=0.5,ax=axes,alpha=0.4)mglearn.discrete_scatter(X[:,0],X[:,1],y,ax=axes)plt.legend(["Class0","Class1"],loc=4)axes.set_xlabel("firstfeature")axes.set_ylabel("secondfeature")plt.show()
KNN算法虽然使分类算法,但是还可以用于回归问题。在分类任务中可使用投票法,选择这K个样本中出现最多的类别标记作为预测结果;在回归任务中可使用平均法,将这K个样本的实值输出标记的平均值作为预测结果。当然还可以基于距离远近程度进行加权平均等方法。工作原理回归问题我们将用到sklearn中make_regression函数
n_samples表示生成数据集的数据数量,n_features表示特征数,n_informative表示有信息的特征数量,也就是用来构造线性模型,生成输出的特征数量,n_targets表示回归目标的数量,也就是对应于一个样本输出向量y的维度,默认输出是标量,noise代表数据中噪声数量。fromsklearn.datasetsimportmake_regressionfromsklearn.neighborsimportKNeighborsRegressorfromsklearn.model_selectionimporttrain_test_splitX,y=make_regression(n_samples=100,n_features=1,n_informative=1,noise=12,random_state=11)X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=11)knn=KNeighborsRegressor(n_neighbors=1)knn.fit(X_train,y_train)score=knn.score(X_test,y_test)print("knn.score={}".format(score))对knn算法参数进行调整fromsklearn.datasetsimportmake_regressionfromsklearn.neighborsimportKNeighborsRegressorfromsklearn.model_selectionimporttrain_test_splitX,y=make_regression(n_samples=100,n_features=1,n_informative=1,noise=12,random_state=11)X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=11)knn=KNeighborsRegressor(n_neighbors=3)knn.fit(X_train,y_train)train_score=knn.score(X_train,y_train)test_score=knn.score(X_test,y_test)print("knn.train_score={}".format(train_score))print("knn.test_score={}".format(test_score))可视化决策边界fromsklearn.datasetsimportmake_regressionfromsklearn.neighborsimportKNeighborsRegressorfromsklearn.model_selectionimporttrain_test_splitimportnumpyasnpimportmatplotlib.pyplotaspltX,y=make_regression(n_samples=100,n_features=1,n_informative=1,noise=12,random_state=11)X_train,X_test,y_train,y_test=train_test_split(X,y)knn=KNeighborsRegressor(n_neighbors=3)fit=knn.fit(X,y)fig,axes=plt.subplots(figsize=(6,6))line=np.linspace(-3,3,100).reshape(-1,1)axes.plot(line,knn.predict(line))axes.plot(X,y,"^")plt.show()优点1、KNN可以处理分类问题,同样也可以处理多分类问题,比如鸢尾花的分类。2、简单好用,容易理解,精度高,理论成熟。同时也很强大,对于手写数字的识别,鸢尾花这一类问题来说,准确率很高。3、可以用来做分类也可以用来做回归,可用于数值型数据和离散型数据,无数据输入假定,对异常值不敏感。缺点1、时间复杂度和空间复杂性高。因为每一次分类或者回归,都要把训练数据和测试数据都算一遍,如果数据量很大的话,需要的算力会很惊人,但是在机器学习中,大数据处理又是很常见的一件事。2、对训练数据依赖度特别大,虽然所有机器学习的算法对数据的依赖度很高,但是KNN尤其严重,因为如果我们的训练数据集中,有一两个数据是错误的,刚刚好又在我们需要分类的数值的旁边,这样就会直接导致预测的数据的不准确,对训练数据的容错性太差。3、一般数值很大的时候不用这个,计算量太大。但是单个样本又不能太少,否则容易发生误分。最大的缺点是无法给出数据的内在含义。3.2线性回归
线性回归属于回归算法,回归算法是一种根据数据构建模型,再利用这个模型训练其中的数据进行处理的算法,其标签是连续的。回归算法主要以线性模型为主。线性模型指的不是一个模型,而是一类模型,包括线性回归、岭回归、LASSO回归,逻辑回归等。本节先对线性回归、多项式回归做一下介绍。对于线性模型,其公式一般是如下所示:公式中,X[0]-X[n]表示特征,w[0]-w[n]和b表示模型的参数。当我们的数据集特征为1时,此时的线性模型公式是这样的:
假如我们给出一些数据,线性模型可以做出相应的决策:
通过模型可以看到,满足上述一个特征的公式。在一次函数中,自变量前面的w代表斜率,b代表截距。对于多个特征线性模型仍能做出决策:线性回归
线性回归,又被称为最小二乘法。在线性回归中,特征值与目标值之间存在着线性关系。线性回归算法指的是在认为数据满足线性关系的时候,根据训练数据构建出一个模型,并用此模型进行预测。
线性回归就是求线性回归方程,寻找参数w和b,使得对训练集的预测值与真实的回归目标值y之间的损失函数最小。线性回归模型的损失函数一般有两种,绝对损失和平方损失。
绝对损失函数,即
平方损失函数,即
因为平方误差利于算法的运算,通常将平方误差作为线性回归模型的损失函数,线性回归模型求解就是为了使损失函数最小。
在线性回归中,没有需要调节的参数。但存在两个参数coef_和intercept_用来保存回归模型的系数和截距。fromsklearn.datasetsimportload_breast_cancerfromsklearn.model_selectionimporttrain_test_splitfromsklearn.linear_modelimportLinearRegressioncanner=load_breast_cancer()X_train,X_test,y_train,y_test=train_test_split(canner.data,canner.target,random_state=2)reg=LinearRegression()reg.fit(X_train,y_train)score=reg.score(X_test,y_test)print("系数矩阵{}".format(reg.coef_))print("线性回归模型:{}".format(ercept_))print("score={}".format(score))
线性回归在线性可分的情况下表现得非常出色,但对于线性不可分的情况下,会表现得束手无策,比如对于以下数据:从图中可以看出该数据的决策边界应该是个二次函数,接下来我们通过线性回归进行决策。importnumpyasnpimportmatplotlib.pyplotaspltfromsklearn.linear_modelimportLinearRegressionX=np.array([1,3,5,7,9,11,13,15,17,19,21])X=X.reshape(-1,1)y=np.array([80,64,52,36,59,24,66,79,72,89,100])plt.scatter(X,y)plt.show()liner=LinearRegression()liner.fit(X,y)#预测结果展示#生成待预测的数据y_predict=liner.predict(X)#预测数据plt.scatter(X,y)plt.plot(X,y_predict,c="r")plt.show()
可以看到效果差强人意。那么既然线性不可分,利用线性回归无法进行划分,应该怎么处理呢?下面就是就线性不可分数据的处理,多项式回归。多项式回归
线性回归适合于线性可分的数据,当我们处理非线性可分的数据时可以使用多项式回归。在这种回归中,我们是要找到一条曲线来拟合数据点,在特征工程公有多项式特征类似于这个算法。
如果我们在用线性回归划分的话无从下手,可以尝试多项式回归。算法式子可用下式表示:importnumpyasnpimportmatplotlib.pyplotaspltfromsklearn.preprocessingimportPolynomialFeaturesfromsklearn.linear_modelimportLinearRegression#生成原始数据X=np.array([1,3,5,7,9,11,13,15,17,19,21])#重塑数据,使其变为二维X=X.reshape(-1,1)y=np.array([80,64,52,36,59,24,66,79,72,89,100])plt.scatter(X,y)plt.show()#多项式特征转换poly=PolynomialFeatures(degree=2)X1=poly.fit_transform(X)#下面与线性回归步骤相同建立模型,开始训练liner=LinearRegression()liner.fit(X1,y)#预测结果展示#生成待预测的数据y_predict=liner.predict(X1)#预测数据plt.scatter(X,y)plt.plot(X,y_predict,c="r")plt.show()可以看到多项式回归对数据拟合的比较完美。线性回归优点:1、回归分析法在分析多因素模型时,建模速度快,不需要很复杂的计算,在数据量大的情况下依然运行速度很快。更加简单和方便;2、回归分析可以准确地计量各个因素之间的相关程度与回归拟合程度的高低,提高预测方程式的效果;3、可以根据系数给出每个变量的理解和解释缺点:1、回归方程式只是一种推测,这影响了因子的多样性和某些因子的不可测性,使得回归分析在某些情况下受到限制。2、对异常值很敏感。多项式回归优点1、能够拟合非线性可分的数据,更加灵活的处理复杂的关系
2、因为需要设置变量的指数,所以它是完全控制要素变量的建模
缺点1、需要一些数据的先验知识才能选择最佳指数
2、如果指数选择不当容易出现过拟合3.3岭回归
岭回归是由最小二乘法改进而来,虽然利用了最小二乘法,但放弃了其无偏性,以降低精度来获得回归系数更为符合实际的回归方法,这种方法要强于最小二乘法。在岭回归中,不但要求模型特征系数w要表现的好,而且会添加约束,尽量减小特征的系数值大小,使之接近于0,这种约束方式被称为L2正则化,其目的是为了避免过拟合。
在岭回归中还添加了参数,其中最重要的莫过于alpha,通过调整alpha的值来降低特征系数的大小。在本例中,对岭回归与线性回归进行对比,观察其特点fromsklearn.datasetsimportload_breast_cancerfromsklearn.model_selectionimporttrain_test_splitfromsklearn.linear_modelimportLinearRegressioncanner=load_breast_cancer()X_train,X_test,y_train,y_test=train_test_split(canner.data,canner.target,random_state=2)reg=LinearRegression()reg.fit(X_train,y_train)train_score=reg.score(X_train,y_train)test_score=reg.score(X_test,y_test)print("系数矩阵{}".format(reg.coef_))print("线性回归模型:{}".format(ercept_))print("train_score={}".format(train_score))print("test_score={}".format(test_score))fromsklearn.datasetsimportload_breast_cancerfromsklearn.model_selectionimporttrain_test_splitfromsklearn.linear_modelimportRidgecanner=load_breast_cancer()X_train,X_test,y_train,y_test=train_test_split(canner.data,canner.target,random_state=2)reg=Ridge()reg.fit(X_train,y_train)train_score=reg.score(X_train,y_train)test_score=reg.score(X_test,y_test)print("系数矩阵{}".format(reg.coef_))print("岭回归模型:{}".format(ercept_))print("train_score={}".format(train_score))print("test_score={}".format(test_score))
可以从岭回归得到的精度发现,训练集的精度有所下降,而测试集的精度却提高了,说明了存在过拟合问题。
通过对alpha参数的调整,发现测试集上的分数上升了。而那么alpha的改变到底改变了什么呢?又是如何改变的呢?下面通过可视化观察其特征变化。fromsklearn.datasetsimportload_breast_cancerfromsklearn.model_selectionimporttrain_test_splitimportmatplotlib.pyplotaspltfromsklearn.linear_modelimportLinearRegressionfromsklearn.linear_modelimportRidgecanner=load_breast_cancer()X_train,X_test,y_train,y_test=train_test_split(canner.data,canner.target,random_state=2)lr=LinearRegression().fit(X_train,y_train)r1=Ridge().fit(X_train,y_train)r01=Ridge(alpha=0.1).fit(X_train,y_train)plt.plot(lr.coef_,'o',label='Linearregression')plt.plot(r1.coef_,'^',label='Ridgealpha=1')plt.plot(r01.coef_,'v',label='Ridgealpha=0.1')plt.xlabel("Coefficientindex")plt.ylabel("Coefficientmagnitude")plt.hlines(0,0,len(lr.coef_))plt.legend()plt.show()
从图中我们可以看到,线性模型没有经过正则化的处理,特征系数的数值都比较大,而岭回归中的系数几乎都接近于零。当岭回归的alpha值为1时,特征系数几乎都在零在一条线上,当alpha值为0.1时,特征系数有所增加。对于alpha值,当alpha值增大时,数据集的特征系数会减小,从而降低训练集的性能,但是会提升测试集的性能,也就是泛化性能,当alpha减小时,特征系数则会增大,如果alpha值非常小时,则会消除正则化,建立的模型也会趋向于线性回归。优点1、岭回归可以解决特征数量比样本量多的问题。2、岭回归作为一种缩减算法可以判断哪些特征重要或者不重要,有点类似于降维的效果3、岭回归可以解决变量间存在共线性问题。缺点1、不能降低样本特征数计算量大。2、牺牲了一定的精确度。3.4LASSON回归
与岭回归相似,套索(LASSO)回归也是用于限制数据的特征系数,防止过拟合。不同的是LASSO回归中用绝对值偏差作为算法的正则化项。即在LASSO回归中,会使某些特征系数恰好为0。LASSO回归处理后,某些特征被完全忽略,从而研究重要特征对数据的影响,这种称为L1正则化。
LASSO系数也与岭回归类似,比较重要的是alpha。
既然有了一种正则化的方式,为什么还要出现另一种呢?
这是因为L1正则化用于处理高维数据,高维数据就是指数据的维度很高,也就是说特征变量十分多的情况。在处理高维数据过程中碰到最大的问题就是维数过高,因为维数越高计算量会增加,还有就是不能可视化,无法观察工作原理,还会导致过拟合,无法精确预测。L2正则化会保留特征来降低系数,这样并不会减少计算量,而L1正则化会直接删掉一些特征系数。因此L1正则化在高维数据集中的优势尤其明显。
在LASSO回归中,我们仍使用线性回归和岭回归中的数据集fromsklearn.datasetsimportload_breast_cancerfromsklearn.model_selectionimporttrain_test_splitfromsklearn.linear_modelimportLassocanner=load_breast_cancer()X_train,X_test,y_train,y_test=train_test_split(canner.data,canner.target,random_state=2)reg=Lasso(alpha=0.001)reg.fit(X_train,y_train)train_score=reg.score(X_train,y_train)test_score=reg.score(X_test,y_test)print("系数矩阵{}".format(reg.coef_))print("LASSO回归模型:{}".format(ercept_))print("train_score={}".format(train_score))print("test_score={}".format(test_score))
经过LASSO回归处理后,系数矩阵中有的特征系数为零。下面通过可视化观察系数改变后特征的变化。fromsklearn.datasetsimportload_breast_cancerfromsklearn.model_selectionimporttrain_test_splitimportmatplotlib.pyplotaspltfromsklearn.linear_modelimportLassofromsklearn.linear_modelimportRidgecanner=load_breast_cancer()X_train,X_test,y_train,y_test=train_test_split(canner.data,canner.target,random_state=2)r1=Ridge(alpha=0.1).fit(X_train,y_train)l1=Lasso().fit(X_train,y_train)l01=Lasso(alpha=0.01).fit(X_train,y_train)l001=Lasso(alpha=0.00001).fit(X_train,y_train)plt.plot(l1.coef_,'o',label='Lassoalpha=1')plt.plot(l01.coef_,'^',label='Lassoalpha=0.01')plt.plot(l001.coef_,'v',label='Lassoalpha=0.00001')plt.plot(r1.coef_,'.',label="Ridgealpha=0.1")plt.xlabel("Coefficientindex")plt.ylabel("Coefficientmagnitude")plt.legend()plt.show()
通过图中数据可以看到,当LASSO系数较大时,数据集的特征几乎全为0,随着alpha值的减小,特征系数才逐渐增大,当alpha等于0.00001时,几乎没有了正则化的约束,而Ridge回归中,虽然有特征系数很小的点,但都不为0。在LASSO回归和Ridge回归中,虽然都是alpha系数,但意义完全不同,在岭回归中,随着alpha值的增大,数据集的特征系数会减小,随着alpha值的减小,数据集的特征系数会增大,而LASSO回归中,随着alpha值的增大,特征系数会增大,随着alpha值的减小,特征系数会减小。而且岭回归中,特征系数不会为0,LASSO回归中会。1、Lasso回归的出现能够有效的解决线性回归出现的过拟合。2、岭回归与Lasso回归最大的区别在于岭回归引入的是L2正则化,Lasso回归引入的是L1正则化,Lasso回归能够使得许多特征变量变成0,这点要优于岭回归,是得运算素的变快。缺点3、不适用一般情况,仅适用于特征非常多和对模型解释。3.5逻辑回归
在分类算法中,有的可以用于回归问题,同样对于回归算法,有的适用于分类问题。而逻辑回归就属于线性模型中的一种,用于解决分类问题。逻辑回归是用来处理自变量和结果的回归问题,虽然被叫做回归,但却是一种分类方法。主要有两个使用场景,第一,用于研究二分类或者多分类问题,第二寻找因变量的影响因素。
逻辑回归算法与线性回归算法最大的差异是,逻辑回归中的
被当做决策边界,而对于线性回归等模型中是一条直线、平面或者超平面。逻辑回归建立的模型如下面这个公式:
在公式中0代表阈值,但是对于现实数据,阈值的设置也是一个问题,如果采取平均值,假设正常数据点都处于0左右,而出现一个异常值非常大,则会出现错误。
于是需要建立的一个函数来映射概率,sigmoid函数:
该函数将所有数据都映射到0-1之间,对于异常值进行了处理,其图像这样的:
与训练线性回归模型类似,为了逻辑回归模型的参数w和b需要一个代价函数,算法的代价函数是对m个样本的损失函数求和然后除以m,因为对于线性模型损失函数对于模型的影响不是很大,所以不作详细介绍。逻辑回归的原理是:根据一个问题,建立代价函数,然后通过迭代优化求解出最优的模型参数,然后测试验证我们这个求解的模型的好坏。
逻辑回归有一个重要的参数C,C值越大正则化越弱。与前面类似如果参数C值较大,那么特征系数也将会越大,逻辑回归可能将训练集拟合到最好,而如果C值较小,那么模型更强调使特征系数接近于0,正则化越强。我们继续对乳腺癌数据集进行建模。fromsklearn.datasetsimportload_breast_cancerfromsklearn.model_selectionimporttrain_test_splitfromsklearn.linear_modelimportLogisticRegressioncanner=load_breast_cancer()X_train,X_test,y_train,y_test=train_test_split(canner.data,canner.target,random_state=2)reg=LogisticRegression()reg.fit(X_train,y_train)train_score=reg.score(X_train,y_train)test_score=reg.score(X_test,y_test)print("系数矩阵{}".format(reg.coef_))print("逻辑回归模型:{}".format(ercept_))print("train_score={}".format(train_score))print("test_score={}".format(test_score))
可以看到精确度非常高,因为该数据集本身就是分类问题,恰好也说明了线性模型中的逻辑回归适用于分类。对C值进行调节,并通过可视化观察特征系数的变化。fromsklearn.datasetsimportload_breast_cancerfromsklearn.model_selectionimporttrain_test_splitimportmatplotlib.pyplotaspltfromsklearn.linear_modelimportLogisticRegressioncanner=load_breast_cancer()X_train,X_test,y_train,y_test=train_test_split(canner.data,canner.target,random_state=2)lg01=LogisticRegression(C=0.1).fit(X_train,y_train)lg1=LogisticRegression().fit(X_train,y_train)lg10=LogisticRegression(C=10).fit(X_train,y_train)plt.plot(lg01.coef_.T,'x',label='LogisticC=0.1')plt.plot(lg1.coef_.T,'o',label='LogisticC=1')plt.plot(lg10.coef_.T,'.',label='LogisticC=10')plt.xticks(range(canner.data.shape[1]),canner.feature_names,rotation=90)plt.hlines(0,0,canner.data.shape[1])plt.xlabel("Coefficientindex")plt.ylabel("Coefficientmagnitude")plt.legend()plt.show()因为逻辑回归使用L2正则化,可以看到随着C值增大特征系数也会变大,可以看到随着C值减小特征系数也会变小,但是不会为0。优点:
1、简单、速度快,适用于二分类问题。2、易于理解,能直接看到各个特征的权重。3、容易吸收新的数据更新模型。缺点:
1、适应能力弱,对数据适应能力有局限性。3.6朴素贝叶斯算法
贝叶斯算法是一类分类算法的总称,来源于统计学。它是由18世纪英国数学家贝叶斯学派创始人塔马斯·贝叶斯所提出的利用概率统计知识进行分类的方法演变而来,贝叶斯学派很古老,但是从诞生到一百年前一直不是主流。
朴素贝叶斯分类与我们介绍的线性模型十分相似,是一种十分简单的分类算法,叫它朴素贝叶斯分类是因为这种方法的思想真的很朴素,朴素贝叶斯的原理是:对于给出的待分类项,求解在此项出现的条件下各个类别出现的概率,哪个最大,就认为此待分类项属于哪个类别。即如果一个事物在一些属性条件发生的情况下,事物属于A的概率>属于B的概率,则判定事物属于A。朴素贝叶斯算法较为简单、高效,在处理分类问题上,是值得优先考虑的方法之一,但是泛化能力比分类模型较差。
朴素贝叶斯分类算法,核心是下面这个贝叶斯公式:
朴素贝叶斯算法同样有多种算法,分别是高斯朴素贝叶斯(GaussianNaiveBayes),伯努利朴素贝叶斯(BernoulliNaiveBayes),多项式朴素贝叶斯(MultinomialNaiveBayes)。高斯朴素贝叶斯其实就是正态分布用于解决一些连续数据的问题,伯努利朴素贝叶斯就是应用于二分类,多项式朴素贝叶斯文本计数中经常使用。接下来对这三种贝叶斯算法进行模型的构建。
在对KNN算法处理回归问题中,用到了sklearn库中的make_regression函数,该函数可通过设置得到想要的数据集,同时在sklearn库中还有一个手动设置的分类数据集,make_blobs。
n_samples表示数据的数量。
n_features表示特征的数量。
centers表示类别的数量。
首先函数生成数据为300个、特征为2、类别为7的数据集,然后利用三种朴素贝叶斯算法观察其精度。#高斯朴素贝叶斯fromsklearn.datasetsimportmake_blobsfromsklearn.model_selectionimporttrain_test_splitfromsklearn.naive_bayesimportGaussianNBX,y=make_blobs(n_samples=300,centers=7,random_state=3)X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=3)bayes=GaussianNB()bayes.fit(X_train,y_train)train_score=bayes.score(X_train,y_train)test_score=bayes.score(X_test,y_test)print("trainpredict={}".format(train_score))print("testpredict={}".format(test_score))#伯努利朴素贝叶斯fromsklearn.datasetsimportmake_blobsfromsklearn.model_selectionimporttrain_test_splitfromsklearn.naive_bayesimportBernoulliNBX,y=make_blobs(n_samples=300,centers=7,random_state=3)X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=3)bayes=BernoulliNB()bayes.fit(X_train,y_train)train_score=bayes.score(X_train,y_train)test_score=bayes.score(X_test,y_test)print("trainpredict={}".format(train_score))print("testpredict={}".format(test_score))因为多项式朴素贝叶斯只适用于处理非负离散数值,所以在下面对数据进行了归一化。#多项式朴素贝叶斯fromsklearn.datasetsimportmake_blobsfromsklearn.model_selectionimporttrain_test_splitfromsklearn.naive_bayesimportMultinomialNBimportnumpyasnpimportmatplotlib.pyplotaspltfromsklearn.preprocessingimportMinMaxScalerX,y=make_blobs(n_samples=300,centers=7,random_state=3)X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=3)scaler=MinMaxScaler()scaler.fit(X_train)X_train_scaler=scaler.transform(X_train)X_test_scaler=scaler.transform(X_test)bayes=MultinomialNB()bayes.fit(X_train_scaler,y_train)train_score=bayes.score(X_train_scaler,y_train)test_score=bayes.score(X_test_scaler,y_test)print("trainpredict={}".format(train_score))print("testpredict={}".format(test_score))
因为有的算法不适用该数据集的缘故,可以看到评分越来越低。列下来通过决策可视化观察其决策边界。
伯努利朴素贝叶斯主要解决的是二项分布,多项式朴素贝叶斯多用于转化为对文本的处理,所以效果不是很好。优点1、朴素贝叶斯算法分类效率稳定,不仅能处理二分类还能处理多分类,适用于小规模数据,而且还能做增量式训练,即数据量过多超出内存时,我们可以分批的去增量训练。2、对缺失数据不太敏感,算法也比较简单,常用于文本分类。3、当属性相关性较小时,朴素贝叶斯性能最好。缺点1、在属性个数比较多或者属性之间相关性较大时,分类效果不好,往往无法预测精确的数据。2、需要知道先验概率,且先验概率很多时候取决于假设,因此在某些时候会由于假设的先验模型的原因导致预测效果不佳。3、由于我们是通过先验和数据来决定后验的概率从而决定分类,所以分类决策存在一定的错误率,并且对输入数据的表达形式很敏感。3.7决策树
决策树是一种相对普遍的机器学习算法,常用于分类和回归。在机器学习中,决策树是一个预测模型,他代表的是对象属性与对象值之间的一种映射关系,它在对数据进行分类的同时,还可以给出各个特征的重要性评分。决策树在决策过程中,会根据数据的特征来划分数据的类别。
对于上表数据,如果做出划分你会怎么做?决策树可能会做出以下划分:
当然可能也会有其他划分方法,总而言之,在使用决策树分类的时候,从根结点开始,对数据集的某一个特征进行测验,选择最优特征,然后每一个数据被对应着分配到子结点。如此循环继续进行,当到达叶结点时,循环停止,这时每个数据都被分到一个类别。如果还有子集不能够被正确的分类,那么就对这些子集选择新的最优特征,继续对其进行分割,构建相应的节点,如此递归进行,直至所有训练数据子集被基本正确的分类,或者没有合适的特征为止。每个子集都被分到叶节点上,即都有了明确的类,这样就生成了一颗决策树。
但是如果特征的数量非常大,数据非常多的情况下,算法的计算量肯定也会非常大,那应该如何处理呢?
从决策树函数中看到决策树的参数比较多,其中比较重要的参数是max_depth决策树的最大深度。因为决策树模型比较复杂,对于训练集中的数据表现得很好,但在测试集上的表现并不是很好,所以容易产生过拟合。通过对最大深度的限制则可以解决这一问题。
通过对最大深度的限制则可以解决这一问题,这种对树预先进行处理的操作,称为预剪枝。 预剪枝是在树的生长过程中设定一个指标,当达到该指标时就停止生长,这样虽然方便但是容易出现局限性,一旦达到指标,使得结点就变成了叶结点,如果往后继续分支可能会出现更好的分类方法。所以说采用预剪枝可能会误导更优分类。
还有一种方式,先构建树,然后删除信息量很少的结点,这种方式被称为后剪枝,也叫做剪枝。后剪枝中树首先要充分生长,充分利用全部数据集。让叶结点都有最小的不纯度值,然后对所有相邻的成对叶节点考虑是否消去它们,如果消去能引起令人满意的不纯度增长,那么执行消去,并令它们的公共父节点成为新的叶节点。这种"合并"叶节点的做法和节点分支的过程恰好相反,经过剪枝后叶节点常常会分布在很宽的层次上,树也变得非平衡。
实际中构建决策树并不只包含剪枝,它包括两个重要部分:特征选择、决策树的生成。特征选择就是把数据集中的众多的特征中选择一个特征,当成当前结点的判断标志。如何选择特征有许多不同的评估标准,通常包括这些标准,基尼指数、信息增益率、信息熵,从而衍生出不同的决策树算法。基于基尼指数的算法被称为CART算法,基于信息熵、信息增益率的算法包括ID3、C4.5算法。
ID3算法于1975年被提出,以“信息熵”为核心计算每个属性的信息增益,结点划分标准是选取信息增益最高的属性作为划分属性。ID3算法只能处理离散属性,并且类别值较多的输入变量比类别值少的输入变量更有机会成为当前最佳划分点。
C4.5算法使用信息增益率来选择属性,存在取值数目较少属性的偏好,因此,采用一个启发式搜索方法,先从候选划分属性中找出信息增益高于平均水平的属性,再从中选择信息增益率最高的属性作为划分属性。基于这些改进,C4.5算法克服了ID3算法使用信息增益选择属性时偏向选择取值多的属性的不足。
CART算法生成的决策树为结构简单的二叉树,每次对样本集的划分都计算Gini系数,Gini系数越小则划分越合理。Gini系数又称基尼不纯度,表示一个随机选中的样本在在子集中被分错的可能性。
算法的选择可以根据函数中的criterion参数进行调整,默认为基尼指数gini,可以调节为信息增益的熵entropy。通过min_impurity_decrease来优化模型,这个参数用来指定信息墒或者基尼不纯度的阀值,当决策树分裂后,其信息增益低于这个阀值时则不再分裂。
信息熵表示事件的不确定性。变量不确定性越高,熵越高。划分数据集的大原则是:让数据从无序变得有序,在划分数据集前后信息发生的变化称为信息增益获得信息增益最高的特征就是最好的选择。
Gini系数是一种与信息熵类似的做特征选择的方式,通常用于cart算法中。基尼不纯度表示一个随机选中一个数据,他在被划分的时候分错的可能性。基尼不纯度为这个样本被选中的概率乘以它被分错的概率。当一个节点中所有样本都是一个类时,基尼不纯度为零。
决策树生成是根据选择的特征评估标准,从上至下递归地生成子节点,直到数据集不可分则停止决策树停止生长。树结构来说,递归结构是最容易理解的方式。接下来通过鸢尾花数据集对CART树进行分析。fromsklearn.datasetsimportload_irisfromsklearn.model_selectionimporttrain_test_splitfromsklearn.treeimportDecisionTreeClassifieriris=load_iris()X_train,X_test,y_train,y_test=train_test_split(iris.data,iris.target,random_state=3)tree=DecisionTreeClassifier(random_state=3)tree.fit(X_train,y_train)score=tree.score(X_test,y_test)print(score)因为决策树的算法复杂,容易产生过拟合,所以我们要对训练集进行测试。train_score=tree.score(X_train,y_train)print(train_score)
可以看到在训练集上的评分达到了1.0,与测试集上的评分差的比较多,所以肯定出现了过拟合。所以可以对数据进行剪枝。fromsklearn.datasetsimportload_irisfromsklearn.model_selectionimporttrain_test_splitfromsklearn.treeimportDecisionTreeClassifieriris=load_iris()X_train,X_test,y_train,y_test=train_test_split(iris.data,iris.target,random_state=3)tree=DecisionTreeClassifier(max_depth=3,random_state=3)tree.fit(X_train,y_train)train_score=tree.score(X_train,y_train)test_score=tree.score(X_test,y_test)print("训练集精度:{}".format(train_score))print("测试集精度:{}".format(test_score))接下来通过可视化观察决策树构建的树。从图片中我们看到,对鸢尾花数据集的决策只用到了petallength和petalwidth两个特征。在决策树中还可以看模型的特征重要性,特征的值全部在0-1之间,越接近1表示特征越重要。通过以下代码还可以查看特征重要性fromsklearn.datasetsimportload_irisfromsklearn.model_selectionimporttrain_test_splitfromsklearn.treeimportDecisionTreeClassifieriris=load_iris()X_train,X_test,y_train,y_test=train_test_split(iris.data,iris.target,random_state=3)tree=DecisionTreeClassifier(max_depth=3,random_state=3)tree.fit(X_train,y_train)print("特征重要性{}".format(tree.feature_importances_))
接下来查看树的决策边界可以看到构建的模型对原数据基本划分正确。优点1、决策树通过可视化的树容易解释。人们在通过解释后都有能力去理解决策树所表达的意义。2、易于通过静态测试来对模型进行评测。可以处理连续和种类字段。决策树可以清晰的显示哪些字段比较重要。其他的技术往往要求数据属性的单一。3、可以对有许多属性的数据集构造决策树。在相对短的时间内能够对大型数据源做出可行且效果良好的结果。4、决策树可很好地扩展到大型数据库中,同时它的大小独立于数据库的大小,计算量相对来说不是很大。缺点:1、对于那些各类别样本数量不一致的数据,在决策树当中,信息增益的结果偏向于那些具有更多数值的特征。决策树处理缺失数据时的困难。2、过度拟合问题的出现。3、对有时间顺序的数据,需要很多预处理的工作。4、忽略数据集中属性之间的相关性。当类别太多时,错误可能就会增加的比较快。一般的算法分类的时候,只是根据一个字段来分类。3.8随机森林
因为决策树通常会出现过拟合的情况,所以出现了随机森林这一方法。随机森林是集成算法的一种。
集成算法常见的的有三类,分别是装袋(Bagging)算法,提升(Boosting)算法和投票(Voting)算法。装袋算法就是将训练集奋力成多个子集,然后对各个子集进行训练模型。提升算法就是训练多个模型并组成一个序列,序列中的每一个模型都会修正前一个模型的错误。投票算法就是训练多个模型,并采用样本统计来提高模型的准确度。
随机森林属于Bagging算法的一种,在分类和回归问题上都可以运用,相对是一种比较新的机器学习算法。所谓随机森林就是将变量、数据的进行随机化,用随机的方式建立一个森林,森林里面有很多的决策树组成,随机森林的每一棵决策树之间是没有关联的,决策树算法通过循环的二分类,计算量大大降低。在得到森林之后,当有一个新的输入样本进入的时候,就让森林中的每一棵决策树分别进行一下判断,看看这个样本应该属于哪一类(对于分类算法),然后看看哪一类被选择最多,就预测这个样本为那一类。
随机森林在对数据进行分类的同时,还可以给出各个变量的重要性评分,评估各个变量在分类中所起的作用,再汇总分类树的结果。许多研究表明,组合分类器比单一分类器的分类效果好,随机森林在运算量没有显著提高的前提下提高了预测精度。随机森林对多元公线性不敏感,结果对缺失数据和非平衡的数据比较稳健,可以很好地预测多达千个解释变量的作用,被誉为当前最好的算法之一。
在随机森林中,有三个比较重要的特征,分别是最大特征数量max_features,分类器的个数n_estimators,最小样本叶片数量min_sample_leaf。max_features是随机森林允许在单个树中尝试的最大特征数,如果设置max_features等于决策树中的n_features,那么每次划分数据集的时候都要考虑所有特征,没有了随机性.但在随机森林中,bootstrap表示自主取样,即有放回的取样,这样增加了随机森林的随机性。如果设置max_features等于1,那么划分时无法选择对那个特征进行测试只能对特征搜索不同的阈值。所以最大特征数量的设置非常重要。n_estimators表示随机森林中迭代器的数量。min_sample_leaf是最小样本叶片大小。叶是决策树的末端节点。较小的叶子使模型更容易捕捉训练数据中的噪声。一般来说将最小叶子节点数目设置为大于50,应该尽量尝试多种叶子大小种类,以找到最优的那个。接下来实现又三棵树组成的随机森林。fromsklearn.datasetsimportload_irisfromsklearn.model_selectionimporttrain_test_splitfromsklearn.ensembleimportRandomForestClassifierimportmatplotlib.pyplotaspltimportmglearniris=load_iris()X=iris.data[:,2:4]y=iris.targetX_train,X_test,y_train,y_test=train_test_split(X,y,random_state=3)forest=RandomForestClassifier(n_estimators=3,max_depth=3)forest.fit(X_train,y_train)fig,axes=plt.subplots(2,2,figsize=(6,6))fori,(ax,tree)inenumerate(zip(axes.ravel(),forest.estimators_)):ax.set_title("tree{}".format(i))mglearn.plots.plot_tree_partition(X_train,y_train,tree,ax=ax)mglearn.plots.plot_2d_separator(forest,X_train,fill=True,alpha=0.4)axes[-1,-1].set_title("Randomforest")mglearn.discrete_scatter(X_train[:,0],X_train[:,1],y_train)plt.show()
从图中可以看出每棵树都有不同的决策边界,而随机森林最后的模型由三棵树综合而成。随机森林比任何一棵树的过拟合都要小,给出的决策边界也更符合直觉。还查看随机森林对数据集中特征重要的的处理。fromsklearn.datasetsimportload_irisfromsklearn.model_selectionimporttrain_test_splitfromsklearn.ensembleimportRandomForestClassifieriris=load_iris()X_train,X_test,y_train,y_test=train_test_split(iris.data,iris.target,random_state=3)tree=RandomForestClassifier(max_depth=3,n_estimators=3)tree.fit(X_train,y_train)print("特征重要性{}".format(tree.feature_importances_))
从特征中看到,没有一个为0的特征,也就说明了随机森林构建的模型比起决策树更能从总体上分析。优点1、在数据集上表现良好,两个随机性的引入,使得随机森林不容易陷入过拟合。2、在当前的很多数据集上,相对其他算法有着很大的优势,两个随机性的引入,使得随机森林具有很好的抗噪声能力。3、训练速度快,容易做成并行化方法,实现比较简单。4、它能够处理很高维度的数据,并且不用做特征选择,对数据集的适应能力强:既能处理离散型数据,也能处理连续型数据,数据集无需规范化。缺点1、随机森林已经被证明在某些噪音较大的分类或回归问题上会过拟合。2、对于有不同取值的属性的数据,取值划分较多的属性会对随机森林产生更大的影响,所以随机森林在这种数据上产出的属性权值是不可信的。3.9核支持向量机
核支持向量机是一种十分经典的算法,其应用领域主要是就是文本分类、图像识别。为避免过拟合提供了很好的理论保证。核支持向量机是一种二分类的模型。当然如果进行修改之后也是可以用于多类别问题的分类,还可以用于回归分析,它在解决小样本、非线性及高维模式识别中表现出许多特有的优势,并能够推广应用到函数拟合等其他机器学习问题中。
感知机的分类原理就是尝试找到一条直线,能够把二元数据隔离开。放到三维空间或者更高维的空间,感知机的模型就是尝试找到一个超平面,能够把所有的二元类别隔离开。 关键问题就是如何寻找这个面,所以就要借助支持向量的作用,支持向量就是他们就是离分界线最近的向量。
对于这个分离的超平面,我们定义为
,如果在函数的上方我们就使y=1,在y的下方就使y=-1。
超平面之所以成为超平面,是因为当维数过高大于三的时候,我们肉眼已经看不到这个平面,更无法想象。那些距离这个超平面最近的点就是所谓支持向量,实际上如果确定了支持向量也就确定了这个超平面,确定了超平面之后,这些支持向量也就没有了特殊的作用,与其他样本一样。
其中最重要的三个参数为:kernel、gamma、C。
kernel:可以选择的kernel有rbf,linear,polyandothers。其中rbf和poly适用于非线性超平面。
C:和逻辑回归中的C值一样,C值越大正则化越弱。与前面类似如果参数C值较大,那么特征系数也将会越大,逻辑回归和线性svm可能将训练集拟合到最好,而如果C值较小,那么模型更强调使特征向量接近于0。 gamma:gamma值越大,SVM就会倾向于越准确的划分每一个训练集里的数据。
在支持向量机中用一个核的选择,那么对于核的选择技巧是什么呢?第一,如果样本数量小于特征数,那么就没必要选择非线性核,简单的使用线性核就可以了。第二,如果样本数量大于特征数目,这时可以使用非线性核,将样本映射到更高维度,一般可以得到更好的结果。第三,如果样本数目和特征数目相等,该情况可以使用非线性核,原理和第二种一样。优点1、使用核函数可以向高维空间进行映射,对高维分类问题效果好
2、使用核函数可以解决非线性的分类3、分类效果,较好分类思想很简单,就是将样本与决策面的间隔最大化4.因为最终只使用训练集中的支持向量,所以节约内存缺点:1、当数据量较大时,训练时间会较长
2、当数据集的噪音过多时,表现不好3、内存消耗大,难以解释,运行和调参也麻烦4、无法直接支持多分类,但是可以使用间接的方法来做3.10神经网络
神经网络,也称为简称为人工神经网络或类神经网络,是一种模拟动物神经元的算法,类似大脑中神经突触连接,通过进行分布式并行处理信息,并建立数学模型。这种网络依靠系统的复杂程度,调节系统内部的连接关系,从而达到处理信息的目的,并具有自学习和自适应的能力。
神经网络是一种运算模型,一般是通过统计学的一种方法进行优化,所以神经网络也是数学统计学方法的实践,通过统计学的方法我们可以得到大量函数来应用于神经网络结构,另一方面在人工智能的感知领域,我们通过数学统计学的应用可以来做人工感知方面的决定问题,这种方法比起正式的逻辑学推理演算更具有优势。典型的神经网络具有以下三个部分:结构:结构指定了网络中的变量和它们的拓扑关系。例如,神经网络中的变量可以是神经元连接的权重和神经元的激励值。激励函数:每个神经元都有一个激活函数,它主要是一个根据输入传递输出的函数.大部分神经网络模型具有一个短时间尺度的动力学规则,来定义神经元如何根据其他神经元的活动来改变自己的激励值。一般激励函数依赖于网络中的权重。学习规则:学习规则指定了网络中的权重如何随着时间推进而调整。这一般被看做是一种长时间尺度的动力学规则。一般情况下,学习规则依赖于神经元的激励值。它也可能依赖于监督者提供的目标值和当前权重的值。
神经网络中比较重要的就是多层感知器,MLP算法了。MLP也被称为前馈神经网络,或者被泛称为神经网络。我们重点介绍这一算法。
神经网络的预测精确,但是计算量也相对来说大。神经元之间的每个连接都有一个权重。这个权重表示输入值的重要性。一个特征的权重越高,说明该特征比其他特征更为重要。我们在线性回归时写下了这样一个公式:
在这x表示特征,w表示特征的权重,y就是加权求和。模型如下图所示:
而神经网络的神经元分为三种不同类型的层次:输入层,隐藏层,人工神经网络。输入层接收输入数据,隐藏层对输入数据进行数学计算。人
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 专项消防设备增设协议样本版A版
- 2025年度厂房装饰装修工程节能合同范本4篇
- 2025年度创新产业园厂房转租服务合同标准4篇
- 做菜知识培训课件图片
- 二零二五年度体育场馆建设担保协议3篇
- 2025年度高原地区柴油发电机组销售及售后服务合同3篇
- 《社区调解实务讲解》课件
- 2024年04月河南郑州银行信息科技部社会招考笔试历年参考题库附带答案详解
- 个人对公司长期借款合同(2024年版)
- 专业美甲技术劳务合作协议样本(2024版)版B版
- 科室医疗质量与安全管理小组工作制度
- 中华民族共同体概论课件第五讲大一统与中华民族共同体初步形成(秦汉时期)
- 初二生地会考试卷及答案-文档
- 私营企业廉洁培训课件
- 施工单位值班人员安全交底和要求
- 中国保险用户需求趋势洞察报告
- 数字化转型指南 星展银行如何成为“全球最佳银行”
- 中餐烹饪技法大全
- 灵芝孢子油减毒作用课件
- 现场工艺纪律检查表
- 医院品管圈与护理质量持续改进PDCA案例降低ICU病人失禁性皮炎发生率
评论
0/150
提交评论