尝试估计未知变量时的奇怪行为

时间:2016-07-31 05:39:32

标签: python statistics

我试图以非常高的精度估计未知变量(p)。我所拥有的是大量有序值(我称之为t值)。每个值都有一个序列号(n)。这些t值中的每一个基本上是将n乘以p然后添加随机偏移("噪声")的结果。我的想法是简单地根据序列号对t值进行排序,然后取所有偏移量的均值。它工作得很好。以下是10个估算示例(真p为1.0,t值为100000):

1.0000737485173519
0.9999987583319258
1.0000688058361697
1.0002021529901506
0.9999391175701831
1.000012370796987
0.9999891218161053
1.0001566049086157
0.9999818309412788
0.9999594118399372

足够接近我想要的东西。

但实际上,一定数量的t值也会丢失。如果我引入t值的随机丢失,精度会急剧下降,即使丢失的t值的数量低至0.001% - 0.01%,这也是奇怪的部分,即使我通过产生更多的t补偿 - 值因此计算均值时使用的t值的数量是相同的!

以下是大约1%的值被删除的10个例子:

1.0024257205135292
1.0019969333070318
1.0019520792036436
1.001061555944925
0.997728342781954
1.000205614588305
0.9964173869854615
1.0028314864552466
1.0014389330965119
0.9954499027939065

为什么会这样?

我在Python中进行了模拟演示。要查看差异,请先按原样运行。然后将drop_probability更改为0.01并再次运行。

的Python:

#!/usr/bin/python3
import random

random.seed(42)

runs = 10
effective_number_of_values = 100000

real_period=1
static_offset=0.5
lambd=0.2

drop_probability=0.00000001
#drop_probability=0.0001
#drop_probability=0.001
#drop_probability=0.01
#drop_probability=0.1
#drop_probability=0.5


for run in range(0, runs):
    values = []
    dropped_ts = 0

    last_was_dropped = False
    num_values = 0
    n = 1
    t = 0
    while num_values < effective_number_of_values + 1:

        actual_t = t
        noise = static_offset + random.expovariate(lambd)
        effective_t = actual_t + noise

        if drop_probability is not None and \
            random.random() <= drop_probability:

            values.append((n, effective_t, True))
            dropped_ts += 1
            last_was_dropped = True
        else:
            values.append((n, effective_t, False))
            if not last_was_dropped:
                num_values += 1
            last_was_dropped = False

        t += real_period
        n += 1

    values.sort()

    last_n = 0
    last_t = 0
    last_was_dropped = False
    avg_sum = 0
    avg_n = 0
    for v in values:
            n, t, dropped = v

            if n > 1:
                    if not dropped and not last_was_dropped:
                        avg_sum += t - last_t
                        avg_n += 1

            last_t = t
            last_n = n
            last_was_dropped = dropped

    print(avg_sum / avg_n, "(values used: %d, dropped along the way: %.2f%% (%d))" % (avg_n, (dropped_ts/len(values))*100, dropped_ts))
                         <br>

3 个答案:

答案 0 :(得分:0)

您的问题是由于您的抽样性质。随着您增加丢弃值的百分比,降低值的总体百分比将增加指数,并将大幅降低您的准确性和精确度。

毋庸置疑,随着样本丢失百分比的增加,采样数量的这种显着变化会导致您的测量结果呈指数级变得更加不精确。随着人口增加,这个问题变得不那么明显了。如果您希望删除更多值,请采用更大的样本。如果您的采样方法如此不准确以至于损失超过10%的样本,那么您必须通过减少样本量,减少采样量或重新考虑是否需要少于1%的方差来纠正此问题,从而降低准确度。你的估计。

其中很大一部分源于统计理论。对概率和随机抽样的粗略研究将产生许多有用的方程式和经验法则,以帮助确保对未知参数的准确估计。

为此目的,您需要使用的主要公式是计算正态分布的误差范围以表示采样方法:ME = z * sqrt( (p_hat * q_hat) / n)

您还需要泊松分布的误差范围来表示噪声引入的误差:formula, given large values of n*lambdME = z * sqrt( lambd / n )。您需要在采样后将此值包含在总误差中,并且95%置信度,10,000个样本和0.2的lambd,您会发现它高达0.45%,解释了大部分意外情况错误。

然而,这种确定泊松分布误差余量的方法只是粗略的近似,将其视为正态分布。在你的情况下,对于这么小的羔羊,你可能希望考虑this paper中包含的19个近似值中的一个。

摘要

看来您对丢失准确性(假设正态分布)是正确的,但可能是由于使用了random.expovariate(lambd)

  

“指数分布......如果lambd为正,则返回值的范围从0到正无穷大。”

使用均值函数将产生有效结果,因为泊松分布的u=0.2值较低(基本上是expovariate)将是非对称的,如证明的那样来自CalTech的W.R.Leo

  

请注意,分布不对称。因此,分布的峰值或最大值不对应于均值。然而,随着μ变大,分布变得越来越对称并接近高斯形式。

答案 1 :(得分:0)

我不确定我是否完全理解您的问题,但我正在努力提供帮助。

我确实相信你所看到的结果。假设丢弃率增加使得平均每秒测量值下降。两次连续剩余测量之间的平均差异将是之前的两倍。因此下降率确实会影响结果。同样,如果你只下降10%,那么差异应该增加~10%。

这是我重写代码的方式。在这个版本中,我总是使用random.sample函数丢弃一定量的测量值。

import random

#random.seed(42)

effective_number_of_values = 100000

real_period = 1
static_offset = 0.5
lambd = 0.2

drop_probabilities = [0.00001, 0.001, 0.01, 0.1, 0.2, 0.3, 0.5, 0.9, 0.99]

values = []
t = 0
for drop_probability in drop_probabilities:
    desiredlen = round(effective_number_of_values * (1 + drop_probability))

    for t in range(desiredlen):
        noise = static_offset + random.expovariate(lambd)
        effective_t = t + noise
        values.append((t, effective_t))

    values_after_drop = random.sample(values, effective_number_of_values)
    values_after_drop.sort()

    diff_t = [values_after_drop[i][1] - values_after_drop[i-1][1]
              for i in range(1, len(values_after_drop))]

    avg = sum(diff_t)/len(diff_t)

    print("avg = {}. {} dropped out of {} at {} probability".
          format(avg, len(values) - effective_number_of_values,
                 len(values), drop_probability))

答案 2 :(得分:0)

为了完整性,这里是我正在努力解决的实际问题:

两台计算机连接到互联网。 计算机A以固定的间隔向计算机B发送特殊类型的数据包(数据包基于UDP)。计算机B需要以非常高的精度估计这个间隔。

数据包有序列号。每个数据包显然会或多或少地延迟,有些会丢失。有些人会以错误的顺序到达。

所以计算机B知道的是:到达的数据包列表及其序列号和到达时间。由此我希望能够估计至少有四位小数精度的间隔,不超过大约10000个样本(因为我想考虑白天计算机时钟的小波动,典型的间隔将是1秒我不想使用更多)。我希望即使丢包率很高(例如50%),这也是可能的。