模型的假设检验(F与T):
F检验(主要检验模型是否合理)
'''
F检验:提出原假设和备择假设 之后计算统计量与理论值 最后比较
F检验主要检验的是模型是否合理
'''
# 置信度95%时 F值(单边)
1 """模型F的检验""" 2 # 计算统计量 3 4 # 导⼊第三⽅模块 5 import numpy as np 6 # 计算建模数据中因变量的均值 7 ybar=train.Profit.mean() 8 # 统计变量个数和观测个数 9 p=model2.df_model 10 n=train.shape[0] 11 # 计算回归离差平⽅和 12 RSS=np.sum((model2.fittedvalues-ybar)**2) 13 # 计算误差平⽅和 14 ESS=np.sum(model2.resid**2) 15 # 计算F统计量的值 16 F=(RSS/p)/(ESS/(n-p-1)) 17 print('F统计量的值:',F) 18 F统计量的值:174.6372 19 20 # 对比所得结论 21 22 # 导⼊模块 23 from scipy.stats import f 24 # 计算F分布的理论值 25 F_Theroy = f.ppf(q=0.95, dfn = p,dfd = n-p-1) 26 print('F分布的理论值为:',F_Theroy) 27 out: 28 F分布的理论值为: 2.5026 29 30 """ 31 计算出来的F统计量值174.64远远⼤于F分布的理论值2.50 32 所以应当拒绝原假设(先假设模型不合理) 33 原假设就是先假设模型不合理 34 """
T检验(看参数是否合理)
"""T检验更加侧重于检验模型的各个参数是否合理""" model.summary() # 绝对值越小影响越大
# 主要看这个研发成本
线性回归模型的短板:
###########################################################
1.自变量的个数大于样本数量 比如一家店的购物人数只有3个 但是影响人是否购物的因素有很多大于3
2.自变量之间存在多重共线性 简单来说就是自变量之间不能有明显的关系 比如昨天配置哑变量中三个州数据
###########################################################
如何去解决这个短板呢?解决方法如下:
# 岭回归模型 在线性回归模型的基础之上添加一个l2惩罚项(平方项、正则项) '''该模型最终转变成求解圆柱体与椭圆抛物线的焦点问题'''
# 如下图
# 交叉验证 将所有数据都参与到模型的构建和测试中 最后生成多个模型 再从多个模型中筛选出得分最高(准确度)的模型
# 糖尿病小案例
1 # 导入第三方模块 2 import pandas as pd 3 import numpy as np 4 from sklearn import model_selection 5 from sklearn.linear_model import Ridge,RidgeCV 6 import matplotlib.pyplot as plt 7 8 # 读取糖尿病数据集 9 diabetes = pd.read_excel(r'diabetes.xlsx') 10 diabetes.head() 11 # 构造自变量(剔除患者性别、年龄和因变量) 12 predictors = diabetes.columns[2:-1] 13 # 将数据集拆分为训练集和测试集 14 '''在之后稍微有点技术含量的模型都是要拆分4项的''' 15 X_train, X_test, y_train, y_test = model_selection.train_test_split(diabetes[predictors], diabetes['Y'], 16 test_size = 0.2, random_state = 1234 )
1 # 构造不同的Lambda值 后面的np.logspace就是个函数 2 Lambdas = np.logspace(-5, 2, 200) # 这里是个匿名函数 用来生成均匀的自定义点数 3 # 岭回归模型的交叉验证 4 # 设置交叉验证的参数,对于每一个Lambda值,都执行10重交叉验证 5 ridge_cv = RidgeCV(alphas = Lambdas, normalize=True, scoring='neg_mean_squared_error', cv = 10) 6 # 模型拟合 7 ridge_cv.fit(X_train, y_train) 8 # 返回最佳的lambda值 9 ridge_best_Lambda = ridge_cv.alpha_ 10 ridge_best_Lambda # 最后得出Lanbda的值最佳是多少
1 # 导入第三方包中的函数 2 from sklearn.metrics import mean_squared_error 3 # 基于最佳的Lambda值建模 4 ridge = Ridge(alpha = ridge_best_Lambda, normalize=True) 5 ridge.fit(X_train, y_train) 6 # 返回岭回归系数 7 pd.Series(index = ['Intercept'] + X_train.columns.tolist(),data = [ridge.intercept_] + ridge.coef_.tolist()) 8 # 预测 9 ridge_predict = ridge.predict(X_test) 10 # 预测效果验证 11 RMSE = np.sqrt(mean_squared_error(y_test,ridge_predict)) 12 RMSE # 所得到的值 越小越好
# Lasso回归模型 在线性回归模型的基础之上添加一个l1惩罚项(绝对值项、正则项) 相较于岭回归降低了模型的复杂度 '''该模型最终转变成求解正方体与椭圆抛物线的焦点问题'''
# 交叉验证与上 方法非常接近
Logistic回归模型:
将线性回归的模型做Logit变换 既为Logistic模型
将预测问题变成了一个0到1之间的预测值
# 以性别和肿瘤作为患癌的参数案例
混淆矩阵:
混淆矩阵的关键就在下图中的表格和最下面的文字概率
表格部分简单理解就变成了右侧的表
模型的评估方法:
# ROC曲线
通过计算AUC阴影部分的面积来判断模型是否合理(通常大于0.8表示OK)
# KS曲线
通过计算两条折现之间最大距离来衡量模型是否合理(通常大于0.4表示OK)
1 # 导入第三方模块 2 import pandas as pd 3 import numpy as np 4 import matplotlib.pyplot as plt 5 6 # 自定义绘制ks曲线的函数 7 def plot_ks(y_test, y_score, positive_flag): 8 # 对y_test重新设置索引 9 y_test.index = np.arange(len(y_test)) 10 # 构建目标数据集 11 target_data = pd.DataFrame({'y_test':y_test, 'y_score':y_score}) 12 # 按y_score降序排列 13 target_data.sort_values(by = 'y_score', ascending = False, inplace = True) 14 # 自定义分位点 15 cuts = np.arange(0.1,1,0.1) 16 # 计算各分位点对应的Score值 17 index = len(target_data.y_score)*cuts 18 scores = np.array(target_data.y_score)[index.astype('int')] 19 # 根据不同的Score值,计算Sensitivity和Specificity 20 Sensitivity = [] 21 Specificity = [] 22 for score in scores: 23 # 正例覆盖样本数量与实际正例样本量 24 positive_recall = target_data.loc[(target_data.y_test == positive_flag) & (target_data.y_score>score),:].shape[0] 25 positive = sum(target_data.y_test == positive_flag) 26 # 负例覆盖样本数量与实际负例样本量 27 negative_recall = target_data.loc[(target_data.y_test != positive_flag) & (target_data.y_score<=score),:].shape[0] 28 negative = sum(target_data.y_test != positive_flag) 29 Sensitivity.append(positive_recall/positive) 30 Specificity.append(negative_recall/negative) 31 # 构建绘图数据 32 plot_data = pd.DataFrame({'cuts':cuts,'y1':1-np.array(Specificity),'y2':np.array(Sensitivity), 33 'ks':np.array(Sensitivity)-(1-np.array(Specificity))}) 34 # 寻找Sensitivity和1-Specificity之差的最大值索引 35 max_ks_index = np.argmax(plot_data.ks) 36 plt.plot([0]+cuts.tolist()+[1], [0]+plot_data.y1.tolist()+[1], label = '1-Specificity') 37 plt.plot([0]+cuts.tolist()+[1], [0]+plot_data.y2.tolist()+[1], label = 'Sensitivity') 38 # 添加参考线 39 plt.vlines(plot_data.cuts[max_ks_index], ymin = plot_data.y1[max_ks_index], 40 ymax = plot_data.y2[max_ks_index], linestyles = '--') 41 # 添加文本信息 42 plt.text(x = plot_data.cuts[max_ks_index]+0.01, 43 y = plot_data.y1[max_ks_index]+plot_data.ks[max_ks_index]/2, 44 s = 'KS= %.2f' %plot_data.ks[max_ks_index]) 45 # 显示图例 46 plt.legend() 47 # 显示图形 48 plt.show()
1 # 导入虚拟数据 2 virtual_data = pd.read_excel(r'virtual_data.xlsx') 3 # 应用自定义函数绘制k-s曲线 4 plot_ks(y_test = virtual_data.Class, y_score = virtual_data.Score,positive_flag = 'P')
1 # 导入第三方模块 2 import pandas as pd 3 import numpy as np 4 from sklearn import model_selection 5 from sklearn import linear_model 6 7 # 读取数据 8 sports = pd.read_csv(r'Run or Walk.csv') 9 # 提取出所有自变量名称 10 predictors = sports.columns[4:] 11 # 构建自变量矩阵 12 X = sports.loc[:,predictors] 13 # 提取y变量值 14 y = sports.activity 15 # 将数据集拆分为训练集和测试集 16 X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size = 0.25, random_state = 1234) 17 18 # 利用训练集建模 19 sklearn_logistic = linear_model.LogisticRegression() 20 sklearn_logistic.fit(X_train, y_train) 21 # 返回模型的各个参数 22 print(sklearn_logistic.intercept_, sklearn_logistic.coef_) 23 # 输出结果如下
1 # 模型预测 2 sklearn_predict = sklearn_logistic.predict(X_test) 3 # 预测结果统计 4 pd.Series(sklearn_predict).value_counts()
1 # 导入第三方模块 2 from sklearn import metrics 3 # 混淆矩阵 4 cm = metrics.confusion_matrix(y_test, sklearn_predict, labels = [0,1]) 5 cm
1 Accuracy = metrics.scorer.accuracy_score(y_test, sklearn_predict) 2 Sensitivity = metrics.scorer.recall_score(y_test, sklearn_predict) 3 Specificity = metrics.scorer.recall_score(y_test, sklearn_predict, pos_label=0) 4 print('模型准确率为%.2f%%:' %(Accuracy*100)) 5 print('正例覆盖率为%.2f%%' %(Sensitivity*100)) 6 print('负例覆盖率为%.2f%%' %(Specificity*100))
1 # 混淆矩阵的可视化 2 # 导入第三方模块 3 import seaborn as sns 4 import matplotlib.pyplot as plt 5 %matplotlib 6 # 绘制热力图 7 sns.heatmap(cm, annot = True, fmt = '.2e',cmap = 'GnBu') 8 # 图形显示 9 plt.show()
sklearn_logistic.predict_proba(X_test)
1 # y得分为模型预测正例的概率 2 y_score = sklearn_logistic.predict_proba(X_test)[:,1] 3 # 计算不同阈值下,fpr和tpr的组合值,其中fpr表示1-Specificity,tpr表示Sensitivity 4 fpr,tpr,threshold = metrics.roc_curve(y_test, y_score) 5 # 计算AUC的值 6 roc_auc = metrics.auc(fpr,tpr) 7 8 # 绘制面积图 9 plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black') 10 # 添加边际线 11 plt.plot(fpr, tpr, color='black', lw = 1) 12 # 添加对角线 13 plt.plot([0,1],[0,1], color = 'red', linestyle = '--') 14 # 添加文本信息 15 plt.text(0.5,0.3,'ROC curve (area = %0.2f)' % roc_auc) 16 # 添加x轴与y轴标签 17 plt.xlabel('1-Specificity') 18 plt.ylabel('Sensitivity') 19 # 显示图形 20 plt.show()
# 调用自定义函数,绘制K-S曲线 plot_ks(y_test = y_test, y_score = y_score, positive_flag = 1)
# -----------------------第一步 建模 ----------------------- # # 导入第三方模块 import statsmodels.api as sm # 将数据集拆分为训练集和测试集 X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size = 0.25, random_state = 1234) # 为训练集和测试集的X矩阵添加常数列1 X_train2 = sm.add_constant(X_train) X_test2 = sm.add_constant(X_test) # 拟合Logistic模型 sm_logistic = sm.Logit(y_train, X_train2).fit() # 返回模型的参数 sm_logistic.params # -----------------------第二步 预测构建混淆矩阵 ----------------------- # # 模型在测试集上的预测 sm_y_probability = sm_logistic.predict(X_test2) # 根据概率值,将观测进行分类,以0.5作为阈值 sm_pred_y = np.where(sm_y_probability >= 0.5, 1, 0) # 混淆矩阵 cm = metrics.confusion_matrix(y_test, sm_pred_y, labels = [0,1]) cm # -----------------------第三步 绘制ROC曲线 ----------------------- # # 计算真正率和假正率 fpr,tpr,threshold = metrics.roc_curve(y_test, sm_y_probability) # 计算auc的值 roc_auc = metrics.auc(fpr,tpr) # 绘制面积图 plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black') # 添加边际线 plt.plot(fpr, tpr, color='black', lw = 1) # 添加对角线 plt.plot([0,1],[0,1], color = 'red', linestyle = '--') # 添加文本信息 plt.text(0.5,0.3,'ROC curve (area = %0.2f)' % roc_auc) # 添加x轴与y轴标签 plt.xlabel('1-Specificity') plt.ylabel('Sensitivity') # 显示图形 plt.show() # -----------------------第四步 绘制K-S曲线 ----------------------- # # 调用自定义函数,绘制K-S曲线 sm_y_probability.index = np.arange(len(sm_y_probability)) plot_ks(y_test = y_test, y_score = sm_y_probability, positive_flag = 1) '''代码的整体思路就是这样做下来'''
决策树:
"""
决策树与随机森林
默认情况下解决分类问题(买与不买、带与不带、走与不走)
也可以切换算法解决预测问题(具体数值多少)
"""
树其实是一种计算机底层的数据结构 与现实不同
计算机里面的树都是自上而下的生长
决策树则是算法模型中的一种概念 有三个主要部分
根节点 起始的最基本的判断要素 所有分支的基础
枝节点 根节点和枝节点存储的都是条件判断(中间节点)
叶子节点 就是没法再继续分支了
# 根节点与枝节点用于存放条件 叶子节点存放真正的数据结果
# 信息熵 eg : 信息熵小相当于红路灯 只有三个数据非常有序 ''' 信息熵既可以用来解决分类问题(买与不买、带与不带、走与不走) 也可以用来解决预测问题 '''
条件熵
其实就是由信息熵再次细分而来
比如有九个用户购买了商品五个没有购买 那么条件熵就是继续从购买不购买的用户中再选择一个条件(比如按照性别计算男和女的熵)
信息增益 信息增益可以反映出某个条件是否对最终的分类有决定性的影响 在构建决策树时根节点与枝节点所放的条件按照信息增益由大到小排 ''' 也就是某个条件对于结果影响的大小 影响越大的条件在构建决策树的时候越要靠根节点放 '''
信息增益率
决策树中的ID3算法使⽤信息增益指标实现根节点或中间节点的字段选择,但是该指标存在⼀个⾮常明显的缺点,即信息增益会偏向于取值较多的字段。
为了克服信息增益指标的缺点,提出了信息增益率的概念,它的思想很简单,就是在信息增益的基础上进⾏相应的惩罚。
简言之:信息增益会偏向于取值较多的指标
为平衡这一现象给他加入了惩罚项
即取值越多公式中会除以一个越大的数
# 基尼指数 可以让模型解决预测问题(通过公式将模型数学化 从而解决连续性变量)
# 基尼指数增益 与信息增益类似,还需要考虑⾃变量对因变量的影响程度 因变量的基尼指数下降速度的快慢,下降得越快,⾃变量对因变量的影响就越强
随机森林:
随机森林中每颗决策树都不限制节点字段选择 #尽可能细分 有多棵树组成的随机森林 在解决分类问题的时候采用投票法 # 选择树 解决预测问题的时候采用均值法 # 回归模型
1 # 导入第三方模块 2 import pandas as pd 3 import numpy as np 4 import matplotlib.pyplot as plt 5 from sklearn import model_selection 6 from sklearn import linear_model 7 # 读⼊数据 8 Titanic = pd.read_csv(r'Titanic.csv') 9 Titanic 10 # 删除⽆意义的变量,并检查剩余变量是否含有缺失值 11 Titanic.drop(['PassengerId','Name','Ticket','Cabin'], axis = 1, inplace = True) 12 Titanic.isnull().sum(axis = 0) 13 # 对Sex分组,⽤各组乘客的平均年龄填充各组中的缺失年龄 14 fillna_Titanic = [] 15 for i in Titanic.Sex.unique(): 16 update = Titanic.loc[Titanic.Sex == i,].fillna(value = {'Age': Titanic.Age[Titanic.Sex == i].mean()}, inplace 17 = False) 18 fillna_Titanic.append(update) 19 Titanic = pd.concat(fillna_Titanic) 20 # 使⽤Embarked变量的众数填充缺失值 21 Titanic.fillna(value = {'Embarked':Titanic.Embarked.mode()[0]}, inplace=True)
1 # 将数值型的Pclass转换为类别型,否则⽆法对其哑变量处理 2 Titanic.Pclass = Titanic.Pclass.astype('category') 3 # 哑变量处理 4 dummy = pd.get_dummies(Titanic[['Sex','Embarked','Pclass']]) 5 # ⽔平合并Titanic数据集和哑变量的数据集 6 Titanic = pd.concat([Titanic,dummy], axis = 1) 7 # 删除原始的Sex、Embarked和Pclass变量 8 Titanic.drop(['Sex','Embarked','Pclass'], inplace=True, axis = 1) 9 # 取出所有⾃变量名称 10 predictors = Titanic.columns[1:] 11 # 将数据集拆分为训练集和测试集,且测试集的⽐例为25% 12 X_train, X_test, y_train, y_test = model_selection.train_test_split(Titanic[predictors], Titanic.Survived, 13 test_size = 0.25, random_state = 1234) 14 15 from sklearn.model_selection import GridSearchCV 16 from sklearn import tree,metrics 17 # 预设各参数的不同选项值 18 max_depth = [2,3,4,5,6] 19 min_samples_split = [2,4,6,8] 20 min_samples_leaf = [2,4,8,10,12] 21 # 将各参数值以字典形式组织起来 22 parameters = {'max_depth':max_depth, 'min_samples_split':min_samples_split, 23 'min_samples_leaf':min_samples_leaf} 24 # ⽹格搜索法,测试不同的参数值 25 grid_dtcateg = GridSearchCV(estimator = tree.DecisionTreeClassifier(), param_grid = parameters, cv=10) 26 # 模型拟合 27 grid_dtcateg.fit(X_train, y_train) 28 # 返回最佳组合的参数值 29 grid_dtcateg.param_grid 30 # 输出结果如下图
1 # 构建分类决策树 2 CART_Class = tree.DecisionTreeClassifier(max_depth=3,min_samples_leaf=4,min_samples_split=2) 3 # 模型拟合 4 decision_tree = CART_Class.fit(X_train,y_train) 5 # 模型在测试集上的预测 6 pred = CART_Class.predict(X_test) 7 # 模型的准确率 8 print('模型在测试集的预测准确率:\n',metrics.accuracy_score(y_test,pred)) 9 print('模型在训练集的预测准确率:\n', 10 metrics.accuracy_score(y_train,CART_Class.predict(X_train)))
K近邻模型:
思想:根据位置样本点周边K个邻居样本完成预测或者分类 # K值的选择 1.先猜测 2.交叉验证 3.作图选择最合理的k值 准确率(越大越好) MSE(越小越好)
# 过拟合与欠拟合 # 就是精确度一个太高(过拟合 )一个太低 (欠拟合) # 太高模型的泛用性就会很差