数据预处理(Data Preprocessing)基本框架

文章目录

  • 0 写在前面
  • 1 数据预处理概述
  • 2 数据清洗
    • 2.1 删除重复数据
    • 2.2 缺失值处理
    • 2.3 异常值和歧义值处理
    • 2.4 文本数据的清洗
  • 3 数据变换
    • 3.1 数据标准化
      • 3.1.1 标准正态分布标准化(均值为0,方差为1)
      • 3.1.2 标准化到某个区间
      • 3.1.3 sklearn.preprocessing实现数据标准化
        • 3.1.3.1 转化为标准正态分布
        • 3.1.3.2 转化到某个区间
        • 3.1.3.3 Scaler方法
        • 3.1.3.4 归一化
        • 3.1.3.5 非线性标准化
        • 3.1.3.6 实例
    • 3.2 分布不均和偏态分布处理
      • 3.2.1 探索
      • 3.2.2 处理
    • 3.3 特征编码
      • 3.3.1 特征类别转换
      • 3.3.2 特征编码
        • 3.3.2.1 手动编码(map)
        • 3.3.2.2 sklearn.preprocessing工具
        • 3.3.2.3 Dummy Variable:
        • 3.3.2.4 Tips
    • 3.4 连续变量离散化(分箱)
  • 5 数据集成
  • 6 数据重采样

0 写在前面

参考资料:

  1. 阿水总结的数据竞赛Tricks

1 数据预处理概述

在机器学习任务中,数据集的质量优劣对数据分析的结果影响非常大,所谓Garbage in, garbage out,数据决定模型的上限,因此数据质量成为数据分析流程不可或缺的一个环节。即使是像Kaggle那样主办方已经把数据集准备好的场景,也需要评估train set和test set的分布是否一致,存不存在偏斜等。如果两者不一致,可能会导致离线cv分数非常高,可是在leaderborad却下跌了很多,以至于大量花在模型调参上的功夫其实都白费了。

sklearn.preprocessing提供了许多很有用的函数帮助我们将原始特征向量转化为更适合训练的数据。
大部分情况下,在构造 Feature 之前,我们需要对比赛提供的数据集进行一些处理。通常的处理有:

  1. 处理 Missing Data。
  2. 处理 Outlier。
  3. 有些 Float 变量可能是从未知的 Int 变量转换得到的,这个过程中发生精度损失会在数据中产生不必要的 Noise,即两个数值原本是相同的却在小数点后某一位开始有不同。这对 Model 可能会产生很负面的影响,需要设法去除或者减弱 Noise。
  4. 连续数据标准化

数据清洗可以从以下几个角度完成:

  1. 对于类别变量,可以统计比较少的取值;
  2. 对于数字变量,可以统计特征的分布异常值;
  3. 统计字段的缺失比例;

2 数据清洗

2.1 删除重复数据

  1. .drop_duplicates(subset=,keep=)

subset:指出需要删除重复数据的列。
keep:保留重复的哪一个数据,last,first,False,false表示删除所有重复数据。

2.2 缺失值处理

每个变量都应该根据业务实际情况来处理

  1. 删除
# 删除变量
df_train = df_train.drop((missing_data[missing_data['Total'] > 1]).index,1)
# 删除样本
df_train = df_train.drop(df_train.loc[df_train['Electrical'].isnull()].index)
.dropna()
train_df=train_df[~train_df['order_detail_status'].isin([101])]# 删除101订单状态订单
  1. 填充
    .fillna()填充缺失值,如all_data = all_data.fillna(all_data.mean()),以下是常用的填充值
  • 根据业务实际情况填充。

  • 统计量:众数、中位数、均值

  • 插值法填充:包括随机插值,多重差补法,热平台插补,拉格朗日插值,牛顿插值等

  • 模型填充:使用回归、贝叶斯、随机森林、决策树等模型对缺失数据进行预测。

  • 定值填充

  • 其他:
    np.random.randint(age_avg - age_std, age_avg + age_std, size=age_null_count)
    int( 中位数/0.5 + 0.5 ) * 0.5

  • 还可以分组填充

  • 保留缺失值,用'None'填充

  • 偏正态分布,使用均值代替,可以保持数据的均值;偏长尾分布,使用中值代替,避免受 outlier 的影响

2.3 异常值和歧义值处理

# 标准化
saleprice_scaled = StandardScaler().fit_transform(df_train['SalePrice'][:,np.newaxis])
# 删除
talExposureLog = totalExposureLog.loc[(totalExposureLog.pctr<=1000)]

df_train = df_train.drop(df_train[df_train['Id'] == 1299].index)

2.4 文本数据的清洗

在比赛当中,如果数据包含文本,往往需要进行大量的数据清洗工作。如去除HTML 标签,分词,拼写纠正, 同义词替换,去除停词,抽词干,数字和单位格式统一等

3 数据变换

3.1 数据标准化

在有Outlier的情况下,稳健的(robust)scaler 或 transformers会表现得更好。那么我们该如何选择标准化方法呢?

3.1.1 标准正态分布标准化(均值为0,方差为1)

也叫做z-score标准化。z−score标准化对个别极端元素不敏感,且把所有元素分布在0的周围,一般情况下元素越多,0周围区间会分布大部分的元素,每当有新的元素进来,都要重新计算方差与均值。

x ′ = x − x ˉ σ x x'=\frac{x-\bar x}{\sigma_x} x=σxxxˉ

3.1.2 标准化到某个区间

  1. Min-max归一化

方法简单,而且保证规范化后所有元素都是正的,每当有新的元素进来,只有在该元素大于最大值或者小于最小值时才要重新计算全部元素。但是若存在一个极大(小)的元素,会导致其他元素变的非常小(大)。

在这里插入图片描述
若标准化到[0,1],则有以下代码

def scale_minmax(col):
    return (col-col.min())/(col.max()-col.min())
  1. 最大绝对值标准化
  2. 非线性标准化
    QuantileTransformerand quantile_transform
    PowerTransformer

3.1.3 sklearn.preprocessing实现数据标准化

3.1.3.1 转化为标准正态分布

  1. .StandardScaler(copy=True, with_mean=True, with_std=True) :该标准器本质上是保留了原数据的均值和标准差,并可以同样标准化作用于测试数据。
  2. .scale(X, axis=0, with_mean=True, with_std=True, copy=True)

3.1.3.2 转化到某个区间

  1. .MinMaxScaler(feature_range=(0, 1), copy=True)把数据转化到某个区间
  2. .MaxAbsScaler(copy=True),用法同MinMaxScaler,范围变成[-1,1]
  3. .minmax_scale(X, feature_range=(0, 1), axis=0, copy=True)
  4. .maxabs_scale(X, axis=0, copy=True)

3.1.3.3 Scaler方法

  1. .fit(X_train)
  2. .transform(X_test)
  3. .fit_transform(X_train)

3.1.3.4 归一化

  1. .normalize(X, norm=’l2’, axis=1, copy=True, return_norm=False)
  2. .Normalizer(norm=’l2’, copy=True)

3.1.3.5 非线性标准化

  1. .RobustScaler(with_centering=True, with_scaling=True, quantile_range=(25.0, 75.0), copy=True):使数据在面对异常值时robust。

3.1.3.6 实例

#standardizing data
saleprice_scaled = StandardScaler().fit_transform(df_train['SalePrice'][:,np.newaxis]);
low_range = saleprice_scaled[saleprice_scaled[:,0].argsort()][:10]
high_range= saleprice_scaled[saleprice_scaled[:,0].argsort()][-10:]
print('outer range (low) of the distribution:')
print(low_range)
print('\nouter range (high) of the distribution:')
print(high_range)

outer range (low) of the distribution:
[[-1.83820775]
[-1.83303414]
[-1.80044422]
[-1.78282123]
[-1.77400974]
[-1.62295562]
[-1.6166617 ]
[-1.58519209]
[-1.58519209]
[-1.57269236]]

outer range (high) of the distribution:
[[3.82758058]
[4.0395221 ]
[4.49473628]
[4.70872962]
[4.728631 ]
[5.06034585]
[5.42191907]
[5.58987866]
[7.10041987]
[7.22629831]]

3.2 分布不均和偏态分布处理

3.2.1 探索

训练集与验证集的分布不一致会带来许多问题。

df_train['SalePrice'].describe():描述信息
df_train['SalePrice'].value_counts:频数

# 直方图和分布函数曲线
sns.distplot(df_train['SalePrice'], fit=norm)

数据预处理(Data Preprocessing)基本框架_第1张图片

# 显示偏度和峰度
print("Skewness: %f" % df_train['SalePrice'].skew())
print("Kurtosis: %f" % df_train['SalePrice'].kurt())
# 或调用scipy.stat库中的函数
from scipy.stats import kurt, skew
skew(df_train)
kurt(df_train)
# 概率图?
res = stats.probplot(df_train['SalePrice'], plot=plt)

数据预处理(Data Preprocessing)基本框架_第2张图片

3.2.2 处理

# log处理
df_train['SalePrice'] = np.log(df_train['SalePrice'])
# 若该变量存在大量值为0的样本,可分类处理或者使用log1p,处理完之后若要还原要使用expm1
df_train.loc[df_train['TotalBsmtSF']>0,'TotalBsmtSF'] = np.log(df_train['TotalBsmtSF'])
train["SalePrice"] = np.log1p(train["SalePrice"])
# log1p转换偏度过高的变量
numeric_feats = all_data.dtypes[all_data.dtypes != "object"].index

skewed_feats = train[numeric_feats].apply(lambda x: skew(x.dropna())) #compute skewness
skewed_feats = skewed_feats[skewed_feats > 0.75]
skewed_feats = skewed_feats.index

all_data[skewed_feats] = np.log1p(all_data[skewed_feats])
# 一般情况下,可以对连续变量进行Box-Cox变换。
# 通过变换可以使得模型更好的优化,通常也会带来效果上的提升。
skewness = skewness[abs(skewness) > 0.75]
print("There are {} skewed numerical features to Box Cox transform".format(skewness.shape[0]))

from scipy.special import boxcox1p
skewed_features = skewness.index
lam = 0.15
for feat in skewed_features:
    #all_data[feat] += 1
    all_data[feat] = boxcox1p(all_data[feat], lam)
    
#all_data[skewed_features] = np.log1p(all_data[skewed_features])

3.3 特征编码

  1. 对于类别特征来说,有如下处理方式:
  • 自然数编码(Label Encoding)
  • 独热编码(Onehot Encoding)
  • 哈希编码(Hash Encoding)
  • 统计编码(Count Encoding)
  • 目标编码(Target Encoding)
  • 嵌入编码(Embedding Encoding)
  • 缺失值编码(NaN Encoding)
  • 多项式编码(Polynomial Encoding)
  • 布尔编码(Bool Encoding)
  1. 对于数值特征来说,有如下处理方式:
  • 取整(Rounding)
  • 分箱(Binning)
  • 放缩(Scaling)

3.3.1 特征类别转换

3.3.2 特征编码

3.3.2.1 手动编码(map)

  1. 例如:title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}dataset['Title'].map(title_mapping)
  2. 简化类别

3.3.2.2 sklearn.preprocessing工具

  1. .OneHotEncoder(n_values=None, categorical_features=None, categories=None, drop=None, sparse=True, dtype=, handle_unknown=’error’):热编码,若有n个类,则生成n个特征,其中一个是1其余是0.

sparse:默认为True表示用稀疏矩阵表示,一般使用.toarray()转换到False,即数组。

  1. .OrdinalEncoder(categories=’auto’, dtype=):序数编码,0到 n c a t e g o r i e s − 1 n_{categories}-1 ncategories1
  2. .LabelEncoder():和OrdinalEncoder类似。
# 示例代码
LabelEncoder().fit_transform(data[feature].astype(np.str)

3.3.2.3 Dummy Variable:

  1. pd.get_dummies

3.3.2.4 Tips

  1. 对于频数较少的那些分类变量可以归类到‘其他’pandas.DataFrame.replace后再进行编码。
  2. 对于字符型的特征,要在编码后转换数据类型pandas.DataFrame.astype

3.4 连续变量离散化(分箱)

  1. 连续特征离散化pandas.cut,然后通过pandas.Series.value_counts观察切分点,再将对应bins或者说区间的连续值通过pandas.DataFrame.replacepandas.DataFrame.loc到离散点0,1,2,…后再进行编码。

一般切分点的选择可以用IV指标来评估,若把改变量离散成n个块,则 I V = ∑ i = 1 n ( a i − b i ) ∗ l n ( a i b i ) IV=\sum_{i=1}^n(a_i-b_i)*ln(\frac{a_i}{b_i}) IV=i=1n(aibi)ln(biai),其中 a i a_i ai为该块中正样本占总正样本的比例, b i b_i bi为该块中负样本占总负样本的比例。

IV 划分效果
<0.03 无预测能力
0.03~0.09
0.1~0.29
0.3~0.49
>=0.5 极高
  1. preprocessing.KBinsDiscretizer
  2. preprocessing.Binarizer

5 数据集成

多表数据整合

6 数据重采样

数据预处理(Data Preprocessing)基本框架_第3张图片

数据预处理(Data Preprocessing)基本框架_第4张图片

你可能感兴趣的:(机器学习和数据挖掘)