关于归一化报错问题——以Python为例
不少小伙伴在开始数据处理,进行归一化的时候,会出现以下报错问题
ValueError: non-broadcastable output operand with shape (8,1) doesn’t match the broadcast shape (8,6)
本文将讲述报错原因以及如何改正。在改错之前,首先要了解归一化的原理。
归一化介绍
通常,在做数据分析的时候,数据归一化是必不可少的一步,特别是对于多维的数据。Why?,简而言之,数据归一化就是将数据中的每一个元素映射到一个较小的区间,这样,多维数据间的数字差距就会减小,消除量纲的影响。特别是在分析多维数据对标签的影响时更为重要。
常见的归一化方法主要有:
Min-Max
x−minXmaxX−minX\frac{x - minX}{maxX- minX}maxX−minXx−minX
Min-Max归一化方法将所有的值映射到[0, 1]。
Z-score
x−μσ\frac{x-\mu}{\sigma}σx−μ
Z-score方法,其中μ\muμ为处理数据中的均值,σ\sigmaσ为处理数据中的方差。该方法将数据归一化为均值为0,方差为1。对于服从正态分布类的数据而言,适用于该归一化方法。
除上述两种归一化方法,在机器学习中,还有常见的Sigmoid归一化函数、tanh函数……,这里就不一一赘述了。
报错原理
我们以Min-Max归一化方法为例,我们将下面矩阵归一化处理:
[ABCD24560275171243308522439308653499329522499457170439329170765125797796879810059536177672143186318631677]
\left[
\begin{matrix}
A &B &C &D\\
245 &602 &751 &712\\
43 &308 &522 &439\\
308 &653 &499 &329\\
522 &499 &457 &170\\
439 &329 &170 &765\\
1257 &977 &968 &798\\
1005 &953 &617 &767\\
2143 &1863 &1863 &1677
\end{matrix} \right]
⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡A24543308522439125710052143B6023086534993299779531863C7515224994571709686171863D7124393291707657987671677⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
w = pd.read_excel("data.xlsx")
origin = np.array(w)
sc = MinMaxScaler()
data = sc.fit_transform(origin)
处理后得到如下归一化矩阵:
[ABCD0.096190480.189067520.343177790.35965494000.207914940.178500330.126190480.221864950.194329590.105507630.228095240.122829580.1695215600.188571430.0135048200.394824150.578095240.430225080.471352630.416721960.458095240.4147910.264028350.396151291111]
\left[
\begin{matrix}
A&B&C&D\\
0.09619048& 0.18906752& 0.34317779& 0.35965494\\
0 &0 &0.20791494 &0.17850033\\
0.12619048& 0.22186495 &0.19432959& 0.10550763\\
0.22809524 &0.12282958 &0.16952156& 0 \\
0.18857143& 0.01350482 &0 &0.39482415\\
0.57809524& 0.43022508& 0.47135263 &0.41672196\\
0.45809524 &0.414791 & 0.26402835& 0.39615129\\
1 &1 &1 &1
\end{matrix} \right]
⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡A0.0961904800.126190480.228095240.188571430.578095240.458095241B0.1890675200.221864950.122829580.013504820.430225080.4147911C0.343177790.207914940.194329590.1695215600.471352630.264028351D0.359654940.178500330.1055076300.394824150.416721960.396151291⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
根据上面个归一化数据可知,对于数据框,Sklearn库中归一化方法是将数据分列进行处理的。现在,我们将A列数据反归一化。返回原来的值:
#对第一列数据进行反归一化操作
w2 = data[::, 0]
#改变数据维度,不然会报错
w2 = w2.reshape(8, 1)
pr_data = sc.inverse_transform(w2)
print(pr_data)
此时报错:
ValueError: non-broadcastable output operand with shape (8,1) doesn’t match the broadcast shape (8,4)
这是因为我们上面是将一个数据框进行归一化,而当我们在反归一化时只对其中的一列数据进行操作。而程序无法判断我们进行操作的数据对应数据框的哪一列,自然就无法进行反归一化。
注意:从数据框中提取数据需要重新塑造维度,若没有改变数据维度,则会报错:
ValueError: Expected 2D array, got 1D array instead
解决方案
针对以上的报错,这里提供两种解决方法:
1. 用需要反归一化的数据,替换掉历史的数据。
例如现在用A,B,C前三列数据分析D列数据,得到新的一列数据E需要与原数据D进行比较,这时候我们只需要加上两行代码将新数据E代替D列,再反归一化即可。
data = pd.DataFrame(data)
data.iloc[:, 3] = new_data #新数据列替换D列数据
data = sc.inverse_transform(data) #反归一化
注意:系统会利用归一化中存储的最值进行反一化操作,因此在反归一化数据是允许出现在[0,1]外的。
2. 自己编写归一化函数
并且实际的数据处理中,对于样本量较小的情况下,调用归一化函数是不合理的。因为小样本数据不符合大数定律,无法客观反映事件的整体特性,即数学语言中的均值,方差,最值等。此时建议对数据归一化处理时所需的数字特征另外获取,并根据数据特性编写归一化代码。