我正在尝试使用以下代码在 python 中对数据集进行中心化和规范化
mean = np.mean(train, axis=0)
std = np.std(train, axis=0)
norm_train = (train - mean) / std
问题是我得到了一个零错误的定义。数据集中的两个值最终具有零标准。数据集的形状为 (3750, 55)。我的统计技能不是那么强,所以我不知道如何克服这一点。有什么建议么?
我正在尝试使用以下代码在 python 中对数据集进行中心化和规范化
mean = np.mean(train, axis=0)
std = np.std(train, axis=0)
norm_train = (train - mean) / std
问题是我得到了一个零错误的定义。数据集中的两个值最终具有零标准。数据集的形状为 (3750, 55)。我的统计技能不是那么强,所以我不知道如何克服这一点。有什么建议么?
由于标准偏差是通过对均值的平方偏差求和来计算的,因此只有当变量的所有值都相同(都等于均值)时,零标准偏差才有可能。在这种情况下,这些变量没有区分能力,因此可以从分析中删除。它们无法改进任何分类、聚类或回归任务。许多实现会为您执行此操作或引发有关矩阵计算的错误。
一个标准是包含一个防止被零除的 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.]
您可以将该功能的 0 std 替换为 1 。这基本上意味着该特征的所有数据点的缩放值将为零。这是有道理的,因为这意味着特征值甚至不会偏离平均值(因为值是常数,常数就是平均值。)
仅供参考-这就是 sklearn 所做的! https://github.com/scikit-learn/scikit-learn/blob/7389dbac82d362f296dc2746f10e43ffa1615660/sklearn/preprocessing/data.py#L70
回到它的定义,z_score 背后的想法是根据标准偏差给出元素与样本均值之间的距离。如果所有元素都相同,则意味着它们与平均值的距离为 0,因此 zscore 是标准偏差的 0 倍,因为所有数据点都处于平均值。标准除法的除法是将距离与数据的分散联系起来的一种方式。从视觉上很容易理解并得出这个结论:https ://en.wikipedia.org/wiki/Standard_score#/media/File:The_Normal_Distribution.svg