Ну не действительно RANDBETWEEN()
. Я пытаюсь создать UDF, чтобы вернуть индекс числа в массив, где чем больше число, тем вероятнее, что он будет выбран.
Я знаю, как назначать вероятности случайным числам на листе (т.е. используя MATCH()
в сумме вероятностей, там много материала на SO, объясняющем это), но я хочу UDF, потому что я передаю специальный входной массив в функцию - не только выбранный диапазон.
Моя проблема в том, что взвешивание выключено, более вероятно, что числа, полученные позже в массиве, будут возвращены, чем предыдущие в массиве, и я не вижу, где в моем коде я ошибался. Здесь UDF пока:
Public Function PROBABLE(ParamArray inputArray() As Variant) As Long
'Takes a set of relative or absolute probabilities and ranks a random number within them
Application.Volatile (True)
Dim outputArray() As Variant
Dim scalar As Single
Dim rankNum As Single
Dim runningTot As Single
'''''
'Here I take inputArray() and convert to outputArray(),
'which is fed into the probability code below
'''''
scalar = 1 / WorksheetFunction.Sum(outputArray)
rankNum = Rnd()
runningTot = 0
For i = 0 To UBound(outputArray)
runningTot = runningTot + outputArray(i)
If runningTot * scalar >= rankNum Then
PROBABLE = i + 1
Exit Function
End If
Next i
End Function
Функция должна смотреть на относительные размеры чисел в outputArray()
и выбирать случайным образом, но взвешивать по отношению к большему числу.
Например. outputArray()
of {1,0,0,1}
должен присваивать вероятности соответственно {50%,0%,0%,50%}
. Однако, когда я тестировал, что outputArray()
, для 1000 выборок и 100 итераций, и нарисовал, как часто возвращался элемент 1 или элемент 4 в массиве, я получил этот результат:
Примерно 20%: 80% распределения. График {1,1,1,1}
(все должны иметь равный шанс) дал 10%: 20%: 30%: 40% распределение
Я знаю, что мне не хватает чего-то очевидного, но я не могу сказать, что, любая помощь?
UPDATE
Некоторые люди спрашивали полный код, вот он.
Public Function PROBABLE(ParamArray inputArray() As Variant) As Long
'Takes a set of relative or absolute probabilities and ranks a random number within them
Application.Volatile (True) 'added some dimensions up here
Dim outputArray() As Variant
Dim inElement As Variant
Dim subcell As Variant
Dim scalar As Single
Dim rankNum As Single
Dim runningTot As Single
'convert ranges to values
'creating a new array from the mixture of ranges and values in the input array
''''
'This is where I create outputArray() from inputArray()
''''
ReDim outputArray(0)
For Each inElement In inputArray
'Normal values get copied from the input UDF to an output array, ranges get split up then appended
If TypeName(inElement) = "Range" Or TypeName(inElement) = "Variant()" Then
For Each subcell In inElement
outputArray(UBound(outputArray)) = subcell
ReDim Preserve outputArray(UBound(outputArray) + 1)
Next subcell
'Stick the element on the end of an output array
Else
outputArray(UBound(outputArray)) = inElement
ReDim Preserve outputArray(UBound(outputArray) + 1)
End If
Next inElement
ReDim Preserve outputArray(UBound(outputArray) - 1)
''''
'End of new code, the rest is as before
''''
scalar = 1 / WorksheetFunction.Sum(outputArray)
rankNum = Rnd()
runningTot = 0
For i = 0 To UBound(outputArray)
runningTot = runningTot + outputArray(i)
If runningTot * scalar >= rankNum Then
PROBABLE = i + 1
Exit Function
End If
Next i
End Function
Начальный раздел inputArray()
🡒 outputArray()
используется для стандартизации различных методов ввода. То есть пользователь может ввести смесь значений, ссылок/диапазонов ячеек и массивов, и функция может справиться. например {=PROBABLE(A1,5,B1:C15,IF(ISTEXT(D1:D3),LEN(D1:D3),0))}
(вы получаете изображение) должен работать так же хорошо, как =PROBABLE(A1:A3)
. Я просматриваю подэлементы inputArray() и помещаю их в свой outputArray(). Я вполне уверен, что с этой частью кода ничего не случилось.
Затем, чтобы получить мои результаты, я скопировал UDF в A1:A1000
, использовал COUNTIF(A1:A1000,1)
или вместо count 1, я сделал счет 2, 3, 4 и т.д. для каждого из возможных выходов UDF и сделал короткий макрос пересчитать лист 100 раз, каждый раз копируя результат countif в таблицу на график. Я не могу точно сказать, как я это сделал, потому что я оставил все это на работе, но я обновлю в понедельник.