【问题标题】:Numpy transformation to normal distributionNumpy 转换为正态分布
【发布时间】:2016-03-04 03:38:40
【问题描述】:

我有一个数据数组。我检查了它是否是正态分布的:

import sys
import scipy
from scipy import stats
from scipy.stats import mstats
from scipy.stats import normaltest

Data = []
for line in open(sys.argv[1]):
    line = line.strip()
    Data.append(float(line))
print scipy.stats.normaltest(Data)

输出为:(36.444648754208075, 1.2193968690198398e-08)

然后,我写了一个小脚本来规范化数据:

import sys
import numpy as np
fileopen = open(sys.argv[1])
UntransformedArray = []
for line in fileopen:
    line = float(line.strip())
    UntransformedArray.append(line)
TransformedArray = (UntransformedArray - np.mean(UntransformedArray)/np.std(UntransformedArray))
NewList = TransformedArray.tolist()
for i in NewList:
    print i

然后我使用第一个脚本再次检查正常性,输出是 (36.444648754209595, 1.2193968690189117e-08)。

...与上一个分数相同,并且不呈正态分布。

我的一个脚本错了吗?

另外,我应该提到我的数据的平均值为 0.056,数字范围从 0.014 到 0.171(85 个观察值),我不确定这些数字如此之小是否重要。

未转换和转换数据的样本:

未转换:

0.055
0.074
0.049
0.067
0.038
0.037
0.045
0.041

转换后的数据:

-2.13696814254
-2.11796814254
-2.14296814254
-2.12496814254
-2.15396814254
-2.15496814254
-2.14696814254

编辑 1:

当我稍微编辑代码以说明括号位置错误时:

TransformedMean = (UntransformedArray - np.mean(UntransformedArray))
TransformedArray = (TransformedMean/np.std(UntransformedArray))
NewList = TransformedArray.tolist()
for i in NewList:
    print i

我得到的输出不同:

例子:

-0.0385683544143
0.705333390576
-0.273484694937
0.431264326632
-0.704164652563
-0.743317375984

但是,当我检查正常时: (36.444648754241328, 1.2193968689995659e-08)

它仍然不是正态分布的(并且仍然与其他时间完全相同)?

编辑2:

然后我尝试了另一种标准化数据的方法:

import sys
import scipy
from scipy import stats
from scipy.stats import boxcox

Data = [(float(line.strip())) for line in open(sys.argv[1])]
scipy.stats.boxcox(Data)

我收到错误:TypeError: unsupported operand type(s) for ** or pow(): 'list' and 'float'

编辑 3:由于用户的评论,问题在于理解标准化值与标准化分布的差异。

修改后的代码:

import sys
import numpy as np

fileopen = open(sys.argv[1])
UntransformedArray = []
for line in fileopen:
    line = float(line.strip())
    UntransformedArray.append(line)

List1 =  np.log(UntransformedArray) 
for i in List1:
    print i

检查规范化: (4.0435072214905938, 0.13242304287973003)

(在这种情况下有效,取决于数据的偏度)。

编辑 4:或使用 BoxCox 转换:

import sys
import scipy
from scipy import stats
from scipy.stats import boxcox
import numpy as np

Data = []
for line in open(sys.argv[1]):
    line = line.strip()
    Data.append(float(line))

data = scipy.stats.boxcox(np.array(Data))
for i in data[0]:
    print i

检查标准化:(2.9085877478631956, 0.23356523218452238)

【问题讨论】:

  • TransformedArray 计算中没有括号问题吗? ( UntransformedArray - np.mean(UntransformedArray) ) /np.std(UntransformedArray)
  • 这就是我所拥有的:TransformedArray = (UntransformedArray - np.mean(UntransformedArray)/np.std(UntransformedArray)) 它似乎运行没有抱怨?括号没有错误?
  • 算术除法 (/) 具有不同的优先级进行减号 (-) 操作。因此,您正在划分均值/标准差,然后仅在应用减法之后。我相信你的括号放错了地方。
  • 谢谢。我稍微改变了脚本(见编辑)。检查正态性脚本可能有问题吗?我问的原因是,现在我已经为检查正态性脚本提供了两个不同的列表,(例如,我的原始转换输出,所有数字都以 -2.XXX 开头,而在我的编辑中,数字是例如0.43、-0.7 等),我仍然从检查正态性脚本得到完全相同的输出?
  • 回复。 boxcox:试试scipy.stats.boxcox(np.array(Data))(如果还没有import numpy as np,请在脚本顶部添加)。顺便说一句,scipy.stats.boxcox(Data) 在较新版本的scipy 中工作。你用的是什么版本?运行import scipy; print(scipy.__version__) 找出答案。

标签: python numpy normalization


【解决方案1】:

正如预期的那样,减去均值并重新调整为单位方差不会改变分布的形状。 normaltest 在两种情况下都正确返回相同的输出,告诉您您的数据不是正态分布。

【讨论】:

    【解决方案2】:

    我同意托马斯的观点。但更准确地说:您正在标准化阵列的分布!这不会改变分布的形状!您可能想使用 numpy.histogram() 函数来了解分布情况!

    我认为您已经成为“规范化”令人困惑的双重用法的牺牲品。一方面,标准化用于描述变量的标准化(以相同的比例获取变量 - 这就是您所做的)。另一方面,归一化用于描述改变概率分布形状的尝试(scipy.stats.normaltest() 用于检查这种分布的形状)。尝试更正常地获得分布的一种简单策略是使用对数转换。 numpy.log() 可能会在这里解决问题,但前提是原始分布不太偏斜。

    【讨论】:

    • 这真的很有用,谢谢,特别是在理解的澄清方面。我已经使用我使用的更新代码进行了编辑。
    【解决方案3】:

    我遇到了同样的问题。我的数据不像你的那样正常,我不得不将我的数据转换为正态分布。要将您的数据转换为正常,您应该通过不同的方法使用正常分数转换,如here 所述。您也可以使用these formulas。我编写了一个 python 代码,用于将元素列表更改为正态分布,如下所示:

    X = [0.055, 0.074, 0.049, 0.067, 0.038, 0.037, 0.045, 0.041]
    
    from scipy.stats import rankdata, norm
    
    newX = norm.ppf(rankdata(x)/(len(x) + 1))
    print(newX)
    
    output:
    [ 0.4307273   1.22064035  0.1397103   0.76470967 -0.76470967 -1.22064035
    -0.1397103  -0.4307273 ]
    

    你可以看到你的新数据在这个转换之后完全正常,你可以通过QQ图看到:

    from scipy import stats
    import matplotlib.pyplot as plt
    
    ax4 = plt.subplot(111)
    res = stats.probplot(newX, plot=plt)
    plt.show()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-09
      • 1970-01-01
      • 2016-07-29
      • 2019-02-22
      • 2018-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多