python - 报告来自两个预先计算的直方图的双样本 K-S 统计量

标签 python numpy matplotlib scipy statistics

问题:

我在这里绘制了 2 个存储在文本文件中的数据集(在列表 dataset 中),每个数据集包含 218 亿个数据点。这使得数据太大而无法作为数组保存在内存中。我仍然能够将它们绘制成直方图,但我不确定如何通过 2 sample KS test 计算它们的差异。 .这是因为我不知道如何访问 plt 对象中的每个直方图。

示例:

下面是一些生成虚拟数据的代码:

mu = [100, 120]
sigma = 30
dataset = ['gsl_test_1.txt', 'gsl_test_2.txt']
for idx, file in enumerate(dataset):
    dist = np.random.normal(mu[idx], sigma, 10000)
    with open(file, 'w') as g:
        for s in dist:
            g.write('{}\t{}\t{}\n'.format('stuff', 'stuff', str(s)))

这会生成我的两个直方图(使 here 成为可能):

chunksize = 1000
dataset = ['gsl_test_1.txt', 'gsl_test_2.txt']
for fh in dataset:
    # find the min, max, line qty, for bins
    low = np.inf
    high = -np.inf

    loop = 0
    for chunk in pd.read_table(fh, header=None, chunksize=chunksize, delimiter='\t'):
        low = np.minimum(chunk.iloc[:, 2].min(), low)
        high = np.maximum(chunk.iloc[:, 2].max(), high)
        loop += 1
    lines = loop*chunksize

    nbins = math.ceil(math.sqrt(lines))   

    bin_edges = np.linspace(low, high, nbins + 1)
    total = np.zeros(nbins, np.int64)  # np.ndarray filled with np.uint32 zeros, CHANGED TO int64

    for chunk in pd.read_table(fh, header=None, chunksize=chunksize, delimiter='\t'):

        # compute bin counts over the 3rd column
        subtotal, e = np.histogram(chunk.iloc[:, 2], bins=bin_edges)  # np.ndarray filled with np.int64

        # accumulate bin counts over chunks
        total += subtotal


    plt.hist(bin_edges[:-1], bins=bin_edges, weights=total)
    plt.savefig('gsl_test_hist.svg')

问题:

大多数examples for KS-statistics使用两个原始数据/观察/点/等数组,但我没有足够的内存来使用这种方法。根据上面的示例,我如何访问这些预先计算的 bin(来自 'gsl_test_1.txt''gsl_test_2.txt' 以计算两个分布之间的 KS 统计数据?

红利: 在图表上记录 KS 统计量和 pvalue!

最佳答案

我稍微清理了你的代码。写入 StringIO 因此它比写入文件更流线。使用 seaborn 而不是 matplotlib 设置默认氛围,使其看起来更现代。如果您希望统计测试对齐,则两个样本的 bins 阈值应该相同。我认为,如果您以这种方式遍历并制作垃圾箱,那么整个事情可能会比需要的时间更长。 Counter 可能很有用 b/c 你只需要循环一次......另外你将能够制作相同的 bin 大小。将 float 转换为整数,因为您将它们合并在一起。 from collections import Counter 然后 C = Counter()C[value] += 1。你将在末尾有一个 dict,你可以从 list(C.keys()) 中创建垃圾箱。这会很好,因为您的数据非常粗糙。另外,你应该看看是否有办法用 numpy 而不是 pandas b/c numpy 来做 chunksize索引速度更快。为 DF.iloc[i,j]ARRAY[i,j] 尝试一个 %timeit,你就会明白我的意思了。我写了很多函数来尝试使其更加模块化。

import numpy as np
import pandas as pd
import math
import matplotlib.pyplot as plt
from io import StringIO
from scipy.stats import ks_2samp
import seaborn as sns; sns.set()

%matplotlib inline

#Added seaborn b/c it looks mo betta

mu = [100, 120]
sigma = 30

def write_random(file,mu,sigma=30):
    dist = np.random.normal(mu, sigma, 10000)
    for i,s in enumerate(dist):
        file.write('{}\t{}\t{}\n'.format("label_A-%d" % i, "label_B-%d" % i, str(s)))
    return(file)

#Writing to StringIO instead of an actual file
gs1_test_1 = write_random(StringIO(),mu=100)
gs1_test_2 = write_random(StringIO(),mu=120)

chunksize = 1000

def make_hist(fh,ax):
    # find the min, max, line qty, for bins
    low = np.inf
    high = -np.inf

    loop = 0

    fh.seek(0)
    for chunk in pd.read_table(fh, header=None, chunksize=chunksize, sep='\t'):
        low = np.minimum(chunk.iloc[:, 2].min(), low) #btw, iloc is way slower than numpy array indexing
        high = np.maximum(chunk.iloc[:, 2].max(), high) #you might wanna import and do the chunks with numpy
        loop += 1
    lines = loop*chunksize

    nbins = math.ceil(math.sqrt(lines))   

    bin_edges = np.linspace(low, high, nbins + 1)
    total = np.zeros(nbins, np.int64)  # np.ndarray filled with np.uint32 zeros, CHANGED TO int64

    fh.seek(0)
    for chunk in pd.read_table(fh, header=None, chunksize=chunksize, delimiter='\t'):

        # compute bin counts over the 3rd column
        subtotal, e = np.histogram(chunk.iloc[:, 2], bins=bin_edges)  # np.ndarray filled with np.int64

        # accumulate bin counts over chunks
        total += subtotal

    plt.hist(bin_edges[:-1], bins=bin_edges, weights=total,axes=ax,alpha=0.5)

    return(ax,bin_edges,total)

#Make the plot canvas to write on to give it to the function
fig,ax = plt.subplots()

test_1_data = make_hist(gs1_test_1,ax)
test_2_data = make_hist(gs1_test_2,ax)

#test_1_data[1] == test_2_data[1] The bins should be the same if you're going try and compare them...
ax.set_title("ks: %f, p_in_the_v: %f" % ks_2samp(test_1_data[2], test_2_data[2]))

enter image description here

关于python - 报告来自两个预先计算的直方图的双样本 K-S 统计量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37262231/

相关文章:

numpy - 为什么 octave 的 prctile 和 numpy 的百分位数之间存在差异?

python - 如何将一个 numpy 数组切片为另一个不同大小的 numpy 数组?

python - 将循环中的数组保存在一个 txt 文件的列中

python - 获取 matplotlib 颜色循环状态

javascript - 如何找到对象之间的关系

python - 如何使用 Mechanize python

python - 使用 python 抓取 Udacity 网站?

python - pytesseract不适用于数字图像

python - 圆柱坐标图?

python - matplotlib:在时间序列图中将周期标签置于周期数据的中心