日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【算法竞赛学习】金融风控之贷款违约预测-特征工程

發(fā)布時(shí)間:2023/12/15 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【算法竞赛学习】金融风控之贷款违约预测-特征工程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Task3 特征工程

此部分為零基礎(chǔ)入門金融風(fēng)控的 Task3 特征工程部分,帶你來了解各種特征工程以及分析方法,歡迎大家后續(xù)多多交流。

賽題:零基礎(chǔ)入門數(shù)據(jù)挖掘 - 零基礎(chǔ)入門金融風(fēng)控之貸款違約

項(xiàng)目地址:https://github.com/datawhalechina/team-learning-data-mining/tree/master/FinancialRiskControl

比賽地址:https://tianchi.aliyun.com/competition/entrance/531830/introduction

3.1 學(xué)習(xí)目標(biāo)

  • 學(xué)習(xí)特征預(yù)處理、缺失值、異常值處理、數(shù)據(jù)分桶等特征處理方法
  • 學(xué)習(xí)特征交互、編碼、選擇的相應(yīng)方法
  • 完成相應(yīng)學(xué)習(xí)打卡任務(wù),兩個(gè)選做的作業(yè)不做強(qiáng)制性要求,供學(xué)有余力同學(xué)自己探索

3.2 內(nèi)容介紹

  • 數(shù)據(jù)預(yù)處理
    • 缺失值的填充
    • 時(shí)間格式處理
    • 對(duì)象類型特征轉(zhuǎn)換到數(shù)值
  • 異常值處理
    • 基于3segama原則
    • 基于箱型圖
  • 數(shù)據(jù)分箱
    • 固定寬度分箱
    • 分位數(shù)分箱
      • 離散數(shù)值型數(shù)據(jù)分箱
      • 連續(xù)數(shù)值型數(shù)據(jù)分箱
    • 卡方分箱(選做作業(yè))
  • 特征交互
    • 特征和特征之間組合
    • 特征和特征之間衍生
    • 其他特征衍生的嘗試(選做作業(yè))
  • 特征編碼
    • one-hot編碼
    • label-encode編碼
  • 特征選擇
    • 1 Filter
    • 2 Wrapper (RFE)
    • 3 Embedded

3.3 代碼示例

3.3.1 導(dǎo)入包并讀取數(shù)據(jù)

import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import datetime from tqdm import tqdm from sklearn.preprocessing import LabelEncoder from sklearn.feature_selection import SelectKBest from sklearn.feature_selection import chi2 from sklearn.preprocessing import MinMaxScaler import xgboost as xgb import lightgbm as lgb from catboost import CatBoostRegressor import warnings from sklearn.model_selection import StratifiedKFold, KFold from sklearn.metrics import accuracy_score, f1_score, roc_auc_score, log_loss warnings.filterwarnings('ignore') data_train =pd.read_csv('../train.csv') data_test_a = pd.read_csv('../testA.csv')

3.3.2特征預(yù)處理

  • 數(shù)據(jù)EDA部分我們已經(jīng)對(duì)數(shù)據(jù)的大概和某些特征分布有了了解,數(shù)據(jù)預(yù)處理部分一般我們要處理一些EDA階段分析出來的問題,這里介紹了數(shù)據(jù)缺失值的填充,時(shí)間格式特征的轉(zhuǎn)化處理,某些對(duì)象類別特征的處理。

首先我們查找出數(shù)據(jù)中的對(duì)象特征和數(shù)值特征

numerical_fea = list(data_train.select_dtypes(exclude=['object']).columns) category_fea = list(filter(lambda x: x not in numerical_fea,list(data_train.columns))) label = 'isDefault' numerical_fea.remove(label)

在比賽中數(shù)據(jù)預(yù)處理是必不可少的一部分,對(duì)于缺失值的填充往往會(huì)影響比賽的結(jié)果,在比賽中不妨嘗試多種填充然后比較結(jié)果選擇結(jié)果最優(yōu)的一種;
比賽數(shù)據(jù)相比真實(shí)場(chǎng)景的數(shù)據(jù)相對(duì)要“干凈”一些,但是還是會(huì)有一定的“臟”數(shù)據(jù)存在,清洗一些異常值往往會(huì)獲得意想不到的效果。

缺失值填充

  • 把所有缺失值替換為指定的值0

    data_train = data_train.fillna(0)

  • 向用缺失值上面的值替換缺失值

    data_train = data_train.fillna(axis=0,method=‘ffill’)

  • 縱向用缺失值下面的值替換缺失值,且設(shè)置最多只填充兩個(gè)連續(xù)的缺失值

    data_train = data_train.fillna(axis=0,method=‘bfill’,limit=2)

#查看缺失值情況 data_train.isnull().sum() id 0 loanAmnt 0 term 0 interestRate 0 installment 0 grade 0 subGrade 0 employmentTitle 1 employmentLength 46799 homeOwnership 0 annualIncome 0 verificationStatus 0 issueDate 0 isDefault 0 purpose 0 postCode 1 regionCode 0 dti 239 delinquency_2years 0 ficoRangeLow 0 ficoRangeHigh 0 openAcc 0 pubRec 0 pubRecBankruptcies 405 revolBal 0 revolUtil 531 totalAcc 0 initialListStatus 0 applicationType 0 earliesCreditLine 0 title 1 policyCode 0 n0 40270 n1 40270 n2 40270 n2.1 40270 n4 33239 n5 40270 n6 40270 n7 40270 n8 40271 n9 40270 n10 33239 n11 69752 n12 40270 n13 40270 n14 40270 dtype: int64 #按照平均數(shù)填充數(shù)值型特征 data_train[numerical_fea] = data_train[numerical_fea].fillna(data_train[numerical_fea].median()) data_test_a[numerical_fea] = data_test_a[numerical_fea].fillna(data_train[numerical_fea].median()) #按照眾數(shù)填充類別型特征 data_train[category_fea] = data_train[category_fea].fillna(data_train[category_fea].mode()) data_test_a[category_fea] = data_test_a[category_fea].fillna(data_train[category_fea].mode()) data_train.isnull().sum() id 0 loanAmnt 0 term 0 interestRate 0 installment 0 grade 0 subGrade 0 employmentTitle 0 employmentLength 46799 homeOwnership 0 annualIncome 0 verificationStatus 0 issueDate 0 isDefault 0 purpose 0 postCode 0 regionCode 0 dti 0 delinquency_2years 0 ficoRangeLow 0 ficoRangeHigh 0 openAcc 0 pubRec 0 pubRecBankruptcies 0 revolBal 0 revolUtil 0 totalAcc 0 initialListStatus 0 applicationType 0 earliesCreditLine 0 title 0 policyCode 0 n0 0 n1 0 n2 0 n2.1 0 n4 0 n5 0 n6 0 n7 0 n8 0 n9 0 n10 0 n11 0 n12 0 n13 0 n14 0 dtype: int64 #查看類別特征 category_fea ['grade', 'subGrade', 'employmentLength', 'issueDate', 'earliesCreditLine']
  • category_fea:對(duì)象型類別特征需要進(jìn)行預(yù)處理,其中[‘issueDate’]為時(shí)間格式特征。

時(shí)間格式處理

#轉(zhuǎn)化成時(shí)間格式 for data in [data_train, data_test_a]:data['issueDate'] = pd.to_datetime(data['issueDate'],format='%Y-%m-%d')startdate = datetime.datetime.strptime('2007-06-01', '%Y-%m-%d')#構(gòu)造時(shí)間特征data['issueDateDT'] = data['issueDate'].apply(lambda x: x-startdate).dt.days data_train['employmentLength'].value_counts(dropna=False).sort_index() 1 year 52489 10+ years 262753 2 years 72358 3 years 64152 4 years 47985 5 years 50102 6 years 37254 7 years 35407 8 years 36192 9 years 30272 < 1 year 64237 NaN 46799 Name: employmentLength, dtype: int64

對(duì)象類型特征轉(zhuǎn)換到數(shù)值

def employmentLength_to_int(s):if pd.isnull(s):return selse:return np.int8(s.split()[0]) for data in [data_train, data_test_a]:data['employmentLength'].replace(to_replace='10+ years', value='10 years', inplace=True)data['employmentLength'].replace('< 1 year', '0 years', inplace=True)data['employmentLength'] = data['employmentLength'].apply(employmentLength_to_int) data['employmentLength'].value_counts(dropna=False).sort_index() 0.0 15989 1.0 13182 2.0 18207 3.0 16011 4.0 11833 5.0 12543 6.0 9328 7.0 8823 8.0 8976 9.0 7594 10.0 65772 NaN 11742 Name: employmentLength, dtype: int64
  • 對(duì)earliesCreditLine進(jìn)行預(yù)處理
data_train['earliesCreditLine'].sample(5) 519915 Sep-2002 564368 Dec-1996 768209 May-2004 453092 Nov-1995 763866 Sep-2000 Name: earliesCreditLine, dtype: object for data in [data_train, data_test_a]:data['earliesCreditLine'] = data['earliesCreditLine'].apply(lambda s: int(s[-4:]))

類別特征處理

# 部分類別特征 cate_features = ['grade', 'subGrade', 'employmentTitle', 'homeOwnership', 'verificationStatus', 'purpose', 'postCode', 'regionCode', \'applicationType', 'initialListStatus', 'title', 'policyCode'] for f in cate_features:print(f, '類型數(shù):', data[f].nunique()) grade 類型數(shù): 7 subGrade 類型數(shù): 35 employmentTitle 類型數(shù): 79282 homeOwnership 類型數(shù): 6 verificationStatus 類型數(shù): 3 purpose 類型數(shù): 14 postCode 類型數(shù): 889 regionCode 類型數(shù): 51 applicationType 類型數(shù): 2 initialListStatus 類型數(shù): 2 title 類型數(shù): 12058 policyCode 類型數(shù): 1

像等級(jí)這種類別特征,是有優(yōu)先級(jí)的可以labelencode或者自映射

for data in [data_train, data_test_a]:data['grade'] = data['grade'].map({'A':1,'B':2,'C':3,'D':4,'E':5,'F':6,'G':7}) # 類型數(shù)在2之上,又不是高維稀疏的,且純分類特征 for data in [data_train, data_test_a]:data = pd.get_dummies(data, columns=['subGrade', 'homeOwnership', 'verificationStatus', 'purpose', 'regionCode'], drop_first=True)

3.3.3 異常值處理

  • 當(dāng)你發(fā)現(xiàn)異常值后,一定要先分清是什么原因?qū)е碌漠惓V?#xff0c;然后再考慮如何處理。首先,如果這一異常值并不代表一種規(guī)律性的,而是極其偶然的現(xiàn)象,或者說你并不想研究這種偶然的現(xiàn)象,這時(shí)可以將其刪除。其次,如果異常值存在且代表了一種真實(shí)存在的現(xiàn)象,那就不能隨便刪除。在現(xiàn)有的欺詐場(chǎng)景中很多時(shí)候欺詐數(shù)據(jù)本身相對(duì)于正常數(shù)據(jù)勒說就是異常的,我們要把這些異常點(diǎn)納入,重新擬合模型,研究其規(guī)律。能用監(jiān)督的用監(jiān)督模型,不能用的還可以考慮用異常檢測(cè)的算法來做。
  • 注意test的數(shù)據(jù)不能刪。

檢測(cè)異常的方法一:均方差

在統(tǒng)計(jì)學(xué)中,如果一個(gè)數(shù)據(jù)分布近似正態(tài),那么大約 68% 的數(shù)據(jù)值會(huì)在均值的一個(gè)標(biāo)準(zhǔn)差范圍內(nèi),大約 95% 會(huì)在兩個(gè)標(biāo)準(zhǔn)差范圍內(nèi),大約 99.7% 會(huì)在三個(gè)標(biāo)準(zhǔn)差范圍內(nèi)。

def find_outliers_by_3segama(data,fea):data_std = np.std(data[fea])data_mean = np.mean(data[fea])outliers_cut_off = data_std * 3lower_rule = data_mean - outliers_cut_offupper_rule = data_mean + outliers_cut_offdata[fea+'_outliers'] = data[fea].apply(lambda x:str('異常值') if x > upper_rule or x < lower_rule else '正常值')return data
  • 得到特征的異常值后可以進(jìn)一步分析變量異常值和目標(biāo)變量的關(guān)系
data_train = data_train.copy() for fea in numerical_fea:data_train = find_outliers_by_3segama(data_train,fea)print(data_train[fea+'_outliers'].value_counts())print(data_train.groupby(fea+'_outliers')['isDefault'].sum())print('*'*10) 正常值 800000 Name: id_outliers, dtype: int64 id_outliers 正常值 159610 Name: isDefault, dtype: int64 ********** 正常值 800000 Name: loanAmnt_outliers, dtype: int64 loanAmnt_outliers 正常值 159610 Name: isDefault, dtype: int64 ********** 正常值 800000 Name: term_outliers, dtype: int64 term_outliers 正常值 159610 Name: isDefault, dtype: int64 ********** 正常值 794259 異常值 5741 Name: interestRate_outliers, dtype: int64 interestRate_outliers 異常值 2916 正常值 156694 Name: isDefault, dtype: int64 ********** 正常值 792046 異常值 7954 Name: installment_outliers, dtype: int64 installment_outliers 異常值 2152 正常值 157458 Name: isDefault, dtype: int64 ********** 正常值 800000 Name: employmentTitle_outliers, dtype: int64 employmentTitle_outliers 正常值 159610 Name: isDefault, dtype: int64 ********** 正常值 799701 異常值 299 Name: homeOwnership_outliers, dtype: int64 homeOwnership_outliers 異常值 62 正常值 159548 Name: isDefault, dtype: int64 ********** 正常值 793973 異常值 6027 Name: annualIncome_outliers, dtype: int64 annualIncome_outliers 異常值 756 正常值 158854 Name: isDefault, dtype: int64 ********** 正常值 800000 Name: verificationStatus_outliers, dtype: int64 verificationStatus_outliers 正常值 159610 Name: isDefault, dtype: int64 ********** 正常值 783003 異常值 16997 Name: purpose_outliers, dtype: int64 purpose_outliers 異常值 3635 正常值 155975 Name: isDefault, dtype: int64 ********** 正常值 798931 異常值 1069 Name: postCode_outliers, dtype: int64 postCode_outliers 異常值 221 正常值 159389 Name: isDefault, dtype: int64 ********** 正常值 799994 異常值 6 Name: regionCode_outliers, dtype: int64 regionCode_outliers 異常值 1 正常值 159609 Name: isDefault, dtype: int64 ********** 正常值 798440 異常值 1560 Name: dti_outliers, dtype: int64 dti_outliers 異常值 466 正常值 159144 Name: isDefault, dtype: int64 ********** 正常值 778245 異常值 21755 Name: delinquency_2years_outliers, dtype: int64 delinquency_2years_outliers 異常值 5089 正常值 154521 Name: isDefault, dtype: int64 ********** 正常值 788261 異常值 11739 Name: ficoRangeLow_outliers, dtype: int64 ficoRangeLow_outliers 異常值 778 正常值 158832 Name: isDefault, dtype: int64 ********** 正常值 788261 異常值 11739 Name: ficoRangeHigh_outliers, dtype: int64 ficoRangeHigh_outliers 異常值 778 正常值 158832 Name: isDefault, dtype: int64 ********** 正常值 790889 異常值 9111 Name: openAcc_outliers, dtype: int64 openAcc_outliers 異常值 2195 正常值 157415 Name: isDefault, dtype: int64 ********** 正常值 792471 異常值 7529 Name: pubRec_outliers, dtype: int64 pubRec_outliers 異常值 1701 正常值 157909 Name: isDefault, dtype: int64 ********** 正常值 794120 異常值 5880 Name: pubRecBankruptcies_outliers, dtype: int64 pubRecBankruptcies_outliers 異常值 1423 正常值 158187 Name: isDefault, dtype: int64 ********** 正常值 790001 異常值 9999 Name: revolBal_outliers, dtype: int64 revolBal_outliers 異常值 1359 正常值 158251 Name: isDefault, dtype: int64 ********** 正常值 799948 異常值 52 Name: revolUtil_outliers, dtype: int64 revolUtil_outliers 異常值 23 正常值 159587 Name: isDefault, dtype: int64 ********** 正常值 791663 異常值 8337 Name: totalAcc_outliers, dtype: int64 totalAcc_outliers 異常值 1668 正常值 157942 Name: isDefault, dtype: int64 ********** 正常值 800000 Name: initialListStatus_outliers, dtype: int64 initialListStatus_outliers 正常值 159610 Name: isDefault, dtype: int64 ********** 正常值 784586 異常值 15414 Name: applicationType_outliers, dtype: int64 applicationType_outliers 異常值 3875 正常值 155735 Name: isDefault, dtype: int64 ********** 正常值 775134 異常值 24866 Name: title_outliers, dtype: int64 title_outliers 異常值 3900 正常值 155710 Name: isDefault, dtype: int64 ********** 正常值 800000 Name: policyCode_outliers, dtype: int64 policyCode_outliers 正常值 159610 Name: isDefault, dtype: int64 ********** 正常值 782773 異常值 17227 Name: n0_outliers, dtype: int64 n0_outliers 異常值 3485 正常值 156125 Name: isDefault, dtype: int64 ********** 正常值 790500 異常值 9500 Name: n1_outliers, dtype: int64 n1_outliers 異常值 2491 正常值 157119 Name: isDefault, dtype: int64 ********** 正常值 789067 異常值 10933 Name: n2_outliers, dtype: int64 n2_outliers 異常值 3205 正常值 156405 Name: isDefault, dtype: int64 ********** 正常值 789067 異常值 10933 Name: n2.1_outliers, dtype: int64 n2.1_outliers 異常值 3205 正常值 156405 Name: isDefault, dtype: int64 ********** 正常值 788660 異常值 11340 Name: n4_outliers, dtype: int64 n4_outliers 異常值 2476 正常值 157134 Name: isDefault, dtype: int64 ********** 正常值 790355 異常值 9645 Name: n5_outliers, dtype: int64 n5_outliers 異常值 1858 正常值 157752 Name: isDefault, dtype: int64 ********** 正常值 786006 異常值 13994 Name: n6_outliers, dtype: int64 n6_outliers 異常值 3182 正常值 156428 Name: isDefault, dtype: int64 ********** 正常值 788430 異常值 11570 Name: n7_outliers, dtype: int64 n7_outliers 異常值 2746 正常值 156864 Name: isDefault, dtype: int64 ********** 正常值 789625 異常值 10375 Name: n8_outliers, dtype: int64 n8_outliers 異常值 2131 正常值 157479 Name: isDefault, dtype: int64 ********** 正常值 786384 異常值 13616 Name: n9_outliers, dtype: int64 n9_outliers 異常值 3953 正常值 155657 Name: isDefault, dtype: int64 ********** 正常值 788979 異常值 11021 Name: n10_outliers, dtype: int64 n10_outliers 異常值 2639 正常值 156971 Name: isDefault, dtype: int64 ********** 正常值 799434 異常值 566 Name: n11_outliers, dtype: int64 n11_outliers 異常值 112 正常值 159498 Name: isDefault, dtype: int64 ********** 正常值 797585 異常值 2415 Name: n12_outliers, dtype: int64 n12_outliers 異常值 545 正常值 159065 Name: isDefault, dtype: int64 ********** 正常值 788907 異常值 11093 Name: n13_outliers, dtype: int64 n13_outliers 異常值 2482 正常值 157128 Name: isDefault, dtype: int64 ********** 正常值 788884 異常值 11116 Name: n14_outliers, dtype: int64 n14_outliers 異常值 3364 正常值 156246 Name: isDefault, dtype: int64 **********
  • 例如可以看到異常值在兩個(gè)變量上的分布幾乎復(fù)合整體的分布,如果異常值都屬于為1的用戶數(shù)據(jù)里面代表什么呢?
#刪除異常值 for fea in numerical_fea:data_train = data_train[data_train[fea+'_outliers']=='正常值']data_train = data_train.reset_index(drop=True)

檢測(cè)異常的方法二:箱型圖

  • 總結(jié)一句話:四分位數(shù)會(huì)將數(shù)據(jù)分為三個(gè)點(diǎn)和四個(gè)區(qū)間,IQR = Q3 -Q1,下觸須=Q1 ? 1.5x IQR,上觸須=Q3 + 1.5x IQR;

3.3.4 數(shù)據(jù)分桶

  • 特征分箱的目的:

    • 從模型效果上來看,特征分箱主要是為了降低變量的復(fù)雜性,減少變量噪音對(duì)模型的影響,提高自變量和因變量的相關(guān)度。從而使模型更加穩(wěn)定。
  • 數(shù)據(jù)分桶的對(duì)象:

    • 將連續(xù)變量離散化
    • 將多狀態(tài)的離散變量合并成少狀態(tài)
  • 分箱的原因:

    • 數(shù)據(jù)的特征內(nèi)的值跨度可能比較大,對(duì)有監(jiān)督和無監(jiān)督中如k-均值聚類它使用歐氏距離作為相似度函數(shù)來測(cè)量數(shù)據(jù)點(diǎn)之間的相似度。都會(huì)造成大吃小的影響,其中一種解決方法是對(duì)計(jì)數(shù)值進(jìn)行區(qū)間量化即數(shù)據(jù)分桶也叫做數(shù)據(jù)分箱,然后使用量化后的結(jié)果。
  • 分箱的優(yōu)點(diǎn):

    • 處理缺失值:當(dāng)數(shù)據(jù)源可能存在缺失值,此時(shí)可以把null單獨(dú)作為一個(gè)分箱。
    • 處理異常值:當(dāng)數(shù)據(jù)中存在離群點(diǎn)時(shí),可以把其通過分箱離散化處理,從而提高變量的魯棒性(抗干擾能力)。例如,age若出現(xiàn)200這種異常值,可分入“age > 60”這個(gè)分箱里,排除影響。
    • 業(yè)務(wù)解釋性:我們習(xí)慣于線性判斷變量的作用,當(dāng)x越來越大,y就越來越大。但實(shí)際x與y之間經(jīng)常存在著非線性關(guān)系,此時(shí)可經(jīng)過WOE變換。
  • 特別要注意一下分箱的基本原則:

    • (1)最小分箱占比不低于5%
    • (2)箱內(nèi)不能全部是好客戶
    • (3)連續(xù)箱單調(diào)
  • 固定寬度分箱
  • 當(dāng)數(shù)值橫跨多個(gè)數(shù)量級(jí)時(shí),最好按照 10 的冪(或任何常數(shù)的冪)來進(jìn)行分組:09、1099、100999、10009999,等等。固定寬度分箱非常容易計(jì)算,但如果計(jì)數(shù)值中有比較大的缺口,就會(huì)產(chǎn)生很多沒有任何數(shù)據(jù)的空箱子。

    # 通過除法映射到間隔均勻的分箱中,每個(gè)分箱的取值范圍都是loanAmnt/1000 data['loanAmnt_bin1'] = np.floor_divide(data['loanAmnt'], 1000) ## 通過對(duì)數(shù)函數(shù)映射到指數(shù)寬度分箱 data['loanAmnt_bin2'] = np.floor(np.log10(data['loanAmnt']))
  • 分位數(shù)分箱
  • data['loanAmnt_bin3'] = pd.qcut(data['loanAmnt'], 10, labels=False)
  • 卡方分箱及其他分箱方法的嘗試
    • 這一部分屬于進(jìn)階部分,學(xué)有余力的同學(xué)可以自行搜索嘗試。

    3.3.5 特征交互

    • 交互特征的構(gòu)造非常簡(jiǎn)單,使用起來卻代價(jià)不菲。如果線性模型中包含有交互特征對(duì),那它的訓(xùn)練時(shí)間和評(píng)分時(shí)間就會(huì)從 O(n) 增加到 O(n2),其中 n 是單一特征的數(shù)量。
    for col in ['grade', 'subGrade']: temp_dict = data_train.groupby([col])['isDefault'].agg(['mean']).reset_index().rename(columns={'mean': col + '_target_mean'})temp_dict.index = temp_dict[col].valuestemp_dict = temp_dict[col + '_target_mean'].to_dict()data_train[col + '_target_mean'] = data_train[col].map(temp_dict)data_test_a[col + '_target_mean'] = data_test_a[col].map(temp_dict) # 其他衍生變量 mean 和 std for df in [data_train, data_test_a]:for item in ['n0','n1','n2','n2.1','n4','n5','n6','n7','n8','n9','n10','n11','n12','n13','n14']:df['grade_to_mean_' + item] = df['grade'] / df.groupby([item])['grade'].transform('mean')df['grade_to_std_' + item] = df['grade'] / df.groupby([item])['grade'].transform('std')

    這里給出一些特征交互的思路,但特征和特征間的交互衍生出新的特征還遠(yuǎn)遠(yuǎn)不止于此,拋磚引玉,希望大家多多探索。請(qǐng)學(xué)習(xí)者嘗試其他的特征交互方法。

    3.3.6 特征編碼

    labelEncode 直接放入樹模型中

    #label-encode:subGrade,postCode,title # 高維類別特征需要進(jìn)行轉(zhuǎn)換 for col in tqdm(['employmentTitle', 'postCode', 'title','subGrade']):le = LabelEncoder()le.fit(list(data_train[col].astype(str).values) + list(data_test_a[col].astype(str).values))data_train[col] = le.transform(list(data_train[col].astype(str).values))data_test_a[col] = le.transform(list(data_test_a[col].astype(str).values)) print('Label Encoding 完成') 100%|██████████| 4/4 [00:08<00:00, 2.04s/it]Label Encoding 完成

    邏輯回歸等模型要單獨(dú)增加的特征工程

    • 對(duì)特征做歸一化,去除相關(guān)性高的特征
    • 歸一化目的是讓訓(xùn)練過程更好更快的收斂,避免特征大吃小的問題
    • 去除相關(guān)性是增加模型的可解釋性,加快預(yù)測(cè)過程。
    # 舉例歸一化過程 #偽代碼 for fea in [要?dú)w一化的特征列表]:data[fea] = ((data[fea] - np.min(data[fea])) / (np.max(data[fea]) - np.min(data[fea])))

    3.3.7 特征選擇

    • 特征選擇技術(shù)可以精簡(jiǎn)掉無用的特征,以降低最終模型的復(fù)雜性,它的最終目的是得到一個(gè)簡(jiǎn)約模型,在不降低預(yù)測(cè)準(zhǔn)確率或?qū)︻A(yù)測(cè)準(zhǔn)確率影響不大的情況下提高計(jì)算速度。特征選擇不是為了減少訓(xùn)練時(shí)間(實(shí)際上,一些技術(shù)會(huì)增加總體訓(xùn)練時(shí)間),而是為了減少模型評(píng)分時(shí)間。

    特征選擇的方法:

    • 1 Filter
      • 方差選擇法
      • 相關(guān)系數(shù)法(pearson 相關(guān)系數(shù))
      • 卡方檢驗(yàn)
      • 互信息法
    • 2 Wrapper (RFE)
      • 遞歸特征消除法
    • 3 Embedded
      • 基于懲罰項(xiàng)的特征選擇法
      • 基于樹模型的特征選擇

    Filter

    • 基于特征間的關(guān)系進(jìn)行篩選

    方差選擇法

    • 方差選擇法中,先要計(jì)算各個(gè)特征的方差,然后根據(jù)設(shè)定的閾值,選擇方差大于閾值的特征
    from sklearn.feature_selection import VarianceThreshold #其中參數(shù)threshold為方差的閾值 VarianceThreshold(threshold=3).fit_transform(train,target_train)

    相關(guān)系數(shù)法

    • Pearson 相關(guān)系數(shù)
      皮爾森相關(guān)系數(shù)是一種最簡(jiǎn)單的,可以幫助理解特征和響應(yīng)變量之間關(guān)系的方法,該方法衡量的是變量之間的線性相關(guān)性。
      結(jié)果的取值區(qū)間為 [-1,1] , -1 表示完全的負(fù)相關(guān), +1表示完全的正相關(guān),0 表示沒有線性相關(guān)。
    from sklearn.feature_selection import SelectKBest from scipy.stats import pearsonr #選擇K個(gè)最好的特征,返回選擇特征后的數(shù)據(jù) #第一個(gè)參數(shù)為計(jì)算評(píng)估特征是否好的函數(shù),該函數(shù)輸入特征矩陣和目標(biāo)向量, #輸出二元組(評(píng)分,P值)的數(shù)組,數(shù)組第i項(xiàng)為第i個(gè)特征的評(píng)分和P值。在此定義為計(jì)算相關(guān)系數(shù) #參數(shù)k為選擇的特征個(gè)數(shù)SelectKBest(k=5).fit_transform(train,target_train)

    卡方檢驗(yàn)

    • 經(jīng)典的卡方檢驗(yàn)是用于檢驗(yàn)自變量對(duì)因變量的相關(guān)性。 假設(shè)自變量有N種取值,因變量有M種取值,考慮自變量等于i且因變量等于j的樣本頻數(shù)的觀察值與期望的差距。 其統(tǒng)計(jì)量如下: χ2=∑(A?T)2T,其中A為實(shí)際值,T為理論值
    • (注:卡方只能運(yùn)用在正定矩陣上,否則會(huì)報(bào)錯(cuò)Input X must be non-negative)
    from sklearn.feature_selection import SelectKBest from sklearn.feature_selection import chi2 #參數(shù)k為選擇的特征個(gè)數(shù)SelectKBest(chi2, k=5).fit_transform(train,target_train)

    互信息法

    • 經(jīng)典的互信息也是評(píng)價(jià)自變量對(duì)因變量的相關(guān)性的。 在feature_selection庫的SelectKBest類結(jié)合最大信息系數(shù)法可以用于選擇特征,相關(guān)代碼如下:
    from sklearn.feature_selection import SelectKBest from minepy import MINE #由于MINE的設(shè)計(jì)不是函數(shù)式的,定義mic方法將其為函數(shù)式的, #返回一個(gè)二元組,二元組的第2項(xiàng)設(shè)置成固定的P值0.5 def mic(x, y):m = MINE()m.compute_score(x, y)return (m.mic(), 0.5) #參數(shù)k為選擇的特征個(gè)數(shù) SelectKBest(lambda X, Y: array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(train,target_train)

    Wrapper (Recursive feature elimination,RFE)

    • 遞歸特征消除法 遞歸消除特征法使用一個(gè)基模型來進(jìn)行多輪訓(xùn)練,每輪訓(xùn)練后,消除若干權(quán)值系數(shù)的特征,再基于新的特征集進(jìn)行下一輪訓(xùn)練。 在feature_selection庫的RFE類可以用于選擇特征,相關(guān)代碼如下(以邏輯回歸為例):
    from sklearn.feature_selection import RFE from sklearn.linear_model import LogisticRegression #遞歸特征消除法,返回特征選擇后的數(shù)據(jù) #參數(shù)estimator為基模型 #參數(shù)n_features_to_select為選擇的特征個(gè)數(shù)RFE(estimator=LogisticRegression(), n_features_to_select=2).fit_transform(train,target_train)

    Embedded

    • 基于懲罰項(xiàng)的特征選擇法 使用帶懲罰項(xiàng)的基模型,除了篩選出特征外,同時(shí)也進(jìn)行了降維。 在feature_selection庫的SelectFromModel類結(jié)合邏輯回歸模型可以用于選擇特征,相關(guān)代碼如下:
    from sklearn.feature_selection import SelectFromModel from sklearn.linear_model import LogisticRegression #帶L1懲罰項(xiàng)的邏輯回歸作為基模型的特征選擇SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(train,target_train)
    • 基于樹模型的特征選擇 樹模型中GBDT也可用來作為基模型進(jìn)行特征選擇。 在feature_selection庫的SelectFromModel類結(jié)合GBDT模型可以用于選擇特征,相關(guān)代碼如下:
    from sklearn.feature_selection import SelectFromModel from sklearn.ensemble import GradientBoostingClassifier #GBDT作為基模型的特征選擇 SelectFromModel(GradientBoostingClassifier()).fit_transform(train,target_train)

    本數(shù)據(jù)集中我們刪除非入模特征后,并對(duì)缺失值填充,然后用計(jì)算協(xié)方差的方式看一下特征間相關(guān)性,然后進(jìn)行模型訓(xùn)練

    # 刪除不需要的數(shù)據(jù) for data in [data_train, data_test_a]:data.drop(['issueDate','id'], axis=1,inplace=True) "縱向用缺失值上面的值替換缺失值" data_train = data_train.fillna(axis=0,method='ffill') x_train = data_train.drop(['isDefault','id'], axis=1) #計(jì)算協(xié)方差 data_corr = x_train.corrwith(data_train.isDefault) #計(jì)算相關(guān)性 result = pd.DataFrame(columns=['features', 'corr']) result['features'] = data_corr.index result['corr'] = data_corr.values # 當(dāng)然也可以直接看圖 data_numeric = data_train[numerical_fea] correlation = data_numeric.corr()f , ax = plt.subplots(figsize = (7, 7)) plt.title('Correlation of Numeric Features with Price',y=1,size=16) sns.heatmap(correlation,square = True, vmax=0.8) <matplotlib.axes._subplots.AxesSubplot at 0x12d88ad10>

    features = [f for f in data_train.columns if f not in ['id','issueDate','isDefault'] and '_outliers' not in f] x_train = data_train[features] x_test = data_test_a[features] y_train = data_train['isDefault'] def cv_model(clf, train_x, train_y, test_x, clf_name):folds = 5seed = 2020kf = KFold(n_splits=folds, shuffle=True, random_state=seed)train = np.zeros(train_x.shape[0])test = np.zeros(test_x.shape[0])cv_scores = []for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):print('************************************ {} ************************************'.format(str(i+1)))trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], train_y[valid_index]if clf_name == "lgb":train_matrix = clf.Dataset(trn_x, label=trn_y)valid_matrix = clf.Dataset(val_x, label=val_y)params = {'boosting_type': 'gbdt','objective': 'binary','metric': 'auc','min_child_weight': 5,'num_leaves': 2 ** 5,'lambda_l2': 10,'feature_fraction': 0.8,'bagging_fraction': 0.8,'bagging_freq': 4,'learning_rate': 0.1,'seed': 2020,'nthread': 28,'n_jobs':24,'silent': True,'verbose': -1,}model = clf.train(params, train_matrix, 50000, valid_sets=[train_matrix, valid_matrix], verbose_eval=200,early_stopping_rounds=200)val_pred = model.predict(val_x, num_iteration=model.best_iteration)test_pred = model.predict(test_x, num_iteration=model.best_iteration)# print(list(sorted(zip(features, model.feature_importance("gain")), key=lambda x: x[1], reverse=True))[:20])if clf_name == "xgb":train_matrix = clf.DMatrix(trn_x , label=trn_y)valid_matrix = clf.DMatrix(val_x , label=val_y)params = {'booster': 'gbtree','objective': 'binary:logistic','eval_metric': 'auc','gamma': 1,'min_child_weight': 1.5,'max_depth': 5,'lambda': 10,'subsample': 0.7,'colsample_bytree': 0.7,'colsample_bylevel': 0.7,'eta': 0.04,'tree_method': 'exact','seed': 2020,'nthread': 36,"silent": True,}watchlist = [(train_matrix, 'train'),(valid_matrix, 'eval')]model = clf.train(params, train_matrix, num_boost_round=50000, evals=watchlist, verbose_eval=200, early_stopping_rounds=200)val_pred = model.predict(valid_matrix, ntree_limit=model.best_ntree_limit)test_pred = model.predict(test_x , ntree_limit=model.best_ntree_limit)if clf_name == "cat":params = {'learning_rate': 0.05, 'depth': 5, 'l2_leaf_reg': 10, 'bootstrap_type': 'Bernoulli','od_type': 'Iter', 'od_wait': 50, 'random_seed': 11, 'allow_writing_files': False}model = clf(iterations=20000, **params)model.fit(trn_x, trn_y, eval_set=(val_x, val_y),cat_features=[], use_best_model=True, verbose=500)val_pred = model.predict(val_x)test_pred = model.predict(test_x)train[valid_index] = val_predtest = test_pred / kf.n_splitscv_scores.append(roc_auc_score(val_y, val_pred))print(cv_scores)print("%s_scotrainre_list:" % clf_name, cv_scores)print("%s_score_mean:" % clf_name, np.mean(cv_scores))print("%s_score_std:" % clf_name, np.std(cv_scores))return train, test def lgb_model(x_train, y_train, x_test):lgb_train, lgb_test = cv_model(lgb, x_train, y_train, x_test, "lgb")return lgb_train, lgb_testdef xgb_model(x_train, y_train, x_test):xgb_train, xgb_test = cv_model(xgb, x_train, y_train, x_test, "xgb")return xgb_train, xgb_testdef cat_model(x_train, y_train, x_test):cat_train, cat_test = cv_model(CatBoostRegressor, x_train, y_train, x_test, "cat") lgb_train, lgb_test = lgb_model(x_train, y_train, x_test) ************************************ 1 ************************************ Training until validation scores don't improve for 200 rounds [200] training's auc: 0.749225 valid_1's auc: 0.729679 [400] training's auc: 0.765075 valid_1's auc: 0.730496 [600] training's auc: 0.778745 valid_1's auc: 0.730435 Early stopping, best iteration is: [455] training's auc: 0.769202 valid_1's auc: 0.730686 [0.7306859913754798] ************************************ 2 ************************************ Training until validation scores don't improve for 200 rounds [200] training's auc: 0.749221 valid_1's auc: 0.731315 [400] training's auc: 0.765117 valid_1's auc: 0.731658 [600] training's auc: 0.778542 valid_1's auc: 0.731333 Early stopping, best iteration is: [407] training's auc: 0.765671 valid_1's auc: 0.73173 [0.7306859913754798, 0.7317304414673989] ************************************ 3 ************************************ Training until validation scores don't improve for 200 rounds [200] training's auc: 0.748436 valid_1's auc: 0.732775 [400] training's auc: 0.764216 valid_1's auc: 0.733173 Early stopping, best iteration is: [386] training's auc: 0.763261 valid_1's auc: 0.733261 [0.7306859913754798, 0.7317304414673989, 0.7332610441015461] ************************************ 4 ************************************ Training until validation scores don't improve for 200 rounds [200] training's auc: 0.749631 valid_1's auc: 0.728327 [400] training's auc: 0.765139 valid_1's auc: 0.728845 Early stopping, best iteration is: [286] training's auc: 0.756978 valid_1's auc: 0.728976 [0.7306859913754798, 0.7317304414673989, 0.7332610441015461, 0.7289759386807912] ************************************ 5 ************************************ Training until validation scores don't improve for 200 rounds [200] training's auc: 0.748414 valid_1's auc: 0.732727 [400] training's auc: 0.763727 valid_1's auc: 0.733531 [600] training's auc: 0.777489 valid_1's auc: 0.733566 Early stopping, best iteration is: [524] training's auc: 0.772372 valid_1's auc: 0.733772 [0.7306859913754798, 0.7317304414673989, 0.7332610441015461, 0.7289759386807912, 0.7337723979789789] lgb_scotrainre_list: [0.7306859913754798, 0.7317304414673989, 0.7332610441015461, 0.7289759386807912, 0.7337723979789789] lgb_score_mean: 0.7316851627208389 lgb_score_std: 0.0017424259863954693 testA_result = pd.read_csv('../testA_result.csv') roc_auc_score(testA_result['isDefault'].values, lgb_test) 0.7290917729487896

    3.4 總結(jié)

    特征工程是機(jī)器學(xué)習(xí),甚至是深度學(xué)習(xí)中最為重要的一部分,在實(shí)際應(yīng)用中往往也是所花費(fèi)時(shí)間最多的一步。各種算法書中對(duì)特征工程部分的講解往往少得可憐,因?yàn)樘卣鞴こ毯途唧w的數(shù)據(jù)結(jié)合的太緊密,很難系統(tǒng)地覆蓋所有場(chǎng)景。本章主要是通過一些常用的方法來做介紹,例如缺失值異常值的處理方法詳細(xì)對(duì)任何數(shù)據(jù)集來說都是適用的。但對(duì)于分箱等操作本章給出了具體的幾種思路,需要讀者自己探索。在特征工程中比賽和具體的應(yīng)用還是有所不同的,在實(shí)際的金融風(fēng)控評(píng)分卡制作過程中,由于強(qiáng)調(diào)特征的可解釋性,特征分箱尤其重要。

    總結(jié)

    以上是生活随笔為你收集整理的【算法竞赛学习】金融风控之贷款违约预测-特征工程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。