math - 避免随机生成的减法问题中的偏差

标签 math python-2.7 random

我正在编写一个 Python 脚本来生成心算练习的问题。加法和乘法很简单,但我在尝试为减法生成无偏问题时遇到了麻烦。

我希望能够指定被减数(第一个数字)的最小值和最大值 - 例如,对于两位数减法,它应该在 20 到 99 之间。减数还应该有一个范围选项( 11-99,比如说)。对于这种情况,答案必须是肯定的,并且最好也限制在最小值(例如 10)内。

所以:

  • 20 <被减数<99
  • 11 <减数<99
  • 答案 = 被减数 - 减数
  • 答案 >= 10

当然,所有数值都应该用作变量。

我满足以下条件:

ansMin, ansMax = 10, 99
subtrahendMin, minuendMax = 11,99
# the other max and min did not seem to be necessary here,
# and two ranges was the way I had the program set up

answer = randint(ansMin, ansMax)
subtrahend = randint(subtrahendMin, minuendMax - answer)
minuend = answer + subtrahend # rearranged subtraction equation

这里的问题是,被减数的值最终几乎都超过了 50,因为答案和减数是首先生成并相加的,只有它们都位于范围底部 25% 的部分才会得到结果低于50%。 (编辑:这并不完全正确——例如,底部 1% 加上底部 49% 就可以了,无论如何,百分比都是一种不好的描述方式,但我认为这个想法很明确。)

我还考虑尝试完全随机生成被减数和减数值,然后如果答案不符合条件则丢弃答案(即被减数大于减数至少大于answerMin的值)并且它们都符合上面列出的标准),但我认为这会导致类似的偏差。

我不关心它是否完美,但这太遥远了。我希望被减数值在允许的范围内完全随机,而减数值在被减数允许的范围内随机(如果我想得对,这将偏向于较低的值)。我认为我并不真正关心答案的分布(只要它没有可笑的偏见)。有没有更好的计算方法?

最佳答案

在这种情况下,有多种方法可以定义“不带偏见”的含义。我假设您正在寻找的是以相同的概率选择允许的问题空间中的每个可能的减法问题。快速而肮脏的方法:

  1. 在 [x_min, x_max] 中随机选择 x
  2. 在 [y_min, y_max] 中选择随机 y
  3. 如果 x - y x 和 y 并重新开始。

注意粗体部分。如果您仅丢弃 y 并保留 x,您的问题将在 x 中均匀分布,而不是在整个问题空间中。您需要确保对于每个有效的 x ,至少有一个有效的 y - 这不是您最初选择的范围的情况,我们稍后会看到。

现在是长而正确的方法。首先我们需要找出问题空间的实际大小。

允许的减数集由被减数决定:

x in [21, 99]
y in [11, x-10]

或使用符号常量:

x in [x_min, x_max]
y in [y_min, x - answer_min]

我们可以将其重写为

x in [21, 99]
y = 11 + a
a in [0, x-21]

或者再次使用符号常量

x in [x_min, x_max]
y = y_min + a
a in [0, x - (answer_min + y_min)].

由此,我们看到仅当 x >= (answer_min + y_min) 时才存在有效问题,并且对于给定的 x,存在 x - (answer_min + y_min) + 1 个可能的减数。

现在我们假设 x_max 没有施加任何进一步的约束,例如那answer_min + y_min >= 0:

x in [21, 99], number of problems:
    (99 - 21 + 1) * (1 + 78+1) / 2
x in [x_min, x_max], number of problems:
    (x_max - x_min + 1) * (1 + x_max - (answer_min + y_min) + 1) / 2

上式是利用等差数列之和的公式得到的。因此,您需要在 [1, 4740] 范围内选择一个随机数。为了将这个数字转化为减法问题,我们需要定义问题空间和整数之间的映射。映射示例如下:

  • 1 <=> x = 21,y = 11
  • 2 <=> x = 22,y = 12
  • 3 <=> x = 22,y = 11
  • 4 <=> x = 23,y = 13
  • 5 <=> x = 23,y = 12
  • 6 <=> x = 23,y = 11

等等。请注意,当超出三角数时,x 会跳跃 1。为了根据随机数 r 计算 x 和 y,最好通过在预先计算的表中搜索来找到大于或等于 r 的最小三角数 t;将此数字写为 q*(q+1)/2。那么 x = x_min + q-1 且 y = y_min + t - r。

完整的程序:

import random

x_min, x_max = (21, 99)
y_min = 11
answer_min = 10

triangles = [ (q*(q+1)/2, q) for q in range(1, x_max-x_min+2) ]
upper = (x_max-x_min+1) * (1 + x_max - (answer_min + y_min) + 1) / 2

for i in range(0, 20):
    r = 1 + random.randrange(0, upper)
    (t, q) = next(a for a in triangles if a[0] >= r)
    x = x_min + q - 1
    y = y_min + t - r
    print "%d - %d = ?" % (x, y)

请注意,对于大多数问题(大约 75%),x 将高于 60。这是正确的,因为对于较小的被减数值,允许的减数值较少。

关于math - 避免随机生成的减法问题中的偏差,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19369181/

相关文章:

python - 为什么 -2//4 的输出为 -1?

ios - 为什么 CGFloat 会补足有效数字?

python - 在Python中根据前一个函数的参数调用函数

python - 从python中的随机列表中选择时出错

python - 重用 SystemRandom 是 Python 的好做法吗?

php - 每天运行的电子邮件脚本(需要一些概念上的帮助)

math - 如何在更高维度的超球面上均匀分布点?

python-2.7 - 基于另一个 DataFrame 重命名列

python字典键错误无法解决

python - 从列表中提取满足条件的随机值? Python