模型的假設檢驗(F與T)
F檢驗
提出原假設和備用假設,之后計算統計量與理論值,最后進行比較。
F校驗主要檢驗的是模型是否合理。
導入第三方模塊
import numpy as np import pandas as pd from sklearn import model_selection import statsmodels.api as sm # 數據處理 Profit = pd.read_excel(r'Predict to Profit.xlsx') dummies = pd.get_dummies(Profit.State) Profit_New = pd.concat([Profit,dummies], axis = 1) Profit_New.drop(labels = ['State','New York'], axis = 1, inplace = True) train, test = model_selection.train_test_split(Profit_New, test_size = 0.2, random_state=1234) model2 = sm.formula.ols('Profit~RD_Spend+Administration+Marketing_Spend+Florida+California', data = train).fit()
統計變量個和觀測個數
ybar=train.Profit.mean()
統計變量個數和觀察個數
p=model2.df_model n=train.shape[0]
計算回歸離差平方和
RSS=np.sum((model2.fittedvalues-ybar)**2)
計算誤差平方和
ESS=np.sum(model2.resid**2)
計算F統計量的值
F=(RSS/p)/(ESS/(n-p-1)) print('F統計量的值:',F)
計算F分布的理論值
from scipy.stats import f # 計算F分布的理論值 F_Theroy = f.ppf(q=0.95, dfn = p,dfd = n-p-1) print('F分布的理論值為:',F_Theroy)
結論:
可以看到計算出來的F統計值(174.6)遠遠大於F分布的理論值(2.5),所以應該拒絕原假設。
T檢驗
T檢驗更加側重於檢驗模型的各個參數是否合理。
model.summary() # 絕對值越小影響越大
線性回歸模型的短板
自變量的個數大於樣本量
自變量之間存在多重共線性
解決線性回歸模型的短板
嶺回歸模型
在線性回歸模型的基礎之上添加一個l2懲罰項(平方項、正則項),該模型最終轉變成求解圓柱體與橢圓拋物線的焦點問題。
Lasso回歸模型
在線性回歸模型的基礎之上添加一個l1懲罰項(絕對值項、正則項)
相較於嶺回歸降低了模型的復雜度,該模型最終轉變成求解正方體與橢圓拋物線的焦點問題。
交叉驗證
將所有數據都參與到模型的構建和測試中 最后生成多個模型,再從多個模型中篩選出得分最高(准確度)的模型。
嶺回歸模型的交叉驗證
數據准備
# 導入第三方模塊 import pandas as pd import numpy as np from sklearn import model_selection from sklearn.linear_model import Ridge,RidgeCV import matplotlib.pyplot as plt # 讀取糖尿病數據集 diabetes = pd.read_excel(r'diabetes.xlsx', sep = '') # 構造自變量(剔除患者性別、年齡和因變量) predictors = diabetes.columns[2:-1] # 將數據集拆分為訓練集和測試集 X_train, X_test, y_train, y_test = model_selection.train_test_split(diabetes[predictors], diabetes['Y'], test_size = 0.2, random_state = 1234 )
獲得lambda數值
# 構造不同的Lambda值 Lambdas = np.logspace(-5, 2, 200) # 嶺回歸模型的交叉驗證 # 設置交叉驗證的參數,對於每一個Lambda值,都執行10重交叉驗證 ridge_cv = RidgeCV(alphas = Lambdas, normalize=True, scoring='neg_mean_squared_error', cv = 10) # 模型擬合 ridge_cv.fit(X_train, y_train) # 返回最佳的lambda值 ridge_best_Lambda = ridge_cv.alpha_ ridge_best_Lambda
預測
# 導入第三方包中的函數 from sklearn.metrics import mean_squared_error # 基於最佳的Lambda值建模 ridge = Ridge(alpha = ridge_best_Lambda, normalize=True) ridge.fit(X_train, y_train) # 返回嶺回歸系數 pd.Series(index = ['Intercept'] + X_train.columns.tolist(),data = [ridge.intercept_] + ridge.coef_.tolist()) # 預測 ridge_predict = ridge.predict(X_test) # 預測效果驗證 RMSE = np.sqrt(mean_squared_error(y_test,ridge_predict)) RMSE
lasso回歸模型交叉驗證
獲取lambda值
# 導入第三方模塊中的函數 from sklearn.linear_model import Lasso,LassoCV # LASSO回歸模型的交叉驗證 lasso_cv = LassoCV(alphas = Lambdas, normalize=True, cv = 10, max_iter=10000) lasso_cv.fit(X_train, y_train) # 輸出最佳的lambda值 lasso_best_alpha = lasso_cv.alpha_ lasso_best_alpha
建模並預測
# 基於最佳的lambda值建模 lasso = Lasso(alpha = lasso_best_alpha, normalize=True, max_iter=10000) lasso.fit(X_train, y_train) # 返回LASSO回歸的系數 pd.Series(index = ['Intercept'] + X_train.columns.tolist(),data = [lasso.intercept_] + lasso.coef_.tolist()) # 預測 lasso_predict = lasso.predict(X_test) # 預測效果驗證 RMSE = np.sqrt(mean_squared_error(y_test,lasso_predict)) RMSE
Logistic回歸模型
將線性回歸模型的公式做Logit變換,即為Logistic回歸模型,將預測問題變成了0到1之間的概率問題。
混淆矩陣
准確率
表示正確預測的正負例樣本數與所有樣本數量的⽐值,即(A+D)/(A+B+C+D)
正例覆蓋率
表示正確預測的正例數在實際正例數中的⽐例,即D/(B+D)
負例覆蓋率
表示正確預測的負例數在實際負例數中的⽐例,即A/(A+C)
正例命中率
表示正確預測的正例數在預測正例數中的⽐例,即D/(C+D)
代碼
# 導入第三方模塊 import pandas as pd import numpy as np from sklearn import model_selection from sklearn import linear_model # 讀取數據 sports = pd.read_csv(r'Run or Walk.csv') # 提取出所有自變量名稱 predictors = sports.columns[4:] # 構建自變量矩陣 X = sports.ix[:,predictors] # 提取y變量值 y = sports.activity # 將數據集拆分為訓練集和測試集 X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size = 0.25, random_state = 1234) # 利用訓練集建模 sklearn_logistic = linear_model.LogisticRegression() sklearn_logistic.fit(X_train, y_train) # 返回模型的各個參數 print(sklearn_logistic.intercept_, sklearn_logistic.coef_) # 模型預測 sklearn_predict = sklearn_logistic.predict(X_test) # 預測結果統計 pd.Series(sklearn_predict).value_counts() # 導入第三方模塊 from sklearn import metrics # 混淆矩陣 cm = metrics.confusion_matrix(y_test, sklearn_predict, labels = [0,1]) cm Accuracy = metrics.scorer.accuracy_score(y_test, sklearn_predict) Sensitivity = metrics.scorer.recall_score(y_test, sklearn_predict) Specificity = metrics.scorer.recall_score(y_test, sklearn_predict, pos_label=0) print('模型准確率為%.2f%%:' %(Accuracy*100)) print('正例覆蓋率為%.2f%%' %(Sensitivity*100)) print('負例覆蓋率為%.2f%%' %(Specificity*100))
模型的評估方法
ROC曲線
通過計算AUC陰影部分的面積來判斷模型是否合理(通常大於0.8表示合理)
KS曲線
通過計算兩條折線之間最大距離來衡量模型是否合理(通常大於0.4表示合理)
繪制KS曲線代碼
def內的代碼保存下來即可
# 導入第三方模塊 import pandas as pd import numpy as np import matplotlib.pyplot as plt # 自定義繪制ks曲線的函數 def plot_ks(y_test, y_score, positive_flag): # 對y_test重新設置索引 y_test.index = np.arange(len(y_test)) # 構建目標數據集 target_data = pd.DataFrame({'y_test':y_test, 'y_score':y_score}) # 按y_score降序排列 target_data.sort_values(by = 'y_score', ascending = False, inplace = True) # 自定義分位點 cuts = np.arange(0.1,1,0.1) # 計算各分位點對應的Score值 index = len(target_data.y_score)*cuts scores = np.array(target_data.y_score)[index.astype('int')] # 根據不同的Score值,計算Sensitivity和Specificity Sensitivity = [] Specificity = [] for score in scores: # 正例覆蓋樣本數量與實際正例樣本量 positive_recall = target_data.loc[(target_data.y_test == positive_flag) & (target_data.y_score>score),:].shape[0] positive = sum(target_data.y_test == positive_flag) # 負例覆蓋樣本數量與實際負例樣本量 negative_recall = target_data.loc[(target_data.y_test != positive_flag) & (target_data.y_score<=score),:].shape[0] negative = sum(target_data.y_test != positive_flag) Sensitivity.append(positive_recall/positive) Specificity.append(negative_recall/negative) # 構建繪圖數據 plot_data = pd.DataFrame({'cuts':cuts,'y1':1-np.array(Specificity),'y2':np.array(Sensitivity), 'ks':np.array(Sensitivity)-(1-np.array(Specificity))}) # 尋找Sensitivity和1-Specificity之差的最大值索引 max_ks_index = np.argmax(plot_data.ks) plt.plot([0]+cuts.tolist()+[1], [0]+plot_data.y1.tolist()+[1], label = '1-Specificity') plt.plot([0]+cuts.tolist()+[1], [0]+plot_data.y2.tolist()+[1], label = 'Sensitivity') # 添加參考線 plt.vlines(plot_data.cuts[max_ks_index], ymin = plot_data.y1[max_ks_index], ymax = plot_data.y2[max_ks_index], linestyles = '--') # 添加文本信息 plt.text(x = plot_data.cuts[max_ks_index]+0.01, y = plot_data.y1[max_ks_index]+plot_data.ks[max_ks_index]/2, s = 'KS= %.2f' %plot_data.ks[max_ks_index]) # 顯示圖例 plt.legend() # 顯示圖形 plt.show()
# 應用自定義函數繪制k-s曲線
virtual_data = pd.read_excel(r'virtual_data.xlsx')
plot_ks(y_test = virtual_data.Class, y_score = virtual_data.Score,positive_flag = 'P')
決策樹與隨機森林
默認情況下解決分類問題(買與不買,帶與不帶,走與不走),也可以切換算法解決預測問題(具體數值)
決策樹
樹其實是一種計算機底層的數據結構,計算機里的書都是自上而下的生長。
決策樹則是算法模型中的一種概念 有三個主要部分
根節點、枝節點
用於存放條件
葉子節點
存放真正的數據結果
信息熵
信息熵小的時候相當於紅綠燈情況
信息熵大的時候相當於買彩票中獎情況
條件熵
由信息熵再次細分獲得
例如:有九個用戶購買了商品,五個用戶沒有購買,那么條件熵就是繼續從購買或者不購買的用戶中再選擇一個條件進行判斷:比如按照性別計算男和女的熵
信息增益
信息增益可以反映出某個條件是否對最終的分類有決定性的影響。
在特征選擇的時候常常用信息增益,構建決策樹時根節點與枝節點所放的條件按照信息增益由大到小排,如果信息增益大的話,那么這個特征對於分類來說很關鍵。
信息增益率
決策樹中的ID3算法使⽤信息增益指標實現根節點或中間節點的字段選擇,但是該指標存在⼀個⾮常明顯的缺點,即信息增益會偏向於取值較多的字段。
為了克服信息增益指標的缺點,提出了信息增益率的概念,它的思想很簡單,就是在信息增益的基礎上進⾏相應的懲罰。
基尼指數
可以讓模型解決預測問題。
基尼指數增益
與信息增益類似,還需要考慮⾃變量對因變量的影響程度,即因變量的基尼指數下降速度的快慢,下降得越快,⾃變量對因變量的影響就越強。
隨機森林
隨機森林中每顆決策樹都不限制節點字段選擇,有多棵樹組成的隨機森林
在解決分類問題的時候采用投票法(多數結果)、解決預測問題的時候采用均值法(平均結果)
K近鄰模型
思想:根據位置樣本點周邊k個鄰居樣本完成預測或者分類。
K值的選擇
先猜測
交叉驗證
作圖選擇最合理的K值
過擬合與欠擬合
過擬合
訓練誤差和測試誤差之間的差距太大,也就是模型復雜度高於實際問題,模型在訓練集上表現很好,但在測試集上卻表現很差。
欠擬合
模型不能在訓練集上獲得足夠低的誤差,換句話說,就是模型復雜度低,模型在訓練集上就表現很差。
距離
歐氏距離
兩點間的直線距離。
曼哈頓距離
就像走路需要的實際距離
余弦相似度
查重時使用
K值計算代碼演示
import numpy as np import pandas as pd from sklearn import model_selection import matplotlib.pyplot as plt from sklearn import neighbors Knowledge = pd.read_excel(r'Knowledge.xlsx') predictors = Knowledge.columns[:-1] X_train, X_test, y_train, y_test = model_selection.train_test_split(Knowledge[predictors],Knowledge.UNS,test_size = 0.25, random_state =1234) K = np.arange(1,np.ceil(np.log2(Knowledge.shape[0]))).astype(int) accuracy = [] for k in K: cv_result = model_selection.cross_val_score(neighbors.KNeighborsClassifier(n_neighbors = k, weights = 'distance'), X_train, y_train, cv = 10, scoring='accuracy') accuracy.append(cv_result.mean()) arg_max = np.array(accuracy).argmax() plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False plt.plot(K, accuracy) plt.scatter(K, accuracy) plt.text(K[arg_max], accuracy[arg_max],'最佳k值為%s' %int(K[arg_max])) plt.show()