Генерация коррелированных чисел
вот забавный: мне нужно генерировать случайные пары x/y, которые коррелируют при заданном значении коэффициент корреляции момента продукта Pearson или Pearson r. Вы можете представить это как два массива, массив X и массив Y, где значения массива X и массива Y должны быть сгенерированы, упорядочены или преобразованы до тех пор, пока они не будут коррелированы друг с другом на заданном уровне Пирсона r. Вот Кикер: массив X и массив Y должны быть равномерными распределениями.
I можно сделать это с нормальным распределением, но преобразование значений без искажения распределения ставит меня в тупик. Я попытался переупорядочить значения в массивах, чтобы увеличить корреляцию, но я никогда не получу массивы, коррелированные в 1.00 или -1.00 просто сортировкой.
какие идеи?
--
вот код AS3 для случайных коррелированных гауссов, чтобы заставить колеса вращаться:
public static function nextCorrelatedGaussians(r:Number):Array{
var d1:Number;
var d2:Number;
var n1:Number;
var n2:Number;
var lambda:Number;
var r:Number;
var arr:Array = new Array();
var isNeg:Boolean;
if (r<0){
r *= -1;
isNeg=true;
}
lambda= ( (r*r) - Math.sqrt( (r*r) - (r*r*r*r) ) ) / (( 2*r*r ) - 1 );
n1 = nextGaussian();
n2 = nextGaussian();
d1 = n1;
d2 = ((lambda*n1) + ((1-lambda)*n2)) / Math.sqrt( (lambda*lambda) + (1-lambda)*(1-lambda));
if (isNeg) {d2*= -1}
arr.push(d1);
arr.push(d2);
return arr;
}
6 ответов
Я закончил писать короткая статья об этом
Он не включает ваш метод сортировки (хотя на практике я думаю, что он похож на мой первый метод, окольным путем), но описывает два способа, которые не требуют итерации.
вот реализация алгоритма twolfe18, написанного в Actionscript 3:
for (var j:int=0; j < size; j++) {
xValues[i]=Math.random());
}
var varX:Number = Util.variance(xValues);
var varianceE:Number = 1/(r*varX) - varX;
for (var i:int=0; i < size; i++) {
yValues[i] = xValues[i] + boxMuller(0, Math.sqrt(varianceE));
}
boxMuller
- это просто метод, который генерирует случайный гауссовский с аргументами (mean, stdDev).
size
- это размер дистрибутива.
пример вывода
Target p: 0.8
Generated p: 0.04846346291280387
variance of x distribution: 0.0707786253165176
varianceE: 17.589920412141158
как вы можете видеть, я все еще далеко. Есть предложения?
этот, по-видимому, простой вопрос путался у меня в голове со вчерашнего вечера! Я искал тему моделирования распределений с зависимостью, и лучшее, что я нашел это: имитировать зависимые случайные величины. Суть в том, что вы можете легко имитировать 2 нормали с заданной корреляцией, и они описывают метод преобразования этих не независимых нормалей, но это не сохранит корреляцию. Корреляция преобразования будет коррелирована, так чтобы говорите, но не идентично. См. пункт "коэффициенты ранговой корреляции".
Edit: из того, что я получаю из второй части статьи, метод copula позволит вам моделировать / генерировать случайные величины с ранговой корреляцией.
начнем с модели y = x + e
здесь e
ошибка (нормальная случайная величина). e
должно иметь среднее значение 0 и дисперсию k.
короче говоря, вы можете написать формулу для ожидаемого значения Пирсона в терминах k и решить для k. обратите внимание, что вы не можете случайным образом генерировать данные с Pearson, точно равным определенному значению, только с ожидаемым Pearson определенного значения.
я постараюсь вернуться и отредактировать этот пост, чтобы включить решение закрытой формы, когда у меня есть доступ к какой-то бумаге.
EDIT: хорошо, у меня есть ручное волнистое решение, которое, вероятно, правильно (но потребует тестирования для подтверждения). теперь предположим, что желаемое Pearson = p > 0
(вы можете выяснить p < 0
case). как я уже упоминал ранее, установите модель для Y = X + E
(X
равномерна, E
это нормально).
- образец, чтобы получить ваши x
- вычислить var (x)
- дисперсия E должна быть:
(1/(rsd(x)))^2 - var(x)
- создайте y на основе ваших x и образца из вашей обычной случайной величины
E
на p < 0
, set Y = -X + E
. действуйте соответственно.
в основном это следует из определения Пирсона: cov(x,y)/var(x)*var(y). когда вы добавляете шум к x (Y = X + E
), ожидаемая ковариация cov(x,y) не должна меняться от этого без шума. var (x) не изменяется. var (y) - сумма var(x) и var(e), следовательно, моя решение.
второе редактирование: хорошо, мне нужно лучше читать определения. определение слова Pearson является cov(x, y)/(sd (x)sd (y)). из этого я думаю, что истинное значение var (E) должно быть (1/(rsd(x)))^2 - var (x). посмотрим, сработает ли это.
чтобы получить корреляцию 1, оба X и Y должны быть одинаковыми, поэтому скопируйте X в Y, и у вас есть корреляция 1. Чтобы получить корреляцию -1, сделайте Y = 1-X. (предполагая, что значения X равны [0,1])
- генерация массива X
- клонировать массив X для создания массива Y
- сортировка массива X (вы можете использовать любой метод сортировки массива X -- quicksort, heapsort что-либо стабильное.)
- измерьте начальный уровень R Пирсона с отсортированным массивом X и несортированным массивом Y.
WHILE the correlation is outside of the range you are hoping for
IF the correlation is to low
run one iteration of CombSort11 on array Y then recheck correlation
ELSE IF the correlation is too high
randomly swap two values and recheck correlation
и вот оно! Combsort является реальным ключом, он имеет эффект увеличения корреляция медленно и неуклонно. Проверьте демо Джейсона Харрисона чтобы увидеть, что я имею в виду. Чтобы получить отрицательную корреляцию, вы можете инвертировать сортировку или инвертировать один из массивов после завершения всего процесса.
вот моя реализация в AS3:
public static function nextReliableCorrelatedUniforms(r:Number, size:int, error:Number):Array {
var yValues:Array = new Array;
var xValues:Array = new Array;
var coVar:Number = 0;
for (var e:int=0; e < size; e++) { //create x values
xValues.push(Math.random());
}
yValues = xValues.concat();
if(r != 1.0){
xValues.sort(Array.NUMERIC);
}
var trueR:Number = Util.getPearson(xValues, yValues);
while(Math.abs(trueR-r)>error){
if (trueR < r-error){ // combsort11 for y
var gap:int = yValues.length;
var swapped:Boolean = true;
while (trueR <= r-error) {
if (gap > 1) {
gap = Math.round(gap / 1.3);
}
var i:int = 0;
swapped = false;
while (i + gap < yValues.length && trueR <= r-error) {
if (yValues[i] > yValues[i + gap]) {
var t:Number = yValues[i];
yValues[i] = yValues[i + gap];
yValues[i + gap] = t;
trueR = Util.getPearson(xValues, yValues)
swapped = true;
}
i++;
}
}
}
else { // decorrelate
while (trueR >= r+error) {
var a:int = Random.randomUniformIntegerBetween(0, size-1);
var b:int = Random.randomUniformIntegerBetween(0, size-1);
var temp:Number = yValues[a];
yValues[a] = yValues[b];
yValues[b] = temp;
trueR = Util.getPearson(xValues, yValues)
}
}
}
var correlates:Array = new Array;
for (var h:int=0; h < size; h++) {
var pair:Array = new Array(xValues[h], yValues[h]);
correlates.push(pair);}
return correlates;
}