Home > Net >  Combining for loops and ifelse in R
Combining for loops and ifelse in R

Time:12-16

I am trying to write a for loop that will generate a correlation for a fixed column (LPS0) vs. all other columns in the data set. I don't want to use a correlation matrix because I only care about the correlation of LPS0 vs all other columns, not the correlations of the other columns with themselves. I then want to include an if statement to print only the significant correlations (p.value <= 0.05). I ran into some issues where some of the p.values are returned as NA, so I switched to an if_else loop. However, I am now getting an error. My code is as follows:

for(i in 3:ncol(microbiota_lps_0_morm)) { 
  morm_0 <- cor.test(microbiota_lps_0_morm$LPS0, microbiota_lps_0_morm[[colnames(microbiota_lps_0_morm)[i]]], method = "spearman")
  if_else(morm_0$p.value <= 0.05, print(morm_0), print("Not Sig"), print("NA"))
}

The first value is returned, and then the loop stops with the following error:

Error in if_else(): ! true must be length 1 (length of condition), not 8. Backtrace: 1. dplyr::if_else(morm_0$p.value <= 0.05, print(morm_0), print("Not Sig"), print("NA"))

How can I make the loop print morm only when p.value <- 0.05?

CodePudding user response:

Here's a long piece of code which aytomates the whole thing. it might be overkill but you can just take the matrix and use whatever you need. it makes use of the tidyverse.

df <- select_if(mtcars,is.numeric)
glimpse(df)
# keeping real names
dict <- cbind(original=names(df),new=paste0("v",1:ncol(df)))
# but changing names for better data viz
colnames(df) <- paste0("v",1:ncol(df))

# correlating between variables   p values
pvals <- list()
corss <- list()
for (coln in colnames(df)) {
  pvals[[coln]] <- map(df, ~ cor.test(df[,coln], .)$p.value)
  corss[[coln]] <- map(df, ~ cor(df[,coln], .))
}

# Keeping both matrices in a list
matrices <- list(
  pvalues = matrix(data=unlist(pvals),
                     ncol=length(names(pvals)),
                     nrow=length(names(pvals))),
  
  correlations = matrix(data=unlist(corss),
                   ncol=length(names(corss)),
                   nrow=length(names(corss)))
)


rownames(matrices[[1]]) <- colnames(df)
rownames(matrices[[2]]) <- colnames(df)

# Creating a combined data frame
long_cors <- expand.grid(Var1=names(df),Var2=names(df)) %>% 
  mutate(cor=unlist(matrices["correlations"]),
         pval=unlist(matrices["pvalues"]),
         same=Var1==Var2,
         significant=pval<0.05,
         dpcate=duplicated(cor)) %>% 
  # Leaving no duplicants, non-significant or self-correlation results
  filter(same ==F,significant==T,dpcate==F) %>%
  select(-c(same,dpcate,significant))


# Plotting correlations
long_cors %>%mutate(negative=cor<0) %>% 
  ggplot(aes(x=Var1,y=Var2,
             color=negative,size=abs(cor),fill=Var2,
             label=round(cor,2))) 
  geom_label(show.legend = F,alpha=0.2) 
  scale_color_manual(values = c("black","darkred")) 
  # Sizing each correlation by it's magnitude
  scale_size_area(seq(1,100,length=length(unique(long_cors$Var1))))  theme_light() 
  theme(axis.text = element_text(face = "bold",size=12)) 
  labs(title="Correlation between variables",
       caption = "p < 0.05") xlab("") ylab("")

CodePudding user response:

If you want to correlate a column of a matrix with the remaining columns, you can do so with one function call:

mtx <- matrix(rnorm(800), ncol=8)
cor(mtx[,1], mtx[,-1])

However, you will not get p-values. For getting p-values, I would recommend this approach:

library(tidyverse)
significant <- map_dbl(2:ncol(mtx), 
      ~ cor.test(mtx[,1], mtx[,.], use="p", method="s")$p.value)

Whenever you feel like you need a for loop in R, chances are, you should be using another approach. for is a very un-R construct, and R gives many better ways of handling the same issues. map_* family of functions from tidyverse is but one of them. Another approach, in base R, would be to use apply:

significant <- apply(mtx[,-1], 2, 
         \(x) cor.test(x, mtx[,1], method="s", use="p")$p.value)
  • Related