ermutuxia

2021-03-05   阅读量: 1281

Python

python中如何用xgboost模型填补缺失值?

扫码加入数据分析学习群

如何用xgboost模型填补缺失值?

演示用数据如下:

1614829496_756660.xlsx

代码文件如下:

liushagai1.txt

代码如下:



# ### 导入库
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)


暂无数据

推荐课程

推荐帖子