处理数值型特征

多种原始数值型数据转换为机器学习算法所需特征的方法。

1. 特征的缩放

用sklearn的MinMaxScaler来缩放一个特征数组,将一个数值型特征的值缩放到两个特定的值之间。

import numpy as np
from sklearn import preprocessing

#创建特征
feature = np.array([[-500.5],
                   [-100.1],
                   [0],
                   [100.1],
                   [900.9]])

#创建缩放器
minmax_scale = preprocessing.MinMaxScaler(feature_range=(0,1))
#缩放特征的值
scaled_feature = minmax_scale.fit_transform(feature)
#查看特征
scaled_feature

—>

array([[0.        ],
       [0.28571429],
       [0.35714286],
       [0.42857143],
       [1.        ]])

2. 特征的标准化

对一个特征进行转换,使其平均值为0,标准差为1.

import numpy as np
from sklearn import preprocessing

#创建特征
x = np.array([[-1000.1],
                   [-200.2],
                   [500.5],
                   [600.6],
                   [9000.9]])

#创建缩放器
scaler = preprocessing.StandardScaler()
#转换特征
standardized = scaler.fit_transform(x)
#查看特征
standardized

—>

array([[-0.76058269],
       [-0.54177196],
       [-0.35009716],
       [-0.32271504],
       [ 1.97516685]])

3. 归一化观察值

对观察值的每一个特征进行缩放,使其拥有一致的范数。

使用normalizer并指定norm参数:

import numpy as np
from sklearn.preprocessing import Normalizer
#创建特征
features = np.array([[0.5,0.5],
              [1.1,3.4],
              [1.5,20.2],
              [1.63,34.4],
              [10.9,3.3]])

#创建归一化器
normalizer = Normalizer(norm= "l2")
#转换特征特征
normalizer.transform(features)

—>

array([[0.70710678, 0.70710678],
       [0.30782029, 0.95144452],
       [0.07405353, 0.99725427],
       [0.04733062, 0.99887928],
       [0.95709822, 0.28976368]])

Normalizer提供三个范数选项,默认值是欧式范数(Euclidean norm,L2范数):

∣ ∣ x ∣ ∣ 2 = x 1 2 + ⋅ ⋅ ⋅ + x n 2 ||x||_2 = \sqrt {x_1^2+···+x_n^2} x2=x12++xn2
或者可以指定使用曼哈顿范数(L1范数):
∣ ∣ x ∣ ∣ 1 = ∑ i = 1 n ∣ x i ∣ ||x||_1 = \sum _{i=1}^n |x_i| x1=i=1nxi

4. 生成多项式和交互特征

scikit-learn内置方法创建多项式特征和交互特征:

import numpy as np
from sklearn.preprocessing import PolynomialFeatures

#创建特征矩阵
features = np.array([[2,3],
                     [2,3],
                     [2,3]])
#创建PolynomialFeatures对象
polynomial_interaction = PolynomialFeatures(degree=2,include_bias=False)
#创建多项式特征
polynomial_interaction.fit_transform(features)

—>

array([[2., 3., 4., 6., 9.],
       [2., 3., 4., 6., 9.],
       [2., 3., 4., 6., 9.]])

默认情况下PolynomialFeatures包含交互特征 x 1 x 2 x_1x_2 x1x2

通过设置interaction_only为True,可以强制创建出来的特征只包含交互特征。

用这种方法来产生更高阶的形式——以此表示对目标值造成的非线性影响。

5. 转换特征

在sklearn中,使用FunctionTransformer对一组特征应用在一个函数上,对一个或多个特征进行自定义转换。

import numpy as np
from sklearn.preprocessing import FunctionTransformer
#创建特征矩阵
features = np.array([[2,3],
                     [2,3],
                     [2,3]])
#定义一个简单的函数
def add_ten(x):
  return x+10
#创建转换器
ten_transformer = FunctionTransformer(add_ten)
#转换特征矩阵
ten_transformer.transform(features)

—>

array([[12, 13],
       [12, 13],
       [12, 13]])

在pandas中可以使用apply进行同样的转换

6. 识别异常值

识别样本中的一些异常值

常用的方法是假设数据是正态分布的,基于这个假设,在数据周围“画”一个椭圆,将所有处于椭圆内的观察值视为正常值(标注为1),将所有处于椭圆外的观察值视为异常值(标注为-1)。

import numpy as np
from sklearn.covariance import EllipticEnvelope
from sklearn.datasets import make_blobs
#创建模拟数据
features,_ = make_blobs(n_samples = 10,
                        n_features = 2,
                        centers = 1,
                        random_state = 1)
#将第一个观察值的值替换为极端值
features[0,0] = 10000
features[0,1] = 10000
#创建识别器
outlier_detector = EllipticEnvelope(contamination=0.1)
#拟合识别器
outlier_detector.fit(features)
#预测异常值
outlier_detector.predict(features)

—>

array([-1,  1,  1,  1,  1,  1,  1,  1,  1,  1])

这个方法的一个主要限制是需要制定一个contamination(污染指数)参数,表示异常值在观察值中的比例。

除了查看所有观察值,还可以只查看某些特征,并使用四分位差(interqutile range,IQR)来识别这些特征的异常值。

IQR是数据集的第1个四分位数和第3个四分位数之差。可以将IQR视为数据集中大部分数据的延展距离,而异常值会远远地偏离数据较为集中的区域。异常值常常被定义为比第一个四分位数小1.5IQR的值,或比第3个四分位数大1.5IQR的值。

7. 处理异常值

解决方案:

  • 舍弃异常值
  • 标记异常值,作为数据特征
  • 对有异常值的特征进行转换,降低异常值的影响
import pandas as pd 
#创建数据
houses = pd.DataFrame()
houses['Price'] = [555555,455445,433434,233223]
houses['Bathrooms'] = [2,3,4,999]
houses['Square_Feet'] = [1500,2500,1500,48000]
#筛选出观察值
houses[houses['Bathrooms'] < 20]

—>

    Price	Bathrooms	Square_Feet
0	555555	2	        1500
1	455445	3	        2500
2	433434	4	        1500

第二种方法,标记为异常值作为特征:

import numpy as np
#基于布尔条件语句来创建特征
houses["outlier"] = np.where(houses["Bathrooms"]<20,0,1)
houses

—>

    Price	Bathrooms	Square_Feet	outlier
0	555555	2	        1500	    0
1	455445	3	        2500	    0
2	433434	4	        1500	    0
3	233223	999	        48000	 1

第三种方法,对有异常值的特征进行转换,降低异常值的影响:

#将特征取对数值
houses["Log of Square Feet"] = [np.log(x) for x in houses["Square_Feet"]]
houses

—>

    Price	Bathrooms	Square_Feet	outlier	Log of Square Feet
0	555555	2	        1500	    0	  7.313220
1	455445	3	        2500	    0	  7.824046
2	433434	4	        1500	    0	  7.313220
3	233223	999	        48000	    1	 10.778956

和识别异常值一样,处理异常值时也不存在一个绝对准则。应该基于两个方面来考虑对异常值的处理。

  • 是什么让他们成为异常值
  • 基于机器学习的目标来处理异常值。

所以,对于异常值到底如何处理,首先思考一下为什么是异常值,然后对于数据要有一个最终的目标。最重要的是,要记住“决定不处理异常值”本身就是一个有潜在影响的决定。

另外,如果数据中有异常值,那么采用标准化方法做缩放就不太合适了,因为平均值和方差受异常值的影响很大。在这种情况下,需要针对异常值使用一个鲁棒性更高的缩放方法,比如RobustScaler。

8. 将特征离散化

将一个数值型特征离散化,分到多个离散的小区间中。

根据数据离散化的方式,有两种方法可以使用。

  • 1.根据阈值将特征二值化
import numpy as np
from sklearn.preprocessing import Binarizer
#创建特征
age = np.array([[6],
                [12],
                [20],
                [36],
                [65]])
#创建二值化器
binarizer = Binarizer(18)
#转换特征
binarizer.fit_transform(age)

—>

array([[0],
       [0],
       [1],
       [1],
       [1]])
  • 2.根据多个阈值将数值型特征离散化
np.digitize(age,bins=[20,30,64])

—>

array([[0],
       [0],
       [1],
       [2],
       [3]])

bins参数中的每个数字表示的是每个区间的左边界(左闭右开)。可以设置right参数为True来改变这个行为。

如果有足够多的理由认为某个数值型特征应该被视为一个分类特征(categorical feature),那么离散化会是一个卓有成效的策略。

9. 使用聚类的方式将观察值分组

问题描述:对观察值进行聚类操作,使相似的观察值被分为一组。

解决方案:如果有k个分组,可以使用K-means(K均值)聚类法将相似的观察值分到一个组,并输出一个新的特征,以标识观察值属于哪一组:

import pandas as pd
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
#创建模拟的特征矩阵
features,_=make_blobs(n_samples = 50,
                      n_features = 2,
                      centers = 3,
                      random_state = 1)
#创建数据帧
dataframe = pd.DataFrame(features,columns = ["feature_1","feature_2"])
#创建K-means聚类器
clusterer = KMeans(3,random_state = 0)
#将聚类器应用在特征上
clusterer.fit(features)
#预测聚类的值
dataframe["group"] = clusterer.predict(features)
dataframe.head(5)

—>

    feature_1	feature_2	group
0	-9.877554	-3.336145	2
1	-7.287210	-8.353986	0
2	-6.943061	-7.023744	0
3	-7.440167	-8.791959	0
4	-6.641388	-8.075888	0

10. 删除带有缺失值的观察值

import numpy as np
features = np.array([[1.1,11.1],
                     [2.2,22.2],
                     [3.3,33.3],
                     [4.4,44.4],
                     [np.nan,55]])
#只保留没有缺失值的观察值
features[~np.isnan(features).any(axis=1)]

—>

array([[ 1.1, 11.1],
       [ 2.2, 22.2],
       [ 3.3, 33.3],
       [ 4.4, 44.4]])

或者,使用pandas丢弃有缺失值的观察值:

import pandas as pd
dataframe = pd.DataFrame(features,columns=["feature_1","feature_2"])
#删除带有缺失值的观察值
dataframe.dropna()

—>

    feature_1	feature_2
0	1.1	        11.1
1	2.2	        22.2
2	3.3	        33.3
3	4.4	        44.4

值得注意,删除缺失值可能会在数据中引入偏差,这主要由缺失值的成因决定。缺失值一共有三种类型:

  • 完全随机确实(MCAR)
  • 随机确实(MAR)
  • 完全非随机确实(MNAR)

如果观察值是MCAR或者MAR,有时候删除是可以接受的。但是如果是MNAR,那么数据确实本身其实就是一个信息。删除MNAR观察值会导致数据产生偏差,因为这些观察值是由未观察到的系统效应产生的。

11. 填充缺失值

如果数据量不大,可以使用KNN算法来预测缺失值:

import numpy as np
from fancyimpute import KNN
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
#创建模拟的特征矩阵
features,_=make_blobs(n_samples = 1000,
                      n_features = 2,
                      random_state = 1)
#标准化特征
scaler = StandardScaler()
standardized_features = scaler.fit_transform(features)
#将第一个特征向量的第一个值替换为缺失值
true_value = standardized_features[0,0]
standardized_features[0,0] = np.nan
#预测特征矩阵中的缺失值
features_knn_imputed = KNN(k=5,verbose=0).fit_transform(standardized_features)
#对比真实值和填充值
print("True Value:",true_value)
print("Imputed Value:",features_knn_imputed)

—>

True Value: 0.8730186113995938
Imputed Value: [[ 1.09553327  1.31426523]

还可以使用sklearn的Imputer模块,用特征的平均值、中位数或者众数来填充缺失值,不过效果通常会比使用KNN的差。

比较容易扩展到大数据集的替代方案是用平均值来填充缺失值。

猜你喜欢

转载自blog.csdn.net/weixin_44127327/article/details/108763795