《Python金融大数据风控建模实战》 第8章 Logistic回归模型
本章引言Python代码实现及注释本章引言
Logistic回归是建立评分卡模型最常用的方法,因其具有输出概率、可解释性好和模型参数少等优势,即使在其他各种机器学习算法突飞猛进的情况下,也仍然是工业界建立评分卡模型的主流方法,其模型表现也常作为参考标准,用于衡量其他机器学习模型的效果。
Python代码实现及注释
# 第8章:logistic回归模型import osimport pandas as pdimport numpy as npfrom sklearn.model_selection import train_test_splitimport variable_bin_methods as varbin_methimport variable_encode as var_encodefrom sklearn.metrics import confusion_matrix,recall_score,accuracy_score,precision_scorefrom sklearn.model_selection import GridSearchCVfrom sklearn.linear_model import LogisticRegressionimport warningswarnings.filterwarnings("ignore") ##忽略警告##数据读取def data_read(data_path,file_name):df = pd.read_csv( os.path.join(data_path, file_name), delim_whitespace = True, header = None )##变量重命名columns = ['status_account','duration','credit_history','purpose', 'amount','svaing_account', 'present_emp', 'income_rate', 'personal_status','other_debtors', 'residence_info', 'property', 'age','inst_plans', 'housing', 'num_credits','job', 'dependents', 'telephone', 'foreign_worker', 'target']df.columns = columns##将标签变量由状态1,2转为0,1;0表示好用户,1表示坏用户df.target = df.target - 1##数据分为data_train和 data_test两部分,训练集用于得到编码函数,验证集用已知的编码规则对验证集编码data_train, data_test = train_test_split(df, test_size=0.2, random_state=0,stratify=df.target)return data_train, data_test##离散变量与连续变量区分 def category_continue_separation(df,feature_names):categorical_var = []numerical_var = []if 'target' in feature_names:feature_names.remove('target')##先判断类型,如果是int或float就直接作为连续变量numerical_var = list(df[feature_names].select_dtypes(include=['int','float','int32','float32','int64','float64']).columns.values)categorical_var = [x for x in feature_names if x not in numerical_var]return categorical_var,numerical_varif __name__ == '__main__':path = 'D:\\code\\chapter8'data_path = os.path.join(path ,'data')file_name = 'german.csv'##读取数据data_train, data_test = data_read(data_path,file_name)sum(data_train.target ==0)data_train.target.sum()##区分离散变量与连续变量feature_names = list(data_train.columns)feature_names.remove('target')categorical_var,numerical_var = category_continue_separation(data_train,feature_names)for s in set(numerical_var):print('变量'+s+'可能取值'+str(len(data_train[s].unique())))if len(data_train[s].unique())<=10:categorical_var.append(s)numerical_var.remove(s)##同时将后加的数值变量转为字符串index_1 = data_train[s].isnull()if sum(index_1) > 0:data_train.loc[~index_1,s] = data_train.loc[~index_1,s].astype('str')else:data_train[s] = data_train[s].astype('str')index_2 = data_test[s].isnull()if sum(index_2) > 0:data_test.loc[~index_2,s] = data_test.loc[~index_2,s].astype('str')else:data_test[s] = data_test[s].astype('str')###连续变量分箱dict_cont_bin = {}for i in numerical_var:print(i)dict_cont_bin[i],gain_value_save , gain_rate_save = varbin_meth.cont_var_bin(data_train[i], data_train.target, method=2, mmin=3, mmax=12, bin_rate=0.01, stop_limit=0.05, bin_min_num=20)###离散变量分箱dict_disc_bin = {}del_key = []for i in categorical_var:dict_disc_bin[i],gain_value_save , gain_rate_save ,del_key_1 = varbin_meth.disc_var_bin(data_train[i], data_train.target, method=2, mmin=3,mmax=8, stop_limit=0.05, bin_min_num=20)if len(del_key_1)>0 :del_key.extend(del_key_1)###删除分箱数只有1个的变量if len(del_key) > 0:for j in del_key:del dict_disc_bin[j]##训练数据分箱##连续变量分箱映射df_cont_bin_train = pd.DataFrame()for i in dict_cont_bin.keys():df_cont_bin_train = pd.concat([ df_cont_bin_train , varbin_meth.cont_var_bin_map(data_train[i], dict_cont_bin[i]) ], axis = 1)##离散变量分箱映射# ss = data_train[list( dict_disc_bin.keys())]df_disc_bin_train = pd.DataFrame()for i in dict_disc_bin.keys():df_disc_bin_train = pd.concat([ df_disc_bin_train , varbin_meth.disc_var_bin_map(data_train[i], dict_disc_bin[i]) ], axis = 1)##测试数据分箱##连续变量分箱映射df_cont_bin_test = pd.DataFrame()for i in dict_cont_bin.keys():df_cont_bin_test = pd.concat([ df_cont_bin_test , varbin_meth.cont_var_bin_map(data_test[i], dict_cont_bin[i]) ], axis = 1)##离散变量分箱映射# ss = data_test[list( dict_disc_bin.keys())]df_disc_bin_test = pd.DataFrame()for i in dict_disc_bin.keys():df_disc_bin_test = pd.concat([ df_disc_bin_test , varbin_meth.disc_var_bin_map(data_test[i], dict_disc_bin[i]) ], axis = 1)###组成分箱后的训练集与测试集df_disc_bin_train['target'] = data_train.targetdata_train_bin = pd.concat([df_cont_bin_train,df_disc_bin_train],axis=1)df_disc_bin_test['target'] = data_test.targetdata_test_bin = pd.concat([df_cont_bin_test,df_disc_bin_test],axis=1)data_train_bin.reset_index(inplace=True,drop=True)data_test_bin.reset_index(inplace=True,drop=True)###WOE编码var_all_bin = list(data_train_bin.columns)var_all_bin.remove('target')##训练集WOE编码df_train_woe, dict_woe_map, dict_iv_values ,var_woe_name = var_encode.woe_encode(data_train_bin,data_path,var_all_bin, data_train_bin.target,'dict_woe_map', flag='train')##测试集WOE编码df_test_woe, var_woe_name = var_encode.woe_encode(data_test_bin,data_path,var_all_bin, data_test_bin.target, 'dict_woe_map',flag='test')####取出训练数据与测试数据x_train = df_train_woe[var_woe_name]x_train = np.array(x_train)y_train = np.array(data_train_bin.target)x_test = df_test_woe[var_woe_name]x_test = np.array(x_test)y_test = np.array(data_test_bin.target)########logistic模型##设置优化参数lr_param = {'C': [0.01, 0.1, 0.2, 0.5, 1, 1.5, 2],'class_weight': [{1: 1, 0: 1}, {1: 2, 0: 1}, {1: 3, 0: 1}]}##初始化网格搜索lr_gsearch = GridSearchCV(estimator=LogisticRegression(random_state=0, fit_intercept=True, penalty='l2', solver='saga'),param_grid=lr_param, cv=3, scoring='f1', n_jobs=-1, verbose=2)##执行超参数优化lr_gsearch.fit(x_train, y_train)'''上述网格搜索中有两个超参数,第一个超参数有7种可能性取值,第二个超参数有3种可能性取值,采用2折交叉验证,则总共经历7×3×3=63次模型训练与评估,即每种参数组合都要通过交叉验证的方式得到评估指标的平均结果,即在3折交叉数据中的2折数据上建模,在另1折数据集上测试得到评估指标结果,将平均评估指标最好的的那组参数组合作为最优超参数。'''print('logistic model best_score_ is {0},and best_params_ is {1}'.format(lr_gsearch.best_score_,lr_gsearch.best_params_))##用最优参数,初始化Logistic模型'''这里采用scikit-learn中linear-model模型下的LogisticRegression()函数进行Logistic回归模型训练,其原型如下:class 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='warn', max_iter=100, multi_class = 'warn',verbose=0, warm_start=False, n_jobs=None,l1_ratio=None)主要参数说明:penalty:选择使用哪种正则项来抑制过拟合,为字符串,可以为None、'l1'、'l2'、'elasticnet',不同的正则项可选的优化策略不同,默认为'l2',即使用L2正则,如果为None,则表示不加正则项dual:布尔量,是否使用对偶形式,只能在L2正则且求解方式为liblinear solver才可以使用tol:指定模型迭代收敛的阈值C:正则项的惩罚系数。C=1/λ,因此C与实际作用在模型的惩罚成反比。即C越大,对正则项的惩罚效果越小,模型越容易过拟合,反之,C越小,对正则项的惩罚效果越大,模型越容易过拟合fit_intercept:模型训练时是否添加截距项,即w0。默认为True,即添加截距项。class_weight:确定是否加权来抑制样本不均衡,可以为字典形式的加权也可以自动加权。当设置为'balanced'时,则按照正负样本的比例加权。如果需要自定义加权,可以采用字典的形式,如{'1':3,'0':1}即正样本的权重为3,负样本的权重为1。通过影响损失函数的计算来抑制样本不均衡问题。默认为None即不加权,正负样本的权重相同。random_state:随机数设置,可以固定训练集,方便多个算法在同一个训练集上训练并比较模型的性能。solver:字符串,用于选择不同的优化算法。max_iter:整数,模型优化最大迭代次数。主要属性说明:coef_:用于查询模型训练后最终的权重系数,其数量与特征数相同,即每个特征训练一个权重。intercept_:用于查看截距项n_iter_:返回模型训练实际的迭代次数主要方法说明:fit(self,X,y[,sample_weight]):用于模型训练,在训练集上训练模型perdict(self,X):用于模型训练,在测试集上得到预测结果,这里给出标签输出,即0,1输出。predict_proba(self,X):用于模型预测。与perdict()方法不同的是,该方法给出概率预测结果,如ROC曲线就需要模型提供概率输出才可以进行计算'''LR_model_2 = LogisticRegression(C=lr_gsearch.best_params_['C'], penalty='l2', solver='saga',class_weight=lr_gsearch.best_params_['class_weight'])##训练Logistic模型LR_model_fit = LR_model_2.fit(x_train, y_train)##模型预测y_score_train = LR_model_fit.predict_proba(x_train)[:, 1]y_score_test = LR_model_fit.predict_proba(x_test)[:, 1]##计算混淆矩阵与recall、precisiony_pred = LR_model_fit.predict(x_test)cnf_matrix = confusion_matrix(y_test, y_pred)recall_value = recall_score(y_test, y_pred)precision_value = precision_score(y_test, y_pred)acc = accuracy_score(y_test, y_pred)print(cnf_matrix)print('Validation set: model recall is {0},and percision is {1}'.format(recall_value,precision_value))
如果觉得《《Python金融大数据风控建模实战》 第8章 Logistic回归模型》对你有帮助,请点赞、收藏,并留下你的观点哦!