(六十二)基于logistic回归的信用评级和分类模型评估
案例數據介紹
本案例中的企業從事個人汽車金融服務,向購車的個人提供信用貸款。該公司的風控部門根據貸款申請者的基本屬性、信貸歷史、歷史信用情況、貸款標的物的情況等信息構建貸款違約頂測模型,其中是否違約bad_ind是因變量。數據來自《Python數據科學:技術詳解與商業實踐》第八章。
import numpy as np from sklearn.linear_model import LogisticRegression,LogisticRegressionCV from sklearn.model_selection import train_test_split import pandas as pd from sklearn.metrics import classification_report,confusion_matrix import matplotlib.pyplot as plt accepts = pd.read_csv(r'C:\Users\accepts2.csv').dropna() #%% ##數據說明:本數據是一份汽車貸款違約數據 ##名稱---中文含義 ##application_id---申請者ID ##account_number---帳戶號 ##bad_ind---是否違約 ##vehicle_year---汽車購買時間 ##vehicle_make---汽車制造商 ##bankruptcy_ind---曾經破產標識 ##tot_derog---五年內信用不良事件數量(比如手機欠費消號) ##tot_tr---全部帳戶數量 ##age_oldest_tr---最久賬號存續時間(月) ##tot_open_tr---在使用帳戶數量 ##tot_rev_tr---在使用可循環貸款帳戶數量(比如信用卡) ##tot_rev_debt---在使用可循環貸款帳戶余額(比如信用卡欠款) ##tot_rev_line---可循環貸款帳戶限額(信用卡授權額度) ##rev_util---可循環貸款帳戶使用比例(余額/限額) ##fico_score---FICO打分,越高信用越好 ##purch_price---汽車購買金額(元) ##msrp---建議售價 ##down_pyt---分期付款的首次交款 ##loan_term---貸款期限(月) ##loan_amt---貸款金額 ##ltv---貸款金額/建議售價*100 ##tot_income---月均收入(元) ##veh_mileage---行使里程(Mile) ##used_ind---是否二手車 Out[2]: application_id account_number bad_ind ... veh_mileage used_ind weight 0 2314049 11613 1 ... 24000.0 1 1.00 1 63539 13449 0 ... 22.0 0 4.75 3 8725187 15359 1 ... 10000.0 1 1.00 4 4275127 15812 0 ... 14.0 0 4.75 5 8712513 16979 0 ... 1.0 0 4.75... ... ... ... ... ... ... 5840 2291068 10005156 0 ... 45000.0 1 4.75 5841 7647192 10005616 0 ... 21.0 0 4.75 5842 5993246 10006591 0 ... 25000.0 1 4.75 5843 4766566 10010208 0 ... 0.0 0 4.75 5844 1928782 10010219 0 ... 12.0 0 4.75[4105 rows x 25 columns]下面對數據進行預處理,并生成一些衍生比值指標:
##衍生變量計算函數: def divMy(x,y):if x==np.nan or y==np.nan:return np.nanelif y==0:return -1else:return x/y ##歷史負債收入比:tot_rev_line/tot_income accepts["dti_hist"]=accepts[["tot_rev_line","tot_income"]].apply(lambda x:divMy(x[0],x[1]),axis = 1) ##本次新增負債收入比:loan_amt/tot_income accepts["dti_mew"]=accepts[["loan_amt","tot_income"]].apply(lambda x:divMy(x[0],x[1]),axis = 1) ##本次貸款首付比例:down_pyt/loan_amt accepts["fta"]=accepts[["down_pyt","loan_amt"]].apply(lambda x:divMy(x[0],x[1]),axis = 1) ##新增債務比:loan_amt/tot_rev_debt accepts["nth"]=accepts[["loan_amt","tot_rev_debt"]].apply(lambda x:divMy(x[0],x[1]),axis = 1) ##新增債務額度比:loan_amt/tot_rev_line accepts["nta"]=accepts[["loan_amt","tot_rev_line"]].apply(lambda x:divMy(x[0],x[1]),axis = 1) ##bankruptcy_ind的'Y'和'N'轉換為1和0 accepts["bankruptcy_ind"]=accepts["bankruptcy_ind"].apply(lambda x:1 if x=='Y' else (0 if x=='N' else np.nan))Logistic回歸
Logistic回歸通過logit轉換將取值為正負無窮的線性方程的值域轉化為(0,1) ,正好與概率的取值范圍一致,如下所示:
其中 Pi / (1-Pi) 可解釋為在樣本中違約的概率是不違約的概率的多少倍。在scikit-learn中,與邏輯回歸有關的主要是LogisticRegression、LogisticRegressionCV等。主要區別是LogisticRegressionCV使用了交叉驗證來選擇正則化系數C,而LogisticRegression需要自己每次指定一個正則化系數(其中C參數為正則化系數λ的倒數,默認為1)。
一、LogisticRegression()
sklearn.linear_model.LogisticRegression(penalty=‘l2’, dual=False, tol=0.0001, C=1.0,fit_intercept=True, intercept_scaling=1, class_weight=None, random_state=None,solver=‘liblinear’, max_iter=100, multi_class=‘ovr’, verbose=0,warm_start=False, n_jobs=1),其中最常使用的參數有正則化選擇參數:penalty,優化算法選擇參數:solver,分類方式選擇參數:multi_class,類型權重參數:class_weight以及樣本權重參數:sample_weight等,具體可參閱sun_shengyun:sklearn邏輯回歸類庫使用小結。
正則化選擇參數penalty
- LogisticRegression默認帶了正則化項L2。penalty參數可選擇的值為"l1"和"l2"。
- 上篇博客也說到,在調參時如果主要目的只是為了解決過擬合,一般penalty選擇L2正則化就夠了。如果選擇L2發現還是過擬合,即預測效果差時,就可以考慮L1正則化。另外,如果模型的特征非常多,我們希望一些不重要的特征系數歸零,從而讓模型系數稀疏化的話,也可以使用L1正則化。
- penalty參數的選擇會影響我們損失函數優化算法參數solver的選擇。如果是L2正則化,那么4種可選的算法{‘newton-cg’, ‘lbfgs’, ‘liblinear’, ‘sag’}都可選。但如果是L1正則化,就只能選擇‘liblinear’了。這是因為L1正則化的損失函數不是連續可導的,而{‘newton-cg’, ‘lbfgs’,‘sag’}這三種優化算法時都需要損失函數的一階或者二階連續導數。
優化算法選擇參數solver
- solver參數決定了我們對邏輯回歸損失函數的優化方法,有4種算法可以選擇,分別是:liblinear、 lbfgs、newton-cg、sag。
- L1、liblinear:適用于小數據集;如果選擇L2正則化發現還是過擬合,就可以考慮L1正則化;如果模型的特征非常多,希望一些不重要的特征系數歸零,也可以使用L1正則化。
- L2、liblinear:libniear只支持多元邏輯回歸的OvR,不支持MvM,但MVM相對精確。
- L2、lbfgs/newton-cg/sag:較大數據集,支持one-vs-rest(OvR)和many-vs-many(MvM)兩種分類方式選擇參數下的多元邏輯回歸。
- L2、sag:如果樣本量非常大,比如大于10萬,sag是第一選擇;但不能用于L1正則化。
分類方式選擇參數multi_class
- multi_class參數決定了分類方式的選擇,有 ovr和multinomial兩個值可以選擇,默認是 ovr。
- ovr即前面提到的one-vs-rest(OvR),而multinomial即前面提到的many-vs-many(MvM)。如果是二元邏輯回歸(即只有兩種可能結果,如違約和不違約),ovr和multinomial并沒有任何區別,區別主要在多元邏輯回歸上。
類型權重參數class_weight
- 考慮誤分類代價敏感、分類類型不平衡的問題,class_weight可選 : ‘balanced’, default: None
- class_weight參數用于標示分類模型中各種類型的權重,可以不輸入,即不考慮權重,或者說所有類型的權重一樣。如果選擇輸入的話,可以選擇balanced讓類庫自己計算類型權重,或者我們自己輸入各個類型的權重,比如對于0,1的二元模型,我們可以定義class_weight={0:0.9,1:0.1},這樣類型0的權重為90%,而類型1的權重為10%。
- 如果class_weight選擇balanced,那么類庫會根據訓練樣本量來計算權重。某種類型樣本量越多,則權重越低,樣本量越少,則權重越高。
樣本權重參數sample_weight
- 當樣本是高度失衡的,導致樣本不是總體樣本的無偏估計,從而可能導致我們的模型預測能力下降。調節樣本權重的方法有兩種,第一種是在class_weight使用balanced。第二種是在調用fit函數時,通過sample_weight來自己調節每個樣本權重。
- 如果上面兩種方法都用到了,那么樣本的真正權重是class_weight*sample_weight。
這里我們選擇C=0.01(即λ=100),penalty = ‘l2’,solver=‘lbfgs’。下面根據數據集中25個特征(排除application_id、account_number、vehicle_make)以及bad_ind進行多變量邏輯回歸:
data=accepts.iloc[:,4:]#25個特征數據 target=accepts.bad_ind train_X,test_X,train_y,test_y = train_test_split(data,target,test_size = 0.3,random_state = 0) logit=LogisticRegression(C = 0.01,penalty = 'l2',solver='lbfgs',max_iter = 100000).fit(train_X,train_y) coef = pd.Series(logit.coef_[0,:],index = train_X.columns) ###繪制特征系數大小排名圖 from pylab import mpl mpl.rcParams['font.sans-serif'] = ['SimHei'] mpl.rcParams['axes.unicode_minus']=False plt.figure(figsize=(8,6)) coef.sort_values().plot(kind = "barh",width = 0.35) plt.title("模型中各特征的系數") plt.grid() plt.show()
可以看到25個特征中有不少特征系數幾乎為0,因此可以剔除這些特征再進行邏輯回歸,此處不再贅述。下面是LogisticRegression自帶的一些方法,可以查看對測試集的預測效果:
可以看到第一列為預測結果,二、三列為預測為0(不違約)和1(違約)的概率。在第15條數據中,由于預測為0的概率小于預測為1的概率,因此分類標簽為1。訓練集和測試集的準確率均在80%以上且相差不大,擬合效果較好。
二、LogisticRegressionCV()
交叉驗證法(cross validation)先將數據集劃分為 k 個大小相似的互斥子集,每次用 k-1 個子集的并集作為訓練集,余下的那個子集作為測試集,這樣就可獲得 k 組訓練/測試集,從而可進行 k 次訓練和測試,最終返回的是這 k 個測試結果的均值。交叉驗證法評估結果的穩定性和保真性在很大程度上取決于 k 的取值,為強調這一點,通常把交叉驗證法稱為 k 折交叉驗證 (k-fold cross validation),k 最常用的取值是 5、10、20等。下圖給出了10折交叉驗證的示意:
LogisticRegressionCV(*, self, Cs=10, fit_intercept=True, cv=None, dual=False, penalty=‘l2’, scoring=None, solver=‘lbfgs’, tol=1e-4, max_iter=100, class_weight=None, n_jobs=None, verbose=0, refit=True, intercept_scaling=1., multi_class=‘auto’, random_state=None, l1_ratios=None),其中:
- Cs表示產生C的個數,例如Cs=10,會產生相應的10個C:10(-4), 10(-3.11),10(-2.22), … , 10(-3.11), 104,LogisticRegressionCV會自動進行交叉驗證,從上面10個C里面挑出最佳的C;
- 交叉驗證參數cv,默認fold數量為3,使用3折交叉驗證;
- 并行數n_jobs,默認值1,-1表示與CPU個數一致。
- 其它參數含義可參考官方文檔。
查準率、查全率及F1值
sklearn中的classification_report函數用于顯示主要分類指標的文本報告,在報告中顯示每個類的查準率、查全率及F1值等信息。其中左邊的一列為分類的標簽名、準確度、宏平均和加權平均等,support列為每個標簽的出現次數/總和,precision、recall、f1-score三列分別為各個類別的查準率、查全率及F1值。
print(confusion_matrix(test_y,pred_test,labels=[0,1]))#LogisticRegression方法下的混淆矩陣 print(classification_report(test_y,pred_test))#LogisticRegression方法下的分類結果報告 [[970 18][222 22]]precision recall f1-score support0 0.81 0.98 0.89 9881 0.55 0.09 0.15 244accuracy 0.81 1232macro avg 0.68 0.54 0.52 1232 weighted avg 0.76 0.81 0.74 1232對于二分類問題,可將樣例根據其真實類別與學習器預測類別的組合劃分為真正例(true positive)、假正例(false positive)、真反例(true negative)、 假反例(false negative)四種情形,令TP、FP、TN、FN分別表示其對應的樣例數,則顯然有TP+FP+TN+FN=樣例總數。分類結果的混淆矩陣如下:
查準率和查全率是一對矛盾的度量。一般來說,查準率高時,查全率往往偏低;而查全率高時,查準率往往偏低。F1是基于查準率與查全率的調和平均定義的:
對混淆矩陣結果的判斷可參考Vincent__Lai:如何通過Recall和Precise快速判斷自己模型的問題。在一些應用中,對查準率和查全率的重視程度有所不同。例如在商品推薦系統中,為了盡可能少打擾用戶,更希望推薦內容確是用戶感興趣的,此時查準率更重要;而在逃犯信息檢索系統中,更希望盡可能少漏掉逃犯,此時查全率更重要。而本案例的貸款發生違約的后果嚴重,因此查全率更加重要,后續工作應該是著力于提高標簽1預測的查全率,比如修改分類的默認閾值0.5、提高標簽為1樣本的權重等。下面通過修改class_weight='balanced’來提高查全率:
可以看到標簽1的查全率大大提高了。
ROC和AUC
ROC全稱是"受試者工作特征" (Receiver Operating Characteristic) 曲線。ROC 曲線的縱軸是"真正例率" (True Positive Rate,簡稱 TPR),橫軸是"假正例率" (False Positive Rate,簡稱 FPR),基于前文混淆矩陣中的符號,兩者分別定義為:
顯示 ROC 曲線的圖稱為 ROC 圖,下圖給出了一個示意圖,顯然對角線對應于"隨機猜測"模型,而點 (0,1) 則對應于將所有正例排在所有反例之前的"理想模型"。
繪圖過程很簡單:給定m+個正例和m-個反例,根據學習器預測結果對樣例進行排序,然后把分類閾值設為最大,即把所有樣例均預測為反例,此時真正例率和假正例率均為0,在坐標 (0,0) 處標記一個點。然后,將分類閾值依次設為每個樣例的預測值,即依次將每個樣例劃分為正例。設前一個標記點坐標為 (x,y), 當前若為真正例,則對應標記點的坐標為 (x,y+1/m+);當前若為假正例,則對應標記點的坐標為 (x+1/m-,y),然后用線段連接相鄰點即得。
進行學習器的比較時,若一個學習器的 ROC 曲線被另一個學習器的曲線完全"包住",則可斷言后者的性能優于前者;若兩個學習器的 ROC 曲線發生交叉,則難以斷言兩者孰優孰劣。此時如果一定要進行比較,則較為合理的判據是比較 ROC 曲線下的面積,即AUC (Area Under ROC Curve),如上圖所示。
sklearn.metrics.roc_curve函數可繪制ROC曲線。fpr, tpr, thresholds = roc_curve(y_true, y_score, pos_label = None, sample_weight = None, drop_intermediate = True):
- y_true是真實的樣本標簽,默認為{0,1}或者{-1,1}。如果要設置為其它值,則 pos_label 參數要設置為特定值。
- y_score是預測為正label的概率;
- pos_label即標簽中認定為正的label;
- sample_weight即采樣權重,可選擇取其中的一部分進行計算;
- drop_intermediate(default=True)即可選擇去掉一些對于ROC性能不利的閾值,使得到的曲線有更好的表現性能。
- 返回值fpr, tpr, thresholds即前文提到的假正例率、真正例率和閾值。
下面以LogisticRegression得出的結果為例,畫出ROC曲線,計算AUC值。此處正label為0,因此pos_label=0,y_score為預測標簽為0的概率prob0_test:
from sklearn.metrics import roc_curve,auc false_positive_rate,true_positive_rate,thresholds=roc_curve(test_y,prob0_test,pos_label=0) roc_auc=auc(false_positive_rate, true_positive_rate) plt.title('ROC') plt.plot(false_positive_rate, true_positive_rate,'b',label='AUC = %0.2f'% roc_auc) plt.legend(loc='best') plt.plot([0,1],[0,1],'r--')#隨機猜測45°線 plt.ylabel('TPR') plt.xlabel('FPR') plt.show()參考文獻
https://blog.csdn.net/sun_shengyun/article/details/53811483
https://blog.csdn.net/w1301100424/article/details/84546194
http://www.sofasofa.io/forum_main_post.php?postid=1000383
周志華《機器學習》,清華大學出版社
常國珍等《Python數據科學:技術詳解與商業實踐》,機械工業出版社
總結
以上是生活随笔為你收集整理的(六十二)基于logistic回归的信用评级和分类模型评估的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 百度DuerOS硅谷公布普罗米修斯计划,
- 下一篇: CSS基础教程(下)