【问题标题】:Simplify R code for correlation matrix using for-loop?使用for循环简化相关矩阵的R代码?
【发布时间】:2021-08-10 10:09:15
【问题描述】:

我正在尝试使用 for 循环 或其他更简单/有效的解决方案创建相关矩阵,但老实说,我真的很努力。

这是数据框和相关矩阵的结构:

# Create data frame
ID <- c("r1", "r1", "r1", "r1", "r1", "r2", "r2", "r2", "r2", "r2", "r3", "r3", "r3", "r3", "r3")
V1.1 <- c(3, 3, 3, 3, 3, 3, 2, 3, 3, 1, 2, 2, 1, 1, 2)
V2.1 <- c(2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3)
V3.1 <- c(4, 4, 4, 4, 3, 4, 1, 2, 5, 2, 2, 2, 4, 5, 1)
V4.1 <- c(3, 4, 3, 3, 3, 3, 3, 3, 4, 4, 5, 4, 4, 4, 2)
V5.1 <- c(3, 2, 3, 3, 2, 3, 2, 2, 2, 3, 2, 3, 3, 3, 3)
V1.2 <- c(4, 4, 3, 3, 4, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3)
V2.2 <- c(3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5)
V3.2 <- c(2, 1, 2, 2, 2, 4, 3, 4, 4, 3, 4, 2, 1, 2, 1)
V4.2 <- c(2, 5, 2, 3, 4, 4, 3, 4, 2, 3, 4, 5, 2, 4, 3)
V5.2 <- c(5, 4, 3, 4, 3, 3, 4, 4, 2, 3, 2, 4, 4, 1, 3)

df <- data.frame(ID, V1.1, V2.1, V3.1, V4.1, V5.1, V1.2, V2.2, V3.2, V4.2, V5.2)

# Define variables
ID.vars <- c("r1", "r2", "r3")
vars <- c("V1", "V2", "V3", "V4", "V5")
vars.1 <- c("V1.1", "V2.1", "V3.1", "V4.1", "V5.1")
vars.2 <- c("V1.2", "V2.2", "V3.2", "V4.2", "V5.2")

# Empty data frame for correlation matrix
corrmat <- data.frame(ID = ID.vars)
corrmat <- cbind(corrmat, matrix(NA, nrow = length(ID.vars), ncol = length(vars)))
names(corrmat)[2:ncol(corrmat)] <- vars

这是我想用循环或更好的解决方案做的:

# Subset data per id
r1 <- subset(df, ID == "r1", select = c(vars.1, vars.2))
r2 <- subset(df, ID == "r2", select = c(vars.1, vars.2))
r3 <- subset(df, ID == "r3", select = c(vars.1, vars.2))

# Fill-in correlations matrix
corrmat[corrmat$ID == "r1", "V1"] <- cor(r1$V1.1, r1$V1.2)
corrmat[corrmat$ID == "r1", "V2"] <- cor(r1$V2.1, r1$V2.2)
corrmat[corrmat$ID == "r1", "V3"] <- cor(r1$V3.1, r1$V3.2)
corrmat[corrmat$ID == "r1", "V4"] <- cor(r1$V4.1, r1$V4.2)
corrmat[corrmat$ID == "r1", "V5"] <- cor(r1$V5.1, r1$V5.2)

corrmat[corrmat$ID == "r2", "V1"] <- cor(r2$V1.1, r2$V1.2)
corrmat[corrmat$ID == "r2", "V2"] <- cor(r2$V2.1, r2$V2.2)
corrmat[corrmat$ID == "r2", "V3"] <- cor(r2$V3.1, r2$V3.2)
corrmat[corrmat$ID == "r2", "V4"] <- cor(r2$V4.1, r2$V4.2)
corrmat[corrmat$ID == "r2", "V5"] <- cor(r2$V5.1, r2$V5.2)

corrmat[corrmat$ID == "r3", "V1"] <- cor(r3$V1.1, r3$V1.2)
corrmat[corrmat$ID == "r3", "V2"] <- cor(r3$V2.1, r3$V2.2)
corrmat[corrmat$ID == "r3", "V3"] <- cor(r3$V3.1, r3$V3.2)
corrmat[corrmat$ID == "r3", "V4"] <- cor(r3$V4.1, r3$V4.2)
corrmat[corrmat$ID == "r3", "V5"] <- cor(r3$V5.1, r3$V5.2)

这是尝试的开始,现在我被卡住了:(

# Loop attempt
for(i in ID.vars) {
    results <- subset(df, ID == i, select = c(vars.1, vars.2)) # subset data
    # Loop across variables
    for(j in vars){
    }
}

谢谢!

【问题讨论】:

  • 一旦您开始创建名称中带有数字的变量名称,请停止您正在做的事情,删除变量并根据需要用向量或列表替换它们。代码的简化将不在此范围内。

标签: r for-loop simplify


【解决方案1】:
library(dplyr)
library(tidyr)
df %>% 
  pivot_longer(cols = -ID, names_to = c("set", ".value"), names_pattern = "(V\\d)\\.(\\d)") %>% 
  group_by(ID, set) %>% 
  summarise(c = cor(`1`, `2`), .groups = "drop") %>% 
  pivot_wider(id_cols = ID, names_from = set, values_from = c)
# A tibble: 3 × 6
  ID        V1     V2     V3     V4     V5
  <chr>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
1 r1    NA      0.167 -0.25   0.772  0.327
2 r2    -0.375 NA      0.722 -0.764 -0.218
3 r3    NA      0.408 -0.124  0.320  0.343

【讨论】:

    【解决方案2】:

    现在可以看到一个解决方案,但它已经写好了,所以你去吧。另一种解决方案更有效,但这个解决方案可能更简单

    library(purrr)
    library(dplyr)
    
    ids <- 1:5
    # store as a list of the individual correlation results
    list_output <- lapply(ids, function(i){
      # identify the two columns to do the correlation
      col1 <- paste("V", i, ".1", sep="")
      col2 <- paste("V", i, ".2", sep="")
      
      # dplyr 
      # - group by ID
      # - do the correlation of the col1 and col2. Use get() to extract data
      out <- df %>% 
        group_by(ID) %>% 
        summarise(cor(get(col1), get(col2)))
      # fix column name
      names(out)[2] <- paste("V", i, sep="")
      out
    })
    # merge them together - https://stackoverflow.com/questions/8091303/simultaneously-merge-multiple-data-frames-in-a-list
    # and convert back to data.frame from a tibble
    corrmat <- purrr::reduce(list_output, left_join, by="ID") %>% as.data.frame
    corrmat
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-17
      • 1970-01-01
      • 1970-01-01
      • 2021-04-06
      • 1970-01-01
      • 2013-07-30
      • 1970-01-01
      • 2015-09-05
      相关资源
      最近更新 更多