9

这是一个有趣的:我需要生成随机 x/y 对,它们在Pearson 乘积矩相关系数或 Pearson r的给定值下相关。您可以将其想象为两个数组,数组 X 和数组 Y,其中数组 X 和数组 Y 的值必须重新生成、重新排序或转换,直到它们在给定的 Pearson r 水平上相互关联。这是踢球者:数组 X 和数组 Y 必须是均匀分布。

我可以用正态分布来做到这一点,但是在不扭曲分布的情况下转换值让我很难过。我尝试对数组中的值重新排序以增加相关性,但我永远不会仅仅通过排序就得到 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;
    }
4

6 回答 6

6

我最终为此写了一篇短文

它不包括您的排序方法(尽管在实践中我认为它类似于我的第一种方法,以一种迂回的方式),但确实描述了两种不需要迭代的方法。

于 2009-11-22T22:33:23.637 回答
1

从模型开始,误差y = x + e在哪里(一个正常的随机变量)。均值应为 0,方差为 k。ee

长话短说,你可以用 k 写出 Pearson 期望值的公式,然后求解 k。请注意,您不能随机生成 Pearson 完全等于特定值的数据,只能使用特定值的预期 Pearson。

当我可以访问一些论文时,我会尝试回来编辑这篇文章以包含一个封闭形式的解决方案。

编辑:好的,我有一个可能是正确的手动解决方案(但需要测试确认)。现在,假设需要Pearson = p > 0(你可以弄清楚p < 0情况)。就像我之前提到的,将您的模型设置为Y = X + EX是统一的,E是正常的)。

  1. 样品得到你的 x
  2. 计算 var(x)
  3. E 的方差应该是:(1/(rsd(x)))^2 - var(x)
  4. 根据您的 x 生成您的 y,并从您的正常随机变量中采样E

p < 0,设置Y = -X + E。相应地进行。

基本上,这遵循 Pearson 的定义: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/(r sd(x)))^2 - var(x)。看看这是否有效。

于 2009-11-11T21:19:53.790 回答
1

下面是用 Actionscript 3 编写的 twolfe18 算法的实现:

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只是一种使用参数(均值,stdDev)生成随机高斯的方法。 size是分布的大小。

样本输出

Target p: 0.8
Generated p: 0.04846346291280387
variance of x distribution: 0.0707786253165176
varianceE: 17.589920412141158

正如你所看到的,我还有很长的路要走。有什么建议么?

于 2009-11-12T05:51:42.367 回答
1

从昨天晚上开始,这个看似简单的问题就一直困扰着我!我寻找了模拟具有依赖关系的分布的主题,我发现最好的是:模拟依赖随机变量。它的要点是,您可以轻松地模拟具有给定相关性的 2 个法线,并且它们概述了一种转换这些非独立法线的方法,但这不会保留相关性。可以说,变换的相关性将是相关的,但并不完全相同。请参阅“等级相关系数”段落。

编辑:根据我从文章第二部分收集的信息,copula 方法将允许您模拟/生成具有等级相关性的随机变量。

于 2009-11-12T18:15:53.327 回答
1

要获得 1 的相关性,X 和 Y 应该相同,因此将 X 复制到 Y 并且您有 1 的相关性。要获得 -1 相关性,使 Y = 1 - X。(假设 X 值为 [0, 1])

于 2009-11-17T20:12:08.807 回答
1

一个奇怪的问题需要一个奇怪的解决方案——这就是我解决它的方法。

- 生成数组 X

- 克隆数组 X 以创建数组 Y

- 对数组 X 进行排序(你可以使用任何你想对数组 X 进行排序的方法——快速排序、堆排序任何稳定的东西。)

- 测量 pearson's 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是真正的关键,它具有缓慢而稳定地增加相关性的效果。查看Jason Harrison 的演示,了解我的意思。要获得负相关,您可以在整个过程完成后反转排序或反转数组之一。

这是我在 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;
    }
于 2009-11-19T20:35:33.960 回答