3

我正在尝试使用以下代码在 python 中对数据集进行中心化和规范化

mean = np.mean(train, axis=0)
std = np.std(train, axis=0)
norm_train = (train - mean) / std

问题是我得到了一个零错误的定义。数据集中的两个值最终具有零标准。数据集的形状为 (3750, 55)。我的统计技能不是那么强,所以我不知道如何克服这一点。有什么建议么?

4

4 回答 4

6

由于标准偏差是通过对均值的平方偏差求和来计算的,因此只有当变量的所有值都相同(都等于均值)时,零标准偏差才有可能。在这种情况下,这些变量没有区分能力,因此可以从分析中删除。它们无法改进任何分类、聚类或回归任务。许多实现会为您执行此操作或引发有关矩阵计算的错误。

于 2016-04-07T20:40:37.833 回答
1

一个标准是包含一个防止被零除的 epsilon 变量。理论上,它是不需要的,因为进行这样的计算在逻辑上没有意义。实际上,机器只是计算器,除以零变成 NaN 或 +/-Inf。

简而言之,像这样定义你的函数:

def z_norm(arr, epsilon=1e-100):
    return (arr-arr.mean())/(arr.std()+epsilon)  

这假设一个 1D 数组,但很容易更改为 2D 数组的按行或按列计算。

Epsilon 是故意添加到计算中的错误,以防止创建 NaN 或 Inf。在 Inf 的情况下,您仍然会得到非常大的数字,但以后的计算不会传播 Inf 并且可能仍然保留一些含义。

1/(1 x 10^100) 的值非常小,不会对结果产生太大影响。如果需要,您可以降至 1e-300 左右,但在进一步计算后可能会达到最低精度值。请注意您使用的精度和它可以处理的最小精度。我正在使用float64。

2021-11-03 更新:添加测试代码。此 epsilon 的目标是最大程度地减少损坏并消除数据管道中随机 NaN 的可能性。将 epsilon 设置为正值可以解决问题。

for arr in [
        np.array([0,0]),
        np.array([1e-300,1e-300]),
        np.array([1,1]),
        np.array([1,2])
    ]:
    for epi in [1e-100,0,1e100]:
        stdev = arr.std()
        mean = arr.mean()
        result = z_norm(arr, epsilon=epi)
        print(f' z_norm(np.array({str(arr):<21}),{epi:<7}) ### stdev={stdev}; mean={mean:<6}; becomes --> {str(result):<19} (float-64) --> Truncate to 32 bits. =', result.astype(np.float32))

z_norm(np.array([0 0]                ),1e-100 ) ### stdev=0.0; mean=0.0   ; becomes --> [0. 0.]             (float-64) --> Truncate to 32 bits. = [0. 0.]
z_norm(np.array([0 0]                ),0      ) ### stdev=0.0; mean=0.0   ; becomes --> [nan nan]           (float-64) --> Truncate to 32 bits. = [nan nan]
z_norm(np.array([0 0]                ),1e+100 ) ### stdev=0.0; mean=0.0   ; becomes --> [0. 0.]             (float-64) --> Truncate to 32 bits. = [0. 0.]
z_norm(np.array([1.e-300 1.e-300]    ),1e-100 ) ### stdev=0.0; mean=1e-300; becomes --> [0. 0.]             (float-64) --> Truncate to 32 bits. = [0. 0.]
z_norm(np.array([1.e-300 1.e-300]    ),0      ) ### stdev=0.0; mean=1e-300; becomes --> [nan nan]           (float-64) --> Truncate to 32 bits. = [nan nan]
z_norm(np.array([1.e-300 1.e-300]    ),1e+100 ) ### stdev=0.0; mean=1e-300; becomes --> [0. 0.]             (float-64) --> Truncate to 32 bits. = [0. 0.]
z_norm(np.array([1 1]                ),1e-100 ) ### stdev=0.0; mean=1.0   ; becomes --> [0. 0.]             (float-64) --> Truncate to 32 bits. = [0. 0.]
z_norm(np.array([1 1]                ),0      ) ### stdev=0.0; mean=1.0   ; becomes --> [nan nan]           (float-64) --> Truncate to 32 bits. = [nan nan]
z_norm(np.array([1 1]                ),1e+100 ) ### stdev=0.0; mean=1.0   ; becomes --> [0. 0.]             (float-64) --> Truncate to 32 bits. = [0. 0.]
z_norm(np.array([1 2]                ),1e-100 ) ### stdev=0.5; mean=1.5   ; becomes --> [-1.  1.]           (float-64) --> Truncate to 32 bits. = [-1.  1.]
z_norm(np.array([1 2]                ),0      ) ### stdev=0.5; mean=1.5   ; becomes --> [-1.  1.]           (float-64) --> Truncate to 32 bits. = [-1.  1.]
z_norm(np.array([1 2]                ),1e+100 ) ### stdev=0.5; mean=1.5   ; becomes --> [-5.e-101  5.e-101] (float-64) --> Truncate to 32 bits. = [-0.  0.]
于 2019-07-10T17:12:08.123 回答
0

您可以将该功能的 0 std 替换为 1 。这基本上意味着该特征的所有数据点的缩放值将为零。这是有道理的,因为这意味着特征值甚至不会偏离平均值(因为值是常数,常数就是平均值。)

仅供参考-这就是 sklearn 所做的! https://github.com/scikit-learn/scikit-learn/blob/7389dbac82d362f296dc2746f10e43ffa1615660/sklearn/preprocessing/data.py#L70

于 2019-02-11T03:53:25.000 回答
0

回到它的定义,z_score 背后的想法是根据标准偏差给出元素与样本均值之间的距离。如果所有元素都相同,则意味着它们与平均值的距离为 0,因此 zscore 是标准偏差的 0 倍,因为所有数据点都处于平均值。标准除法的除法是将距离与数据的分散联系起来的一种方式。从视觉上很容易理解并得出这个结论:https ://en.wikipedia.org/wiki/Standard_score#/media/File:The_Normal_Distribution.svg

于 2021-06-15T18:02:53.037 回答