机器学习(machine learning):用已有的数据训练某种模型,利用模型预测未来
Python机器学习库官网https://scikit-learn.org/stable/
机器学习分为有监督的机器学习和无监督的机器学习
有监督的机器学习:回归、分类
无监督的机器学习:聚类、降维
numpy数学计算框架
scipy物理计算框架
pandas数据分析框架
matplotlib绘图框架
scikit-learn机器学习框架
tensorflow谷歌开源的深度学习框架
keras开源的深度学习框架
回归平均值(regression to the mean),回归问题主要关注确定一个唯一的因变量(dependent variable)(需要预测的值)和一个或多个数值型的自变(independent variables)预测变量)之间的关系,广义线性回归,GLM,比如,逻辑回归,泊松回归
线性:y=a*x 一次方变化
回归:回归到平均值
线性回归(预测):一元一次方程组y=a*x+b,影响y的因素(维度)只有一个x即一元
多元线性回归:多元一次方程组y=w1*x1+w2*x2+…+wn*wn即y=W^T*X(权重矩阵W的转置矩阵点积矩阵X)
机器学习是以最快速度找到误差最小最优解(没有完美解)
使用最小二乘法求解样本误差的最小值即为函数模型最优解,样本模型的误差近似正态分布
根据最大似然估计(求样本集相关概率密度函数的参数)和中心极限定理(随机变量序列部分和分布近似正态分布)找到样本模型的误差最小最优解
使用概率密度乘积近似概率乘积的总似然即概率密度乘积最大相当于总似然最大
样本的误差的最小二乘法函数符合凹函数,求导后斜率即梯度为0时误差的和最小最优
θ=(XTX)-1XTY
θ矩阵为样本函数模型最优解的参数矩阵即维度矩阵X的权重
正态分布的概率密度函数:
fx=1σ2πe-(x-μ)22σ2
import numpy as np 引入numpy科学计算模块
import matplotlib.pyplot as plt 引入绘图模块
X=2*np.random.rand(100,1) numpy.random.rand()获取一个或一组服从“0~1”均匀分布的随机样本值
y=4+3*X+np.random.randn(100,1) numpy.random.randn()获取一个或一组服从“0~1”正态分布的随机样本值
X_b=np.c_[np.ones((100,1)),X] numpy.ones()获取给定形状和类型的新数组,numpy.c_[]获取切片对象转换为沿第二轴的连接
theta_best=np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y) numpy.dot()矩阵点积,numpy.linalg.inv()矩阵的逆
X_new=np.array([[0],[2]]) numpy.array()从常规Python列表或元组创建数组
X_new_b=np.c_[(np.ones((2,1))),X_new]
y_predict=X_new_b.dot(theta_best)
plt.plot(X_new,y_predict,"r-") matplotlib.pyplot.plot()绘制图形
plt.plot(X,y,"b.")
plt.axis([0,2,0,15]) matplotlib.pyplot.axis()设置轴属性
plt.show()
维度矩阵的点积复杂度是O(N)三次方
梯度下降法算法:以最快速度找到最优解的算法
梯度下降法一般流程为先初始化theta、求梯度斜率gradient、theta_t+1=theta_t-gradient*learning_rate(超参数learning_rate太大会振荡太小会时间长迭代次数多)、等迭代到gradient<threshold,迭代停止认为收敛,超参数threshold为阈值
=(hθX-Y)Xj
import numpy as np
__author__ = '作者名'
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
learning_rate = 0.1 学习率即步长
n_iterations = 10000 迭代次数
m = 100 样本数量
#初始化theta
theta = np.random.randn(2, 1)
count = 0
#一般不设置阈值设置超参数迭代次数,迭代一定次数后认为收敛
for iteration in range(n_iterations):
count += 1
#求梯度gradient
gradients = 1/m * X_b.T.dot(X_b.dot(theta)-y)
#应用公式调整theta值,theta_t+1= theta_t-gradient*learning_rate
theta = theta - learning_rate * gradients
print(count)
print(theta)
批量梯度下降:使用所有样本求梯度均值grads=(1/m)*X^Transpose*(X*theta-Y)
随机梯度下降:不使用所有样本随机抽取一个样本进行求梯度grad_j=(1/m)* (Xj)^Transpose*(X*theta-y),求梯度速度快但迭代次数多,可能找不到全局最优解
小批量梯度下降(Mini-Batch GD):不使用所有的样本数据而是随机选择一部分样本数据来求梯度
import numpy as np
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
n_epochs=500
t0,t1=5,50 #超参数
m = 100
def learning_schedule(t): 随着迭代次数的增多,不断减小学习率步长
return t0/(t+t1)
theta = np.random.randn(2, 1)
for epoch in range(n_epochs):
for i in range(m):
random_index=np.random.randint(m)
xi=X_b[random_index:random_index+1]
yi=y[random_index:random_index+1]
gradients=2*xi.T.dot(xi.dot(theta)-yi)
learning_rate=learning_schedule(epoch*m+i) 为了让越接近最优解的时候,调整的幅度越小,避免来回震荡
theta=theta-learning_rate*gradients 随着迭代的次数增多,调整的幅度自动减小
print(theta)
维度数据归一化:将数据统一化处理
最大值最小值归一化:把数据归到0到1之间
x-xminxmax-xmin
为了各个维度梯度可以同时收敛,基于梯度进行下降求解最优解都需要归一化处理
如果X1<<X2,那么W1>>W2,那么我们W1初始化之后要到达最优解的位置走的距离就远大于W1初始化之后要到达最优解的位置走的距离!
因为X1<<X2,那么g1 = (y_hat-y)*x1 ,g2 = (y_hat-y) * x2,那么g1<<g2
因为g1<<g2,那么W调整的幅度等于W_t+1 - W_t = - alpha * g
所以g越小,调整的幅度就越小
总结推导:
X1<<X2,W1调整的幅度<<W2调整的幅度,但是W1需要调整的距离>>W2需要调整的距离,如果不做归一化,同样的迭代次数下,W2已经调整到最优,W1还在慢慢的调整,整体看起来比先做归一化,再做梯度下降需要的迭代次数要多
过拟合:拟合过度,用算法生成的模型,很好的拟合了现有的数据样本即训练集数据,但是新的数据即测试集的数据预测的准确率反而降低了
防止过拟合,等价于提高模型的泛化能力或推广能力或者是举一反三的能力即提高模型的容错能力
举例:
学霸:有监督的机器学习
学神:有很强的学习能力,能自己找到学习的方法,无监督的机器学习
学渣:你的算法压根就没选对,数据预处理也没对,学习方法不对
学痴:做练习题都会,考试稍微一变化就不会,过拟合,没有泛化能力
模型参数W个数越少越好,模型参数W的值越小越好(如果X输入有误差,对预测的结果y影响很小),通过正则化惩罚项人为的修改已有的损失函数,比如使用L1、L2正则添加到loss func
L1为多个维度的w绝对值加和,使用L1正则化会使权重W值两极分化于1或0也成为稀疏编码,可以进行降维,一般在数据进行模型训练之前会进行特征工程降维
L2为多个维度的w平方和,使用L2正则化会使权重W值整体偏小,由于特征工程已经进行降维所以一般使用L2
使用随机梯度下降SGD找找最优解的过程中,考虑惩罚项的影响
岭回归(Ridge Regression):使用L2方式人为的改变损失函数,使用惩罚项提高模型的泛化能力,但一定程度上降低了模型正确率即对训练集已有数据的拟合效果,但模型的目的是对未来新的数据进行预测,惩罚项中有超参数alpha即惩罚项的权重,可以通过调整alpha超参数根据需求来决定是注重模型的正确率还是模型的泛化能力
import numpy as np
from sklearn.linear_model import Ridge 引入岭回归模块
from sklearn.linear_model import SGDRegressor 引入随机梯度下降模块
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
ridge_reg = Ridge(alpha=1, solver='sag') 获取超参数alpha为1批量梯度下降的岭回归对象
ridge_reg.fit(X, y) 传入X和Y矩阵
print(ridge_reg.predict(1.5)) 获取x为1.5的预测值
print(ridge_reg.intercept_) 获取截距即w0,传入的样本数据X矩阵中没有x0但Ridge初始化默认超参数fix_ intercept为True
print(ridge_reg.coef_) 获取权重W矩阵
sgd_reg = SGDRegressor(penalty='l2', n_iter=1000) 获取正则化惩罚项为L2(正则化为l2的SGDRegressor与Ridge等价),迭代次数为1000的SGDRegressor对象
sgd_reg.fit(X, y.ravel()) 传入X和Y矩阵
print(sgd_reg.predict(1.5)) 获取x为1.5的预测值
print("W0=", sgd_reg.intercept_) 获取截距即w0,传入的样本数据X矩阵中没有x0但Ridge初始化默认超参数fix_ intercept为True
print("W1=", sgd_reg.coef_) 获取权重W矩阵
Lasso使用L1正则化惩罚项改变损失函数
import numpy as np
from sklearn.linear_model import Lasso
from sklearn.linear_model import SGDRegressor
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
lasso_reg = Lasso(alpha=0.15)
lasso_reg.fit(X, y)
print(lasso_reg.predict(1.5))
print(lasso_reg.coef_)
sgd_reg = SGDRegressor(penalty='l1', max_iter=1000)
sgd_reg.fit(X, y.ravel())
print(sgd_reg.predict(1.5))
print(sgd_reg.coef_)
Elastic Net使用L1和L2两种正则化惩罚项改变损失函数,可以根据超参数修改L1和L2的权重
import numpy as np
from sklearn.linear_model import ElasticNet
from sklearn.linear_model import SGDRegressor
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
elastic_net = ElasticNet(alpha=0.0001, l1_ratio=0.15)
elastic_net.fit(X, y)
print(elastic_net.predict(1.5))
sgd_reg = SGDRegressor(penalty='elasticnet', max_iter=1000)
sgd_reg.fit(X, y.ravel())
print(sgd_reg.predict(1.5))
线性回归算法一般选择顺序:Ridge Regression(L2正则化)、ElasticNet(即包含L1又包含L2)、Lasso Regression(L1正则化)
超参数alpha在Rideg类中是L2正则的权重、在Lasso类中是L1正则的权重、在ElasticNet和SGDRegressor里面是损失函数里面的alpha
超参数l1_ration在ElasticNet和SGDRegressor中是损失函数的p
多项式回归:PolynomialFeatures(多项式特征)不是做拟合的算法是做预处理的方法,转换数据继续升维(维度的次幂,通过degree超参数在原有的维度基础上增加高阶次幂维度),是为了让线性模型去拟合非线性的数据
升维是增加多个影响Y结果的因素,这样考虑的更全面,最终目的是要增加准确率
如果数据是非线性的变化可以使用非线性的算法生成的模型进行拟合,也可以使用PolynomialFeatures将非线性的数据进行变化,变成类似线性的变化,然后使用线性的模型进行拟合
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
m = 100
X = 6 * np.random.rand(m, 1) - 3
y = 0.5 * X ** 2 + X + 2 + np.random.randn(m, 1)
plt.plot(X, y, 'b.')
d = {1: 'g-', 2: 'r+', 10: 'y*'}
for i in d:
poly_features = PolynomialFeatures(degree=i, include_bias=False) 获取degree高阶没有截距(梯度下降算法中默认有截距为避免重复)多项式特征升维对象
X_poly = poly_features.fit_transform(X) 对矩阵X进行多项式特征转换
print(X[0])
print(X_poly[0])
print(X_poly[:, 0])
lin_reg = LinearRegression(fit_intercept=True)
lin_reg.fit(X_poly, y)
print(lin_reg.intercept_, lin_reg.coef_)
y_predict = lin_reg.predict(X_poly)
plt.plot(X_poly[:, 0], y_predict, d[i])
plt.show()
进行模型拟合时需要观测注意数据多样性,采样要均匀是为了模型的功能是对任何年龄段的人都有一个好的预测,读取的数据集就需要包含各个年龄段得数据,而且各个年龄段的数据均匀,防止过拟合
import pandas as pd 引入数据处理模块(pandas的DataFrame数据结构可以被Spark获取进行处理)
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
data = pd.read_csv('./insurance.csv') 读取文件
print(type(data))
print(data.head())
print(data.tail())
# describe做简单的统计摘要
print(data.describe()) 查看数据简单统计摘要
# 采样要均匀
data_count = data['age'].value_counts()
print(data_count)
# data_count[:10].plot(kind='bar')
# plt.show()
# plt.savefig('./temp')
print(data.corr()) 查看数据之间的相关性,默认使用计算数值型的pearson公式
reg = LinearRegression()
x = data[['age', 'sex', 'bmi', 'children', 'smoker', 'region']]
y = data['charges']
# python3.6 报错 sklearn ValueError: could not convert string to float: 'northwest',加入一下几行解决
x = x.apply(pd.to_numeric, errors='coerce') 将字符串数据转换为数值型
y = y.apply(pd.to_numeric, errors='coerce')
x.fillna(0, inplace=True) 将空的数据转换为0
y.fillna(0, inplace=True)
poly_features = PolynomialFeatures(degree=3, include_bias=False)
X_poly = poly_features.fit_transform(x)
reg.fit(X_poly, y)
print(reg.coef_)
print(reg.intercept_)
y_predict = reg.predict(X_poly)
plt.plot(x['age'], y, 'b.')
plt.plot(X_poly[:, 0], y_predict, 'r.')
plt.show()
Pearson相关系数:测量两组变量之间的线性相关性,区间范围为-1(负相关)到1(正相关)之间,相关系数越接近于0,说明越不相关,两个维度之间相关系数接近于1,可以去掉其中一个维度进行降维,某个维度和结果Y之间的相关系数接近于0,可以去掉这个维度进行降维
多元线性回归(Ridge、Lasso、ElasticNet)用于回归预测,逻辑回归(Logistic Regression)用于分类任务
回归预测损失函数为平方均值损失函数MSE
逻辑回归(二分类):函数曲线范围在[0,1]之间,大于大于0.5分成两类
t=WTX
熵是一种测量分子不稳定性的指标,分子运动越不稳定,熵就越大,来自热力学
熵是一种测量信息量的单位,信息熵,包含的信息越多,熵就越大,来自信息论,香农
熵是一种测量不确定性的单位,不确定性越大,概率越小,熵就越大
概率越小,熵会越大
逻辑回归本质是多元线性回归,应用了多元线性回归的公式,把多元线性回归的结果交给sigmoid函数去进行缩放,逻辑回归的损失函数推导的导函数,整个形式上和多元线性回归基本一致,只是y_hat求解公式包含了一个sigmoid过程
逻辑回归的分类损失函数是交叉熵-y*logP,损失函数loss func = (-y*logP + -(1-y)*log(1-P)),loss func损失最小即逻辑回归二分类找到最优解,可以使用梯度下降法来求解最优解
由于线性回归区间是负无穷到正无穷的可以按照0来分成两部分代入sigmoid公式后t=0,y=0.5,所有逻辑回归阈值是0.5
import numpy as np
from sklearn import datasets 引入数据集模块
from sklearn.linear_model import LogisticRegression 引入逻辑回归模块
from sklearn.model_selection import GridSearchCV 引入网格搜索交叉验证模块
import matplotlib.pyplot as plt
from time import time 引入时间模块
iris = datasets.load_iris() 获取数据集中的数据
print(list(iris.keys())) 获取数据集中的键值
print(iris['DESCR']) 获取数据集的变量名
print(iris['feature_names']) 获取数据集的描述
X = iris['data'][:, 3:] 获取数据集中矩阵指定行列
print(X)
print(iris['target']) 获取数据中的目标即分类号
y = iris['target']
# y = (iris['target'] == 2).astype(np.int)
print(y)
# Utility function to report best scores
# def report(results, n_top=3):
# for i in range(1, n_top + 1):
# candidates = np.flatnonzero(results['rank_test_score'] == i)
# for candidate in candidates:
# print("Model with rank: {0}".format(i))
# print("Mean validation score: {0:.3f} (std: {1:.3f})".format(
# results['mean_test_score'][candidate],
# results['std_test_score'][candidate]))
# print("Parameters: {0}".format(results['params'][candidate]))
# print("")
# start = time()
# param_grid = {"tol": [1e-4, 1e-3, 1e-2],
# "C": [0.4, 0.6, 0.8]}
log_reg = LogisticRegression(multi_class='ovr', solver='sag') 获取逻辑回归二分类ovr(multi_class多分类soft-max回归)使用梯度下降法的对象
# grid_search = GridSearchCV(log_reg, param_grid=param_grid, cv=3) 获取对log_reg模型算法对象超参数为param_grid使用cv折交叉验证的网格搜索验证对象
log_reg.fit(X, y)
# print("GridSearchCV took %.2f seconds for %d candidate parameter settings."
# % (time() - start, len(grid_search.cv_results_['params'])))
# report(grid_search.cv_results_)
X_new = np.linspace(0, 3, 1000).reshape(-1, 1) 生成测试集数据,生成1000个从0到3区间平均分割区间段的数值
print(X_new)
y_proba = log_reg.predict_proba(X_new) 预测分类概率值
y_hat = log_reg.predict(X_new) 预测分类号
print(y_proba)
print(y_hat)
plt.plot(X_new, y_proba[:, 2], 'g-', label='Iris-Virginica')
plt.plot(X_new, y_proba[:, 1], 'r-', label='Iris-Versicolour')
plt.plot(X_new, y_proba[:, 0], 'b--', label='Iris-Setosa')
plt.show()
print(log_reg.predict([[1.7], [1.5]]))
逻辑回归进行多分类实质是通过改变数据y的值将多分类转换为多个二分类,多分类的权重W矩阵是多个二分类所有的权重W,例如进行三分类需要同时训练三个互相不影响的二分类模型,模型有n个维度,那三分类w参数的个数就会是(n+1)*3个参数
傅里叶变化:将振幅、时间、频率维度的数据转换为振幅和频率维度的数据
使用logistic regression处理音乐数据,音乐数据训练样本的获得和使用快速傅里叶变换(FFT)预处理的方法
# 音乐数据分类
import numpy as np
from sklearn import linear_model, datasets
import matplotlib.pyplot as plt
from scipy.stats import norm
from scipy import fft
from scipy.io import wavfile
def create_fft(g, n):
rad = "d:/genres/"+g+"/converted/"+g+"."+str(n).zfill(5)+".au.wav"
sample_rate, X = wavfile.read(rad) 获取音乐数据
fft_features = abs(fft(X)[:1000]) 音乐数据进行傅里叶转换
sad = "d:/trainset/"+g+"."+str(n).zfill(5) + ".fft"
np.save(sad, fft_features) 保存转换后的数据
genre_list = ["classical", "jazz", "country", "pop", "rock", "metal"]
for g in genre_list:
for n in range(100):
create_fft(g, n)
genre_list = ["classical", "jazz", "country", "pop", "rock", "metal"]
X = []
Y = []
for g in genre_list:
for n in range(100):
rad = "d:/StudyMaterials/python/python-sklearn/trainset/"+g+"."+str(n).zfill(5)+ ".fft"+".npy"
fft_features = np.load(rad)
X.append(fft_features) 构建音乐数据集的X
Y.append(genre_list.index(g)) 构建音乐数据集的Y
X = np.array(X) 将X列表转换为X矩阵
Y = np.array(Y) 将Y列表转换为Y矩阵
import random
randomIndex=random.sample(range(len(Y)),int(len(Y)*8/10)) 拆分数据集为训练数据集和测试数据集
trainX=[];trainY=[];testX=[];testY=[]
for i in range(len(Y)):
if i in randomIndex:
trainX.append(X[i])
trainY.append(Y[i])
else:
testX.append(X[i])
testY.append(Y[i])
from sklearn.linear_model import LogisticRegression
model = LogisticRegression() 获取逻辑回归默认线性代数的解析解(数据量少可以使用,数据量大无法直接解析解进行计算使用梯度下降)
model.fit(X, Y)
# predictYlogistic=map(lambda x:logclf.predict(x)[0],testX)
# 可以采用Python内建的持久性模型 pickle 来保存scikit的模型
import pickle 引入保存scikit的模型的模块
s = pickle.dumps(clf)
clf2 = pickle.loads(s)
clf2.predict(X[0])
非线性算法神经网络(仿生)ANN(artificial neural network)进行预测,神经网络是深度学习的基础,多层感知机MLP(multiple layer percepton)、卷积神级网络CNN(常用于图像识别)、循环神经网络RNN
激活函数:将神经元的净输入信号转换成单一的输出信号以便进一步在神经网络中传播
网络拓扑:描述神经网络模型中神经元的数量以及层数和神经元之间的连接方式
训练算法:指定如何设置连接权重,以便抑制或增加神经元在输入信号中的比重
激活函数的选择:对应神经元中的逻辑,两部分相乘相加和非线性的变化,相乘相加固定不变,非线性的变化需要根据效果进行选择
网络拓扑结构的选择:处理更加复杂的问题需要更多的网络层,需要每层上设置更多的人工神经元,神经网络拓扑结构的第一层为输入层最后一层为输出层,中间层成为隐藏层
训练算法的选择:在求解神经网络模型的时候即求解所有神经元的权重W,需要选择优化算法提高运算速度,可以使用SGD算法(硬件上可以使用GPU代替CPU进行计算)
激活函数常用有:Sigmoid函数(0到1之间)、Tangent函数(-1到1之间)、Relu函数max(0,x)
没有隐藏层的神经网络即单层神经网络实质是逻辑回归
神经网络算法的隐藏层增加了推理演绎的能力,随着隐藏层增多,推理和演绎的过程也增多,考虑的更深入,隐藏层的隐藏节点(神经元)数量比上一层的节点多,相当于进行升维考虑更多因素考虑更全面,隐藏层的隐藏节点数量比上一层的节点少,相当于降维进行归纳总结
from sklearn.neural_network import MLPClassifier 引入多层感知机分类算法模块
X = [[0., 0.], [1., 1.]]
y = [0, 1]
clf = MLPClassifier(solver='sgd', alpha=1e-5, activation='logistic',
hidden_layer_sizes=(5, 2), max_iter=2000, tol=1e-4) 获取sgd随机梯度下降优化算法L2正则化激活函数为logistic隐藏层为(5,2)两层最大迭代次数2000梯度阈值1e-4的多层感知机分类算法对象
clf.fit(X, y)
predicted_value = clf.predict([[2., 2.], [-1., -2.]])
print(predicted_value)
predicted_proba = clf.predict_proba([[2., 2.], [-1., -2.]])
print(predicted_proba)
print([coef.shape for coef in clf.coefs_]) 获取神经网络中权重的形状
print([coef for coef in clf.coefs_]) 获取神经网络权重值
soft-max回归基于多元线性回归进行多分类的算法
K为类别分数
soft-max回归的损失函数为交叉熵
逻辑回归近似是soft-max回归k=2时的特殊情况,soft-max回归每个类别之间互相关联
数据集一般分为训练集(训练和评估验证)和测试集
交叉验证(Cross-Validation)用于将训练集大部分数据样本进行建立模型,小部分训练集对建立的模型进行预报评估记录预报误差平方和
K折交叉验证:将训练集数据随机分为K份,每份作为验证集进行一次训练模型评估,找到超参数中K折交叉验证预报误差最小的超参数组合即找到模型最适合的超参数,由于超参数的组合多和K的数量会导致迭代次数多时间长
决策树和随机森林是非线性有监督分类模型
决策树(Decision Tree)使用的数据样本需要离散化:连续的数据可以根据区间段分割的方式将数据离散化到M+1种数据形式中,离散数据使用One-hot编码进行离散化成2^M中数据形式
决策树生成:数据样本按照每个维度进行分裂递归过程,将相同类别的数据归到树的一边,找到树的叶子节点中纯度最高的维度根节点的决策树为最优决策树
决策树分类纯度指标有:基尼系数(Gini Impurity)、熵(Entropy)和方差(Variance)
单颗决策树的缺点:运算量大,需要一次加载所有数据进内存并且找寻分割条件非常耗费资源的工作,训练样本中出现异常数据时,将会对决策树产生很大影响即抗干扰能力差,逻辑回归通过正则化进行泛化容错性好,决策树不能像逻辑回归可以给出分类的概率
决策树解决方法:减少决策树所需训练样本,随机采样降低异常数据的影响
随机森林(Random Forests):随机抽取数据集中多个部分数据样本生成多个决策树,将多个决策树分类结果汇总按照少数服从多数机制进行最终分类
逻辑回归是软分类输出有概率意义线性模型抗干扰能力强
随机森林是硬分类输出无概率意义非线性模型抗干扰能力弱
决策树生成时可以通过超参数对树进行预剪枝调节树的层数和叶子节点数量来提高数的泛化能力防止过拟合,决策树生成可以进行后剪枝进行提高泛化能力
单个决策树:
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris 引入数据集模块
from sklearn.tree import DecisionTreeClassifier 引入决策树分类模块
from sklearn.tree import export_graphviz
from sklearn.tree import DecisionTreeRegressor引入决策树回归模块
from sklearn.model_selection import train_test_split 引入数据集训练与测试数据分割模块
from sklearn.metrics import accuracy_score 引入评估准确率模块
import matplotlib.pyplot as plt
import matplotlib as mpl
iris = load_iris() 导入数据集
data = pd.DataFrame(iris.data) 转换成DataFrame数据类型
data.columns = iris.feature_names 数据加入列名称
data['Species'] = load_iris().target
# print(data)
x = data.iloc[:, :2] # 花萼长度和宽度
y = data.iloc[:, -1]
# y = pd.Categorical(data[4]).codes
# print(x)
# print(y)
x_train, x_test, y_train, y_test = train_test_split(x, y, train_size=0.75, random_state=42) 数据集切分成75%训练集25%测试集随机切分种子为42
tree_clf = DecisionTreeClassifier(max_depth=8, criterion='entropy') 获取决策树树最大层数为8纯度标准为entropy的模型对象
tree_clf.fit(x_train, y_train)
y_test_hat = tree_clf.predict(x_test)
print("acc score:", accuracy_score(y_test, y_test_hat)) 获取预测的正确率
"""
export_graphviz(
tree_clf,
out_file="./iris_tree.dot",
feature_names=iris.feature_names[:2],
class_names=iris.target_names,
rounded=True,
filled=True
)
# ./dot -Tpng ~/PycharmProjects/mlstudy/bjsxt/iris_tree.dot -o ~/PycharmProjects/mlstudy/bjsxt/iris_tree.png
"""
print(tree_clf.predict_proba([[5, 1.5]]))
print(tree_clf.predict([[5, 1.5]]))
depth = np.arange(1, 15)
err_list = []
for d in depth: 遍历超参数树深度层数找到最优的超参数
clf = DecisionTreeClassifier(criterion='entropy', max_depth=d)
clf.fit(x_train, y_train)
y_test_hat = clf.predict(x_test)
result = (y_test_hat == y_test)
if d == 1:
print(result)
err = 1 - np.mean(result)
print(100 * err)
err_list.append(err)
print(d, ' 错误率:%.2f%%' % (100 * err))
mpl.rcParams['font.sans-serif'] = ['SimHei'] 设置字体为SimHei
plt.figure(facecolor='w') 图底色白色
plt.plot(depth, err_list, 'ro-', lw=2) 设置图横坐