cor和cov2cor与use = pairwise.complete.obs的结果不同

时间:2019-10-29 11:13:39

标签: r r-base

运行:

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")

3 个答案:

答案 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)

摘要

事实证明差异在于方差的计算方式。如果我们只有变量xy,其中x有一些NA,则cov函数将使用以下公式计算y_meanvar_y y中的所有观察结果。另一方面,cor函数将仅使用y_mean中与var_y中非缺失值相对应的值来计算yx

由于分析中涉及的所有变量应具有相同数量的观察值,因此在计算相关统计量时,一个输入(协方差)包含的观察值少于另一个输入(方差)就没有意义。也许只是见仁见智,而只要丢失的比例很低,可能就没那么重要了,但是显然这两个功能应该默默提供不同的结果是不可取的。

动机

以下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创建