数据的标准化与归一化

最近做一个抖音的数据分析的时候,在数据归一化和标准化经常看到不一样的解释,通过不断地百度+知乎+测试,算是大概明白了这个过程。简单总结一下。

标准化与归一化

其实这个问题主要的原因是这这些概念都是直接翻译过来的,Normalize和Standard等等经常会被认为是一个意思,其实还是有一定的差别的。

归一化是将样本的特征值转换到同一量纲下把数据映射到[0,1]或者[-1, 1]区间内,仅由变量的极值决定,因区间放缩法是归一化的一种。标准化是依照特征矩阵的列处理数据,转换为”标准正态分布”,注意这里标准正态分布是打了引号的。和整体样本分布相关,每个样本点都能对标准化产生影响。

为了统一,我们将均值和标准差设为常见的mu和sigma。

1.标准化的定义
$$
x’ = \frac{x-\mu}{\sigma}
$$
这是最常用的标准话的定义,通过这样的一个方式,可以将数据分布在一个均值0,方差为1的一个区间。但是不代表处理过后的数据就是正态分布,因为其实这样一个过程改变了均值和方差但是并没有改变分布。所以如果原来是服从正态分布,那么现在也是,原来是什么分布,那现在也是什么分布。他有一个好处,就是可以加快收敛,在深度学习中经常用到,所以一般在深度学习中不知道用啥那就用这个吧。证明过程我也实在是忘了,用的就是方差的性质。

2.归一化
$$
x’ = \frac{x-min(x)}{max(x)-min(x)}
$$

$$
x’ = \frac{x-\mu}{max(x)-min(x)}
$$

这个有两种表示,第一种是min-max归一化,第二种是mean归一化,这个不难理解,相当于把数据分布给压缩了,结果也是在0-1之间,但是压缩的程度完全取决于极值,这样这种方式就不够稳定。

3.Normalize

我姑且称这种方式叫做正则把,也可以叫归一化,它保留原始数据的分布,只是同时除以一个数,这个数就是向量的L1-norm值。
$$
x’ = \frac{x}{\sqrt{x_1^2+x_2^2+…+x_n^2}}
$$
这种其实也是一种常见的归一化。

在sklearn中的使用

在sklearn中,这几种都在preprocessing包中,使用也就一行代码的事,这里先引用知乎中的一段代码

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import preprocessing

def plot(data, title):
    sns.set_style('dark')
    f, ax = plt.subplots()
    ax.set(ylabel='frequency')
    ax.set(xlabel='height(blue) / weight(green)')
    ax.set(title=title)
    sns.distplot(data[:, 0:1], color='blue')
    sns.distplot(data[:, 1:2], color='green')
    plt.savefig(title + '.png')
    plt.show()

np.random.seed(42)
height = np.random.normal(loc=168, scale=5, size=1000).reshape(-1, 1)
weight = np.random.normal(loc=70, scale=10, size=1000).reshape(-1, 1)

original_data = np.concatenate((height, weight), axis=1)
plot(original_data, 'Original')

standard_scaler_data = preprocessing.StandardScaler().fit_transform(original_data)
plot(standard_scaler_data, 'StandardScaler')

min_max_scaler_data = preprocessing.MinMaxScaler().fit_transform(original_data)
plot(min_max_scaler_data, 'MinMaxScaler')

max_abs_scaler_data = preprocessing.MaxAbsScaler().fit_transform(original_data)
plot(max_abs_scaler_data, 'MaxAbsScaler')

normalizer_data = preprocessing.Normalizer().fit_transform(original_data)
plot(normalizer_data, 'Normalizer')

robust_scaler_data = preprocessing.RobustScaler().fit_transform(original_data)
plot(robust_scaler_data, 'RobustScaler')

链接:https://www.zhihu.com/question/20467170/answer/839255695.

要注意的一点是,如果给定的是一个矩阵,除了normalize,其他的都是默认对列向量进行归一化或标准化,但是normalize是对行进行标准化,这个很有意思。

from sklearn import preprocessing

arr = np.array([
    [1, 2, 2],
    [1, 1, 3],
    [0, 1, 2]
])
scarlar = preprocessing.StandardScaler()
print(scarlar.fit_transform(arr))

scarlar = preprocessing.Normalizer()
print(scarlar.fit_transform(arr))


输出:
[[ 0.70710678  1.41421356 -0.70710678]
 [ 0.70710678 -0.70710678  1.41421356]
 [-1.41421356 -0.70710678 -0.70710678]]

[[0.33333333 0.66666667 0.66666667]
 [0.30151134 0.30151134 0.90453403]
 [0.         0.4472136  0.89442719]]

可以简单的带进去算一下,就很清晰了。

初始化

还有一个比较重要的一点,很多数据需要进行初始化,比如normal等等,这些初始化是从给定的分布中堆积选择数据。举个例子,初始化一个服从正态分布N(1, 3)的100x100维度的矩阵,并不是说这些数据每一列或者每一行恰好服从均值为1方差为3的正态分布,而是矩阵中所有的值都是从这个分布中随机选的值。但是一般数据量大一些的时候如50x100等其实已经很接近设定的这个分布了。如果3x3或者2x4这种一般会均值方差会比较抖动。

import os
import torch
import random
import numpy as np
import torch.nn as nn
from common_tools import set_seed

set_seed(1)  # 设置随机种子


class MLP(nn.Module):
    def __init__(self, neural_num, layers):
        super(MLP, self).__init__()
        self.linears = nn.ModuleList([nn.Linear(neural_num, neural_num, bias=False) for i in range(layers)])
        self.neural_num = neural_num

    def forward(self, x):
        for (i, linear) in enumerate(self.linears):
            x = linear(x)
#             x = torch.relu(x)

            print("layer:{}, std:{}".format(i, x.std()))
            if torch.isnan(x.std()):
                print("output is nan in {} layers".format(i))
                break

        return x

    def initialize(self):
        for m in self.modules():
            if isinstance(m, nn.Linear):
                # 使用这个会造成梯度消失或爆炸,方差在精度内无法表示
                nn.init.normal_(m.weight.data)   # normal: mean=0, std=1

                # nn.init.normal_(m.weight.data, std=np.sqrt(1/self.neural_num))  

                # a = np.sqrt(6 / (self.neural_num + self.neural_num))
                #
                # tanh_gain = nn.init.calculate_gain('tanh')
                # a *= tanh_gain
                #
                # nn.init.uniform_(m.weight.data, -a, a)

                # nn.init.xavier_uniform_(m.weight.data, gain=tanh_gain)

                # nn.init.normal_(m.weight.data, std=np.sqrt(2 / self.neural_num))
                # nn.init.kaiming_normal_(m.weight.data)
wc = torch.ones((3, 4))
ans = nn.init.normal_(wc, std=1, mean=0)
ans2 = nn.init.xavier_normal(wc)

print(ans[0].std())
print(ans2[0].std())

参考文章

知乎回答

CSDN

特征工程


  转载请注明: April 数据的标准化与归一化

 本篇
数据的标准化与归一化 数据的标准化与归一化
最近做一个抖音的数据分析的时候,在数据归一化和标准化经常看到不一样的解释,通过不断地百度+知乎+测试,算是大概明白了这个过程。简单总结一下。 标准化与归一化其实这个问题主要的原因是这这些概念都是直接翻译过来的,Normalize和Stand
2020-04-22
下一篇 
Docker安装Mongodb及使用 Docker安装Mongodb及使用
最近有点偷懒,没有好好学习。因为预计接下来用mongodb会比较多,做一个简单的总结。 Docker + Mongodbdocker是真的好用,谁用谁知道,因为抖音的评论数据字段是在太多了,不知道哪些以后可能用得着,而返回的本身又是json
2020-03-30
  目录