机器学习-3.0特征工程

本文详细介绍了数据预处理的多个步骤,包括缺失值填充、异常值处理(3σ原则和箱型图)、数据分箱(等距、等频、卡方分箱)以及特征交互和编码。此外,还探讨了特征归一化的方法,如StandardScaler、MinMaxScaler、MaxAbsScaler和Normalizer,并展示了PCA降维的应用。最后,提供了Python和Spark MLlib的代码示例,帮助读者理解和实践这些技术。
摘要由CSDN通过智能技术生成

目录

1 数据预处理

1.1 缺失值的填充

1.2 时间格式处理

2 异常值处理

2.1 基于3segama原则

2.2 基于箱型图

3 数据分箱

3.1 等距分箱

3.2 等频分箱

3.2.1 离散数值型数据分箱

3.2.2 连续数值型数据分箱

3.3 卡方分箱

4 特征交互

4.1 特征和特征之间组合

4.2 特征和特征之间衍生

4.3 其他特征衍生的尝试

5 特征编码

5.1 one-hot-encode编码

5.2 label-encode编码

6 特征归一化

6.1 StandardScaler(标准化,操作列)

6.2 MinMaxScaler(区间缩放法,操作列)

6.3 MaxAbsScaler(绝对值最大标准化,操作列)

6.4 Normalizer(正则化,操作行)

7 降维PCA

8 演示代码


1 数据预处理

1.1 缺失值的填充

包括均值/中位数/众数/建模预测/多重插补/压缩感知补全/矩阵补全等;

#分组均值补充
age_group_mean = combined.groupby(['Sex', 'Pclass', 'Title'])['Age'].mean().reset_index()
#使用平均值填充。
combined['Fare'].fillna(combined['Fare'].mean(), inplace=True)
#Embarked:只有两个缺失值,使用众数填充。
combined['Embarked'].fillna(combined['Embarked'].mode(), inplace=True)

1.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

2 异常值处理

2.1 基于3segama原则

基本上可以把区间(μ-3σ,μ+3σ)看作是随机变量X实际可能的取值区间,这称之为正态分布的“3σ”原则。
在这里插入图片描述

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

 得到特征的异常值后可以进一步分析变量异常值和目标变量的关系

for fea in numerical_fea:
    data_train = find_outliers_by_3segama(data_train,fea)
    print(data_train[fea+'_outliers'].value_counts())
    print(data_train.groupby(fea+'_outliers')['isDefault'].sum())
    print('*'*10)

2.2 基于箱型图

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

3 数据分箱

数据分箱是用于减少次要观察误差的影响,是一种将多个连续值分组为较少数量的“分箱”的方法。

  • 特征分箱的目的:
    • 从模型效果上来看,特征分箱主要是为了降低变量的复杂性,减少变量噪音对模型的影响,提高自变量和因变量的相关度。从而使模型更加稳定。
  • 数据分桶的对象:
    • 将连续变量离散化
    • 将多状态的离散变量合并成少状态
  • 分箱的原因:
    • 数据的特征内的值跨度可能比较大,对有监督和无监督中如k-均值聚类它使用欧氏距离作为相似度函数来测量数据点之间的相似度。都会造成大吃小的影响,其中一种解决方法是对计数值进行区间量化即数据分桶也叫做数据分箱,然后使用量化后的结果。
  • 分箱的优点:

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

    • (1)等距分箱:无监督
    • (2)等频分箱:无监督
    • (3)卡方分箱:有监督

3.1 等距分箱

从最小值到最大值之间,均分为 N 等份, 这样, 如果 A,B 为最小最大值, 则每个区间的长度为 W=(B−A)/N , 则区间边界值为A+W,A+2W,….A+(N−1)W 。这里只考虑边界,每个等份里面的实例数量可能不等

""" 
通过除法映射到间隔均匀的分箱中,每个分箱的取值范围都是loanAmnt/1000
"""
data['loanAmnt_bin1'] = np.floor_divide(data['loanAmnt'], 1000)

"""
通过对数函数映射到指数宽度分箱
"""
data['loanAmnt_bin2'] = np.floor(np.log10(data['loanAmnt']))

3.2 等频分箱

区间的边界值要经过选择,使得每个区间包含大致相等的实例数量。比如说 N=10 ,每个区间应该包含大约10%的实例。

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

3.2.1 离散数值型数据分箱

3.2.2 连续数值型数据分箱

3.3 卡方分箱

卡方检验就是对分类数据的频数进行分析的一种方法,它的应用主要表现在两个方面:拟合优度检验和独立性检验

"""
# 当然还有很多原因,LightGBM 在改进 XGBoost 时就增加了数据分桶,增强了模型的泛化性
"""
bin = [i*10 for i in range(31)]
data['power_bin'] = pd.cut(data['power'], bin, labels=False)
data[['power_bin', 'power']].head()

4 特征交互

交互特征的构造非常简单,使用起来却代价不菲。如果线性模型中包含有交互特征对,那它的训练时间和评分时间就会从 O(n) 增加到 O(n2),其中 n 是单一特征的数量。

4.1 特征和特征之间组合

特征组合:是指通过将两个或多个输入特征相乘来对特征空间中的非线性规律进行编码的合成特征。
“cross”(组合)这一术语来自 cross product(向量积)。我们通过将 x1(横坐标)与 x2(纵坐标) 组合来创建一个名为 x3 的特征组合
特征组合的种类
[A X B]:将两个特征的值相乘形成的特征组合。
[A x B x C x D x E]:将五个特征的值相乘形成的特征组合。
[A x A]:对单个特征的值求平方形成的特征组合

4.2 特征和特征之间衍生

基于一个特征,使用特征值打平(扩展)的方式衍生多个标注类型的特征,也可以理解为离散化。

对于分类变量,直接one-hot编码;

对于数值型特征,离散化到几个固定的区间段,然后用one-hot编码。

4.3 其他特征衍生的尝试

5 特征编码

假如有三种颜色特征:红、黄、蓝。 在利用机器学习的算法时一般需要进行向量化或者数字化。那么你可能想令 红=1,黄=2,蓝=3. 那么这样其实实现了标签编码,即给不同类别以标签。然而这意味着机器可能会学习到“红<黄<蓝”,但这并不是我们的让机器学习的本意,只是想让机器区分它们,并无大小比较之意。所以这时标签编码是不够的,需要进一步转换。因为有三种颜色状态,所以就有3个比特。即红色:1 0 0 ,黄色: 0 1 0,蓝色:0 0 1 。如此一来每两个向量之间的距离都是根号2,在向量空间距离都相等,所以这样不会出现偏序性,基本不会影响基于向量空间度量算法的效果。

5.1 one-hot-encode编码

使用one-hot编码,将离散特征的取值扩展到了欧式空间,离散特征的某个取值就对应欧式空间的某个点。将离散型特征使用one-hot编码,会让特征之间的距离计算更加合理。离散特征进行one-hot编码后,编码后的特征,其实每一维度的特征都可以看做是连续的特征。就可以跟对连续型特征的归一化方法一样,对每一维特征进行归一化

5.2 label-encode编码

利用LabelEncoder() 将转换成连续的数值型变量。即对不连续的数字或者文本进行编号

5.3 count-encode编码

5.4 target-encoder编码

5.5 catboost-encoder编码

6 特征归一化

特征归一化,又叫 特征缩放,各特征由于数值大小范围不一致,通过缩放特征的取值范围,可以消除量纲,使特征具有可比性。只有各特征之间的大小范围一致,才能使用距离度量等算法
详情:培训_Dataguru炼数成金_国内首创逆向收费式网络培训|专注于Hadoop培训及大数据、数据分析、数据库、编程技术、运维自动化等网络逆向培训

6.1 StandardScaler(标准化,操作列)

StandardScaler方法是将原始数据集归一化为均值为0、方差1的数据集,归一化公式如下:

其中,μ、σ分别为原始数据集的均值和方法。该种归一化方式要求原始数据的分布可以近似为高斯分布,否则归一化的效果会变得很糟糕。

6.2 MinMaxScaler(区间缩放法,操作列)

MinMaxScaler方法是将原始数据转换到[0 1]的范围,归一化公式如下:

该方法实现对原始数据的等比例缩放,其中Xnorm为归一化后的数据,X为原始数据,Xmax、Xmin分别为原始数据集的最大值和最小值。

6.3 MaxAbsScaler(绝对值最大标准化,操作列)

与上述标准化方法相似,但是它通过除以最大值将训练集缩放至[-1,1]

6.4 Normalizer(正则化,操作行)

就是将一条记录中各个特征取值范围固定到【0,1】之间。从而使每一个特征值都在一个范围内。不至于各个特征值之间相差较大的范围。

7 降维PCA

#PCA处理去除多重共线形问题
from sklearn.decomposition import PCA
#保持16维度信息数据
pca=PCA(n_components=16)
#训练集
new_train_pca_16=pca.fit_transform(train_data_scaler.iloc[:,0:-1])
new_train_pca_16=pd.DataFrame(new_train_pca_16)
new_train_pca_16['target']=train_data_scaler['target']
new_train_pca_16.describe()
#测试集
new_test_pca_16=pca.transform(test_data_scaler)
new_test_pca_16=pd.DataFrame(new_test_pca_16)
new_test_pca_16.describe()

8 演示代码

"""
数据准备
"""
import org.apache.spark.ml.linalg.Vectors

val dataFrame = spark.createDataFrame(Seq(
  (0, Vectors.dense(1.0, 0.5, -1.0)),
  (1, Vectors.dense(2.0, 1.0, 1.0)),
  (2, Vectors.dense(4.0, 10.0, 2.0))
)).toDF("id", "features")

dataFrame.show

// 原始数据
+---+--------------+
| id|      features|
+---+--------------+
|  0|[1.0,0.5,-1.0]|
|  1| [2.0,1.0,1.0]|
|  2|[4.0,10.0,2.0]|
+---+--------------+

"""
StandardScaler(标准化,操作列)
"""
import org.apache.spark.ml.feature.StandardScaler

val scaler = new StandardScaler()
  .setInputCol("features")
  .setOutputCol("scaledFeatures")
  .setWithStd(true)
  .setWithMean(false)

// Compute summary statistics by fitting the StandardScaler.
val scalerModel = scaler.fit(dataFrame)

// Normalize each feature to have unit standard deviation.
val scaledData = scalerModel.transform(dataFrame)
scaledData.show

// 将每一列的标准差缩放到1。
+---+--------------+------------------------------------------------------------+
|id |features      |scaledFeatures                                              |
+---+--------------+------------------------------------------------------------+
|0  |[1.0,0.5,-1.0]|[0.6546536707079772,0.09352195295828244,-0.6546536707079771]|
|1  |[2.0,1.0,1.0] |[1.3093073414159544,0.1870439059165649,0.6546536707079771]  |
|2  |[4.0,10.0,2.0]|[2.618614682831909,1.870439059165649,1.3093073414159542]    |

"""
MinMaxScaler(区间缩放法,操作列)
"""
#将每一维特征线性地映射到指定的区间,通常是[0, 1]。
import org.apache.spark.ml.feature.MinMaxScaler

val scaler = new MinMaxScaler()
  .setInputCol("features")
  .setOutputCol("scaledFeatures")

// Compute summary statistics and generate MinMaxScalerModel
val scalerModel = scaler.fit(dataFrame)

// rescale each feature to range [min, max].
val scaledData = scalerModel.transform(dataFrame)
println(s"Features scaled to range: [${scaler.getMin}, ${scaler.getMax}]")
scaledData.select("features", "scaledFeatures").show

// 每维特征线性地映射,最小值映射到0,最大值映射到1。
+--------------+-----------------------------------------------------------+
|features      |scaledFeatures                                             |
+--------------+-----------------------------------------------------------+
|[1.0,0.5,-1.0]|[0.0,0.0,0.0]                                              |
|[2.0,1.0,1.0] |[0.3333333333333333,0.05263157894736842,0.6666666666666666]|
|[4.0,10.0,2.0]|[1.0,1.0,1.0]                                              |
+--------------+-----------------------------------------------------------+

"""
MaxAbsScaler(绝对值最大标准化,操作列)
"""
#MaxAbsScaler将每一维的特征变换到[-1, 1]闭区间上,通过除以每一维特征上的最大的绝对值,它不会平移整#个分布,也不会破坏原来每一个特征向量的稀疏性。
import org.apache.spark.ml.feature.MaxAbsScaler

val scaler = new MaxAbsScaler()
  .setInputCol("features")
  .setOutputCol("scaledFeatures")

// Compute summary statistics and generate MaxAbsScalerModel
val scalerModel = scaler.fit(dataFrame)

// rescale each feature to range [-1, 1]
val scaledData = scalerModel.transform(dataFrame)
scaledData.select("features", "scaledFeatures").show()

// 每一维的绝对值的最大值为[4, 10, 2]
+--------------+----------------+                                               
|      features|  scaledFeatures|
+--------------+----------------+
|[1.0,0.5,-1.0]|[0.25,0.05,-0.5]|
| [2.0,1.0,1.0]|   [0.5,0.1,0.5]|
|[4.0,10.0,2.0]|   [1.0,1.0,1.0]|
+--------------+----------------+


"""
Normalizer(正则化,操作行)
"""
import org.apache.spark.ml.feature.Normalizer

#正则化每个向量到1阶范数
val normalizer = new Normalizer()
  .setInputCol("features")
  .setOutputCol("normFeatures")
  .setP(1.0)

##val l1NormData = normalizer.transform(dataFrame)
#println("Normalized using L^1 norm")
#l1NormData.show()

#将每一行的规整为1阶范数为1的向量,1阶范数即所有值绝对值之和。
+---+--------------+------------------+
| id|      features|      normFeatures|
+---+--------------+------------------+
|  0|[1.0,0.5,-1.0]|    [0.4,0.2,-0.4]|
|  1| [2.0,1.0,1.0]|   [0.5,0.25,0.25]|
|  2|[4.0,10.0,2.0]|[0.25,0.625,0.125]|
+---+--------------+------------------+

#正则化每个向量到无穷阶范数
#val lInfNormData = normalizer.transform(dataFrame, normalizer.p -> Double.PositiveInfinity)
println("Normalized using L^inf norm")
lInfNormData.show()

#向量的无穷阶范数即向量中所有值中的最大值
+---+--------------+--------------+
| id|      features|  normFeatures|
+---+--------------+--------------+
|  0|[1.0,0.5,-1.0]|[1.0,0.5,-1.0]|
|  1| [2.0,1.0,1.0]| [1.0,0.5,0.5]|
|  2|[4.0,10.0,2.0]| [0.4,1.0,0.2]|
+---+--------------+--------------+

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值