Nested loop or equivalent - r

I am trying to make a nested loop, I start with a simple loop and I would like make the same with differents data frames;
This work fine:
set.seed(123)
df1= data.frame(date= 1:10,
vartre=rnorm(10, 30, 4),
varpre=rnorm(10, 10, 5))
var=names(df1)
for(x in var ) {
plot(df1$date,df1[,x], type="l", main=x)
}
Now, I would like make the same with differents df´s, I tried to do with a nested loop but this dont work, example:
df2= data.frame(date= 1:10,
varkyt=rnorm(10, 100, 40),
varkdr=rnorm(10, 50, 5))
df3= data.frame(date= 1:10,
varwer=rnorm(10, 300, 400),
varpou=rnorm(10, 1000, 500))
dfs=c("df1", "df2", "df3")
for(i in dfs) {
var=names(i)
for(x in var ) {
plot(i$date,i[,x], type="l", main=paste(i,x)))
}
}
Thanks in advance

We can use lapply to loop over the list (mget -returns the list of data.frame from the string identifiers) and plot
out <- lapply(mget(dfs), function(dat) {
var <- names(dat)[-1]
lapply(var, function(x) plot(dat$date, dat[,x], type = "l",
main = x))
})
If we need to save it in a folder
path <- "path/to/folder/"
lapply(mget(dfs), function(dat) {
var <- names(dat)[-1]
lapply(var, function(x) {
png(filename=paste(path, "grafico", x,".png"))
plot(dat$date, dat[,x], type = "l",
main = x)
dev.off()
}
)
})

Related

How to use list elements as plot title in r?

I have this kind of data:
d<- list(d1 = list(`1979` = 3.8234619080332, `1980` = 3.94835997755299,
`1981` = 4.40780893307071), d2 = list(`1979` = 3.78682062013644,
`1980` = 3.89720895853959, `1981` = 4.35137469930167))
I am trying to plot my data and I want to use the list names d1 and d2 as plot titles.
I have tried this function with lapply;
fun1<-function(x) {
y<-x
x<-unlist(x)
plot(ecdf(x), main=deparse(substitute(y)))
}
lapply(d, fun1)
What I got are:
But I want to see d1 for the first plot and d2 for the second plot as the main title name instead of "list(d1 = list(1979 = 3.823461...."
You could use mapply to loop over both d and names(d) to pass the name of the list element to your function:
d<- list(d1 = list(`1979` = 3.8234619080332, `1980` = 3.94835997755299,
`1981` = 4.40780893307071), d2 = list(`1979` = 3.78682062013644,
`1980` = 3.89720895853959, `1981` = 4.35137469930167))
fun1<-function(x, y) {
plot(ecdf(unlist(x)), main=y)
}
mapply(fun1, d, names(d))
You could include the lapply() in your function and use the names().
fun1 <- function(d) {
nm <- names(d)
lapply(nm, function(i) plot(ecdf(unlist(d[[i]])), main=i))
}
op <- par(mfrow=c(1, 2))
fun1(d)
par(op)
Using purrr::imap -
fun1<-function(x, y) {
plot(ecdf(unlist(x)), main=y)
}
purrr::imap(d, fun1)

Loop a function in r to create a new table

I have a dataframe in r and want to perform the levene's/ variance test on multiple variables with two groups and save all results in a table. I have tried to do this using a for() loop and sapply() but I get neither working:
df <- data.frame(
x = rnorm(100, 0, 1),
y = rnorm(100, 50, 1),
z = rnorm(100, 70, 2),
group = rep(c(0,1), each = 50)
)
varlist <- c("x","y","z")
res.var <- character(length(varlist))
res.f <- numeric(length(varlist))
res.p <- numeric(length(varlist))
Option 1)
for(i in seq_along(varlist)) {
form <- substitute(i ~ group, list(i = as.name(varlist)))
result <- var.test(
formula = form,
data = df)
res.var[i] <- varlist[i]
res.f[i] <- result$estimate
res.p[i] <- result$p.value
}
Option 2:
sapply(varlist, function(x) {
form <- substitute(i ~ group, list(i = as.name(varlist)))
result <- var.test(
formula = form,
data = df)
res.var[i] <- varlist[i]
res.f[i] <- result$estimate
res.p[i] <- result$p.value
})
Maybe there's an easier way to that this. I'd be glad for any help ;o) Thank you in advance.

ggarrange generates an empty pdf file

I am dealing with a function that takes a big data frame (36 rows and 194 columns) which performs a Principal Component Analysis and then generates a list of plots where I have the combination of 26 Principal Components which are 325 in total, using 'expand.grid'.
My problem is that when I am using ggarrange(), from ggpubr, to merge all the plots in only one pdf file, this file is empty.
My code:
a = 26
row.pairs = 325
PC.Graph <- function(df, col1, col2, tag, id){
df1 <- df[,-c(col1:col2)]
pca <- prcomp(df1, scale. = T)
pc.summ <- summary(pca)
a <- sum(pc.summ$importance[3,] < 0.975)
b <- c(1:a)
pc.grid <- expand.grid(b, b)
pc.pairs <- pc.grid[pc.grid$Var1 < pc.grid$Var2,]
row.pairs <- nrow(pc.pairs)
components <- c(1:row.pairs)
S.apply.FUN <- function(x){
c <- sapply(pc.pairs, "[", x, simplify = F)
pcx <- c$Var1
pcy <- c$Var2
df2 <- df
row.names(df2) <- df[, tag]
name = paste("PCA_", pcx, "_vs_", pcy)
autoplot(pca, data = df2, colour = id, label = T, label.repel = T, main = name,
x = pcx, y = pcy)
}
all.plots <- Map(S.apply.FUN, components)
pdf(file = "All_PC.pdf", width = 50, height = 70)
print(ggarrange(all.plots))
dev.off()
}
PC.Graph(Final_DF, col1 = 1, col2 = 5, tag = "Sample", id = "Maturation")
You would have to pass a plotlist to ggarrange, but I am not sure you would get any useful plot out of that plot area in the PDF file, so I would advise you to split the plotlist into chunks (e.g. of 20) and plot these to multiple pages.
Specifically, I would export all.plots from your PC.Graph function (and remove the code to write to PDF there).
I would also change the expand.grid(b, b) to t(combn(b, 2)), since you don't need to plot the PC combinations twice.
Then I would do something like this:
# export the full list of plots
plots <- PC.Graph(Final_DF, col1 = 1, col2 = 5, tag = "Sample", id = "Maturation")
# split the plotlist
splitPlots <- split(plots, ceiling(seq_along(plots)/20))
plotPlots <- function(x){
out <- cowplot::plot_grid(plotlist = x, ncol = 5, nrow = 4)
plot(out)
}
pdf(file = "All_PC.pdf", width = 50, height = 45)
lapply(splitPlots, plotPlots)
dev.off()

Nested for loop not working properly R

I am trying trying to create a nested for loop, but somehow, the dimensions of mdata are mostly incorrect. For instance, the values for length(mdata[[1:5]]) are almost all 81, when they should be 81, 50, 60, etc. After the first five, length(mdata) becomes all 108s. Is there something wrong with my nested loop?
Code:
chrdata <- list()
mdata <- list()
res_df <- list()
for(i in 1:24) {
l <- length(olap[[i]])
for (j in 1:l) {
#for each row in granges object
sub_olap <- as.data.frame(mcols(subsetByOverlaps(all_list, olap[[i]][j])))
chrdata[[j]] <- data.frame(median(sub_olap$log2Ratio), #make metadata a single row and determine median
paste0(sub_olap$pvalue, collapse = ","),
paste0(sub_olap$length, collapse = ","),
paste0(sub_olap$sample, collapse = ","), stringsAsFactors = F)
colnames(chrdata[[j]]) <- c("med_log2Ratio", "pvalue", "length", "sample")
}
mdata[[i]] <- chrdata
mdf <- data.frame(matrix(unlist(mdata[[i]]), nrow = l, byrow = T))
colnames(mdf) <- c("med_log2Ratio", "pvalue", "length", "sample")
res_df[[i]] <- cbind(chr[[i]], mdf)
}

Function inputs from a list

How can I run a function (in R) where some of the inputs are pulled from a list (or data frame)? Am I right in thinking that this would be more efficient than running a for-loop?
I am running simulations and want to change the variable values, but as they take a long time to run I want them to run overnight and to just tick through the different values automatically.
Here's the code for the function:
n = 10000
mu = 0
sd = 1
n.sub = 100
iboot = 100
isim = 1000 ### REDUCED FOR THIS EXAMPLE ###
var.values <- NULL
var.values.pop <- NULL
hist.fn <- function(n,mu,sd,n.sub,iboot)
{
Pop <- rnorm(n,mu,sd)
var.pop <- var(Pop)
Samp <- sample(Pop, n.sub, replace = FALSE)
var.samp <- var(Samp)
for(i in 1:isim) {
for(j in 1:iboot) {
Boot <- sample(Samp, n.sub, replace = TRUE)
var.values[j] <- var(Boot)
}
Samp <- sample(Pop, n.sub, replace = FALSE)
var.values.pop[i] <- var(Samp)
}
hist.pop <- hist(var.values.pop,plot=F)
hist.boot <- hist(var.values,plot=F)
#mypath = file.path("C:", "Output", paste("hist.boot_n.", n.sub, "_var.", sd^2, "_isim.", isim, "_iboot.", iboot, ".wmf", sep=""))
#win.metafile(file=mypath)
plot.new() #### ADDED FOR THIS EXAMPLE INSTEAD OF OUTPUTTING TO FILE ####
plot(hist.pop, freq=FALSE, xlim=range(var.values.pop, var.values), ylim=range(hist.pop$density, hist.boot$density), main = paste("Histogram of variances \n n=",n.sub," mu=",mu,"var=",sd^2,"\n n.sim=",isim,"n.boot=",iboot,"\n"), cex.main=0.8, xlab="Variance", col="red")
plot(hist.boot, freq=FALSE, col="blue", border="blue", add=T, density=20, angle=45)
abline(v=var.pop, lty=2, col="black", lwd=2)
legend("topright", legend=c("sample","bootstrap"),col=c("red","blue"),lty=1,lwd=2,bty="n",cex=0.7)
#dev.off()
}
hist.fn(n,mu,sd,n.sub,iboot)
Then I want sd, n.sub, and iboot to change by running through the following values:
sd <- c(1,10,100,1000)
n.sub <- c(4,10,100,1000)
iboot <- c(100,1000,10000)
Perhaps something like this?
n = 10000
mu = 0
sd = 1
n.sub = 100
iboot = 100
isim = 1000
sd <- c(1,10,100,1000)
n.sub <- c(4,10,100,1000)
iboot <- c(100,1000,10000)
# hist.fn parameters: n,mu,sd,n.sub,iboot
params <- expand.grid(n = n, mu = mu, sd = sd,
n.sub = n.sub, iboot = iboot)
apply(params, 1, FUN = function(x) do.call(hist.fn, as.list(x) ) )
You probably want to put these:
var.values <- NULL
var.values.pop <- NULL
Inside hist.fn, because assigning values to variables outside a function doesn't work like you seem to think.
You should use do.call, which will apply the function using arguments in a list. I have simplified your example to run less loops for the example. You can modify the printline of the script in order to monitor your progress for a larger job:
# The function
hist.fn <- function(n,mu,isim,sd,n.sub,iboot)
{
Pop <- rnorm(n,mu,sd)
var.pop <- var(Pop)
Samp <- sample(Pop, n.sub, replace = FALSE)
var.samp <- var(Samp)
var.values <- NaN*seq(isim) # sets up an empty vector for results
var.values.pop <- NaN*seq(isim) # sets up an empty vector for results
for(i in seq(isim)) {
for(j in seq(iboot)) {
Boot <- sample(Samp, n.sub, replace = TRUE)
var.values[j] <- var(Boot)
print(paste("i =", i, "; j =", j))
}
Samp <- sample(Pop, n.sub, replace = FALSE)
var.values.pop[i] <- var(Samp)
}
list(var.values=var.values, var.values.pop=var.values.pop) #returns results in the form of a list
}
# Global variables
n = 100
mu = 0
isim = 10
# Changing variables
sd <- c(1,10,20,30)
n.sub <- c(4,10,20,30)
iboot <- c(100,200,300,400)
df <- data.frame(sd=sd, n.sub=n.sub, iboot=iboot)
res <- vector(mode="list", nrow(df)) # sets up an empty list for results
for(i in seq(nrow(df))){
res[[i]] <- do.call(hist.fn, c(n=n, mu=mu, isim=isim, df[i,]) )
}
res # show results
sd <- 1:3
n.sub <- 4:6
iboot <- 7:9
funct1<-function(x,y,z) print(x+y+z)
for (i in 1:length(sd)){
funct1(sd[i],n.sub[i],iboot[i])
}
just an example. Doing it with loop.

Resources