2021-03-05
阅读量:
1807
python中如何用xgboost模型填补缺失值?
如何用xgboost模型填补缺失值?
演示用数据如下:
代码文件如下:
代码如下:
# ### 导入库
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) # 取消科学计数法
#定义一个函数来判断一个变量到底是什么类型
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转化为字符型
#2.对这个字符串变量x进行正则表达式的匹配,如果没有匹配成功,则返回缺失值,并且直接作用于x
#3.删除变量x里面的缺失值,并且直接作用于x
#4.数一数变量x里面有多少个唯一值,
#5.将唯一值的个数和diff_limit进行比较
#6.如果大于diff_limit则将其判定为numeric类型,否则将其判定为categorical类型。
#7.也就是categorical类型变量的取值是不能太多的,不能超过我们设定的阀值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的设定非常重要,这个值最好与get_kind函数里面的设定值保持一致,否则可能出现漏洞
#比如这里设定为了8,而get_kind里面设定为了10,那么当判断一个变量是否要处理为object变量的时候
#就可能出现问题,比如这个变量的不重复值有9个,到了get_kind函数那里,将其处理为了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变量进行处理
for col in tqdm(self.cate_list):
file = X.copy()
if file[col].isnull().any():
#如果变量有缺失值的话,则用XGBClassifier分类器进行填补,填补后的变量放在了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数据框
not_null = df.dropna(subset=[col])
#将not_null中col以外的列设定为x_,将col列设定为y_
x_ = not_null.drop([col], axis=1)
y_ = not_null[col]
#实例化分类器
xgb_cla = xgb.XGBClassifier(random_state=self.random_state)
#xgb_cla是一个针对col列预测的分类器
#用fit方法拟合这个分类器的参数
xgb_cla.fit(x_, y_)
#将拟合好的分类器传给字典self.xgb_cla_dict[col]
self.xgb_cla_dict[col] = xgb_cla
#对numberic变量进行处理
for col in tqdm(self.num_list):
file = X.copy()
if file[col].isnull().any():
#如果变量有缺失值的话,则用XGBRegressor回归器进行填补,填补后的变量放在了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变量进行填补
print("cate_list",col,sep="************************")
file = X.copy()
if file[col].isnull().any():
print(col,"有缺失")
#如果col列中有缺失值的话则进行如下处理
#1将数据框file里面的全部object变量都转化为虚拟变量,并且把缺失值也看成一个类别。
#2把数据框保存为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变量存在缺失值的行保存为数据框null
null = df.drop(not_null.index)
#根据数据框null的除col列的其他列的值对col列进行插补
#开始调用实例的predict方法
#如果调用predict方法就会先调用fit方法
#接下来可以转到上面的fit方法定义那里看一下
#完成fit之后数据就会插补成功了,并且将插补后的结果放到了self.xgb_cla_dict里面
#然后用self.xgb_cla_dict里面的值对数据框null里面的col列进行赋值。
print(null.drop([col],axis=1).dtypes)
null[col] = self.xgb_cla_dict[col].predict(null.drop([col], axis=1))
#然后对X里面的col列进行赋值
X[col] = pd.concat([null, not_null], axis=0)[col]
else:
#如果col列中没有缺失值的话则进行如下处理
X[col] = file[col]
#对float64变量进行填补
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")
#我们看一下现在data数据里面的变量类型
#其中类型为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)
#我们看一下经过转化后的data数据里面的变量类型
#其中类型为object的变量有age,sex,region,
#float64:'B0003', 'B0005', 'B0006', 'B0010', 'B0012','B0015', 'B0016', 'B0018', 'B0124',
#object:'B0004','B0008','B0011','B0014','B0017','Target'
#将数据转化好后进行数据拆分
x1_ = data.drop(['Target'], axis=1)
y1_ = data['Target'].values
#实例化
xgbf = xgb_fill()
#调用fit_transform方法进行插补
x_=xgbf.fit_transform(x1_) #这个就是插补之后的结果希望大家运行愉快!
0.0000
1
0
关注作者
收藏
评论(0)
发表评论
暂无数据
推荐帖子
0条评论
0条评论
0条评论

