ฉันจะอธิบายวิธีแก้ปัญหาที่เป็นไปได้ทั่วไปที่สุด การแก้ปัญหาในรุ่นนี้ช่วยให้เราสามารถใช้งานซอฟต์แวร์ที่มีขนาดกะทัดรัดได้อย่างน่าทึ่งเพียงแค่R
โค้ดสั้น ๆ สองบรรทัด
เลือกเวกเตอร์ของยาวเช่นเดียวกับ , ตามการกระจายใด ๆ ที่คุณชอบ Letจะเหลือของสี่เหลี่ยมถดถอยน้อยของกับ : นี้สารสกัดจากส่วนประกอบจากXโดยการเพิ่มกลับมาหลายที่เหมาะสมของจะเราอาจผลิตเวกเตอร์ที่มีความสัมพันธ์ใด ๆ ที่ต้องการกับYจนถึงค่าคงที่สารเติมแต่งโดยพลการและค่าคงที่การคูณเชิงบวก - ซึ่งคุณมีอิสระที่จะเลือกในทางใด ๆ - การแก้ปัญหาคือY Y ⊥ X Y Y X Y Y ⊥ ρ YXYY⊥XYYXYY⊥ρY
XY;ρ=ρSD(Y⊥)Y+1−ρ2−−−−−√SD(Y)Y⊥.
(" " ย่อมาจากการคำนวณตามสัดส่วนกับส่วนเบี่ยงเบนมาตรฐาน)SD
นี่คือR
รหัสการทำงาน หากคุณไม่ระบุโค้ดจะดึงค่าจากการแจกแจงปกติแบบหลายตัวแปรมาตรฐานX
complement <- function(y, rho, x) {
if (missing(x)) x <- rnorm(length(y)) # Optional: supply a default if `x` is not given
y.perp <- residuals(lm(x ~ y))
rho * sd(y.perp) * y + y.perp * sd(y) * sqrt(1 - rho^2)
}
เพื่อแสดงให้เห็นว่าฉันสร้างสุ่มโดยมีส่วนประกอบและสร้างซึ่งมีความสัมพันธ์ต่าง ๆ ที่ระบุกับนี้ พวกเขาถูกสร้างขึ้นทั้งหมดที่มีเวกเตอร์เริ่มต้นเดียวกัน50) นี่คือแผนการกระจายของพวกเขา "rugplots" ที่ด้านล่างของแต่ละแผงแสดงเวกเตอร์ทั่วไป50 X Y ; ρ Y X = ( 1 , 2 , ... , 50 ) YY50XY;ρYX=(1,2,…,50)Y
มีความคล้ายคลึงกันที่น่าทึ่งในแปลงไม่มี :-)
หากคุณต้องการทดสอบนี่คือรหัสที่สร้างข้อมูลและตัวเลขเหล่านี้ (ฉันไม่ได้รำคาญที่จะใช้อิสระในการเลื่อนและปรับขนาดผลลัพธ์ซึ่งใช้งานง่าย)
y <- rnorm(50, sd=10)
x <- 1:50 # Optional
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)))
library(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")
BTW วิธีนี้ได้อย่างง่ายดาย generalizes มากกว่าหนึ่ง : ถ้าเป็นไปได้ในทางคณิตศาสตร์ก็จะได้พบกับมีความสัมพันธ์ที่ระบุไว้กับทั้ง ชุดY_iเพียงใช้สี่เหลี่ยมจัตุรัสขั้นต่ำธรรมดาเพื่อแยกเอฟเฟกต์ของทั้งหมดจากและสร้างการผสมผสานเชิงเส้นที่เหมาะสมของและส่วนที่เหลือ (มันช่วยในการทำสิ่งนี้ในแง่ของพื้นฐานสองประการสำหรับซึ่งได้มาจากการคำนวณหลอกแบบผกผันรหัส follownig ใช้ SVD ของเพื่อทำสิ่งนั้นให้สำเร็จ)X Y 1 , Y 2 , … , Y k ; ρ 1 , ρ 2 , ... , ρ k Y ฉันY ฉัน X Y ฉัน Y YYXY1,Y2,…,Yk;ρ1,ρ2,…,ρkYiYiXYiYY
นี่คือภาพร่างของอัลกอริทึมR
ที่ถูกกำหนดให้เป็นคอลัมน์ของเมทริกซ์:Yiy
y <- scale(y) # Makes computations simpler
e <- residuals(lm(x ~ y)) # Take out the columns of matrix `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))
return(y.dual %*% rho + sqrt(sigma2)*e)
ต่อไปนี้เป็นการใช้งานที่สมบูรณ์ยิ่งขึ้นสำหรับผู้ที่ต้องการทดสอบ
complement <- function(y, rho, x) {
#
# Process the arguments.
#
if(!is.matrix(y)) y <- matrix(y, ncol=1)
if (missing(x)) x <- rnorm(n)
d <- ncol(y)
n <- nrow(y)
y <- scale(y) # Makes computations simpler
#
# Remove the effects of `y` on `x`.
#
e <- residuals(lm(x ~ y))
#
# Calculate the coefficient `sigma` of `e` so that the correlation of
# `y` with the linear combination y.dual %*% rho + sigma*e is the desired
# vector.
#
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))
#
# Return this linear combination.
#
if (sigma2 >= 0) {
sigma <- sqrt(sigma2)
z <- y.dual %*% rho + sigma*e
} else {
warning("Correlations are impossible.")
z <- rep(0, n)
}
return(z)
}
#
# Set up the problem.
#
d <- 3 # Number of given variables
n <- 50 # Dimension of all vectors
x <- 1:n # Optionally: specify `x` or draw from any distribution
y <- matrix(rnorm(d*n), ncol=d) # Create `d` original variables in any way
rho <- c(0.5, -0.5, 0) # Specify the correlations
#
# Verify the results.
#
z <- complement(y, rho, x)
cbind('Actual correlations' = cor(cbind(z, y))[1,-1],
'Target correlations' = rho)
#
# Display them.
#
colnames(y) <- paste0("y.", 1:d)
colnames(z) <- "z"
pairs(cbind(z, y))