2021-03-05
閱讀量:
1768
python中如何用xgboost模型填補(bǔ)缺失值?
如何用xgboost模型填補(bǔ)缺失值?
演示用數(shù)據(jù)如下:
代碼文件如下:
代碼如下:
# ### 導(dǎo)入庫 import pandas as pd import numpy as np import xgboost as xgb from sklearn.base import BaseEstimator, TransformerMixin #from sklearn.ensemble import BaggingClassifier, RandomForestClassifier #pip install pyecharts -i https://pypi.tuna.tsinghua.edu.cn/simple pd.options.display.max_columns = None # 顯示所有列 pd.set_option('display.float_format', lambda x: '%.3f' % x) # 取消科學(xué)計數(shù)法 #定義一個函數(shù)來判斷一個變量到底是什么類型 def get_kind(x: pd.Series, diff_limit: int = 10): x = x.astype('str') x = x.str.extract(r'(^(\-|)(?=.*\d)\d*(?:\.\d*)?$)')[0] x.dropna(inplace=True) if x.nunique() > diff_limit: kind = 'numeric' else: kind = 'categorical' return kind #1.先將這個變量x轉(zhuǎn)化為字符型 #2.對這個字符串變量x進(jìn)行正則表達(dá)式的匹配,如果沒有匹配成功,則返回缺失值,并且直接作用于x #3.刪除變量x里面的缺失值,并且直接作用于x #4.數(shù)一數(shù)變量x里面有多少個唯一值, #5.將唯一值的個數(shù)和diff_limit進(jìn)行比較 #6.如果大于diff_limit則將其判定為numeric類型,否則將其判定為categorical類型。 #7.也就是categorical類型變量的取值是不能太多的,不能超過我們設(shè)定的閥值10 class wrong_value_fillna(BaseEstimator, TransformerMixin): def __init__(self, num_list: list = None, cate_list: list = None, wrong_value: list = None, diff_num: int = 10): self.num_list = num_list self.cate_list = cate_list self.diff_num = diff_num self.wrong_value = wrong_value def fit(self, X, y=None): X = X.copy() if self.num_list is None: self.num_list = [] for col in X.columns: kind = get_kind(x=X[col], diff_limit=self.diff_num) if kind == 'numeric': self.num_list.append(col) if self.cate_list is None: self.cate_list = [] for col in X.columns: kind = get_kind(x=X[col], diff_limit=self.diff_num) if kind == 'categorical': self.cate_list.append(col) return self def transform(self, X): X = X.copy() X.replace(self.wrong_value, np.nan, inplace=True) for col in X.columns: if get_kind(X[col]) == 'numeric': X[col] = X[col].astype('float') else: X[col] = X[col].astype('object') return X class xgb_fill(BaseEstimator, TransformerMixin): def __init__(self, num_list: list = None, cate_list: list = None, diff_num: int = 10, #注意這個diff_num的設(shè)定非常重要,這個值最好與get_kind函數(shù)里面的設(shè)定值保持一致,否則可能出現(xiàn)漏洞 #比如這里設(shè)定為了8,而get_kind里面設(shè)定為了10,那么當(dāng)判斷一個變量是否要處理為object變量的時候 #就可能出現(xiàn)問題,比如這個變量的不重復(fù)值有9個,到了get_kind函數(shù)那里,將其處理為了object變量, #在這里就會被處理成float變量 random_state: int = 0): self.num_list = num_list self.cate_list = cate_list self.diff_num = diff_num self.random_state = random_state self.xgb_cla_dict = {} self.xgb_reg_dict = {} def fit(self, X, y=None): from tqdm import tqdm X = X.copy() #1.先找到numberic變量列表self.num_list #2.再找到categorical變量列表self.cate_list if self.num_list is None: self.num_list = [] for col in X.columns: kind = get_kind(x=X[col], diff_limit=self.diff_num) if kind == 'numeric': self.num_list.append(col) if self.cate_list is None: self.cate_list = [] for col in X.columns: kind = get_kind(x=X[col], diff_limit=self.diff_num) if kind == 'categorical': self.cate_list.append(col) #對categorical變量進(jìn)行處理 for col in tqdm(self.cate_list): file = X.copy() if file[col].isnull().any(): #如果變量有缺失值的話,則用XGBClassifier分類器進(jìn)行填補(bǔ),填補(bǔ)后的變量放在了xgb_cla_dict里面 df = pd.get_dummies(file, columns=[i for i in self.cate_list if i != col], prefix=[i for i in self.cate_list if i != col], dummy_na=True) #找出col列沒有缺失值的行,生成not_null數(shù)據(jù)框 not_null = df.dropna(subset=[col]) #將not_null中col以外的列設(shè)定為x_,將col列設(shè)定為y_ x_ = not_null.drop([col], axis=1) y_ = not_null[col] #實例化分類器 xgb_cla = xgb.XGBClassifier(random_state=self.random_state) #xgb_cla是一個針對col列預(yù)測的分類器 #用fit方法擬合這個分類器的參數(shù) xgb_cla.fit(x_, y_) #將擬合好的分類器傳給字典self.xgb_cla_dict[col] self.xgb_cla_dict[col] = xgb_cla #對numberic變量進(jìn)行處理 for col in tqdm(self.num_list): file = X.copy() if file[col].isnull().any(): #如果變量有缺失值的話,則用XGBRegressor回歸器進(jìn)行填補(bǔ),填補(bǔ)后的變量放在了xgb_reg_dict里面 df = pd.get_dummies(file, columns=self.cate_list, dummy_na=True, prefix=self.cate_list) not_null = df.dropna(subset=[col]) x_ = not_null.drop([col], axis=1) y_ = not_null[col] xgb_reg = xgb.XGBRegressor(random_state=self.random_state, objective='reg:squarederror') xgb_reg.fit(x_, y_) self.xgb_reg_dict[col] = xgb_reg print('fit xgb fill the Na success!') return self def transform(self, X): print("cate_list1",self.cate_list,sep="************************") X = X.copy() from tqdm import tqdm print("******************",self.cate_list) for col in tqdm(self.cate_list): #對object變量進(jìn)行填補(bǔ) print("cate_list",col,sep="************************") file = X.copy() if file[col].isnull().any(): print(col,"有缺失") #如果col列中有缺失值的話則進(jìn)行如下處理 #1將數(shù)據(jù)框file里面的全部object變量都轉(zhuǎn)化為虛擬變量,并且把缺失值也看成一個類別。 #2把數(shù)據(jù)框保存為df df = pd.get_dummies(file, columns=[i for i in self.cate_list if i != col], prefix=[i for i in self.cate_list if i != col], dummy_na=True) #刪除col變量存在缺失值的行,保留col變量不存在缺失值的行,保存為not_null not_null = df.dropna(subset=[col]) #把col變量存在缺失值的行保存為數(shù)據(jù)框null null = df.drop(not_null.index) #根據(jù)數(shù)據(jù)框null的除col列的其他列的值對col列進(jìn)行插補(bǔ) #開始調(diào)用實例的predict方法 #如果調(diào)用predict方法就會先調(diào)用fit方法 #接下來可以轉(zhuǎn)到上面的fit方法定義那里看一下 #完成fit之后數(shù)據(jù)就會插補(bǔ)成功了,并且將插補(bǔ)后的結(jié)果放到了self.xgb_cla_dict里面 #然后用self.xgb_cla_dict里面的值對數(shù)據(jù)框null里面的col列進(jìn)行賦值。 print(null.drop([col],axis=1).dtypes) null[col] = self.xgb_cla_dict[col].predict(null.drop([col], axis=1)) #然后對X里面的col列進(jìn)行賦值 X[col] = pd.concat([null, not_null], axis=0)[col] else: #如果col列中沒有缺失值的話則進(jìn)行如下處理 X[col] = file[col] #對float64變量進(jìn)行填補(bǔ) for col in tqdm(self.num_list): print("num_list",col,sep="************************") file = X.copy() if file[col].isnull().any(): df = pd.get_dummies(file, columns=self.cate_list, dummy_na=True, prefix=self.cate_list) not_null = df.dropna(subset=[col]) null = df.drop(not_null.index) null[col] = self.xgb_reg_dict[col].predict(null.drop([col], axis=1)) X[col] = pd.concat([null, not_null], axis=0)[col] else: X[col] = file[col] print('transform xgb fill the NA success!') return X wvf = wrong_value_fillna(wrong_value=['.', '?']) data = pd.read_excel(r"C:\Users\Administrator\Desktop\1614829496_756660.xlsx") #我們看一下現(xiàn)在data數(shù)據(jù)里面的變量類型 #其中類型為object的變量有age,sex,region, #float64:'B0003', 'B0004', 'B0005', 'B0006', 'B0008', 'B0010', 'B0011', 'B0014', 'B0015', 'B0016', 'B0018', #int64:'B0012','B0017', 'B0124', 'Target' data = wvf.transform(data) #我們看一下經(jīng)過轉(zhuǎn)化后的data數(shù)據(jù)里面的變量類型 #其中類型為object的變量有age,sex,region, #float64:'B0003', 'B0005', 'B0006', 'B0010', 'B0012','B0015', 'B0016', 'B0018', 'B0124', #object:'B0004','B0008','B0011','B0014','B0017','Target' #將數(shù)據(jù)轉(zhuǎn)化好后進(jìn)行數(shù)據(jù)拆分 x1_ = data.drop(['Target'], axis=1) y1_ = data['Target'].values #實例化 xgbf = xgb_fill() #調(diào)用fit_transform方法進(jìn)行插補(bǔ) x_=xgbf.fit_transform(x1_) #這個就是插補(bǔ)之后的結(jié)果
希望大家運(yùn)行愉快!






評論(0)


暫無數(shù)據(jù)
推薦帖子
0條評論
0條評論
0條評論
0條評論