特征工程

本文介绍了机器学习特征工程中的多种处理方法,包括标准化、归一化、正则化、二值化、标签二值化、多标签二值化、哑编码和缺省值填充。这些方法可对特征进行无量纲化、缩放、二值处理等,能加快模型求解速度,提升模型效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

  1. 标准化
  2. 归一化
  3. 正则化
  4. 二值化
  5. 标签二值化
  6. 多标签二值化
  7. 哑编码
  8. 缺省值填充
    掉包方法:
处理方法sklearn掉包备注
标准化from sklearn.preprocessing import StandardScaler
归一化from sklearn.preprocessing import MinMaxScaler
正则化from sklearn.preprocessing import Normalizer
二值化from sklearn.preprocessing import Binarizer
标签二值化from sklearn.preprocessing import LabelBinarizer
哑编码from sklearn.preprocessing import OneHotEncoder只能处理数据类型
哑编码2from sklearn.preprocessing import LabelEncoder处理带字符的哑编码,需配合OneHot使用
缺省值填充from sklearn.preprocessing import Imputer

标准化、归一化是对X的特征进行处理,标准化、归一化又叫做无量纲化, 一般用于将多个特征属性之间的取值范围转换为同一个取值范围,可以加快模型的求解速度,也可以让模型效果更加稳定、效果更好。正则化是对每条样本的特征进行缩放,按照L1范数、L2范数、LP范数来进行

1、标准化

x = (x-u)/sigma
标准化公式: X=(x−u)σX =\frac{(x-u)}{\sigma}X=σ(xu)
标准化后均值为0,方差为1

#1、设置数据
import numpy as np
import pandas as pd
X = [
    [1, 2, 3, 2],
    [7, 8, 9, 2.01],
    [4, 8, 2, 2.01],
    [9, 5, 2, 1.99],
    [7, 5, 3, 1.99],
    [1, 4, 9, 2]
]
x_test = [
    [12,11,13,12],
    [5,6,7,9]
]

#2、查看原始数据主要指标
df=pd.DataFrame(X)
df.describe().T

#3、 标准化操作,转换前查看
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(X)
print(ss.mean_)# 计算每个特征属性的均值
print(ss.n_samples_seen_)  #输出有多少个样本进行训练
print(ss.scale_)# 输出每个特征属性的标准差(σ),注:方差(σ²)等于标准差的平方

#4、标准化转换并查看
Std_train=ss.transform(X)
Std_test=ss.transform(x_test)
# 相当于对训练集做一个数据转换
print('标准化后的训练集数据:\n',Std_train)
print('标准化后训练集数据主要指标:\n',pd.DataFrame(Std_train).describe().T)

2、归一化

缩、放特征
x = (x-min_x)/(max_x-min_x)
0-1的范围内

#1、设置数据
import numpy as np
from sklearn.preprocessing import MinMaxScaler
X = np.array([
    [1, -1, 2, 3],
    [2, 0, 0, 3],
    [0, 1, -10, 3]
], dtype=np.float64)

#2、归一化操作,转换前查看数据重要指标
scaler = MinMaxScaler(feature_range=(0,1))#feature_range属性为最后映射到的范围,这里最后是把所有数据映射到0~1之间
scaler.fit(X)
# 原始特征属性的最大值
print(scaler.data_max_)
# 原始特征属性的最小值
print(scaler.data_min_)
# 原始特征属性的取值范围大小(最大值-最小值)
print(scaler.data_range_)

#3、归一化后的数据转换
MinMax_X=scaler.transform(X)
print(MinMax_X)


3、正则化

正则化则是将样本的某个范数缩放到单位1(针对的是单个样本的)。

L1范式公式: L1=∣x1∣+∣x2∣+∣x3∣+…∣xi∣L1 = |x1|+|x2|+|x3|+…|xi|L1=x1+x2+x3+xi

L2范式公式: L2=(x1)2+(x2)2+(x3)2+…(xi)2L2 = \sqrt {(x1)^2+(x2)^2+(x3)^2+…(xi)^2}L2=(x1)2+(x2)2+(x3)2+(xi)2

LP范式公式: LP=(x1)p+(x2)p+(x3)p+…(xi)pPLP = \sqrt[P] {(x1)^p+(x2)^p+(x3)^p+…(xi)^p}LP=P(x1)p+(x2)p+(x3)p+(xi)p

#正则化
#1、设置数据
import numpy as np
from sklearn.preprocessing import Normalizer
X = np.array([
    [1, -1, 2],
    [2, 0, 0],
    [0, 2, -10]
], dtype=np.float64)

#2、定义正则化
normalizer1 = Normalizer(norm='l1') #norm属性可填正则:l1范式、l2范式、max范式
normalizer2 = Normalizer(norm='l2')
normalizer3 = Normalizer(norm='max')
normalizer1.fit(X)
normalizer2.fit(X)
normalizer3.fit(X)
#3、正则化后转换数据
L1_X=normalizer1.transform(X)
L2_X=normalizer2.transform(X)
Max_X=normalizer3.transform(X)
print('L1范数:\n',L1_X) #l1正则化后,将Xi=Xi/l1  l1=|X1|+|X2|+|X3|……|Xn|   ,l1正则化之后的样本l1=1
print("**********************************")
print('L2范数:\n',L2_X)#l2正则化后,将Xi=Xi/l2  l1=(|X1|²+|X2|²+|X3|²……|Xn|²)½
print("**********************************")
print('Max范数:\n',Max_X)


L1范数:
[[ 0.25 -0.25 0.5 ]
[ 1. 0. 0. ]
[ 0. 0.16666667 -0.83333333]]


L2范数:
[[ 0.40824829 -0.40824829 0.81649658]
[ 1. 0. 0. ]
[ 0. 0.19611614 -0.98058068]]


Max范数:
[[ 0.5 -0.5 1. ]
[ 1. 0. 0. ]
[ 0. 1. -5. ]]

4、二值化

掉包方法:
from sklearn.preprocessing import Binarizer

对特征实现0或1的二值处理
1、一般情况下,对于每个特征需要使用不同的阈值进行二值化操作;
2、一般情况下,对数据进行划分的时候,不是进行二值化,而是进行多值化(分区化/分桶化);即:将一个连续的数据,按照不同的取值范围,分为不同的级别;比如:在某一个模型中,存在人的收入情况,单位为元,根据业务来判断的话,可能会得到影响因变量的因素其实是区间后的收入情况,那么这个时候就可以基于业务的特征,将收入划分为收入等级,比如:1w -> 0, 1w~2w -> 1, 2w~3w -> 2, 3w+ -> 3(至于这里到底做不做哑编码操作,具体的看对于区间化之后的数据的理解。如果认为区间化之后的特征数据是具有等级意义的,那么就可以考虑不做哑编码。如果认为区间化之后的数据是一个类别数据,那么一般需要做哑编码操作)

#二值化代码
#1、加载数据
import numpy as np
from sklearn.preprocessing import Binarizer
arr = np.array([
    [1.5, 2.3, 1.9],
    [0.5, 0.5, 1.6],
    [1.1, 2, 0.2]
])

# 2、定义二值化学习器;针对所有的特征属性选择同一个阈值
binarizer = Binarizer(threshold=1.5) #定义二值化学习器,threshold属性为阈值,大于该阈值的为1,小于等于该阈值的为0
binarizer.fit(arr)#学习训练
Bin_arr=binarizer.transform(arr)#数据二值化转换
print('原始的arr:\n',arr)
print('threshold=1.5:\n',Bin_arr)

#2.1、对单独的列设置阈值进行过滤
binarizer = Binarizer(threshold=[1.0,2.0,1.0])
binarizer.fit(arr)
Bin_arr2=binarizer.transform(arr)
print('threshold=[1.0,2.0,1.0]:\n',Bin_arr2)

#2.2 、使用特征的均值来进行二值化处理
print("均值:{}".format(np.mean(arr, axis=0)))
binarizer = Binarizer(threshold=np.mean(arr, axis=0))
binarizer.fit(arr)
Bin_arr3=binarizer.transform(arr)
print('使用特征的均值来进行二值化处理:\n',Bin_arr3)

# 2.3、基于NumPy API进行转换
arr2 = arr.copy()
print('原始arr2:\n',arr2)
condition1 = arr <= [1.0,2.0,1.0]
print('arr小于等于[1.0,2.0,1.0]的结果:\n',condition1)
condition2 = arr > [1.0,2.0,1.0]
print('arr大于[1.0,2.0,1.0]的结果:\n',condition2)
arr2[condition1] = 0#第一步True值填充0,False不能处理
arr2[condition2] = 1#第二步True值填充1,False不能处理
print('过滤后的arr2:\n',arr2)#合起来的结果就是0、1二值化了


原始的arr:
[[1.5 2.3 1.9]
[0.5 0.5 1.6]
[1.1 2. 0.2]]
threshold=1.5:
[[0. 1. 1.]
[0. 0. 1.]
[0. 1. 0.]]

threshold=[1.0,2.0,1.0]:
[[1. 1. 1.]
[0. 0. 1.]
[1. 0. 0.]]

均值:[1.03333333 1.6 1.23333333]
使用特征的均值来进行二值化处理:
[[1. 1. 1.]
[0. 0. 1.]
[1. 1. 0.]]

原始arr2:
[[1.5 2.3 1.9]
[0.5 0.5 1.6]
[1.1 2. 0.2]]
arr小于等于[1.0,2.0,1.0]的结果:
[[False False False]
[ True True False]
[False True True]]
arr大于[1.0,2.0,1.0]的结果:
[[ True True True]
[False False True]
[ True False False]]
过滤后的arr2:
[[1. 1. 1.]
[0. 0. 1.]
[1. 0. 0.]]

5、标签二值化

掉包方法:
from sklearn.preprocessing import LabelBinarizer
参数:
neg_label:必须对负标签进行编码的值
pos_label:必须编码正标签的值。
sparse_output:如果希望转换的返回数组采用稀疏格式,则为True。
sparse_output=True neg_label=0

#标签二值化——两个特征
#1、定义数据
from sklearn.preprocessing import LabelBinarizer
labelList=['男', '女', '女', '男']

# 2、将标签矩阵二值化
lb = LabelBinarizer()
dummY=lb.fit_transform(labelList)
print('两个特征(男、女)二值化:',dummY.T)

#3、 逆过程
yesORno=lb.inverse_transform(np.array([[0],[1]]))#注意逆过程学习器里面必须传入np.array
print('[[0],[1]]逆过程:',yesORno)

输出:
两个特征(男、女)二值化: [[1 0 0 1]]
[[0],[1]]逆过程: [‘女’ ‘男’]

#标签二值化——多个特征
#1、加载数据
from sklearn import preprocessing
# 标签矩阵
labelList=['yes', 'no', 'no', 'yes','unknow','ok']
print('原始特征列表labelList:\n',labelList)
# 2、将标签矩阵二值化
lb = preprocessing.LabelBinarizer()
dummY=lb.fit_transform(labelList)
print('输出四个特征二值化结果:\n',dummY)
print('输出四个特征:\n',lb.classes_)
#3、 逆过程
yesORno=lb.inverse_transform(dummY)
print('输出逆结果:\n',yesORno)

原始特征列表labelList:
[‘yes’, ‘no’, ‘no’, ‘yes’, ‘unknow’, ‘ok’]
输出四个特征二值化结果:
[[0 0 0 1]
[1 0 0 0]
[1 0 0 0]
[0 0 0 1]
[0 0 1 0]
[0 1 0 0]]
输出四个特征:
[‘no’ ‘ok’ ‘unknow’ ‘yes’]
输出逆结果:
[‘yes’ ‘no’ ‘no’ ‘yes’ ‘unknow’ ‘ok’]

6、多标签二值化

掉包方法:
sklearn.preprocessing.MultiLabelBinarizer(classes=None, sparse_output=False)

参数:
classes_属性:若设置classes参数时,其值等于classes参数值,否则从训练集统计标签值

①classes默认值,classes_属性值从训练集中统计标签值
②设置classes参数,classes_属性值等于classes参数值

#多标签二值化
#1、定义标签数据
from sklearn.preprocessing import MultiLabelBinarizer
label = [(1,2),(2,3),(3,5),(6,)]
print('原始数据:',label)
#2、定义学习器,不设定参数
mlb = MultiLabelBinarizer()
mlb_label=mlb.fit_transform(label)
print('不设定特征类别,转换后的结果:\n',mlb_label)
print('输出5个特征类别:',mlb.classes_)

#3、定义学习器,设定特征
mlb01 = MultiLabelBinarizer(classes=[7,1,2,3,4,5,6])
mlb_label2=mlb01.fit_transform(label)
print('设定了7个特征,转换后的结果:\n',mlb_label2)
print('输出7个特征类别:',mlb01.classes_)
print('转换(7,4),(2,3)样本结果:\n',mlb01.transform([(7,4),(2,3)]))

原始数据: [(1, 2), (2, 3), (3, 5), (6,)]
不设定特征类别,转换后的结果:
[[1 1 0 0 0]
[0 1 1 0 0]
[0 0 1 1 0]
[0 0 0 0 1]]
输出5个特征类别: [1 2 3 5 6]

设定了7个特征,转换后的结果:
[[0 1 1 0 0 0 0]
[0 0 1 1 0 0 0]
[0 0 0 1 0 1 0]
[0 0 0 0 0 0 1]]
输出7个特征类别: [7 1 2 3 4 5 6]
转换(7,4),(2,3)样本结果:
[[1 0 0 0 1 0 0]
[0 0 1 1 0 0 0]]

多标签输出结果解析:
1 2 3 5 6
[[1 1 0 0 0] #(1, 2)
[0 1 1 0 0] #(2, 3)
[0 0 1 1 0] #(3, 5)
[0 0 0 0 1]] #(6,)

7、哑编码

常用于:回归算法(线性回归、Ridge、Lasso、Logistic回归等)、SVM(svc/svr)、KNN、KMeans等
一般不需要哑编码的算法:决策树、贝叶斯、HMM等

7.1哑编码——只对数据类型的处理

注意:OneHotEncoder要求数据类别必须是数值的

#哑编码
# OneHotEncoder要求数据类别必须是数值的
# categorical_features:给定对哪些列的数据进行哑编码操作,默认是对所有列数据做
# n_values:明确给定各个特征属性的类别数目,其实是最大值+1


1、加载数据
from sklearn.preprocessing import OneHotEncoder
import numpy as np
import pandas as pd
a=np.array([
    [0, 0, 3], 
    [2, 1, 0], 
    [0, 2, 1], 
    [1, 0, 2],
    [1, 1, 1]])

#2、定义学习器
enc = OneHotEncoder()
enc.fit(a) 
print('原始数据:\n',a)

#3、数据转换输出
OH_a=enc.transform(a).toarray()
print('转换后的数据:\n',OH_a)
print("每列特征数:",enc.n_values_)
print("每个定性特征的有效值范围:\n",enc.feature_indices_)
print('备注上面特征范围,结果指的是,前0~3表示第一个特征,3~6表示第二个特征,6~10表示第三个特征')


原始数据:
[[0 0 3]
[2 1 0]
[0 2 1]
[1 0 2]
[1 1 1]]
转换后的数据:
[[1. 0. 0. 1. 0. 0. 0. 0. 0. 1.]
[0. 0. 1. 0. 1. 0. 1. 0. 0. 0.]
[1. 0. 0. 0. 0. 1. 0. 1. 0. 0.]
[0. 1. 0. 1. 0. 0. 0. 0. 1. 0.]
[0. 1. 0. 0. 1. 0. 0. 1. 0. 0.]]
每列特征数: [3 3 4]
每个定性特征的有效值范围:
[ 0 3 6 10]
备注上面特征范围,结果指的是,前03表示第一个特征,36表示第二个特征,6~10表示第三个特征

7.2哑编码——只对类别数据是字符串类型处理

两种方法

方法一:
使用pandas命令:get_dummies()方法实现,如下代码
注意:该命令只转换字符串类型的特征,对于数字类型的特征不转换

# 如果类别数据是字符串类型的,可以使用pandas的API进行哑编码转换
#该命令只转换字符串类型的特征,对于数字类型的特征不转换
a = DataFrame([
    ['a', 1, 2],
    ['b', 1, 1],
    ['a', 2, 1],
    ['c', 1, 2],
    ['d', 1, 2]
], columns=['c1', 'c2', 'c3'])

print('原始数据:\n',a)

# 将DataFrame中的字符串列转换为哑编码的形式
a = pd.get_dummies(a)
print('pandas命令实现字符串类型的转换:\n',a)

输出->
原始数据:
c1 c2 c3
0 a 1 2
1 b 1 1
2 a 2 1
3 c 1 2
4 d 1 2
pandas命令实现字符串类型的转换:
c2 c3 c1_a c1_b c1_c c1_d
0 1 2 1 0 0 0
1 1 1 0 1 0 0
2 2 1 1 0 0 0
3 1 2 0 0 1 0
4 1 2 0 0 0 1

方法二:
使用sklearn,掉包命令:
from sklearn.preprocessing import LabelEncoder

注意:该命令只能对单列特征进行转换

# 如果类别数据是字符串类型的,首先使用sklearn中的API将数据转换为从0开始的值
#哑编码——带字符类型数据转换
#1.设置数据
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder
a = DataFrame([
    ['aa', 1, 2],
    ['b', 1, 1],
    ['a', 2, 1],
    ['c', 1, 2],
    ['c', 1, 2]
], columns=['c1', 'c2', 'c3'])
print('原始数据:\n',a)

# 2、定义学习器,学习转换数据
le = LabelEncoder()
a['c4'] = le.fit_transform(a['c1'])#把C1列的转换的结果给了C4,这种结果后期需进行One-Hot
print('添加C4列转换后的数据:\n',a)
print('[0,1,2,3]逆结果:\n',le.inverse_transform([0,1,2,3]))#逆结果
data = a.drop('c1', axis=1)#删除C1列特征
print('删除C1列特征后的结果:\n',data)

# 3.1、进行哑编码操作,只对第C3列进行哑编码操作转换为0/1
enc = OneHotEncoder(categorical_features=[2])
enc.fit(data)
print('只对第C3列进行哑编码操作的结果:\n',enc.transform(data).toarray())

# 3、进行哑编码操作,对所有进行哑编码操作的转换为0/1
enc = OneHotEncoder()
enc.fit(data)
print('对所有进行哑编码操作的结果:\n',enc.transform(data).toarray())

原始数据:
c1 c2 c3
0 aa 1 2
1 b 1 1
2 a 2 1
3 c 1 2
4 c 1 2
添加C4列转换后的数据:
c1 c2 c3 c4
0 aa 1 2 1
1 b 1 1 2
2 a 2 1 0
3 c 1 2 3
4 c 1 2 3
[0,1,2,3]逆结果:
[‘a’ ‘aa’ ‘b’ ‘c’]
删除C1列特征后的最终结果:
c2 c3 c4
0 1 2 1
1 1 1 2
2 2 1 0
3 1 2 3
4 1 2 3
只对第C3列进行哑编码操作的结果:
[[0. 1. 0. 0. 1. 2.]
[0. 0. 1. 0. 1. 1.]
[1. 0. 0. 0. 2. 1.]
[0. 0. 0. 1. 1. 2.]
[0. 0. 0. 1. 1. 2.]]
对所有进行哑编码操作的结果:
[[1. 0. 0. 1. 0. 1. 0. 0.]
[1. 0. 1. 0. 0. 0. 1. 0.]
[0. 1. 1. 0. 1. 0. 0. 0.]
[1. 0. 0. 1. 0. 0. 0. 1.]
[1. 0. 0. 1. 0. 0. 0. 1.]]

8、缺省值填充
#缺省值填充
#1、读取数据
import numpy as np
from sklearn.preprocessing import Imputer
X = [
    [2, 2, 4, 1],
    [np.nan, 3, 4, 4],
    [1, 1, 1, np.nan],
    [2, 2, np.nan, 3]
]
X2 = [
    [2, 6, np.nan, 1],
    [np.nan, 5, np.nan, 1],
    [4, 1, np.nan, 5],
    [np.nan, np.nan, np.nan, 1]
]

#2、按照列进行填充计算
# 按照列进行填充值的计算(计算每个特征属性的填充值)(一般使用填充方式)
imp1 = Imputer(missing_values='NaN', strategy='mean', axis=0)
# 如果以列进行数据填充的时候,是计算每个特征属性的填充值分别是什么
imp1.fit(X)
print('X原始数据:\n',pd.DataFrame(X))
print('X2原始数据:\n',pd.DataFrame(X2))
# 当axis=0的时候,获取每个特征的计算出来的填充值
print('获取训练X的填充均值:\n',imp1.statistics_)
print('用X训练的列数据均值([1.666,2.0,3.0,2.666]),进行填充X2:\n',imp1.transform(X2))

#3、按照行进行填充计算
# 按照行计算填充值(计算每个样本的填充值) -- 一般不用
#(如果按照行进行填充的话,那么是不需要进行模型fit的,直接使用X的现有的行信息进行填充的)
imp2 = Imputer(missing_values='NaN', strategy='mean', axis=1)
print(imp2)

# imp2.fit(X) # 因为按照行数据进行填充转换的时候,是不需要计算到底填充值是什么的
print('按照X2的行平均值([3.0,3.0,3.333,1])行进行填充X2:\n',imp2.transform(X2))

#4、使用不同的填充方法(平均值、中值、众数)进行填充
imp1 = Imputer(missing_values='NaN', strategy='mean', axis=0)
imp2 = Imputer(missing_values='NaN', strategy='median', axis=0)
imp3 = Imputer(missing_values='NaN', strategy='most_frequent', axis=0)
imp1.fit(X)
imp2.fit(X)
imp3.fit(X)
print('X原始数据:\n',pd.DataFrame(X))
print('使用X的平均值特征列表填充:',imp1.statistics_)
print('使用X的中值特征列表填充:',imp2.statistics_)
print('使用X的众数特征列表填充:',imp3.statistics_)

X原始数据:
0 1 2 3
0 2.0 2 4.0 1.0
1 NaN 3 4.0 4.0
2 1.0 1 1.0 NaN
3 2.0 2 NaN 3.0
X2原始数据:
0 1 2 3
0 2.0 6.0 NaN 1
1 NaN 5.0 NaN 1
2 4.0 1.0 NaN 5
3 NaN NaN NaN 1
获取训练X的填充均值:
[1.66666667 2. 3. 2.66666667]
用X训练的列数据均值([1.666,2.0,3.0,2.666]),进行填充X2:
[[2. 6. 3. 1. ]
[1.66666667 5. 3. 1. ]
[4. 1. 3. 5. ]
[1.66666667 2. 3. 1. ]]

Imputer(axis=1, copy=True, missing_values=‘NaN’, strategy=‘mean’, verbose=0)

按照X2的行平均值([3.0,3.0,3.333,1])行进行填充X2:
[[2. 6. 3. 1. ]
[3. 5. 3. 1. ]
[4. 1. 3.33333333 5. ]
[1. 1. 1. 1. ]]

X原始数据:
0 1 2 3
0 2.0 2 4.0 1.0
1 NaN 3 4.0 4.0
2 1.0 1 1.0 NaN
3 2.0 2 NaN 3.0
使用X的平均值特征列表填充: [1.66666667 2. 3. 2.66666667]
使用X的中值特征列表填充: [2. 2. 4. 3.]
使用X的众数特征列表填充: [2. 2. 4. 1.]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值