天池二手车预测:特征工程

特征工程

1. 特征工程目标及主要工作

  • 特征工程的目标主要是对特征进行进一步的分析和构造,将数据转换为能更好的表示潜在问题的特征,从而提升机器学习的性能
  • 常见的主要工作包括:
  1. 异常处理:
    通过箱线图(或 3-Sigma)分析删除异常值;
    BOX-COX 转换(处理有偏分布);
    长尾截断;
  2. 特征归一化/标准化:
    标准化(转换为标准正态分布);
    归一化(抓换到 [0,1] 区间);
    针对幂律分布,可以采用公式:
  3. 数据分桶:
    等频分桶;
    等距分桶;
    Best-KS 分桶(类似利用基尼指数进行二分类);
    卡方分桶;
  4. 缺失值处理:
    不处理(针对类似 XGBoost 等树模型);
    删除(缺失数据太多);
    插值补全,包括均值/中位数/众数/建模预测/多重插补/压缩感知补全/矩阵补全等;
    分箱,缺失值一个箱;
  5. 特征构造:
    构造统计量特征,报告计数、求和、比例、标准差等;
    时间特征,包括相对时间和绝对时间,节假日,双休日等;
    地理信息,包括分箱,分布编码等方法;
    非线性变换,包括 log/ 平方/ 根号等;
    特征组合,特征交叉;
    仁者见仁,智者见智。
  6. 特征筛选
    过滤式(filter):先对数据进行特征选择,然后在训练学习器,常见的方法有 Relief/方差选择发/相关系
    数法/卡方检验法/互信息法;
    包裹式(wrapper):直接把最终将要使用的学习器的性能作为特征子集的评价准则,常见方法有
    LVM(Las Vegas Wrapper) ;
    嵌入式(embedding):结合过滤式和包裹式,学习器训练过程中自动进行了特征选择,常见的有
    lasso 回归;
  7. 降维
    PCA/ LDA/ ICA;
    特征选择也是一种降维。

2. 代码实现

import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
from operator import itemgetter
%matplotlib inline

0.导入数据

train = pd.read_csv('used_car_train_20200313.csv', sep = ' ')
test = pd.read_csv('used_car_testA_20200313.csv', sep = ' ')
print(train.shape)
print(test.shape)
(150000, 31)
(50000, 30)
train.head().append(train.tail())
SaleIDnameregDatemodelbrandbodyTypefuelTypegearboxpowerkilometer...v_5v_6v_7v_8v_9v_10v_11v_12v_13v_14
007362004040230.061.00.00.06012.5...0.2356760.1019880.1295490.0228160.097462-2.8818032.804097-2.4208210.7952920.914762
1122622003030140.012.00.00.0015.0...0.2647770.1210040.1357310.0265970.020582-4.9004822.096338-1.030483-1.7226740.245522
221487420040403115.0151.00.00.016312.5...0.2514100.1149120.1651470.0621730.027075-4.8467491.8035591.565330-0.832687-0.229963
337186519960908109.0100.00.01.019315.0...0.2742930.1103000.1219640.0333950.000000-4.5095991.285940-0.501868-2.438353-0.478699
4411108020120103110.051.00.00.0685.0...0.2280360.0732050.0918800.0788190.121534-1.8962400.9107830.9311102.8345181.923482
14999514999516397820000607121.0104.00.01.016315.0...0.2802640.0003100.0484410.0711580.0191741.988114-2.9839730.589167-1.304370-0.302592
14999614999618453520091102116.0110.00.00.012510.0...0.2532170.0007770.0840790.0996810.0793711.839166-2.7746152.5539940.924196-0.272160
1499971499971475872010100360.0111.01.00.0906.0...0.2333530.0007050.1188720.1001180.0979142.439812-1.6306772.2901971.8919220.414931
149998149998459072006031234.0103.01.00.015615.0...0.2563690.0002520.0814790.0835580.0814982.075380-2.6337191.4149370.431981-1.659014
1499991499991776721999020419.0286.00.01.019312.5...0.2844750.0000000.0400720.0625430.0258191.978453-3.1799130.031724-1.483350-0.342674

10 rows × 31 columns

test.head().append(test.tail())
SaleIDnameregDatemodelbrandbodyTypefuelTypegearboxpowerkilometer...v_5v_6v_7v_8v_9v_10v_11v_12v_13v_14
01500006693220111212222.045.01.01.031315.0...0.2644050.1218000.0708990.1065580.078867-7.050969-0.8546264.8001510.620011-3.664654
11500011749601999021119.0210.00.00.07512.5...0.2617450.0000000.0967330.0137050.0523833.679418-0.729039-3.796107-1.541230-0.757055
215000253562009030482.0210.00.00.01097.0...0.2602160.1120810.0780820.0620780.050540-4.9266901.0011060.8265620.1382260.754033
315000350688201004050.000.00.01.01607.0...0.2604660.1067270.0811460.0759710.048268-4.8646370.5054931.8703790.3660381.312775
41500041614281997070326.0142.00.00.07515.0...0.2509990.0000000.0778060.0286000.0817093.616475-0.673236-3.197685-0.025678-0.101290
4999519999520903199605034.044.00.00.011615.0...0.2846640.1300440.0498330.0288070.004616-5.9785111.303174-1.207191-1.981240-0.357695
49996199996708199910110.000.00.00.07515.0...0.2681010.1080950.0660390.0254680.025971-3.9138251.759524-2.075658-1.1548470.169073
4999719999766932004041249.010.01.01.022415.0...0.2694320.1057240.1176520.0574790.015669-4.6390650.6547131.137756-1.3905310.254420
49998199998969002002000827.010.00.01.033415.0...0.2611520.0004900.1373660.0862160.0513831.833504-2.8286872.465630-0.911682-2.057353
4999919999919338420041109166.061.0NaN1.0689.0...0.2287300.0003000.1035340.0806250.1242642.914571-1.1352700.5476282.094057-1.552150

10 rows × 30 columns

train.columns
Index(['SaleID', 'name', 'regDate', 'model', 'brand', 'bodyType', 'fuelType',
       'gearbox', 'power', 'kilometer', 'notRepairedDamage', 'regionCode',
       'seller', 'offerType', 'creatDate', 'price', 'v_0', 'v_1', 'v_2', 'v_3',
       'v_4', 'v_5', 'v_6', 'v_7', 'v_8', 'v_9', 'v_10', 'v_11', 'v_12',
       'v_13', 'v_14'],
      dtype='object')
test.columns
Index(['SaleID', 'name', 'regDate', 'model', 'brand', 'bodyType', 'fuelType',
       'gearbox', 'power', 'kilometer', 'notRepairedDamage', 'regionCode',
       'seller', 'offerType', 'creatDate', 'v_0', 'v_1', 'v_2', 'v_3', 'v_4',
       'v_5', 'v_6', 'v_7', 'v_8', 'v_9', 'v_10', 'v_11', 'v_12', 'v_13',
       'v_14'],
      dtype='object')

1.删除异常值
箱型图:是一种用作显示一组数据分散情况的统计图,参考https://m.sohu.com/a/220236877_434937
使用seaborn绘制箱型图,参考https://blog.csdn.net/LuohenYJ/article/details/90677918

# 包装一个异常值处理的函数,以备调用
# 通过箱线图分析删除异常值
def outliers_proc(data, col_name, scale=3):
    """
    用于清洗异常值,默认用box_plot(scale=3)清洗
    :param data:接收pandas格式数据
    :param col_name:pandas列名
    :param scale:尺度
    :return:
    """
    
    def box_plot_outliers(data_ser, box_scale):
        """
        利用箱线图去除异常值
        :param data_ser:接收pandas.Series数据
        :param box_scale:箱线图尺度
        :return:
        """
        # 计算四分位距并计算上下限
        iqr = box_scale * (data_ser.quantile(0.75) - data_ser.quantile(0.25))
        val_low = data_ser.quantile(0.25) - iqr
        val_up = data_ser.quantile(0.75) + iqr
        # 根据上下限值筛选数据
        rule_low = (data_ser < val_low)
        rule_up = (data_ser > val_up)
        return (rule_low, rule_up), (val_low, val_up)
    
    data_n = data.copy()
    data_series = data_n[col_name]
    rule, value = box_plot_outliers(data_series, box_scale=scale)
    index = np.arange(data_series.shape[0])[rule[0] | rule[1]]
    print("Delete number is:{}".format(len(index)))
    data_n = data_n.drop(index)
    data_n.reset_index(drop=True, inplace=True)
    print("Now column number is:{}".format(data_n.shape[0]))
    index_low = np.arange(data_series.shape[0])[rule[0]]
    outliers = data_series.iloc[index_low]
    print("Description of data less than the lower bound is:")
    print(pd.Series(outliers).describe())
    index_up = np.arange(data_series.shape[0])[rule[1]]
    outliers = data_series.iloc[index_up]
    print("Description of data more than the upper bound is:")
    print(pd.Series(outliers).describe())
    
    fig, ax = plt.subplots(1, 2, figsize=(10, 7))
    sns.boxplot(y=data[col_name], data=data, palette="Set1", ax=ax[0])
    sns.boxplot(y=data_n[col_name], data=data_n, palette="Set1", ax=ax[1])
    return data_n
# 通过上述函数可以进行某列异常数据的删除操作
# 删不删需要自行判断,但是test的数据不能删

train = outliers_proc(train, 'power', scale=3)
Delete number is:963
Now column number is:149037
Description of data less than the lower bound is:
count    0.0
mean     NaN
std      NaN
min      NaN
25%      NaN
50%      NaN
75%      NaN
max      NaN
Name: power, dtype: float64
Description of data more than the upper bound is:
count      963.000000
mean       846.836968
std       1929.418081
min        376.000000
25%        400.000000
50%        436.000000
75%        514.000000
max      19312.000000
Name: power, dtype: float64

2.特征构造

# 将训练集和测试集放在一起,方便构造特征
train['train'] = 1
test['train'] = 0
data = pd.concat([train, test], ignore_index=True, sort=False)
data.shape
(199037, 32)
data.head().append(data.tail())
SaleIDnameregDatemodelbrandbodyTypefuelTypegearboxpowerkilometer...v_6v_7v_8v_9v_10v_11v_12v_13v_14train
007362004040230.061.00.00.06012.5...0.1019880.1295490.0228160.097462-2.8818032.804097-2.4208210.7952920.9147621
1122622003030140.012.00.00.0015.0...0.1210040.1357310.0265970.020582-4.9004822.096338-1.030483-1.7226740.2455221
221487420040403115.0151.00.00.016312.5...0.1149120.1651470.0621730.027075-4.8467491.8035591.565330-0.832687-0.2299631
337186519960908109.0100.00.01.019315.0...0.1103000.1219640.0333950.000000-4.5095991.285940-0.501868-2.438353-0.4786991
4411108020120103110.051.00.00.0685.0...0.0732050.0918800.0788190.121534-1.8962400.9107830.9311102.8345181.9234821
19903219999520903199605034.044.00.00.011615.0...0.1300440.0498330.0288070.004616-5.9785111.303174-1.207191-1.981240-0.3576950
199033199996708199910110.000.00.00.07515.0...0.1080950.0660390.0254680.025971-3.9138251.759524-2.075658-1.1548470.1690730
19903419999766932004041249.010.01.01.022415.0...0.1057240.1176520.0574790.015669-4.6390650.6547131.137756-1.3905310.2544200
199035199998969002002000827.010.00.01.033415.0...0.0004900.1373660.0862160.0513831.833504-2.8286872.465630-0.911682-2.0573530
19903619999919338420041109166.061.0NaN1.0689.0...0.0003000.1035340.0806250.1242642.914571-1.1352700.5476282.094057-1.5521500

10 rows × 32 columns

# 使用时间:data['creatDate']和data['regData'],反映汽车使用时间,一般来说价格与使用时间成反比
# 注意:数据中存在时间出错的格式,需要errors=‘coerce’
data['used_time'] = (pd.to_datetime(data['creatDate'], format='%Y%m%d', errors='coerce') - 
                    pd.to_datetime(data['regDate'], format='%Y%m%d', errors='coerce')).dt.days
data.head().append(data.tail()).iloc[:, 8:18]
powerkilometernotRepairedDamageregionCodesellerofferTypecreatDatepricev_0v_1
06012.50.0104600201604041850.043.3577963.966344
1015.0-436600201603093600.045.3052735.236112
216312.50.0280600201604026222.045.9783594.823792
319315.00.043400201603122400.045.6874784.492574
4685.00.0697700201603135200.044.3835112.031433
19903211615.00.032190020160320NaN45.6213915.958453
1990337515.00.018570020160329NaN43.9351624.476841
19903422415.00.034520020160305NaN46.5371374.170806
19903533415.00.019980020160404NaN46.771359-3.296814
199036689.00.032760020160322NaN43.731010-3.121867
# 观察used_time的数据缺失
data['used_time'].isnull().sum()
15072

可以看到,有15k个数据缺失,可以选择删除,也可以选择放着
如果选择XGBoost之类的决策树,本身就可以处理缺失值,所以可以不用管

# 从邮编中提取城市信息,因为是德国的数据,所以参考德国的邮编,相当于加入了先验知识
data['city'] = data['regionCode'].apply(lambda x : str(x)[:-3])
data.head().append(data.tail())
SaleIDnameregDatemodelbrandbodyTypefuelTypegearboxpowerkilometer...v_8v_9v_10v_11v_12v_13v_14trainused_timecity
007362004040230.061.00.00.06012.5...0.0228160.097462-2.8818032.804097-2.4208210.7952920.91476214385.01
1122622003030140.012.00.00.0015.0...0.0265970.020582-4.9004822.096338-1.030483-1.7226740.24552214757.04
221487420040403115.0151.00.00.016312.5...0.0621730.027075-4.8467491.8035591.565330-0.832687-0.22996314382.02
337186519960908109.0100.00.01.019315.0...0.0333950.000000-4.5095991.285940-0.501868-2.438353-0.47869917125.0
4411108020120103110.051.00.00.0685.0...0.0788190.121534-1.8962400.9107830.9311102.8345181.92348211531.06
19903219999520903199605034.044.00.00.011615.0...0.0288070.004616-5.9785111.303174-1.207191-1.981240-0.35769507261.03
199033199996708199910110.000.00.00.07515.0...0.0254680.025971-3.9138251.759524-2.075658-1.1548470.16907306014.01
19903419999766932004041249.010.01.01.022415.0...0.0574790.015669-4.6390650.6547131.137756-1.3905310.25442004345.03
199035199998969002002000827.010.00.01.033415.0...0.0862160.0513831.833504-2.8286872.465630-0.911682-2.0573530NaN1
19903619999919338420041109166.061.0NaN1.0689.0...0.0806250.1242642.914571-1.1352700.5476282.094057-1.55215004151.03

10 rows × 34 columns

# 计算某品牌的销售量统计
# 要以训练集中的数据进行统计
train_gb = train.groupby("brand")
all_info = {}
for kind, kind_data in train_gb:
    info = {}
    kind_data = kind_data[kind_data['price'] > 0]
    info['brand_amout'] = len(kind_data)
    info['brand_price_max'] = kind_data.price.max()
    info['brand_price_median'] = kind_data.price.median()
    info['brand_price_min'] = kind_data.price.min()
    info['brand_price_sum'] = kind_data.price.sum()
    info['brand_price_std'] = kind_data.price.std()
    info['brand_price_average'] = round(kind_data.price.sum() / (len(kind_data) + 1), 2)
    all_info[kind] = info
brand_fe = pd.DataFrame(all_info).T.reset_index().rename(columns={"index":"brand"})
data = data.merge(brand_fe, how = 'left', on='brand')
data.shape
data.columns
Index(['SaleID', 'name', 'regDate', 'model', 'brand', 'bodyType', 'fuelType',
       'gearbox', 'power', 'kilometer', 'notRepairedDamage', 'regionCode',
       'seller', 'offerType', 'creatDate', 'price', 'v_0', 'v_1', 'v_2', 'v_3',
       'v_4', 'v_5', 'v_6', 'v_7', 'v_8', 'v_9', 'v_10', 'v_11', 'v_12',
       'v_13', 'v_14', 'train', 'used_time', 'city', 'brand_amout',
       'brand_price_average', 'brand_price_max', 'brand_price_median',
       'brand_price_min', 'brand_price_std', 'brand_price_sum'],
      dtype='object')
# 数据分桶,以power为例
# 数据分桶的目的:
# 1)离散后稀疏向量内机乘法运算速度更快,计算结果也方便存储,容易扩展
# 2)离散后的特征对异常值更具鲁棒性,如 age>30 为 1 否则为 0,对于年龄为 200 的也不会对模型造成很大影响
# 3)LR 属于广义线性模型,表达能力有限,经过离散化后,每个变量有单独的权重,这相当于引入了非线性,可以提升模型的性能
# 4)离散后特征可以进行特征交叉,提升表达能力
# 5)特征离散后模型更稳定,如用户年龄区间,不会因为用户年龄长了一岁就变化

bin = [i * 10 for i in range(31)]
data['power_bin'] = pd.cut(data['power'], bin, labels=False)
data[['power_bin', 'power']].head()
power_binpower
05.060
1NaN0
216.0163
319.0193
46.068
# 删除利用过的数据
data = data.drop(['creatDate', 'regDate', 'regionCode'], axis=1)
data = data.drop('SaleID', axis=1)
print(data.shape)
data.columns
(199037, 38)

Index(['name', 'model', 'brand', 'bodyType', 'fuelType', 'gearbox', 'power',
       'kilometer', 'notRepairedDamage', 'seller', 'offerType', 'price', 'v_0',
       'v_1', 'v_2', 'v_3', 'v_4', 'v_5', 'v_6', 'v_7', 'v_8', 'v_9', 'v_10',
       'v_11', 'v_12', 'v_13', 'v_14', 'train', 'used_time', 'city',
       'brand_amout', 'brand_price_average', 'brand_price_max',
       'brand_price_median', 'brand_price_min', 'brand_price_std',
       'brand_price_sum', 'power_bin'],
      dtype='object')
# 目前的数据已经可以给树模型使用了,将数据导出
data.to_csv('data_for_tree.csv', index=0)
# 可以再构造一份数据供LR NN之类的模型使用
# 不同模型对数据集的要求不同
# 观察数据分布
data['power'].plot.hist()
<matplotlib.axes._subplots.AxesSubplot at 0x5b70128>
# 我们刚刚对train进行了异常值处理,之所以还会出现这么异常的分布是因为test中还存在异常值
# 所以对train中的异常值不删为好,可以用长尾分布截断来代替
train['power'].plot.hist()
<matplotlib.axes._subplots.AxesSubplot at 0x9e93208>
# 我们对其取log,再作归一化处理
from sklearn import preprocessing
min_max_scaler = preprocessing.MinMaxScaler()
data['power'] = np.log(data['power'] + 1)
data['power'] = ((data['power']-np.min(data['power'])) / (np.max(data['power'])-np.min(data['power'])))
data['power'].plot.hist()
# kl的值比较正常,应该是已经做过分桶了
data['kilometer'].plot.hist()
# 直接对kl做归一化处理
data['kilometer'] = ((data['kilometer'] - np.min(data['kilometer'])) / (np.max(data['kilometer']) - np.min(data['kilometer'])))
data['kilometer'].plot.hist()
data.columns
Index(['name', 'model', 'brand', 'bodyType', 'fuelType', 'gearbox', 'power',
       'kilometer', 'notRepairedDamage', 'seller', 'offerType', 'price', 'v_0',
       'v_1', 'v_2', 'v_3', 'v_4', 'v_5', 'v_6', 'v_7', 'v_8', 'v_9', 'v_10',
       'v_11', 'v_12', 'v_13', 'v_14', 'train', 'used_time', 'city',
       'brand_amout', 'brand_price_average', 'brand_price_max',
       'brand_price_median', 'brand_price_min', 'brand_price_std',
       'brand_price_sum', 'power_bin'],
      dtype='object')
# 对前面已经构造的统计量特征做变换
def max_min(x):
    return (x - np.min(x)) / (np.max(x) - np.min(x))
data['brand_amout'] = ((data['brand_amout'] - np.min(data['brand_amout'])) / (np.max(data['brand_amout']) - np.min(data['brand_amout'])))
data['brand_price_average'] = ((data['brand_price_average'] - np.min(data['brand_price_average'])) / (np.max(data['brand_price_average']) - np.min(data['brand_price_average'])))
data['brand_price_max'] = ((data['brand_price_average']) - np.min(data['brand_price_average']) / (np.max(data['brand_price_average']) - np.min(data['brand_price_average'])))
data['brand_price_median'] = ((data['brand_price_median'] - np.min(data['brand_price_median'])) / (np.max(data['brand_price_median']) - np.min(data['brand_price_median'])))
data['brand_price_min'] = ((data['brand_price_min'] - np.min(data['brand_price_min'])) / (np.max(data['brand_price_min']) - np.min(data['brand_price_min'])))
data['brand_price_std'] = ((data['brand_price_std'] - np.min(data['brand_price_std'])) / (np.max(data['brand_price_std']) - np.min(data['brand_price_std'])))
data['brand_price_sum'] = ((data['brand_price_sum'] - np.min(data['brand_price_sum'])) / np.max(data['brand_price_sum']) - np.min(data['brand_price_sum']))
# 对类别特征进行OneEncode
data = pd.get_dummies(data, columns=['model', 'brand', 'bodyType', 'fuelType', 'gearbox', 'notRepairedDamage', 'power_bin'])
print(data.shape)
data.columns
(199037, 369)

Index(['name', 'power', 'kilometer', 'seller', 'offerType', 'price', 'v_0',
       'v_1', 'v_2', 'v_3',
       ...
       'power_bin_20.0', 'power_bin_21.0', 'power_bin_22.0', 'power_bin_23.0',
       'power_bin_24.0', 'power_bin_25.0', 'power_bin_26.0', 'power_bin_27.0',
       'power_bin_28.0', 'power_bin_29.0'],
      dtype='object', length=369)
# 这份数据可以给LR用
data.to_csv('data_for_lr.csv', index=0)

3.特征筛选
1)过滤式

# 相关性分析
print(data['power'].corr(data['price'], method='spearman'))
print(data['kilometer'].corr(data['price'], method='spearman'))
print(data['brand_amout'].corr(data['price'], method='spearman'))
print(data['brand_price_average'].corr(data['price'], method='spearman'))
print(data['brand_price_max'].corr(data['price'], method='spearman'))
print(data['brand_price_median'].corr(data['price'], method='spearman'))
0.5728285196051496
-0.4082569701616764
0.058156610025581514
0.3834909576057687
0.3834909576057687
0.38691042393409447
# 用热力图分析相关性
data_numeric = data[['power', 'kilometer', 'brand_amout', 'brand_price_average', 'brand_price_max', 'brand_price_median']]
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)
pip install mlxtend
from mlxtend.feature_selection import SequentialFeatureSelector as SFS
from sklearn.linear_model import LinearRegression
sfs = SFS(LinearRegression(), k_features=10, forward=True, floating=False, scoring='r2', cv=0)
x = data.drop(['price'], axis=1)
x = x.fillna(0)
y = data['price']
y = y.fillna(0)
sfs.fit(x, y)
sfs.k_feature_names_

3. 总结

特征工程是比赛中最至关重要的的一块,特别的传统的比赛,大家的模型可能都差不多,调参带来的效果增幅是非常有限的,但特征工程的好坏往往会决定了最终的排名和成绩。
特征工程的主要目的还是在于将数据转换为能更好地表示潜在问题的特征,从而提高机器学习的性能。比如,异常值处理是为了去除噪声,填补缺失值可以加入先验知识等。
特征构造也属于特征工程的一部分,其目的是为了增强数据的表达。
有些比赛的特征是匿名特征,这导致我们并不清楚特征相互直接的关联性,这时我们就只有单纯基于特征进行处理,比如装箱,groupby,agg 等这样一些操作进行一些特征统计,此外还可以对特征进行进一步的 log,exp 等变换,或者对多个特征进行四则运算(如上面我们算出的使用时长),多项式组合等然后进行筛选。由于特性的匿名性其实限制了很多对于特征的处理,当然有些时候用 NN 去提取一些特征也会达到意想不到的良好效果。
对于知道特征含义(非匿名)的特征工程,特别是在工业类型比赛中,会基于信号处理,频域提取,丰度,偏度等构建更为有实际意义的特征,这就是结合背景的特征构建,在推荐系统中也是这样的,各种类型点击率统计,各时段统计,加用户属性的统计等等,这样一种特征构建往往要深入分析背后的业务逻辑或者说物理原理,从而才能更好的找到 magic。
当然特征工程其实是和模型结合在一起的,这就是为什么要为 LR NN 做分桶和特征归一化的原因,而对于特征的处理效果和特征重要性等往往要通过模型来验证。
总的来说,特征工程是一个入门简单,但想精通非常难的一件事。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值