单元测试概率



我有一个方法,可以在给定的x时间内创建 2 个不同的实例(M, N) (math.random * x)该方法将创建对象M,其余时间对象N

我已经编写了模拟随机数的单元测试,因此我可以确保该方法按预期运行。但是,我不确定如何(以及是否)测试概率是否准确,例如,如果x = 0.1我希望十分之一的情况返回实例 M。

如何测试此功能?

拆分测试。第一个测试应该允许您定义随机数生成器返回的内容(我假设您已经有了)。这部分测试只是满足"如果随机数生成器返回一些值,我是否得到预期的结果"。

第二个测试应该使用一些统计分析函数运行随机数生成器(例如计算它返回每个值的频率)。

我建议用一个返回"create M"和"create N"(或者可能只是 0 和 1)的包装器包装真正的生成器。这样,您可以将实现与使用它的位置分开(创建两个不同实例的代码不需要知道生成器是如何初始化的,或者如何将实际结果转换为"create X"。

我将以Python的形式执行此操作。

首先描述您的功能:

def binomial_process(x):
    '''
    given a probability, x, return M with that probability, 
    else return N with probability 1-x 
    maybe: return random.random() > x
    '''

然后测试此功能:

import random
def binom(x):
    return random.random() > x

然后编写测试函数,首先是一个设置函数,将来自昂贵过程的数据放在一起:

def setUp(x, n):
    counter = dict()
    for _ in range(n):
        result = binom(x)
        counter[result] = counter.get(result, 0) + 1
    return counter

然后实际测试:

import scipy.stats
trials = 1000000

def test_binomial_process():
    ps = (.01, .1, .33, .5, .66, .9, .99)
    x_01 = setUp(.01, trials)
    x_1 = setUp(.1, trials)
    x_33 = setUp(.1, trials)
    x_5 = setUp(.5, trials)
    x_66 = setUp(.9, trials)
    x_9 = setUp(.9, trials)
    x_99 = setUp(.99, trials)
    x_01_result = scipy.stats.binom_test(x_01.get(True, 0), trials, .01)
    x_1_result = scipy.stats.binom_test(x_1.get(True, 0), trials, .1)
    x_33_result = scipy.stats.binom_test(x_33.get(True, 0), trials, .33)
    x_5_result = scipy.stats.binom_test(x_5.get(True, 0), trials)
    x_66_result = scipy.stats.binom_test(x_66.get(True, 0), trials, .66)
    x_9_result = scipy.stats.binom_test(x_9.get(True, 0), trials, .9)
    x_99_result = scipy.stats.binom_test(x_99.get(True, 0), trials, .99)
    setups = (x_01, x_1, x_33, x_5, x_66,  x_9, x_99)
    results = (x_01_result, x_1_result, x_33_result, x_5_result,
               x_66_result, x_9_result, x_99_result)
    print 'can reject the hypothesis that the following tests are NOT the'
    print 'results of a binomial process (with their given respective'
    print 'probabilities) with probability < .01, {0} trials each'.format(trials)
    for p, setup, result in zip(ps, setups, results):
        print 'p = {0}'.format(p), setup, result, 'reject null' if result < .01 else 'fail to reject'

然后编写你的函数(好的,我们已经这样做了):

def binom(x):
    return random.random() > x

并运行测试:

test_binomial_process()

在最后一个输出中给我:

can reject the hypothesis that the following tests are NOT the
results of a binomial process (with their given respective
probabilities) with probability < .01, 1000000 trials each
p = 0.01 {False: 10084, True: 989916} 4.94065645841e-324 reject null
p = 0.1 {False: 100524, True: 899476} 1.48219693752e-323 reject null
p = 0.33 {False: 100633, True: 899367} 2.96439387505e-323 reject null
p = 0.5 {False: 500369, True: 499631} 0.461122365668 fail to reject
p = 0.66 {False: 900144, True: 99856} 2.96439387505e-323 reject null
p = 0.9 {False: 899988, True: 100012} 1.48219693752e-323 reject null
p = 0.99 {False: 989950, True: 10050} 4.94065645841e-324 reject null

为什么我们不能在p=0.5时拒绝?让我们看看scipy.stats.binom_test上的帮助:

Help on function binom_test in module scipy.stats.morestats:
binom_test(x, n=None, p=0.5, alternative='two-sided')
    Perform a test that the probability of success is p.
    This is an exact, two-sided test of the null hypothesis
    that the probability of success in a Bernoulli experiment
    is `p`.
    Parameters
    ----------
    x : integer or array_like
        the number of successes, or if x has length 2, it is the
        number of successes and the number of failures.
    n : integer
        the number of trials.  This is ignored if x gives both the
        number of successes and failures
    p : float, optional
        The hypothesized probability of success.  0 <= p <= 1. The
        default value is p = 0.5
    alternative : {'two-sided', 'greater', 'less'}, optional
        Indicates the alternative hypothesis. The default value is
        'two-sided'.

因此,.5 是检验的默认原假设,在这种情况下不拒绝原假设是有意义的。

最新更新