本文通过Python实现三种常见的数据规范化方法,包括最小-最大规范化,零-均值规范化,小数定标规范化。
最小-最大规范化(Min-max): x ∗ = x − m i n m a x − m i n x^*=\frac{x-min}{max-min} x∗=max−minx−min,min表示最小值,max表示最大值
零-均值规范化(Z-score): x ∗ = x − x ˉ σ x^*=\frac{x-\bar{x}}{\sigma} x∗=σx−xˉ, x ˉ \bar{x} xˉ表示均值, σ \sigma σ表示方差
小数定标规范化: x ∗ = x 1 0 k x^*=\frac{x}{10^k} x∗=10kx,k表示小数点移动的位数
实现代码
import numpy as np
import pandas as pd
# 原始数据,每一行表示一个样本,每一列表示一个特征
raw_data = np.array([
[78, 521, 602, 2862],
[144, -600, -521, 2245],
[95, -457, 468, -1283],
[69, 596, 695, 1054],
[190, 527, 691, 2051],
[101, 403, 470, 2487]
])
data = pd.DataFrame(raw_data)
# 最小-最大规范化
min_max = (data-data.min()) / (data.max()-data.min())
# 零-均值规范化
z_score = (data-data.mean()) / data.std()
# 小数定标规范化
decimal_scaling = data / 10**np.ceil(np.log10(data.abs().max()))
# 打印结果
print(min_max)
print(z_score)
print(decimal_scaling)
输出结果
min_max
Out[26]:
0 1 2 3
0 0.074380 0.937291 0.923520 1.000000
1 0.619835 0.000000 0.000000 0.851146
2 0.214876 0.119565 0.813322 0.000000
3 0.000000 1.000000 1.000000 0.563812
4 1.000000 0.942308 0.996711 0.804343
5 0.264463 0.838629 0.814967 0.909530
z_score
Out[27]:
0 1 2 3
0 -0.759445 0.656051 0.434805 0.848567
1 0.679503 -1.409773 -1.992464 0.443540
2 -0.388807 -1.146247 0.145175 -1.872406
3 -0.955665 0.794264 0.635816 -0.338289
4 1.682407 0.667108 0.627171 0.316189
5 -0.257993 0.438596 0.149498 0.602400
decimal_scaling
Out[28]:
0 1 2 3
0 0.078 0.521 0.602 0.2862
1 0.144 -0.600 -0.521 0.2245
2 0.095 -0.457 0.468 -0.1283
3 0.069 0.596 0.695 0.1054
4 0.190 0.527 0.691 0.2051
5 0.101 0.403 0.470 0.2487
实现代码
from sklearn import preprocessing
import numpy as np
# 原始数据,每一行表示一个样本,每一列表示一个特征
raw_data = np.array([
[78, 521, 602, 2862],
[144, -600, -521, 2245],
[95, -457, 468, -1283],
[69, 596, 695, 1054],
[190, 527, 691, 2051],
[101, 403, 470, 2487]
])
# 最小-最大规范化
# 将数据进行[0,1]规范化;最小最大值区间可以指定,默认是映射到[0,1]区间
min_max_scaler = preprocessing.MinMaxScaler()
min_max = min_max_scaler.fit_transform(raw_data)
# 零-均值规范化
z_score = preprocessing.scale(raw_data)
# 小数定标规范化
# 主要是通过NumPy库来计算小数点的位数
k = np.ceil(np.log10(np.max(abs(raw_data))))
decimal_scaling = raw_data / (10**k)
# 打印结果
print(min_max)
print(z_score)
print(decimal_scaling)
输出结果
min_max
Out[10]:
array([[0.07438017, 0.93729097, 0.92351974, 1. ],
[0.61983471, 0. , 0. , 0.85114596],
[0.21487603, 0.11956522, 0.81332237, 0. ],
[0. , 1. , 1. , 0.56381182],
[1. , 0.94230769, 0.99671053, 0.80434258],
[0.26446281, 0.83862876, 0.81496711, 0.90952955]])
z_score
Out[11]:
array([[-0.83193017, 0.71866807, 0.47630463, 0.92955909],
[ 0.74435857, -1.54432887, -2.18263537, 0.4858732 ],
[-0.4259164 , -1.2556504 , 0.15903129, -2.0511184 ],
[-1.04687863, 0.87007286, 0.69650179, -0.37057719],
[ 1.84298406, 0.73078046, 0.68703095, 0.34636743],
[-0.28261743, 0.48045787, 0.16376671, 0.65989587]])
decimal_scaling
Out[12]:
array([[ 0.0078, 0.0521, 0.0602, 0.2862],
[ 0.0144, -0.06 , -0.0521, 0.2245],
[ 0.0095, -0.0457, 0.0468, -0.1283],
[ 0.0069, 0.0596, 0.0695, 0.1054],
[ 0.019 , 0.0527, 0.0691, 0.2051],
[ 0.0101, 0.0403, 0.047 , 0.2487]])
观察仔细的小伙伴,应该就可以发现,两种方法得到的结果存在差异。这是为什么呢?
主要原因还是两种方法的实现不同,处理的对象主体也不同。我们可以通过测试每一步的输出,以及查看源码来发现和解决问题。
接下来,主要针对两种方法进行小数定标规范化后,得到的结果存在差异的原因,进行分析。
在方法一中,处理的数据是 DataFrame 对象。原始数据(raw_data)被转换成 Pandas 的 DataFrame 对象(data),对 data 执行统计计算,例如求均值,方差,最大值时,默认是对每一列求均值,方差,最大值。(也可以通过修改axis的取值,对每一行执行操作。)本例中的 data 有4列,对 data 求最大值,则有4个结果。
decimal_scaling = data / 10**np.ceil(np.log10(data.abs().max()))
data
Out[42]:
0 1 2 3
0 78 521 602 2862
1 144 -600 -521 2245
2 95 -457 468 -1283
3 69 596 695 1054
4 190 527 691 2051
5 101 403 470 2487
type(data) # data是DataFrame类型
Out[43]: pandas.core.frame.DataFrame
data.describe() # 对data的描述
Out[44]:
0 1 2 3
count 6.000000 6.000000 6.000000 6.000000
mean 112.833333 165.000000 400.833333 1569.333333
std 45.866836 542.640581 462.659882 1523.351656
min 69.000000 -600.000000 -521.000000 -1283.000000
25% 82.250000 -242.000000 468.500000 1303.250000
50% 98.000000 462.000000 536.000000 2148.000000
75% 133.250000 525.500000 668.750000 2426.500000
max 190.000000 596.000000 695.000000 2862.000000
data.abs().max() # 对data的每一列取绝对值后,再求每一列的最大值
Out[45]:
0 190
1 600
2 695
3 2862
dtype: int32
方法二中,处理的数据是 numpy 的数组 ndarray。当对数据取均值,最大值等统计值时,是以整个数组为主体,最后求得的均值,最大值,都分别只有一个。
k = np.ceil(np.log10(np.max(abs(raw_data))))
decimal_scaling = raw_data / (10**k)
raw_data
Out[13]:
array([[ 78, 521, 602, 2862],
[ 144, -600, -521, 2245],
[ 95, -457, 468, -1283],
[ 69, 596, 695, 1054],
[ 190, 527, 691, 2051],
[ 101, 403, 470, 2487]])
type(raw_data)
Out[14]: numpy.ndarray
np.mean(raw_data) # 求均值
Out[15]: 562.0
# 对所有数值求绝对值后,再求出所有数值当中的最大值,只返回一个结果
np.abs(raw_data).max()
Out[17]: 2862
结论:具体问题具体分析,根据实际场景的需要,选择合适的计算方式。