以德国信用数据为例,用logistict regression算法做信用评分卡原理性实现,因此并未考虑feature selection.
第一步:导入必要的库
import pandas as pd import numpy as np from sklearn.cross_validation import train_test_split
第二步:导入数据
german = pd.read_csv('D:/CreditDatasets/german.data', sep=' ', header=None) german.columns = ['Status_of_existing_checking_account', 'Duration_in_month', 'Credit_history','Purpose', 'Credit_amount', 'Savings_account', 'Present_employment_since','Installment_rate', 'Personal_status_and_sex', 'Other_debtors', 'Present_residence_since','Property', 'Age', 'Other_installment_plans', 'Housing', 'Number_of_existing_credits','Job', 'Number_of_people', 'Telephone', 'foreign_worker', 'default'] Grp = german.groupby('default') total_good = Grp.size()[1] total_bad = Grp.size()[2]
第三步:分别计算名义变量和数值变量的woe值,对取值较少的数值变量也用名义变量woe计算方法实现,其余数值变量均5等分
def CalcWOE(VarName): WOE_Map = pd.DataFrame() Vars = np.unique(german[VarName]) for v in Vars: tmp = german[VarName] == v grp = german[tmp].groupby('default') Good = grp.size()[1] Bad = grp.size()[2] good_ratio = float(Good)/total_good bad_ratio = float(Bad)/total_bad WOE = np.log(bad_ratio/good_ratio) IV = (bad_ratio - good_ratio)*WOE result = pd.DataFrame([[VarName, v, WOE, IV]], index=None, columns=['variable', 'class', 'woe', 'iv']) WOE_Map = WOE_Map.append(result, ignore_index=True) return WOE_Map # nominal variable woe status_checking_account_woe = CalcWOE('Status_of_existing_checking_account') Credit_history_woe = CalcWOE('Credit_history') Purpose_woe = CalcWOE('Purpose') Savings_account_woe = CalcWOE('Savings_account') Present_employment_since_woe= CalcWOE('Present_employment_since') Personal_status_and_sex_woe = CalcWOE('Personal_status_and_sex') Other_debtors_woe = CalcWOE('Other_debtors') Property_woe = CalcWOE('Property') Other_installment_plans_woe = CalcWOE('Other_installment_plans') Housing_woe = CalcWOE('Housing') Job_woe = CalcWOE('Job') Telephone_woe = CalcWOE('Telephone') foreign_worker_woe = CalcWOE('foreign_worker') # numeric variable woe, no binning Installment_rate_woe = CalcWOE('Installment_rate') Present_residence_since_woe = CalcWOE('Present_residence_since') Number_of_existing_credits_woe = CalcWOE('Number_of_existing_credits') Number_of_people_woe = CalcWOE('Number_of_people') def CalcWOE_bin(VarName,N): WOE_Map = pd.DataFrame() max_value = max(german[VarName]) min_value = min(german[VarName]) bin = float(max_value - min_value)/N for i in range(N): bin_U = min_value + (i+1)*bin bin_L = bin_U - bin if i == 1: tmp = (german[VarName] >= bin_L) & (german[VarName] <= bin_U) grp = german[tmp].groupby('default') else: tmp = (german[VarName] > bin_L) & (german[VarName] <= bin_U) grp = german[tmp].groupby('default') Good = grp.size()[1] Bad = grp.size()[2] good_ratio = float(Good)/total_good bad_ratio = float(Bad)/total_bad WOE = np.log(bad_ratio/good_ratio) IV = (bad_ratio - good_ratio)*WOE result = pd.DataFrame([[VarName, [bin_L, bin_U, WOE], WOE, IV]], index=None, columns=['variable', 'class+woe', 'woe', 'iv']) WOE_Map = WOE_Map.append(result, ignore_index=True) return WOE_Map Duration_in_month_woe = CalcWOE_bin('Duration_in_month', 5) Credit_amount_woe = CalcWOE_bin('Credit_amount', 5) Age_woe = CalcWOE_bin('Age', 5)
第四步:用woe值替代原来的值
def ReplaceWOE(VarName, SourceDF, VarWOE): dict1 = dict.fromkeys(VarWOE['class']) j = 0 for key in dict1: dict1[key] = VarWOE['woe'][j] j = j + 1 SourceDF[VarName] = SourceDF[VarName].map(dict1) return SourceDF german_woe = german temp = ReplaceWOE('Status_of_existing_checking_account', german_woe, status_checking_account_woe) temp1 = ReplaceWOE('Credit_history', temp, Credit_history_woe) temp = ReplaceWOE('Purpose', temp1, Purpose_woe) temp1 = ReplaceWOE('Savings_account', temp, Savings_account_woe) temp = ReplaceWOE('Present_employment_since', temp1, Present_employment_since_woe) temp1 = ReplaceWOE('Personal_status_and_sex', temp, Personal_status_and_sex_woe) temp = ReplaceWOE('Other_debtors', temp1, Other_debtors_woe) temp1 = ReplaceWOE('Property', temp, Property_woe) temp = ReplaceWOE('Other_installment_plans', temp1, Other_installment_plans_woe) temp1 = ReplaceWOE('Housing', temp, Housing_woe) temp = ReplaceWOE('Job', temp1, Job_woe) temp1 = ReplaceWOE('Telephone', temp, Telephone_woe) temp = ReplaceWOE('foreign_worker', temp1, foreign_worker_woe) temp1 = ReplaceWOE('Installment_rate', temp, Installment_rate_woe) temp = ReplaceWOE('Present_residence_since', temp1, Present_residence_since_woe) temp1 = ReplaceWOE('Number_of_existing_credits', temp, Number_of_existing_credits_woe) temp = ReplaceWOE('Number_of_people', temp1, Number_of_people_woe) def ReplaceWOE_bin(VarName, SourceDF, VarWOE): items = np.unique(SourceDF[VarName]) m = min(SourceDF[VarName]) dict2 = {} for it in items: if it == m: dict2[it] = VarWOE['class+woe'][0][2] else: for l, u, w in VarWOE['class+woe']: if (it > l) & (it <= u): dict2[it] = w SourceDF[VarName] = SourceDF[VarName].map(dict2) return SourceDF temp1 = ReplaceWOE_bin('Duration_in_month', temp, Duration_in_month_woe) temp = ReplaceWOE_bin('Credit_amount', temp1, Credit_amount_woe) temp1 = ReplaceWOE_bin('Age', temp, Age_woe)
第五步:将数据集拆分为训练集和测试集
X = temp1[list(temp1.columns)[:-1]] y = temp1['default'] - 1 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=0)
第六步:在训练集上应用logistic regression算法
from sklearn.linear_model.logistic import LogisticRegression classifier = LogisticRegression() classifier.fit(X_train, y_train) predictions = classifier.predict(X_test)
第七步:评估模型分类精度
from sklearn.metrics import accuracy_score # print 'Accuracy:', accuracy_score(y_test, predictions) from sklearn.cross_validation import cross_val_score scores = cross_val_score(classifier, X_train, y_train, cv=5) # print np.mean(scores), scores
第八步:创建评分卡
# score = A - B*log(theta) # P0 = A - B*log(theta0), P0 + PDO = A - B*log(2*theta0) P0 = 600 PDO = 20 theta0 = 1.0/60 B = PDO/np.log(2) A = P0 + B*np.log(theta0) coef = classifier.coef_ beta0 = classifier.intercept_ status_checking_account_woe['score'] = (A - B*beta0)/20 - B*coef[0][0]*status_checking_account_woe['woe'] Duration_in_month_woe['score'] = (A - B*beta0)/20 - B*coef[0][1]*Duration_in_month_woe['woe'] Credit_history_woe['score'] = (A - B*beta0)/20 - B*coef[0][2]*Credit_history_woe['woe'] Purpose_woe['score'] = (A - B*beta0)/20 - B*coef[0][3]*Purpose_woe['woe'] Credit_amount_woe['score'] = (A - B*beta0)/20 - B*coef[0][4]*Credit_amount_woe['woe'] Savings_account_woe['score'] = (A - B*beta0)/20 - B*coef[0][5]*Savings_account_woe['woe'] Present_employment_since_woe['score'] = (A - B*beta0)/20 - B*coef[0][6]*Present_employment_since_woe['woe'] Installment_rate_woe['score'] = (A - B*beta0)/20 - B*coef[0][7]*Installment_rate_woe['woe'] Personal_status_and_sex_woe['score'] = (A - B*beta0)/20 - B*coef[0][8]*Personal_status_and_sex_woe['woe'] Other_debtors_woe['score'] = (A - B*beta0)/20 - B*coef[0][9]*Other_debtors_woe['woe'] Present_residence_since_woe['score'] = (A - B*beta0)/20 - B*coef[0][10]*Present_residence_since_woe['woe'] Property_woe['score'] = (A - B*beta0)/20 - B*coef[0][11]*Property_woe['woe'] Age_woe['score'] = (A - B*beta0)/20 - B*coef[0][12]*Age_woe['woe'] Other_installment_plans_woe['score'] = (A - B*beta0)/20 - B*coef[0][13]*Other_installment_plans_woe['woe'] Housing_woe['score'] = (A - B*beta0)/20 - B*coef[0][14]*Housing_woe['woe'] Number_of_existing_credits_woe['score'] = (A - B*beta0)/20 - B*coef[0][15]*Number_of_existing_credits_woe['woe'] Job_woe['score'] = (A - B*beta0)/20 - B*coef[0][16]*Job_woe['woe'] Number_of_people_woe['score'] = (A - B*beta0)/20 - B*coef[0][17]*Number_of_people_woe['woe'] Telephone_woe['score'] = (A - B*beta0)/20 - B*coef[0][18]*Telephone_woe['woe'] foreign_worker_woe['score'] = (A - B*beta0)/20 - B*coef[0][19]*foreign_worker_woe['woe']
初次用python实现,不当之处请不吝批评指正!