如何生成平均值遵循 Ruby 正弦波的随机数?
How can I generate random numbers whose average follows a sine wave in Ruby?
我不是学数学的,所以我真的不知道我想做的事情叫什么名字,但我确定它有一个名字。 ;-)
我想在 Ruby 中生成随机数数组,数组中每个元素的平均值都遵循正弦波。我所说的 每个元素的平均值 是元素 n
的平均值 ary[0..n].inject(:+).to_f / (n + 1)
。因此,如果我从 0..n
遍历随机数数组并像我描述的那样生成平均值,我希望结果值遵循正弦波。我只是不知道如何以这种方式实际生成随机数...
# assuming `ary` is the array of random numbers
# I'm trying to figure out how to generate...
averages = []
(0..ary.size).each do |n|
averages << ary[0..n].inject(:+).to_f / (n + 1)
end
# `averages` should plot as a sine wave now...
这是一个主意。创建一个 class,它有一些样本大小,它在正弦波中生成点,加上一些高于或低于该点的随机 "fudge factor"(方差)。这样,如果您绘制样本量中的点数,您应该根据配置的方差(软糖因子)看到带有 "roughness" 的正弦波。
class RandomSineWave
attr_reader :size
def initialize(size=20, variance=0.2)
@size = size
@step = 2 * Math::PI / size
@position = 0
@variance = variance
end
def next
@position = 0 if @position >= 2 * Math::PI
next_rand = Math.sin(@position) + (rand * @variance) - (@variance / 2)
@position += @step
next_rand
end
end
# Generate TSV output for demonstration.
rsw = RandomSineWave.new
rsw.size.times { |i| puts [i, rsw.next].join "\t" }
您可以通过修改构造函数的第二个参数来 fiddle 和 "roughness":
rsw = RandomSineWave.new(20, 0.8) # Results plotted below...
据我了解,给定一些正整数 n
,您想要构建一个 n
概率分布数组,使得随机变量的部分和的期望值描述一个正弦波。我假设正弦波在区间 (0..2*π)
内并且期望值在该区间内均匀分布。
我们必须首先问这些概率分布是否在统计上是独立的。如果它们不是,它就会变得非常复杂,所以我会假设它们是独立的。在针对它们的均值差异进行调整后,它们是否是相同的分布是没有必要的,甚至是不重要的。我稍后再讲。
由于您希望随机变量 X
i 的部分和的期望值来描述正弦波,我们要求:
E [∑j=0...iXj] = k * sin(2*π*i/n)
对于所有 i = 0...n-1
,对于给定的比例因子,k
(其中(E[..]
表示 "expected value")。我们可以假设,不失一般性, k=1
,因为我们总是可以按 k
缩放随机变量,导致它们的均值按相同的常数缩放。
因为分布是独立的,我们可以写成:
∑j=0...imj = sin(2*π*i/n)
哪里
mi = E[Xi] 是 Xi 的均值。
在 Ruby 中,对于 n
值(浮点数)的数组 x
,这是:
x[0,i].reduce(:+) = Math::sin(2.0 * Math::PI * i.to_f/n)
我们可以很容易地计算出x
。假设 n = 36
。
对于 i = 0
:
x[0,0].reduce(:+) = Math::sin(2.0 * Math::PI * 0.0/36)
# x[0] = 0
设:
s = x[0]
#=> 0.0
对于i = 1
:
x[0,1].reduce(:+) = Math::sin(2.0 * Math::PI * 1.0/36).round(6)
#=> 0.0 + x[1] = Math::sin(0.17453292519943295).round(6)
#=> = 0.173648
所以
x[1] = 0.173648 - 0.0
#=> 0.173648
现在让
s += x[1]
#=> 0.173648
对于i = 2
:
x[0,2].reduce(:+) = Math::sin(2.0 * Math::PI * 2.0/36).round(6)
#=> s + x[2] = Math::sin(0.3490658503988659).round(6)
#=> 0.173648 + x[2] = 0.342020
所以
x[2] = 0.342020 - 0.173648
#=> 0.168372
然后我们更新s
:
s += 0.168372
#=> 0.173648 += 0.168372
#=> 0.342020
然后类似地计算x[3]
,然后每个剩余的x
:
def compute(n, p=6)
sum = 0.0
n.times.map do |i|
if i.zero?
[0.0, 0.0, 0.0, 0.0]
else
x = Math::sin(2.0 * Math::PI * i.to_f/n) - sum
sum += x
[(2.0*(i.to_f/n)*Math::PI).round(p), x.round(p),
sum.round(p), Math::sin(sum).round(p)]
end
end
end
compute(36)
# radians x sum sin(sum) degrees
# [[0.0, 0.0, 0.0, 0.0 ], 0
# [0.174533, 0.173648, 0.173648, 0.172777],
# ...
# [1.396263, 0.045115, 0.984808, 0.833166],
# [1.570796, 0.015192, 1.0, 0.841471], 90
# [1.745329, -0.015192, 0.984808, 0.833166],
# ...
# [2.967060, -0.168372, 0.173648, 0.172777],
# [3.141593, -0.173648, 0.0, 0.0 ], 180
# [3.316126, -0.173648, -0.173648, -0.172777],
# ...
# [4.537856, -0.045115, -0.984808, -0.833166],
# [4.712389, -0.015192, -1.0, -0.841471], 270
# [4.886922, 0.015192, -0.984808, -0.833166],
# ...
# [5.934119, 0.15798, -0.34202, -0.335391],
# [6.108652, 0.168372, -0.173648, -0.172777]] 350
当我有时间熟悉@maeric 的漂亮绘图工具时,我将添加这些值的图表。
现在我们有了均值,我们可以考虑构建具有这些均值的概率分布。
假设,例如,我们假设每个随机变量具有相同的均匀分布,范围(最大-最小)为rng
,均值不同。如果平均值是 0.325467
,我们可以生成一个伪随机变量,如下所示:
rng * (rand-0.325467)
哪里
(0.5-0.174533).round(6)
#=> 0.325467
因此,我们可以为具有给定范围的均匀分布生成伪随机变量,均值如下:
def uniform_rv(rng, mean)
rng.to_f * (rand -0.5 -mean)
end
我不是学数学的,所以我真的不知道我想做的事情叫什么名字,但我确定它有一个名字。 ;-)
我想在 Ruby 中生成随机数数组,数组中每个元素的平均值都遵循正弦波。我所说的 每个元素的平均值 是元素 n
的平均值 ary[0..n].inject(:+).to_f / (n + 1)
。因此,如果我从 0..n
遍历随机数数组并像我描述的那样生成平均值,我希望结果值遵循正弦波。我只是不知道如何以这种方式实际生成随机数...
# assuming `ary` is the array of random numbers
# I'm trying to figure out how to generate...
averages = []
(0..ary.size).each do |n|
averages << ary[0..n].inject(:+).to_f / (n + 1)
end
# `averages` should plot as a sine wave now...
这是一个主意。创建一个 class,它有一些样本大小,它在正弦波中生成点,加上一些高于或低于该点的随机 "fudge factor"(方差)。这样,如果您绘制样本量中的点数,您应该根据配置的方差(软糖因子)看到带有 "roughness" 的正弦波。
class RandomSineWave
attr_reader :size
def initialize(size=20, variance=0.2)
@size = size
@step = 2 * Math::PI / size
@position = 0
@variance = variance
end
def next
@position = 0 if @position >= 2 * Math::PI
next_rand = Math.sin(@position) + (rand * @variance) - (@variance / 2)
@position += @step
next_rand
end
end
# Generate TSV output for demonstration.
rsw = RandomSineWave.new
rsw.size.times { |i| puts [i, rsw.next].join "\t" }
您可以通过修改构造函数的第二个参数来 fiddle 和 "roughness":
rsw = RandomSineWave.new(20, 0.8) # Results plotted below...
据我了解,给定一些正整数 n
,您想要构建一个 n
概率分布数组,使得随机变量的部分和的期望值描述一个正弦波。我假设正弦波在区间 (0..2*π)
内并且期望值在该区间内均匀分布。
我们必须首先问这些概率分布是否在统计上是独立的。如果它们不是,它就会变得非常复杂,所以我会假设它们是独立的。在针对它们的均值差异进行调整后,它们是否是相同的分布是没有必要的,甚至是不重要的。我稍后再讲。
由于您希望随机变量 X
i 的部分和的期望值来描述正弦波,我们要求:
E [∑j=0...iXj] = k * sin(2*π*i/n)
对于所有 i = 0...n-1
,对于给定的比例因子,k
(其中(E[..]
表示 "expected value")。我们可以假设,不失一般性, k=1
,因为我们总是可以按 k
缩放随机变量,导致它们的均值按相同的常数缩放。
因为分布是独立的,我们可以写成:
∑j=0...imj = sin(2*π*i/n)
哪里
mi = E[Xi] 是 Xi 的均值。
在 Ruby 中,对于 n
值(浮点数)的数组 x
,这是:
x[0,i].reduce(:+) = Math::sin(2.0 * Math::PI * i.to_f/n)
我们可以很容易地计算出x
。假设 n = 36
。
对于 i = 0
:
x[0,0].reduce(:+) = Math::sin(2.0 * Math::PI * 0.0/36)
# x[0] = 0
设:
s = x[0]
#=> 0.0
对于i = 1
:
x[0,1].reduce(:+) = Math::sin(2.0 * Math::PI * 1.0/36).round(6)
#=> 0.0 + x[1] = Math::sin(0.17453292519943295).round(6)
#=> = 0.173648
所以
x[1] = 0.173648 - 0.0
#=> 0.173648
现在让
s += x[1]
#=> 0.173648
对于i = 2
:
x[0,2].reduce(:+) = Math::sin(2.0 * Math::PI * 2.0/36).round(6)
#=> s + x[2] = Math::sin(0.3490658503988659).round(6)
#=> 0.173648 + x[2] = 0.342020
所以
x[2] = 0.342020 - 0.173648
#=> 0.168372
然后我们更新s
:
s += 0.168372
#=> 0.173648 += 0.168372
#=> 0.342020
然后类似地计算x[3]
,然后每个剩余的x
:
def compute(n, p=6)
sum = 0.0
n.times.map do |i|
if i.zero?
[0.0, 0.0, 0.0, 0.0]
else
x = Math::sin(2.0 * Math::PI * i.to_f/n) - sum
sum += x
[(2.0*(i.to_f/n)*Math::PI).round(p), x.round(p),
sum.round(p), Math::sin(sum).round(p)]
end
end
end
compute(36)
# radians x sum sin(sum) degrees
# [[0.0, 0.0, 0.0, 0.0 ], 0
# [0.174533, 0.173648, 0.173648, 0.172777],
# ...
# [1.396263, 0.045115, 0.984808, 0.833166],
# [1.570796, 0.015192, 1.0, 0.841471], 90
# [1.745329, -0.015192, 0.984808, 0.833166],
# ...
# [2.967060, -0.168372, 0.173648, 0.172777],
# [3.141593, -0.173648, 0.0, 0.0 ], 180
# [3.316126, -0.173648, -0.173648, -0.172777],
# ...
# [4.537856, -0.045115, -0.984808, -0.833166],
# [4.712389, -0.015192, -1.0, -0.841471], 270
# [4.886922, 0.015192, -0.984808, -0.833166],
# ...
# [5.934119, 0.15798, -0.34202, -0.335391],
# [6.108652, 0.168372, -0.173648, -0.172777]] 350
当我有时间熟悉@maeric 的漂亮绘图工具时,我将添加这些值的图表。
现在我们有了均值,我们可以考虑构建具有这些均值的概率分布。
假设,例如,我们假设每个随机变量具有相同的均匀分布,范围(最大-最小)为rng
,均值不同。如果平均值是 0.325467
,我们可以生成一个伪随机变量,如下所示:
rng * (rand-0.325467)
哪里
(0.5-0.174533).round(6)
#=> 0.325467
因此,我们可以为具有给定范围的均匀分布生成伪随机变量,均值如下:
def uniform_rv(rng, mean)
rng.to_f * (rand -0.5 -mean)
end