生成具有特定概率的数字视觉基础 vba
Generating numbers with certain probabilities visual basics vba
我有一些
的概率
26% 18% 26% 20% 10%
我想根据概率组生成一些数字(在一定范围内随机生成)
我之前用 80% 和 20% 的 2 个概率做过,如下所示:
If rnd*100 < 80 then Output = 2
Else output = 10
End if
但我不确定如何在超过 2 个概率的情况下做到这一点!
你可以做到非常相似。您可以利用 vba 的 switch case,而不是编写一个巨大的 if 子句:
Select (rnd*100)
Case 0 to 26:
' do prop 1
Case 26 to 44:
' do prop 2
Case 44 to 70:
' do prop 3
Case 70 to 90:
' do prop 4
Case 90 to 100:
' do prop 5
End Select
在[0,1]中生成一个随机数。开始添加概率(0.26、0.18 等)直到超过所选数字。一旦发生这种情况——选择范围内的相应数字。
下面的函数传递了两个数组(假设长度相同)。第一个包含要从中采样的项目范围(不必是数字),第二个数组是相应的概率:
Function RandItem(items As Variant, probs As Variant) As Variant
Dim i As Long, sum As Double
Dim spin As Double
spin = Rnd()
For i = LBound(probs) To UBound(probs)
sum = sum + probs(i)
If spin <= sum Then
RandItem = items(i)
Exit Function
End If
Next i
'if you get here:
RandItem = items(UBound(probs))
End Function
可以这样测试:
Sub test()
Randomize
Dim i As Long, v As Variant
ReDim v(1 To 50)
For i = 1 To 50
v(i) = RandItem(Array(1, 2, 3, 4, 5), Array(0.26, 0.18, 0.26, 0.2, 0.1))
Next i
Debug.Print Join(v)
End Sub
典型输出:
2 4 2 1 1 4 3 4 2 3 2 4 5 1 1 3 3 4 3 3 3 4 4 2 4 4 1 2 3 1 2 3 5 2 3 4 5 2 3 2 3 4 1 1 1 2 1 4 3 2
这是一个条形图,显示了 1000 个随机选择(使用相同的 5 个概率):
如您所见,它很好地匹配了目标概率。
您可以利用 Median()
函数的一个很好的特性,如下所示:
probs = Array(0.26, 0.18, 0.26, 0.2, 0.1)
vals = Array(1, 2, 3, 4, 5)
For i = 0 To UBound(probs) - 1
If prob = WorksheetFunction.Median(prob, probSum, probSum + probs(i)) Then Exit For
probSum = probSum + probs(i)
Next I
output = vals(i)
完整且(希望)优化的示例如下
Sub main()
Dim vals As Variant, probs As Variant, probsSum As Variant
Dim genVals(1 To 50) As Variant
Dim i As Long
probs = Array(0.26, 0.18, 0.26, 0.2, 0.1)
vals = Array(1, 2, 3, 4, 5)
probsSum = setSums(probs) '<~~ calculate the probs sum once for all!
For i = 1 To 50
Randomize'<~~ 'randomize' before picking a Rnd() if you need a different seed for each one
genVals(i) = GetVals(Rnd(), probsSum, vals)
Next i
End Sub
Function GetVals(prob As Double, probsSum As Variant, vals As Variant) As Variant
Dim i As Long
For i = 0 To UBound(probsSum) - 1
If prob = WorksheetFunction.Median(prob, probsSum(i), probsSum(i + 1)) Then Exit For
Next i
GetVals= vals(i)
End Function
Function setSums(arr As Variant) As Variant
Dim i As Long
ReDim sumArr(0 To UBound(arr) + 1)
sumArr(0) = 0
For i = 0 To UBound(arr)
sumArr(i + 1) = sumArr(i) + arr(i)
Next i
setSums = sumArr
End Function
这里有一个简单的方法来随机选择一个具有定义分布的值:
Dim values(), probabilities()
' define the values and the cumultated probabilities for 26% 18% 26% 20% 10%
values = VBA.Array("a", "b", "c", "d", "e")
probabilities = VBA.Array(0, 0.26, 0.44, 0.7, 0.9)
' generate one value
Debug.Print values(Application.Match(Rnd, probabilities) - 1)
我有一些
的概率26% 18% 26% 20% 10%
我想根据概率组生成一些数字(在一定范围内随机生成)
我之前用 80% 和 20% 的 2 个概率做过,如下所示:
If rnd*100 < 80 then Output = 2
Else output = 10
End if
但我不确定如何在超过 2 个概率的情况下做到这一点!
你可以做到非常相似。您可以利用 vba 的 switch case,而不是编写一个巨大的 if 子句:
Select (rnd*100)
Case 0 to 26:
' do prop 1
Case 26 to 44:
' do prop 2
Case 44 to 70:
' do prop 3
Case 70 to 90:
' do prop 4
Case 90 to 100:
' do prop 5
End Select
在[0,1]中生成一个随机数。开始添加概率(0.26、0.18 等)直到超过所选数字。一旦发生这种情况——选择范围内的相应数字。
下面的函数传递了两个数组(假设长度相同)。第一个包含要从中采样的项目范围(不必是数字),第二个数组是相应的概率:
Function RandItem(items As Variant, probs As Variant) As Variant
Dim i As Long, sum As Double
Dim spin As Double
spin = Rnd()
For i = LBound(probs) To UBound(probs)
sum = sum + probs(i)
If spin <= sum Then
RandItem = items(i)
Exit Function
End If
Next i
'if you get here:
RandItem = items(UBound(probs))
End Function
可以这样测试:
Sub test()
Randomize
Dim i As Long, v As Variant
ReDim v(1 To 50)
For i = 1 To 50
v(i) = RandItem(Array(1, 2, 3, 4, 5), Array(0.26, 0.18, 0.26, 0.2, 0.1))
Next i
Debug.Print Join(v)
End Sub
典型输出:
2 4 2 1 1 4 3 4 2 3 2 4 5 1 1 3 3 4 3 3 3 4 4 2 4 4 1 2 3 1 2 3 5 2 3 4 5 2 3 2 3 4 1 1 1 2 1 4 3 2
这是一个条形图,显示了 1000 个随机选择(使用相同的 5 个概率):
如您所见,它很好地匹配了目标概率。
您可以利用 Median()
函数的一个很好的特性,如下所示:
probs = Array(0.26, 0.18, 0.26, 0.2, 0.1)
vals = Array(1, 2, 3, 4, 5)
For i = 0 To UBound(probs) - 1
If prob = WorksheetFunction.Median(prob, probSum, probSum + probs(i)) Then Exit For
probSum = probSum + probs(i)
Next I
output = vals(i)
完整且(希望)优化的示例如下
Sub main()
Dim vals As Variant, probs As Variant, probsSum As Variant
Dim genVals(1 To 50) As Variant
Dim i As Long
probs = Array(0.26, 0.18, 0.26, 0.2, 0.1)
vals = Array(1, 2, 3, 4, 5)
probsSum = setSums(probs) '<~~ calculate the probs sum once for all!
For i = 1 To 50
Randomize'<~~ 'randomize' before picking a Rnd() if you need a different seed for each one
genVals(i) = GetVals(Rnd(), probsSum, vals)
Next i
End Sub
Function GetVals(prob As Double, probsSum As Variant, vals As Variant) As Variant
Dim i As Long
For i = 0 To UBound(probsSum) - 1
If prob = WorksheetFunction.Median(prob, probsSum(i), probsSum(i + 1)) Then Exit For
Next i
GetVals= vals(i)
End Function
Function setSums(arr As Variant) As Variant
Dim i As Long
ReDim sumArr(0 To UBound(arr) + 1)
sumArr(0) = 0
For i = 0 To UBound(arr)
sumArr(i + 1) = sumArr(i) + arr(i)
Next i
setSums = sumArr
End Function
这里有一个简单的方法来随机选择一个具有定义分布的值:
Dim values(), probabilities()
' define the values and the cumultated probabilities for 26% 18% 26% 20% 10%
values = VBA.Array("a", "b", "c", "d", "e")
probabilities = VBA.Array(0, 0.26, 0.44, 0.7, 0.9)
' generate one value
Debug.Print values(Application.Match(Rnd, probabilities) - 1)