對於模擬研究,我必須生成隨機變量,這些變量顯示與現有變量 $ Y $ span>的預定義(填充)相關性。
我研究了 R
軟件包 copula
和 CDVine
,它們可以產生具有給定依賴關係結構的隨機多變量分佈。但是,不可能將結果變量之一固定為現有變量。
任何想法和指向現有功能的鏈接都將受到讚賞!
結論:提出了兩個有效答案,但有不同的解決方案:
對於模擬研究,我必須生成隨機變量,這些變量顯示與現有變量 $ Y $ span>的預定義(填充)相關性。
我研究了 R
軟件包 copula
和 CDVine
,它們可以產生具有給定依賴關係結構的隨機多變量分佈。但是,不可能將結果變量之一固定為現有變量。
任何想法和指向現有功能的鏈接都將受到讚賞!
結論:提出了兩個有效答案,但有不同的解決方案:
這裡是另一個:對於均值為0的向量,它們的相關性等於其角度的餘弦值。因此,找到具有恰好所需的相關度$ r $的向量$ x $的一種方法,對應於角度$ \ theta $:
這是代碼:
n <- 20#vectorrho的長度<- 0.6#所需相關性= cos(角度)θ<- acos(rho)#對應角度x1 <- rnorm(n,1,1)#固定給定數據x2 <- rnorm(n,2,0.5)#新隨機數據X < -cbind(x1,x2)#matrixXctr <- scale(X,center = TRUE,scale = FALSE)#居中列(平均0)Id <- diag(n)#單位矩陣Q <- qr.Q(qr(Xctr [ ,1,drop = FALSE]))#QR分解,僅矩陣QP <- tcrossprod(Q)#= QQ'#投影到由x1x2o定義的空間<-(Id-P)%*%Xctr [,2]#使x2ctr正交於x1ctrXc2 <- cbind(Xctr [,1],x2o)#綁定到matrixY <- Xc2%*%diag(1 / sqrt(colSums(Xc2 ^ 2)))#將列縮放為長度1x <- Y [,2] +(1 / tan(theta))* Y [,1 ]#最終新向量
cor(x1,x)#檢查相關性= rho
對於正交投影$ P $,我使用了$ QR $分解來改進數值穩定性,從那時起,只需$ P = Q Q'$。
I將描述最通用的解決方案。解決這種普遍性的問題使我們可以實現非常緊湊的軟件實現:僅需兩行 R
代碼即可。
選擇向量 $ X $ span>,其長度與 $ Y $ span>,根據您喜歡的任何分佈。讓 $ Y ^ \ perp $ span>是 $ X $ span>對 $ Y $ span>:這會從 $ Y $ span>組件span class =“ math-container”> $ X $ span>。通過將 $ Y $ span>的適當倍數加回 $ Y ^ \ perp $ span>,我們可以生成一個向量具有 $ \ rho $ span>與 $ Y $ span>的任何期望的相關性。最多可以有一個任意的加法常數和正乘法常數(您可以通過任何方式自由選擇),解決方案是
$$ X_ {Y; \ rho} = \ rho \,\ operatorname {SD}(Y ^ \ perp)Y + \ sqrt {1- \ rho ^ 2} \,\ operatorname {SD}(Y)Y ^ \ perp。$$ span>
(“ $ \操作員名稱{SD} $ span>”表示與標準偏差成比例的任何計算。)
這裡是有效的 R
代碼。如果您不提供 $ X $ span>,則代碼將從多元標準正態分佈中提取其值。
互補<-函數(y,rho,x){
if(missing(x))x <- rnorm(length(y))#可選:如果未指定`x',則提供默認值
y.perp <-殘差(lm(x〜y))
rho * sd(y.perp)* y + y.perp * sd(y)* sqrt(1-rho ^ 2)
}
為了說明,我生成了一個隨機的 $ Y $ span>和 $ 50 $ span>組件,並生成了 $ X_ {Y; \ rho} $ span>與此 $ Y $ span>具有各種指定的相關性。它們都是使用相同的起始向量 $ X =(1,2,\ ldots,50)$ span>創建的。這是他們的散點圖。每個面板底部的“地毯”顯示常見的 $ Y $ span>向量。
劇情之間有明顯的相似之處,不是:-)。
如果您想嘗試,這裡是產生這些數據和圖形的代碼。 (我並不在意自由地移動和縮放結果,這很容易操作。)
y <- rnorm(50,sd = 10)
x <- 1:50#可選
rho <- seq(0,1,length.out = 6)* rep(c(-1,1),3)
X <- data.frame(z = as.vector(sapply(rho,function(rho)complement(y,rho,x))),
rho = ordered(rep(signif(rho,2),each = length(y))),
y = rep(y,length(rho)))
庫(ggplot2)
ggplot(X,aes(y,z,group = rho))+
geom_smooth(method =“ lm”,color =“ Black”)+
geom_rug(sides =“ b”)+
geom_point(aes(fill = rho),alpha = 1/2,shape = 21)+
facet_wrap(〜rho,scales =“ free”)
順便說一句,此方法很容易推廣到多個 $ Y $ span>:如果在數學上可行,它將找到一個 $ X_ {Y_1,Y_2,\ ldots,Y_k; \ rho_1,\ rho_2,\ ldots,\ rho_k} $ span>已指定與整個 $ Y_i $的關聯 span>。只需使用普通最小二乘法從 $ X $ span>和形式中取出所有 $ Y_i $ span>的效果 $ Y_i $ span>和殘差的合適線性組合。 (這有助於對 $ Y $ span>進行對偶運算,這是通過計算偽逆獲得的。下面的代碼使用 $ Y $ span>即可實現。)
這是 R
中算法的草圖,其中 $ Y_i $ span>作為矩陣 y
:
y <- scale(y)#使計算更簡單
e <-residuals(lm(x〜y))#取出矩陣y的列
y.dual <- with(svd(y),(n-1)* u%*%diag(ifelse(d > 0,1 / d,0))%*%t(v))
sigma2 <- c((1- rho%*%cov(y.dual)%*%rho)/ var(e))
返回(y.dual%*%rho + sqrt(sigma2)* e)
另一個線程提供了每行代碼的詳細說明。對於想嘗試的人來說,以下是更完整的實現。
互補<-函數(y,rho,x,threshold = 1e-12){
#
#處理參數。
#
if(!is.matrix(y))y <- matrix(y,ncol = 1)
d <col(y)
n <-row(y)
y <- scale(y,center = FALSE)#使計算更簡單
如果(missing(x))x <- rnorm(n)
#
#刪除y對x的影響。
#
e <-殘差(lm(x〜y))
#
#計算e的係數sigma,使
#線性組合為y的y.dual是%*%rho + sigma * e
#矢量。
#
y.dual <- with(svd(y),(n-1)* u%*%diag(ifelse(d > threshold,1 / d,0))%*%t(v))
sigma2 <- c((1- rho%*%cov(y.dual)%*%rho)/ var(e))
#
#返回此線性組合。
#
如果(sigma2 > = 0){
sigma <- sqrt(sigma2)
z <- y.dual%*%rho + sigma * e
}其他{
警告(“無法進行關聯。”)
z <- rep(0,n)
}
返回(z)
}
#
#設置問題。
#
d <- 3#給定變量的數量
n <- 50#所有向量的維數
x <- 1:n#可選:指定`x`或從任何分佈中繪製
y <- matrix(rnorm(d * n),ncol = d)#以任何方式創建`d`原始變量
rho <- c(0.5,-0.5,0)#指定相關性
#
#驗證結果。
#
z <-補碼(y,rho,x)
cbind('實際相關'= cor(y,z),
“目標相關性” = rho)
#
#顯示它們。
#
colnames(y)<- paste0(“ y。”,1:d)
colnames(z)<-“ z”
對(cbind(z,y))
這是另一種計算方法(該解決方案摘自Enrico Schumann的論壇帖子)。根據Wolfgang(參見註釋),這在計算上與ttnphns提出的解決方案相同。
與caracal的解決方案相反,它不會產生具有$ \ rho $確切相關性的樣本,而是產生兩個人口相關性等於$ \ rho $的向量。 / p>
以下函數可以計算從具有給定$ \ rho $的總體得出的雙變量樣本分佈。它要么計算兩個隨機變量,要么使用一個現有變量(作為參數 x
傳遞)並創建具有所需相關性的第二個變量:
#返回數據與rho#的總體相關性相關的兩個變量的框架。如果需要,可以通過指定xgetBiCop <-function(n,rho,mar.fun = rnorm,x = NULL,..將兩個變量之一固定到現有變量。 。){if(!is.null(x)){X1 <- x}否則{X1 <- mar.fun(n,...)} if(!is.null(x)& length(x)! = n)警告(“變量x與n的長度不同!”)C <-matrix(rho,nrow = 2,ncol = 2)diag(C)<-1 C <- chol(C)X2 < -mar.fun(n)X <- cbind(X1,X2)#誘導相關性(不改變X1)df <- X%*%C ##如果需要的話:檢查結果#all.equal(X1,X [, 1])#cor(X)return(df)}
該函數還可以通過調整參數 mar.fun
來設置非正態的邊際分佈。但是請注意,僅修復一個變量 似乎可以與正態分佈的變量 x
一起使用! (可能與Macro的評論有關)。
還請注意,原始帖子中的“小修正因子”已被刪除,因為它似乎使所產生的相關性產生偏差,至少在高斯分佈和Pearson相關的情況(另請參見註釋)。
讓$ X $為您的固定變量,並且您想生成與$ X $相關的$ Y $變量,金額為$ r $。如果$ X $是標準化的,則(因為$ r $是簡單回歸中的beta係數)$ Y = rX + E $,其中$ E $是來自正態分佈的均值$ 0 $和$ \ text {sd} = \的隨機變量sqrt {1-r ^ 2} $。在$ X $和$ Y $數據之間觀察到的相關性約為$ r $;現在,可以將$ X $和$ Y $視為來自具有$ \ rho = r $的雙變量正常人口(如果$ X $來自正常)的隨機樣本。
現在,如果要在二元樣本恰好 $ r $中獲得相關性,則需要提供$ E $與$ X $具有零相關性。可以通過迭代修改$ E $來將其收緊為零。好吧,只有兩個變量,一個給定($ X $)和一個要生成($ Y $),足夠的迭代次數實際上是1,但是有多個給定變量($ X_1,X_2,X_3,... $
應注意,如果$ X $正常,則在第一個過程(“近似$ r $”)中,$ Y $也將正常。但是,將$ Y $迭代擬合為“精確的$ r $” $ Y $可能會失去正態性,因為該擬合有選擇地利用了案例值。
更新 2017年11月11日。我今天遇到了這個老話題,並決定通過顯示最初討論的迭代擬合算法來擴大答案。
這是一個迭代解決方案,如何訓練一個隨機模擬的或已有的變量 $ Y $ 以精確地關聯或協變量(或非常接近,具體取決於迭代次數)給定變量 $ X $ s(無法修改)。
Disclamer:我發現此迭代解決方案不如優秀解決方案,它基於今天在此線程中找到@whuber的雙重基礎和提議。 @whuber的解決方案不是迭代的,對我來說更重要的是,它似乎對輸入的“ pig”變量的值產生的影響要比“ my”算法的影響小(如果任務是“更正”,這將是一種資產)現有變量,而不是從頭開始生成隨機變量)。儘管如此,我還是出於好奇而發布我的,因為它可以工作(另請參見腳註)。
因此,我們給了(固定的)變量$ X_1,X_2,...,X_m $ ,以及變量$ Y $,它要么是隨機生成的“豬”值,要么是一個存在的數據變量,需要對其進行“校正”,以使$ Y $準確地用於相關性(或可以是協方差)$ r_1, r_2,...,r_m $和$ X $ s。所有數據必須連續;換句話說,應該有很多唯一值。
這個想法:對殘差進行迭代擬合。知道了想要的(目標)相關性/協方差後,我們可以使用$ X $ s作為多個線性預測變量來計算$ Y $的預測值。在獲得初始殘差(根據當前的$ Y $和理想的預測)後,迭代地訓練它們,使其不與預測變量相關。最後,用殘差重新獲得$ Y $。 (該程序是我多年以前對車輪的實驗性發明,當時我不了解該原理;然後在SPSS中對其進行了編碼。)
轉換目標$ r $ s將乘積乘以$ \ text {df} = n-1 $可以得出乘積和:$ S_j = r_j \ text {df} $。 ($ j $是$ X $變量索引。)
Z對所有變量進行Z標準化(每個變量居中,然後除以對$ \之上的值計算的st。偏差。文字{df} $)。因此,$ Y $和$ X $ s是標準的。現在,可觀察到的平方和為= $ \ text {df} $。
根據目標$ r $ s計算預測$ Y $ x $$的回歸係數: $ \ bf b =(X'X)^ {-1} S $。
計算$ Y $的預測值:$ \ hat {Y} = \ bf Xb $。
計算殘差$ E = Y- \ hat { Y} $。
計算殘差所需的(目標)平方和:$ SS_S = \ text {df} -SS _ {\ hat {Y}} $。
(開始迭代。)計算觀察到的當前$ E $與每個$ X_j $之間的叉積之和:$ C_j = \ sum_ {i = 1} ^ n E_i X_ { ij} $
正確的$ E $值,目的是使所有$ C $接近$ 0 $($ i $是一個案例索引):
$$ E_i [\ text {corrected}] = E_i- \ frac {\ sum_ {j = 1} ^ m C_j X_ {ij}} {n \ sum_ {j = 1} ^ m X_ {ij} ^ 2} $$
(分母在迭代中不會改變,需要預先計算)
或者,更有效的公式還可以確保$ E $的均值變成$ 0 $。首先,在步驟7中在每次迭代之前對$ C $ s進行 center $ E $的計算,然後在步驟8上更正為: {corrected}] = E_i- \ frac {\ sum_ {j = 1} ^ m \ frac {C_j X_ {ij} ^ 3} {\ sum_ {i = 1} ^ n X_ {ij} ^ 2}} {\ sum_ {j = 1} ^ m X_ {ij} ^ 2} $$
(同樣,分母是已知的)$ ^ 1 $
將$ SS_E $設為目標值:$ E_i [\ text {corrected}] = E_i \ sqrt {SS_S / SS_E} $
轉到步驟7。(例如,執行10-20次迭代如果目標$ r $ s是現實的,則$ SS_S $是正數,並且如果樣本量$ n $不是太少,則迭代總是直接收斂。 。)
就緒:現在所有$ C $ s幾乎都為零,這意味著已經訓練了殘差$ E $以恢復目標$ r $ s。計算擬合的$ Y $:$ Y [\ text {corrected}] = \ hat {Y} + E $。
獲得的$ Y $幾乎是標準化的。最後,您可能希望對其進行精確的標準化,就像在步驟2一樣。
您可以為$ Y $提供任何您喜歡的方差和平均值。實際上,在四個統計數據中- min , max ,平均值, st。 dev 。 -您可以選擇任意兩個值,並對變量進行線性變換,以使其在不改變您獲得的$ r $ s(相關性)的情況下進行擺放(這全稱為線性縮放)。
再次警告上述內容。通過將$ Y $精確地拉到$ r $,輸出$ Y $不必正態分佈。
$ ^ 1 $校正公式可以更複雜,例如例如,在每一個$ X $上同時確保$ Y $的更大的純正隨機性(以平方和表示),同時獲得相關性,-I也為此實現了代碼。 (我不知道這種“雙重”任務是否可以通過更整潔的,非迭代的方法,例如 whuber的方法來解決。)
我想做一些編程工作,所以我接受了@Adam刪除的答案,並決定在R中編寫一個不錯的實現。我專注於使用面向函數的樣式(即lapply樣式循環)。總體思路是採用兩個向量,將其中一個向量隨機置換,直到它們之間達到一定的相關性為止。這種方法蠻力的,但是易於實現。
首先我們創建一個隨機排列輸入向量的函數:
randomly_permute = function(vec)vec [sample.int(length(vec))] randomly_permute(1:100)[1] 71 34 8 98 3 86 28 37 5 47 88 35 43 100 68 58 67 82 [19] 13 9 61 10 94 29 81 63 14 48 76 6 78 91 74 69 18 12 [37] 1 97 49 66 44 40 65 59 31 54 90 36 41 93 24 11 77 85 [55] 32 79 84 15 89 45 53 22 17 16 92 55 83 42 96 72 21 95 [73] 33 20 87 60 38 7 4 52 27 2 80 99 26 70 50 75 57 19 [91] 73 62 23 25 64 51 30 46 56 39
...和創建一些示例數據
vec1 = runif(100)vec2 = runif(100)
...編寫一個置換輸入向量的函數,然後將其與參考向量相關聯:
permute_and_correlate = function(vec,reference_vec){perm_vec = random_permute(vec)cor_value = cor(perm_ vec,reference_vec)return(list(vec = perm_vec,cor = cor_value))} permute_and_correlate(vec2,vec1)$ vec [1] 0.79072381 0.23440845 0.35554970 0.95114398 0.77785348 0.74418811 [7] 0.47871491 0.55981826 0.08801319 0.360.339760 0.14830718 0.40796732 0.67532970 [19] 0.71901990 0.52031017 0.41357545 0.91780357 0.82437619 0.89799621 [25] 0.07077250 0.12056045 0.46456652 0.21050067 0.30868672 0.55623242 [31] 0.84776853 0.57217746 0.08626022 0.71740151 0.87959539 0.82931652 3983 0.93980.99 389.00
[43] 0.29254936 0.02674156 0.77182339 0.30047034 0.91790830 0.45862163 [49] 0.27077191 0.74445997 0.34622648 0.58727094 0.92285322 0.83244284 [55] 0.61397396 0.40616274 0.32203732 0.84003379 0.81109473 0.50573325 [61] 0.86719899 0.4303 0.80.10.12 09840.9160.88983 0.86170.38940.11 12803998 0.123826901 0.882938940.11 293869098162431280 0.83349287 0.46724807 0.15345334 0.60854785 [79] 0.78854984 0.95770015 0.89193212 0.18885955 0.34303707 0.87332019 [85] 0.08890968 0.22376395 0.02641979 0.43377516 0.58667068 0.22736077 [91] 0.75948043 0.49734797 0.25235660 0.40125309 0.72147500 0.979230.7772> pre> ...並重複一千次:
n_iterations = lapply(1:1000,function(x)permute_and_correlate(vec2,vec1))
> 請注意,R的作用域規則確保在全局環境中匿名fu之外找到 vec1
和 vec2
上面使用的功能。因此,排列都與我們生成的原始測試數據集有關。
接下來,我們找到最大的相關性:
cor_values = sapply(n_iterations,'[[','cor')n_iterations [[which.max(cor_values)] ] $ vec [1] 0.89799621 0.67532970 0.46456652 0.75948043 0.30868672 0.83244284 [7] 0.86719899 0.55623242 0.63877904 0.73996913 0.71901990 0.85240338 [13] 0.81109473 0.52571331 0.82931652 0.60854785 0.19701975 0.26986325 [19] 0.58667068 0.32140366 0.40770.93213 29749603972 ] 0.07729027 0.11796154 0.69356590 0.95770015 0.74418811 0.43377516 [37] 0.55981826 0.93903143 0.30047034 0.84776853 0.32203732 0.25235660 [43] 0.79072381 0.58727094 0.99006038 0.01581969 0.41357545 0.52590383 [49] 0.27980561 0.50573325 0.924230.1 0.1602 0.86543 0.94573 0.84570.34 0.44573 0.44573 0.44573 0.9457345 0.34723 0.84573 0345365 74573456 3 3651 03451 034534563 0345938345 0.24 34563 1345 03456334561 034534563 0345179345 0.43453 34561(3)1 0345 0345345(2)0,0,9352,3,4,5,5,5,0,7,5,7,5
[61] 0.23440845 0.05244047 0.25931398 0.57217746 0.35554970 0.34622648 [67] 0.21050067 0.08890968 0.84003379 0.95114398 0.83349287 0.82437619 [73] 0.46724807 0.02641979 0.71740151 0.74439384 0.14830718 0.82685046 [79] 0.33821824 0.71627101 0.77182339 0.72147500 0.08801319 0.08626022 [85] 0.87332019 0.34303707 0.45393971 0.47871491 0.29254936 0.08939812 [91] 0.35698405 0.67369873 0.27087693 0.78854984 0.87959539 0.22376395 [97] 0.02674156 0.07077250 0.57461506 0.40616274 $ cor [1] 0.3166681
...或找到最接近0.2的值:
n_iterations [[which.min(abs(cor_values-0.2))]] $ vec [1] 0.02641979 0.49734797 0.32203732 0.95770015 0.82931652 0.52571331 [7] 0.25931398 0.30047034 0.55981826 0.08801319 0.29254936 0.23440845 [13] 0.12056045 0.89799621 0.22602602 0.14830718 0.45393971 0.22376395 0.89840404 0.08890968 0.15345334 [25] 0.87332019 0.92285322 0.50573325 0.40796732 0.91780357 0.57217746 [31] 0.52590383 0 0.84003379 0.52031017 0.67532970 0.83244284 0.95114398 [37] 0.81109473 0.35554970 0.92423638 0.83349287 0.34622648 0.18885955 [43] 0.61397396 0.89193212 0.74445997 0.46724807 0.72147500 0.33821824 [49] 0.71740151 0.75948043 0.52140366 0.69356590 0.41357545 0.21050067 [55] 0.87959539 0.11796154 0.73996913 0.30868672 0.47871491 0.63877904 [61] 0.22736077 0.40125309 0.02674156 0.26986325 0.43377516 0.07077250 [67] 0.79072381 0.08939812 0.86719899 0.55623242 0.60854785 0.71627101 [73] 0.40616274 0.35698405 0.67369873 0.82437619 0.27980561 0.77182339 [79] 0.19701975 0.82685046 0.74418811 0.58667068 0.93903143 0.74439384 [85] 0.43 68739783 0.89877843 97839847898685798 9783685984 9783978637 5863978637 5863978637 8685437 685827 3782498637 5863978637 5863978637 85685437 0.71901990 0.25235660 0.11261002 $ cor [1] 0.2000199
要獲得更高的相關性,您需要增加迭代次數。
讓我們解決一個更普遍的問題:給定變量$ Y_1 $如何生成具有相關矩陣$ R $的隨機變量$ Y_2,\ dots,Y_n $?
解決方案:
Python代碼:
將numpy導入為np
導入數學
從scipy.linalg導入toeplitz,cholesky
從statsmodels.stats.moment_helpers導入cov2corr
#創建大的相關矩陣R
p = 4
h = 2 /人
v = np.linspace(1,-1 + h,p)
R = cov2corr(toeplitz(v))
#創建第一個變量
T = 1000;
y = np.random.randn(T)
#生成p-1個相關隨機數
X = np.random.randn(T,p)
X [:,0] = y
C = cholesky(R)
Y = np.matmul(X,C)
#檢查Y是否保持不變
打印(np.max(np.abs(Y [:,0] -y)))
#檢查相關矩陣
打印(R)
打印(np.corrcoef(np.transpose(Y)))
測試輸出:
0.0
[[1. 0.5 0. -0.5]
[0.5 1. 0.5 0.]
[0. 0.5 1. 0.5]
[-0.5 0. 0.5 1.]
[[1. 0.50261766 0.02553882 -0.46259665]
[0.50261766 1. 0.51162821 0.05748082]
[0.02553882 0.51162821 1. 0.51403266]
[-0.46259665 0.05748082 0.51403266 1.]。
使用給定的SAMPLING協方差矩陣生成正態變量
covsam <- function(nobs,covm,seed = 1237){;
庫(expm);
#nons =觀察數,covm =給定的協方差矩陣;
nvar <- ncol(covm);
tot <- nvar * nobs;
dat <- matrix(rnorm(tot),ncol = nvar);
covmat <- cov(dat);
a2 <- sqrtm(solve(covmat));
m2 <- sqrtm(covm);
dat2 <- dat%*%a2%*%m2;
rc <- cov(dat2);};
cm <-矩陣(c(1,0.5,0.1,0.5,1,0.5,0.1,0.5,1),ncol = 3);
厘米;
res <- covsam(10,cm);
RES;
使用給定的POPULATION協方差矩陣生成正態變量
covpop <- function(nobs,covm,seed = 1237){;
庫(expm);
#nons =觀察數,covm =給定的協方差矩陣;
nvar <- ncol(covm);
tot <- nvar * nobs;
dat <- matrix(rnorm(tot),ncol = nvar);
m2 <- sqrtm(covm);
dat2 <- dat%*%m2;
rc <- cov(dat2); };
cm <-矩陣(c(1,0.5,0.1,0.5,1,0.5,0.1,0.5,1),ncol = 3);
厘米;
res <- covpop(10,cm);
資源
只需創建一個隨機向量並進行排序,直到獲得所需的r。