确定并组合完全相关的变量(有效)

时间:2015-10-07 13:09:30

标签: r

我有未知的数据告诉我,我想以编程方式查看相关性,并将任何完全相关的变量(忽略方向)组合在一起。在下面的数据集中,我可以手动查看相关性,并像a, f, g, h一样说b, d, e。我怎么能以编程方式有效地做到这一点。

library(dplyr)

dat <- data_frame(
    a = 1:100,
    b = rnorm(100),
    c = sample(1:100),
    d = b * 3, 
    e = b + 100,
    f = 1001:1100,
    g = a - 100,
    h = 100:1
)

round(cor(dat), 3)

##        a      b      c      d      e      f      g      h
## a  1.000  0.053 -0.042  0.053  0.053  1.000  1.000 -1.000
## b  0.053  1.000  0.092  1.000  1.000  0.053  0.053 -0.053
## c -0.042  0.092  1.000  0.092  0.092 -0.042 -0.042  0.042
## d  0.053  1.000  0.092  1.000  1.000  0.053  0.053 -0.053
## e  0.053  1.000  0.092  1.000  1.000  0.053  0.053 -0.053
## f  1.000  0.053 -0.042  0.053  0.053  1.000  1.000 -1.000
## g  1.000  0.053 -0.042  0.053  0.053  1.000  1.000 -1.000
## h -1.000 -0.053  0.042 -0.053 -0.053 -1.000 -1.000  1.000

期望的结果:

list(
    c('a', 'f', 'g', 'h'),
    c('b', 'd', 'e')
)

3 个答案:

答案 0 :(得分:4)

这个怎么样:

# Save absolute correlation mtx 
cmat <- abs(cor(dat))
# Step over the rows of the matrix and select the column names that have correlation 1
groups <- lapply(rownames(cmat), function(rname) { colnames(cmat)[cmat[rname, ]==1] })
# Choose only unique correlation groups
groups <- unique(groups)

## [[1]]
## [1] "a" "f" "g" "h"

## [[2]]
## [1] "b" "d" "e"

## [[3]]
## [1] "c"
Tyler Rinker的

编辑:3种方法的基准:

library(dplyr)

dat <- data_frame(
    a = 1:100000,
    b = rnorm(100000),
    c = sample(1:100000),
    d = b * 3, 
    e = b + 100000,
    f = 1001:101000,
    g = a - 100,
    h = 100000:1,
    i = runif(100000),
    j = rev(i),
    k = i * 3
)

cor_group_dplyr <- function(dat){

    grps <- data.frame(abs(round(cor(dat), 3))) %>%
        dplyr::add_rownames() %>%
        tidyr::gather(key, value, -rowname) %>%
        dplyr::filter(value == 1) %>%
        dplyr::distinct(rowname) %>%
        dplyr::group_by(key) %>%
        dplyr::summarise(pairs = list(rowname)) %>%
        {.[["pairs"]]} %>%
        {.[sapply(., length) > 1]}

    if (length(grps) == 0) return(NA)
    grps
}

cor_group_data.table <- function(dat){

    res <- data.table::data.table(do.call(paste, data.table::as.data.table(abs(round(cor(dat), 3)))), colnames(dat))
    groups <- res[, .(res = list(V2)), by = V1][["res"]]
    m <- groups[sapply(groups, length) > 1]
    if (length(m) == 0) return(NA)
    m
}    


cor_group_base <- function(dat){
    cmat <- abs(round(cor(dat), 4))
    groups <- lapply(rownames(cmat), function(rname) { colnames(cmat)[cmat[rname, ]==1] })
    groups <- unique(groups)
    m <- groups[sapply(groups, length) > 1]
    if (length(m) == 0) return(NA)
    m
}    

library(microbenchmark)
(op <- microbenchmark( 
    cor_group_base(dat),
    cor_group_dplyr(dat),
    cor_group_data.table(dat),
times=100L))

<强>结果

## Unit: milliseconds
##                       expr      min       lq     mean   median       uq      max neval
##        cor_group_base(dat) 50.83729 52.53670 60.93529 56.65787 58.27536 143.1478   100
##       cor_group_dplyr(dat) 54.25574 55.67910 69.32940 60.76432 64.94523 182.8525   100
##  cor_group_data.table(dat) 53.10673 56.36881 62.42772 58.94608 60.06950 158.2749   100

答案 1 :(得分:2)

另一个选项是将行粘贴到单个值中,然后运行一些table类似的实现,这里是data.table可能的解决方案

library(data.table)
res <- data.table(do.call(paste, as.data.table(abs(round(cor(dat), 3)))), colnames(dat))
res[, .(res = list(V2)), by = V1]$res
# [[1]]
# [1] "a" "f" "g" "h"
# 
# [[2]]
# [1] "b" "d" "e"
# 
# [[3]]
# [1] "c"

答案 2 :(得分:1)

另一种选择,将结果存储在列表变量中:

library(dplyr)
library(tidyr)

df <- data.frame(abs(round(cor(dat), 3))) %>%
  add_rownames %>%
  gather(key, value, -rowname) %>%
  filter(value == 1) %>%
  distinct(rowname) %>%
  group_by(key) %>%
  summarise(pairs = list(rowname))

给出了:

#Source: local data frame [3 x 2]
#
#     key    pairs
#  (fctr)   (list)
#1      a <chr[4]>
#2      b <chr[3]>
#3      c <chr[1]>

要获得所需的输出,只需执行以下操作:

#> df$pairs
#[[1]]
#[1] "a" "f" "g" "h"
#
#[[2]]
#[1] "b" "d" "e"
#
#[[3]]
#[1] "c"