Python打卡第11天

📅 2026/8/23 7:31:43
Python打卡第11天
浙大疏锦行001002003004005006007008009010011012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280importwarningsimportlightgbm as lgbimportmatplotlib.pyplot as pltimportnumpy as npimportpandas as pdfromsklearn.metricsimportaccuracy_scorefromsklearn.model_selectionimportGridSearchCV, RandomizedSearchCV, train_test_splitfromsklearn.neighborsimportKNeighborsClassifierfromsklearn.preprocessingimportLabelEncoder, StandardScalerfromskoptimportBayesSearchCVwarnings.filterwarnings(ignore)plt.rcParams[font.sans-serif][SimHei,Microsoft YaHei]# 优先黑体备选微软雅黑plt.rcParams[axes.unicode_minus]False# 解决坐标轴负号显示方框问题datapd.read_csv(rD:\Desktop\Postgraduate\PythonStudy\Python打卡训练营\Python打卡训练营\python60-days-challenge-master\data.csv)# 读取数据# print(data.info())col_cn_dict{Id:编号,Home Ownership:房屋产权情况,Annual Income:年收入,Years in current job:现工作任职年限,Tax Liens:税务留置次数,Number of Open Accounts:未结清账户数量,Years of Credit History:信用历史年限,Maximum Open Credit:最大开放授信额度,Number of Credit Problems:信用问题次数,Months since last delinquent:上次逾期距今月数,Bankruptcies:破产记录次数,Purpose:贷款用途,Term:贷款期限,Current Loan Amount:当前贷款金额,Current Credit Balance:当前信贷余额,Monthly Debt:月负债,Credit Score:信用评分,Credit Default:是否违约}datadata.rename(columnscol_cn_dict)# print(data.info())# print(data[现工作任职年限].value_counts())defpreprocess_credit_data(data, test_size0.2, random_state42):信贷违约数据完整预处理流程返回: X_train, X_test, y_train, y_test# 1. 划分特征与标签 Xdata.drop(columns[是否违约,编号])# 编号无预测意义丢弃ydata[是否违约]# 2. 划分训练集 / 测试集 X_train, X_test, y_train, y_testtrain_test_split(X, y, test_sizetest_size, random_staterandom_state, stratifyy)# stratifyy 保证训练/测试集中违约比例一致# 3. 区分离散 / 连续特征 discrete_colsX_train.select_dtypes(include[object]).columns.tolist()continuous_colsX_train.select_dtypes(include[np.number]).columns.tolist()special_col现工作任职年限ifspecial_colindiscrete_cols:discrete_cols.remove(special_col)# 任职年限单独字典映射# 4. 缺失值填充 # 连续特征 → 中位数只用训练集统计量防泄露forcolincontinuous_cols:median_valX_train[col].median()X_train[col]X_train[col].fillna(median_val)X_test[col]X_test[col].fillna(median_val)# 离散特征(含任职年限) → 众数forcolindiscrete_cols[special_col]:mode_valX_train[col].mode()[0]X_train[col]X_train[col].fillna(mode_val)X_test[col]X_test[col].fillna(mode_val)# 5. 现工作任职年限字典映射 job_years_map{ 1 year:0,1 year:1,2 years:2,3 years:3,4 years:4,5 years:5,6 years:6,7 years:7,8 years:8,9 years:9,10 years:11,}X_train[special_col]X_train[special_col].map(job_years_map).astype(int)X_test[special_col]X_test[special_col].map(job_years_map).astype(int)# 6. 其余离散特征编码 # 有序特征贷款期限短期 长期→ 标签编码# 无序特征房屋产权情况、贷款用途 → 独热编码ordinal_cols[贷款期限]nominal_cols[cforcindiscrete_colsifcnotinordinal_cols]# 6.1 有序特征 LabelEncoderforcolinordinal_cols:leLabelEncoder()X_train[col]le.fit_transform(X_train[col])X_test[col]le.transform(X_test[col])# 6.2 无序特征 One-Hot测试集按训练集列对齐防止列数不一致X_trainpd.get_dummies(X_train, columnsnominal_cols, drop_firstTrue)X_testpd.get_dummies(X_test, columnsnominal_cols, drop_firstTrue)X_testX_test.reindex(columnsX_train.columns, fill_value0)# 7. 异常值处理IQR 截断不删样本 # 对连续特征 映射后的任职年限做截断独热列和0/1标签列不动outlier_colscontinuous_cols[special_col]forcolinoutlier_cols:Q1X_train[col].quantile(0.25)Q3X_train[col].quantile(0.75)IQRQ3-Q1lower, upperQ1-1.5*IQR, Q31.5*IQRX_train[col]X_train[col].clip(lowerlower, upperupper)X_test[col]X_test[col].clip(lowerlower, upperupper)# 8. 标准化 # 选择 StandardScaler已做 IQR 截断异常值影响可控# 信贷数据右偏明显StandardScaler 比 MinMax 更稳健且适配逻辑回归/SVM/NN# 独热列保持 0/1 不缩放仅缩放连续/有序数值列onehot_cols[cforcinX_train.columnsifany(c.startswith(nc_)forncinnominal_cols)]scale_cols[cforcinX_train.columnsifcnotinonehot_cols]scalerStandardScaler()X_train[scale_cols]scaler.fit_transform(X_train[scale_cols])X_test[scale_cols]scaler.transform(X_test[scale_cols])returnX_train, X_test, y_train, y_test# 调用方式 X_train, X_test, y_train, y_testpreprocess_credit_data(data)# 1. 定义保存结果列表 results[]# 2. 通用工具函数保存结果 defrecord_result(model_name, search_name, best_params,X_train, X_test, y_train, y_test, best_estimator):y_pred_trainbest_estimator.predict(X_train)y_pred_testbest_estimator.predict(X_test)acc_trainround(accuracy_score(y_train, y_pred_train),4)acc_testround(accuracy_score(y_test, y_pred_test),4)results.append({模型: model_name,寻优方法: search_name,最优参数: best_params,训练集准确率: acc_train,测试集准确率: acc_test})# 3. KNN 参数空间 knnKNeighborsClassifier()knn_grid{n_neighbors: [3,5,7,9,11],weights: [uniform,distance],p: [1,2]}knn_random{n_neighbors:list(range(3,15)),weights: [uniform,distance],p: [1,2]}knn_bayes{n_neighbors: (3,15),weights: [uniform,distance],p: (1,2)}# -------- KNN - 网格搜索 --------print( KNN 网格搜索 )gs_knnGridSearchCV(knn, knn_grid, cv5, scoringaccuracy, n_jobs-1)gs_knn.fit(X_train, y_train)record_result(KNN,网格搜索, gs_knn.best_params_, X_train, X_test, y_train, y_test, gs_knn.best_estimator_)# -------- KNN - 随机搜索 --------print( KNN 随机搜索 )rs_knnRandomizedSearchCV(knn, knn_random, cv5, scoringaccuracy,n_iter10, random_state42, n_jobs-1)rs_knn.fit(X_train, y_train)record_result(KNN,随机搜索, rs_knn.best_params_, X_train, X_test, y_train, y_test, rs_knn.best_estimator_)# -------- KNN - 贝叶斯优化 --------print( KNN 贝叶斯优化 )bs_knnBayesSearchCV(knn, knn_bayes, cv5, scoringaccuracy,n_iter10, random_state42, n_jobs-1)bs_knn.fit(X_train, y_train)record_result(KNN,贝叶斯优化, bs_knn.best_params_, X_train, X_test, y_train, y_test, bs_knn.best_estimator_)# 4. LightGBM 参数空间 lgb_clflgb.LGBMClassifier(random_state42, verbosity-1)lgb_grid{learning_rate: [0.01,0.05,0.1],n_estimators: [50,100,200],max_depth: [3,5,7]}lgb_random{learning_rate: np.logspace(-3,-1,10),n_estimators:list(range(50,300,20)),max_depth:list(range(2,10)),subsample: [0.6,0.7,0.8,0.9,1.0]}lgb_bayes{learning_rate: (1e-3,0.3,log-uniform),n_estimators: (50,300),max_depth: (2,10),subsample: (0.6,1.0)}# -------- LightGBM - 网格搜索 --------print( LightGBM 网格搜索 )gs_lgbGridSearchCV(lgb_clf, lgb_grid, cv5, scoringaccuracy, n_jobs-1)gs_lgb.fit(X_train, y_train)record_result(LightGBM,网格搜索, gs_lgb.best_params_, X_train, X_test, y_train, y_test, gs_lgb.best_estimator_)# -------- LightGBM - 随机搜索 --------print( LightGBM 随机搜索 )rs_lgbRandomizedSearchCV(lgb_clf, lgb_random, cv5, scoringaccuracy,n_iter10, random_state42, n_jobs-1)rs_lgb.fit(X_train, y_train)record_result(LightGBM,随机搜索, rs_lgb.best_params_, X_train, X_test, y_train, y_test, rs_lgb.best_estimator_)# -------- LightGBM - 贝叶斯优化 --------print( LightGBM 贝叶斯优化 )bs_lgbBayesSearchCV(lgb_clf, lgb_bayes, cv5, scoringaccuracy,n_iter10, random_state42, n_jobs-1)bs_lgb.fit(X_train, y_train)record_result(LightGBM,贝叶斯优化, bs_lgb.best_params_, X_train, X_test, y_train, y_test, bs_lgb.best_estimator_)# 5. 输出汇总对比表格 df_resultpd.DataFrame(results)# 让 Pandas 在终端中正确计算中文字符宽度避免表头错位pd.set_option(display.unicode.east_asian_width,True)pd.set_option(display.unicode.ambiguous_as_wide,True)# 主表只展示适合横向比较的字段较长的参数字典放到下方分行显示summary_columns[模型,寻优方法,训练集准确率,测试集准确率]df_summarydf_result[summary_columns].copy()accuracy_formatters{训练集准确率:lambdavalue: f{value:.2%},测试集准确率:lambdavalue: f{value:.2%},}print(\n*72)print(【各模型不同超参数寻优方法结果汇总表】)print(*72)print(df_summary.to_string(indexFalse,justifycenter,col_space{模型:12,寻优方法:12},formattersaccuracy_formatters,))print(\n【各模型最优参数明细】)print(-*72)forresultinresults:print(f{result[模型]} - {result[寻优方法]})forparam_name, param_valueinresult[最优参数].items():print(f {param_name}: {param_value})print()