运行:
cor(x, use = "pairwise.complete.obs")`
正在运行
c <- cov(x, use = "pairwise.complete.obs")
cov2cor(c)
给出不同的结果。有谁知道为什么,哪个给出正确的结果?这两个函数都调用C ++代码,我还没有弄清楚如何解析。
可复制的数据:
x <- data.frame(a1 = rnorm(10), a2 = rnorm(10), a3 = rnorm(10))
x$a1[c(1,3)] <- NA
c <- cov(x, use = "pairwise.complete.obs")
cov2cor(c)
cor(x, use = "pairwise.complete.obs")
答案 0 :(得分:1)
我不确定,但是我首先猜到这取决于您用于计算的数据点的数量。您的数据:
x <- data.frame(a1 = rnorm(10), a2 = rnorm(10), a3 = rnorm(10))
x
a1 a2 a3
1 NA -0.13838924 -0.321692757
2 -0.4508542 0.94765320 1.951455501
3 NA 2.31819262 -1.411309267
4 0.7828306 -0.53437879 -1.073991019
5 0.2298984 -0.46396636 -0.008471517
6 0.6543559 -1.67425582 0.163433255
7 0.1454043 0.37971651 1.197296537
8 0.2055262 0.67526617 -0.913544378
9 0.3360491 1.84172088 0.366159132
10 0.2507107 0.08284055 1.819004908
在这里,您看到a1缺少2个值。因此,a1和a3之间以及a1和a2之间的相关仅基于8个数据点,而a2和a3之间的相关基于所有10个数据点。
在?cov2cor
的帮助下:
cov2cor scales a covariance matrix into the corresponding correlation matrix efficiently.
cov2cor
缩放协方差矩阵时,它假设数据点的数量相同。当您仅使用完整的观测值时,结果是相同的:
> c <- cov(x, use = "complete.obs")
> cov2cor(c)
a1 a2 a3
a1 1.0000000 -0.2230619 0.2580796
a2 -0.2230619 1.0000000 0.6152059
a3 0.2580796 0.6152059 1.0000000
> cor(x, use = "complete.obs")
a1 a2 a3
a1 1.0000000 -0.2230619 0.2580796
a2 -0.2230619 1.0000000 0.6152059
a3 0.2580796 0.6152059 1.0000000
因此,您需要问自己,您需要什么信息。如果您使用成对的完整观测值,则我不应该使用cov2cor
。
答案 1 :(得分:0)
事实证明差异在于方差的计算方式。如果我们只有变量x
和y
,其中x
有一些NA,则cov
函数将使用以下公式计算y_mean
和var_y
y
中的所有观察结果。另一方面,cor
函数将仅使用y_mean
中与var_y
中非缺失值相对应的值来计算y
和x
。
由于分析中涉及的所有变量应具有相同数量的观察值,因此在计算相关统计量时,一个输入(协方差)包含的观察值少于另一个输入(方差)就没有意义。也许只是见仁见智,而只要丢失的比例很低,可能就没那么重要了,但是显然这两个功能应该默默提供不同的结果是不可取的。
以下StackoverFlow问题说明了如何查看C ++代码:How can I view the source code for a function?,这是C_cov
函数的代码链接:https://svn.r-project.org/R/trunk/src/library/stats/src/cov.c
下面的R代码演示了计算上的差异。首先自动计算:
dat <- data.frame(x = rnorm(10), y = rnorm(10))
dat$x[c(1,3)] <- NA
d <- cov(dat, use = "pairwise.complete.obs")
cov_version <- cov2cor(d)
cor_version <- cor(dat, use = "pairwise.complete.obs")
手动计算
#Computing the covariance is the same for both cor and cov functions
n <- length(dat$x[!is.na(dat$x)]) #n of non-missing values
x_bar <- mean(dat$x, na.rm = TRUE)
y_bar <- mean(dat$y[!is.na(dat$x)]) #mean of y values where x is not NA
n1 <- n -1
s_x <- dat$x[!is.na(dat$x)] - x_bar
s_y <- dat$y[!is.na(dat$x)] - y_bar
ss_xy <- sum(s_x*s_y) #sums of squares (x, y)
cov_xy <- ss_xy / n1 #same results as cov(dat, use = "pairwise.complete.obs")
all.equal(cov_xy, d[1,2])
[1] TRUE
#The cor approach to computing variances
ss_x <- sum(s_x*s_x)
ss_y <- sum(s_y*s_y)
var_x <- ss_x / n1
var_y <- ss_y / n1
cor_xy <- cov_xy / (sqrt(var_x) *sqrt(var_y)) #same as cor(dat, use = "pairwise.complete.obs")
all.equal(cor_xy, cor_version[1,2])
[1] TRUE
#The cov approach to computing variances, different for the variable without missing values
y_bar2 <- mean(dat$y) #all values of y
s_y2 <- dat$y - y_bar2
ss_y2 <- sum(s_y2*s_y2)
var_y2 <- ss_y2 / (length(dat$y) - 1) #n comes from all values of y
cov_cor <- cov_xy / (sqrt(var_x) * sqrt(var_y2))
all.equal(cov_cor, cov_version[1,2])
[1] TRUE
答案 2 :(得分:0)
@Jaesoc给出了一个很好的解释,这是一个稍微不同的直觉:
直觉上,当缺少值时,每对结果的观察数不同,因此应为每个变量存储不同版本的方差(例如,var(y)包含所有obs,var(y)包含与z相同,等等)。现在的问题是,在计算协方差矩阵时,您只能为每个变量(即对角元素)存储一个版本的方差。因此,cov2cor()
甚至是从协方差矩阵手动计算都不会给您正确的结果。
请注意,在极端情况下,如果观测值少于变量,cov2cor()
甚至可能使相关性大于| 1 |!
set.seed(123)
dat <- data.frame(x = rnorm(4), y = rnorm(4), z=rnorm(4))#, zz=rnorm(4))
dat[1,3] <- NA
dat
#> x y z
#> 1 -0.56047565 0.1292877 NA
#> 2 -0.23017749 1.7150650 -0.4456620
#> 3 1.55870831 0.4609162 1.2240818
#> 4 0.07050839 -1.2650612 0.3598138
## Count number of pairwise observations:
crossprod(as.matrix(!is.na(dat)))
#> x y z
#> x 4 4 3
#> y 4 4 3
#> z 3 3 3
## Compare results
cov2cor(cov(dat, use = "pairwise.complete.obs"))
#> x y z
#> x 1.00000000 -0.01630914 0.9632927
#> y -0.01630914 1.00000000 -0.4893276
#> z 0.96329271 -0.48932759 1.0000000
cor(dat, use = "pairwise.complete.obs")
#> x y z
#> x 1.00000000 -0.01630914 0.9408492
#> y -0.01630914 1.00000000 -0.4005502
#> z 0.94084924 -0.40055017 1.0000000
## Extreme case: N<p
dat_S <- dat[1:3,]
cov2cor(cov(dat_S, use = "pairwise.complete.obs"))
#> x y z
#> x 1.0000000 -0.1777287 1.109409
#> y -0.1777287 1.0000000 -1.060258
#> z 1.1094092 -1.0602577 1.000000
cor(dat_S, use = "pairwise.complete.obs")
#> x y z
#> x 1.0000000 -0.1777287 1
#> y -0.1777287 1.0000000 -1
#> z 1.0000000 -1.0000000 1
由reprex package(v0.3.0)于2020-08-26创建