天池-金融风控训练营-task3-特征工程

1. 学习知识概要

本部分主要介绍数据预处理的内容,包括:数据预处理(缺失值填充、时间格式处理、类别特征处理)、异常值处理、数据分箱、特征交互、特征选择等部分。

2. 学习内容

2.1 数据导入

data_train =pd.read_csv('data/train.csv')
data_test_a = pd.read_csv('data/testA.csv')

2.2 数据预处理

一般我们要处理一些EDA阶段分析出来的问题。

# 首先我们查找出数据中的对象特征和数值特征
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)))
# filter ref : https://www.runoob.com/python/python-func-filter.html
label = 'isDefault'
numerical_fea.remove(label)

2.2.1 缺失值填充

        1. 把所有缺失值替换为指定的值(0;-1;一般数值类型可用平均值填充、类别型可用众数填充)

        2. 用缺失值上面或下面的值替换缺失值

#按照平均数填充数值型特征
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())
#按照众数填充类别型特征
data_train[category_fea] = data_train[category_fea].fillna(data_train[category_fea].mode().T[0])
data_test_a[category_fea] = data_test_a[category_fea].fillna(data_train[category_fea].mode().T[0])

2.2.2 时间格式处理

#转化成时间格式
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')
    #构造时间特征
    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    309552
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
Name: employmentLength, dtype: int64

 可以看到‘employmentLength’这个特征是可以转化为数值型的一个特征。

def employmentLength_to_int(s):
    if pd.isnull(s):
        return s
    else:
        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)
# 对earliesCreditLine进行预处理
data_train['earliesCreditLine'].sample(5)
43832     Nov-2000
87610     Jan-2007
266876    Sep-2000
290878    Feb-2008
236449    Jul-2001
Name: earliesCreditLine, dtype: object
for data in [data_train, data_test_a]:
    data['earliesCreditLine'] = data['earliesCreditLine'].apply(lambda s: int(s[-4:]))

2.2.3 类别特征处理 

# 部分类别特征
cate_features = ['grade', 'subGrade', 'employmentTitle', 'homeOwnership', 'verificationStatus', 'purpose', 'postCode', 'regionCode', \
                 'applicationType', 'initialListStatus', 'title', 'policyCode']
for f in cate_features:
    print(f, '类型数:', data[f].nunique())
grade 类型数: 7
subGrade 类型数: 35
employmentTitle 类型数: 79282
homeOwnership 类型数: 6
verificationStatus 类型数: 3
purpose 类型数: 14
postCode 类型数: 889
regionCode 类型数: 51
applicationType 类型数: 2
initialListStatus 类型数: 2
title 类型数: 12058
policyCode 类型数: 1
# 像等级这种类别特征,是有优先级的可以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})

2.3 异常值处理

* 当你发现异常值后,一定要先分清是什么原因导致的异常值,然后再考虑如何处理。首先,如果这一异常值并不代表一种规律性的,而是极其偶然的现象,或者说你并不想研究这种偶然的现象,这时可以将其删除。其次,如果异常值存在且代表了一种真实存在的现象,那就不能随便删除。在现有的欺诈场景中很多时候欺诈数据本身相对于正常数据来说就是异常的,我们要把这些异常点纳入,重新拟合模型,研究其规律。能用监督的用监督模型,不能用的还可以考虑用异常检测的算法来做。
* 注意test的数据不能删。

2.3.1 检测异常的方法一:均方差

    在统计学中,如果一个数据分布近似正态,那么大约 68% 的数据值会在均值的一个标准差范围内,大约 95% 会在两个标准差范围内,大约 99.7% 会在三个标准差范围内。

def find_outliers_by_3segama(data,fea):
    data_std = np.std(data[fea])
    data_mean = np.mean(data[fea])
    outliers_cut_off = data_std * 3
    lower_rule = data_mean - outliers_cut_off
    upper_rule = data_mean + outliers_cut_off
    data[fea+'_outliers'] = data[fea].apply(lambda x:str('异常值') if x > upper_rule or x < lower_rule else '正常值')
    return data
dict_value_counts = {}
dict_sum = {}
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())
    dict_value_counts[fea+'_outliers'] = data_train[fea+'_outliers'].value_counts().to_dict()
    print(data_train.groupby(fea+'_outliers')['isDefault'].sum())
    dict_sum[fea+'_outliers'] = data_train.groupby(fea+'_outliers')['isDefault'].sum().to_dict()
    print('*'*10)
#删除异常值
for fea in numerical_fea:
    data_train = data_train[data_train[fea+'_outliers']=='正常值']
    data_train = data_train.reset_index(drop=True) 

2.3.2 检测异常的方法二:箱型图

    总结一句话:四分位数会将数据分为三个点和四个区间,IQR = Q3 -Q1,下触须=Q1 − 1.5x IQR,上触须=Q3 + 1.5x IQR

2.4 数据分箱

2.4.1 特征分箱的目的:

* 从模型效果上来看,特征分箱主要是为了降低变量的复杂性,减少变量噪音对模型的影响,提高自变量和因变量的相关度。从而使模型更加稳定。

2.4.2 数据分桶的对象:

* 将连续变量离散化
* 将多状态的离散变量合并成少状态

2.4.3 分箱的原因:

* 数据的特征内的值跨度可能比较大,对有监督和无监督中如k-均值聚类它使用欧氏距离作为相似度函数来测量数据点之间的相似度。都会造成大吃小的影响,其中一种解决方法是对计数值进行区间量化即数据分桶也叫做数据分箱,然后使用量化后的结果。

2.4.4 分箱的优点:

* 处理缺失值:当数据源可能存在缺失值,此时可以把null单独作为一个分箱。
* 处理异常值:当数据中存在离群点时,可以把其通过分箱离散化处理,从而提高变量的鲁棒性(抗干扰能力)。例如,age若出现200这种异常值,可分入“age > 60”这个分箱里,排除影响。
* 业务解释性:我们习惯于线性判断变量的作用,当x越来越大,y就越来越大。但实际x与y之间经常存在着非线性关系,此时可经过WOE变换。

2.4.5 特别要注意一下分箱的基本原则:

(1)最小分箱占比不低于5%
(2)箱内不能全部是好客户
(3)连续箱单调

2.4.6 几种分箱方法

(1) 固定宽度分箱

当数值横跨多个数量级时,最好按照 10 的幂(或任何常数的幂)来进行分组:0\~9、10\~99、100\~999、1000\~9999,等等。固定宽度分箱非常容易计算,但如果计数值中有比较大的缺口,就会产生很多没有任何数据的空箱子。

# 通过除法映射到间隔均匀的分箱中,每个分箱的取值范围都是loanAmnt/1000
data['loanAmnt_bin1'] = np.floor_divide(data['loanAmnt'], 1000)
## 通过对数函数映射到指数宽度分箱
data['loanAmnt_bin2'] = np.floor(np.log10(data['loanAmnt']))

 (2)分位数分箱

data['loanAmnt_bin3'] = pd.qcut(data['loanAmnt'], 10, labels=False)

(3)卡方分箱 

分箱方法整理_nikita_zj的博客-CSDN博客

2.5 特征交互

# 相当于对每个grade统计isdefault的均值,然后每条数据根据自己所在grade获取均值数据,放在新增的一列里面
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].values
    temp_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','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')

2.6 特征编码

#label-encode:subGrade,postCode,title
# 高维类别特征需要进行转换
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 完成')

2.7 特征选择

特征选择技术可以精简掉无用的特征,以降低最终模型的复杂性,它的最终目的是得到一个简约模型,在不降低预测准确率或对预测准确率影响不大的情况下提高计算速度。特征选择不是为了减少训练时间(实际上,一些技术会增加总体训练时间),而是为了减少模型评分时间。

2.7.1 Filter

(1)方差选择法

方差选择法中,先要计算各个特征的方差,然后根据设定的阈值,选择方差大于阈值的特征

train = data_train.copy()
train = train.select_dtypes(exclude = ['object', 'datetime64[ns]'])

from sklearn.feature_selection import VarianceThreshold
#其中参数threshold为方差的阈值
selector = VarianceThreshold(threshold=100).fit(train)

# 方案1 太麻烦
# train_new = selector.transform(train).copy()

# temp = selector.inverse_transform(selector.transform(train)) # 被筛掉的特征,所有样本的该特征值都会变成0
# temp = pd.DataFrame(temp, columns = train.columns) # 将2*2的一个arrray转化成dataframe,并加上列名

# dict_temp = (temp != 0).any().to_dict() # 定义一个字典,被保留的col对应value为True,其他的为false
# temp_col = list(filter(lambda x: dict_temp[x], temp.columns)) # 提取出被保留的列名
# train_final = temp[temp_col] # 基于原dataframe,只保留方差大于阈值的特征

# # 方案2 优于方案1
# threshold=100
# col = train.columns[selector.variances_>threshold]
# train_final = train[col]

# # 方案3 无需调用sklearn.feature_selection中的包,直接计算标准差
# train_final = train[train.columns[train.std()>10]].copy()

(2)相关系数法(pearson 相关系数)

Pearson 相关系数 皮尔森相关系数是一种最简单的,可以帮助理解特征和响应变量之间关系的方法,该方法衡量的是变量之间的线性相关性。 结果的取值区间为 [-1,1] , -1 表示完全的负相关, +1表示完全的正相关,0 表示没有线性相关。

train = data_train.copy()
train = train.select_dtypes(exclude = ['object', 'datetime64[ns]'])

k = 5
temp = train.corr()
best_k = np.abs(temp.isDefault).sort_values(ascending = False).index[1:k]
print(f'best_k is {best_k}') # 输出相关系数最大的k个变量

train_final = train[best_k]
train_final

(3)卡方检验

经典的卡方检验是用于检验自变量对因变量的相关性。 假设自变量有N种取值,因变量有M种取值,考虑自变量等于i且因变量等于j的样本频数的观察值与期望的差距。 其统计量如下: χ2=∑(A−T)2T,其中A为实际值,T为理论值
    (注:卡方只能运用在正定矩阵上,否则会报错Input X must be non-negative)

train = data_train.copy()
train = train.select_dtypes(exclude = ['object', 'datetime64[ns]'])

from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
#参数k为选择的特征个数

# 在该数据集上,这句代码就报错了
SelectKBest(chi2, k=5).fit_transform(train,train.isDefault)

(4)互信息法

经典的互信息也是评价自变量对因变量的相关性的。 在feature_selection库的SelectKBest类结合最大信息系数法可以用于选择特征,相关代码如下:

# train = data_train.copy()
# train = train.select_dtypes(exclude = ['object', 'datetime64[ns]'])

# from sklearn.feature_selection import SelectKBest
# from minepy import MINE
# #由于MINE的设计不是函数式的,定义mic方法将其为函数式的,
# #返回一个二元组,二元组的第2项设置成固定的P值0.5
# def mic(x, y):
#     m = MINE()
#     m.compute_score(x, y)
#     return (m.mic(), 0.5)
# #参数k为选择的特征个数
# SelectKBest(lambda X, Y: array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(train,train.isDefault)

 * 安装模块'minepy'遇到障碍,暂时先放一放 *

2.7.2 Wrapper (RFE)

(1)递归特征消除法

递归特征消除法 递归消除特征法使用一个基模型来进行多轮训练,每轮训练后,消除若干权值系数的特征,再基于新的特征集进行下一轮训练。 在feature_selection库的RFE类可以用于选择特征,相关代码如下(以逻辑回归为例):

from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
#递归特征消除法,返回特征选择后的数据
#参数estimator为基模型
#参数n_features_to_select为选择的特征个数

rfe = RFE(estimator=LogisticRegression(), n_features_to_select=6).fit(train.iloc[:,-10:],train.isDefault)
# ref: http://www.minxueyu.com/2020/03/29/RFE%E4%B8%8ERFECV%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/

print(rfe.support_)
print(rfe.ranking_)

dic = dict(zip(train.iloc[:,-10:].columns, rfe.support_))
col_final = list(filter(lambda x:dic[x], train.iloc[:,-10:].columns))
train_final = train[col_final]

2.7.3 Embedded

(1)基于惩罚项的特征选择法

基于惩罚项的特征选择法 使用带惩罚项的基模型,除了筛选出特征外,同时也进行了降维。 在feature_selection库的SelectFromModel类结合逻辑回归模型可以用于选择特征,相关代码如下:

from sklearn.feature_selection import SelectFromModel
from sklearn.linear_model import LogisticRegression
#带L1惩罚项的逻辑回归作为基模型的特征选择

selector = SelectFromModel(LogisticRegression(solver='liblinear', penalty="l1", C=0.1)).fit(train,train.isDefault)

# ref : https://blog.csdn.net/weixin_46072771/article/details/106190351

# selector.threshold_ # 筛选的阈值
# selector.estimator_.coef_ # 权重
# selector.get_support() # 获取所选特征的掩码或整数索引

(2)基于树模型的特征选择

基于树模型的特征选择 树模型中GBDT也可用来作为基模型进行特征选择。 在feature_selection库的SelectFromModel类结合GBDT模型可以用于选择特征,相关代码如下:

from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import GradientBoostingClassifier
#GBDT作为基模型的特征选择
# selector = SelectFromModel(GradientBoostingClassifier()).fit(train,train.isDefault)

# selector.get_support()

2.8 一个简单又不简单的建模示例

本数据集中我们删除非入模特征后,并对缺失值填充,然后用计算协方差的方式看一下特征间相关性,然后进行模型训练。

# 删除不需要的数据
for data in [data_train, data_test_a]:
    data.drop(['issueDate'], axis=1,inplace=True)

# "纵向用缺失值上面的值替换缺失值"
data_train = data_train.fillna(axis=0,method='ffill')

x_train = data_train
#计算协方差
data_corr = x_train.corrwith(data_train.isDefault) #计算相关性
result = pd.DataFrame(columns=['features', 'corr'])
result['features'] = data_corr.index
result['corr'] = data_corr.values

# 当然也可以直接看图
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)

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 = 5
    seed = 2020
    kf = KFold(n_splits=folds, shuffle=True, random_state=seed)
    # ref:https://zhuanlan.zhihu.com/p/157680082
    # ref:https://zhuanlan.zhihu.com/p/113623623
    
    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_pred
        test = test_pred / kf.n_splits
        cv_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_test

def 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_test

def 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 ************************************
[LightGBM] [Warning] num_threads is set with nthread=28, will be overridden by n_jobs=24. Current value: num_threads=24
[LightGBM] [Warning] Unknown parameter: silent
Training until validation scores don't improve for 200 rounds
[200]	training's auc: 0.749289	valid_1's auc: 0.729271
[400]	training's auc: 0.76494	valid_1's auc: 0.730234
[600]	training's auc: 0.778738	valid_1's auc: 0.729998
Early stopping, best iteration is:
[430]	training's auc: 0.767135	valid_1's auc: 0.730342
[0.730342397936816]
************************************ 2 ************************************
[LightGBM] [Warning] num_threads is set with nthread=28, will be overridden by n_jobs=24. Current value: num_threads=24
[LightGBM] [Warning] Unknown parameter: silent
Training until validation scores don't improve for 200 rounds
[200]	training's auc: 0.748661	valid_1's auc: 0.731083
[400]	training's auc: 0.764536	valid_1's auc: 0.73193
[600]	training's auc: 0.778049	valid_1's auc: 0.731571
Early stopping, best iteration is:
[400]	training's auc: 0.764536	valid_1's auc: 0.73193
[0.730342397936816, 0.7319300859130714]
************************************ 3 ************************************
[LightGBM] [Warning] num_threads is set with nthread=28, will be overridden by n_jobs=24. Current value: num_threads=24
[LightGBM] [Warning] Unknown parameter: silent
Training until validation scores don't improve for 200 rounds
[200]	training's auc: 0.748472	valid_1's auc: 0.732545
[400]	training's auc: 0.763739	valid_1's auc: 0.733638
[600]	training's auc: 0.777847	valid_1's auc: 0.733788
Early stopping, best iteration is:
[580]	training's auc: 0.776458	valid_1's auc: 0.733897
[0.730342397936816, 0.7319300859130714, 0.7338967544912544]
************************************ 4 ************************************
[LightGBM] [Warning] num_threads is set with nthread=28, will be overridden by n_jobs=24. Current value: num_threads=24
[LightGBM] [Warning] Unknown parameter: silent
Training until validation scores don't improve for 200 rounds
[200]	training's auc: 0.749436	valid_1's auc: 0.727429
[400]	training's auc: 0.765192	valid_1's auc: 0.728245
Early stopping, best iteration is:
[365]	training's auc: 0.762778	valid_1's auc: 0.728326
[0.730342397936816, 0.7319300859130714, 0.7338967544912544, 0.7283255575198275]
************************************ 5 ************************************
[LightGBM] [Warning] num_threads is set with nthread=28, will be overridden by n_jobs=24. Current value: num_threads=24
[LightGBM] [Warning] Unknown parameter: silent
Training until validation scores don't improve for 200 rounds
[200]	training's auc: 0.748577	valid_1's auc: 0.732638
[400]	training's auc: 0.764157	valid_1's auc: 0.733404
[600]	training's auc: 0.777919	valid_1's auc: 0.73331
Early stopping, best iteration is:
[430]	training's auc: 0.766206	valid_1's auc: 0.733465
[0.730342397936816, 0.7319300859130714, 0.7338967544912544, 0.7283255575198275, 0.7334651612644021]
lgb_scotrainre_list: [0.730342397936816, 0.7319300859130714, 0.7338967544912544, 0.7283255575198275, 0.7334651612644021]
lgb_score_mean: 0.7315919914250743
lgb_score_std: 0.0020574780807703524

3. 学习问题与解答

各种参考资料,见代码块的注释。

4. 学习思考与总结

特征工程,需要多尝试。

补充:

时间序列相关的特征工程:时间序列数据的特征工程总结 - 知乎

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值