R - for loop only gives the last interaction result - r

I am trying to save the results of all interactions, but for loop only gives me the result of last interaction. Just like this:
l <- list(a = c(1, 3, 5), b = c(4, 8), c = 2)
df <- data.frame()
for (i in 1:length(l)) {
s <- data.frame(name = names(l[i]),
value = mean(l[[i]]))
out <- rbind(df, s)
}
This code returns this:
I need to something like this:
How can I solve this?
Thanks in advance!

Your out variable only contains the result of the last iteration since out is overriden in every iteration of the loop.
Replace out by df like so, your expected result will be in the df variable:
l <- list(a = c(1, 3, 5), b = c(4, 8), c = 2)
df <- data.frame()
for (i in 1:length(l)) {
s <- data.frame(name = names(l[i]),
value = mean(l[[i]]))
df <- rbind(df, s)
}
df

Related

Error in `*tmp*`[[i]]: for loop error in creating nested list in R

I am getting this error: Error in *tmp*[[i]] : subscript out of bounds
When I run a code that iterates through i and j.
Example data below:
#Make example data
A1 <- rnorm(1:100, mean = 10, sd = 1)
B1 <- rep(c(2, 4, 5, 7), each = 25)
AB1 <- rbind(A1, B1)
colnames(AB1) <- rep(c("A","b"), each = 50)
A2 <- rnorm(1:100, mean = 50, sd = 1)
B2 <- rep(c(2, 4, 5, 7), each = 25)
AB2 <- rbind(A2, B2)
colnames(AB2) <- rep(c("A","b"), each = 50)
A3 <- rnorm(1:100, mean = 100, sd = 1)
B3 <- rep(c(2, 4, 5, 7), each = 25)
AB3 <- rbind(A2, B2)
colnames(AB3) <- rep(c("A","b"), each = 50)
data <- list(AB1, AB2, AB3)
# for loop showing error
histlist = NULL
for (i in seq_along(data)) {
columns <- unique(colnames(data[[i]]))
for (j in columns) {
columnsub <- data[[i]][, c(rep(c("A"), each = 50))]
histlist[[i]][[j]] <- hist(columnsub) #error from this line
}
}
I want the loop to create histlist with each i as a nested list having A and B with a nested hist() values. Basically, what you see in histlist after the first iteration.
Any help is greatly appreciated
We can correct the issue by turning histlist = NULL to :
histlist = vector('list', length(data))
This will pre-allocate a vector and allow for assigning to the list correctly.
You can do this with nested lapply call which will generate nested list automatically.
histlist <- lapply(data, function(x) {
cols <- unique(colnames(x))
lapply(cols, function(y) hist(x[, colnames(x) == y]))
})

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.

R: Get index names while looping through df elements

Say, I have a data frame and I need to do something with its cells and remember what cells I have changed. One way is to loop through indices with two for-loops. But is there a way to do this with one loop?
Perfectly I need something like this:
changes = data.frame(Row = character(), Col = character())
for (cell in df){
if (!(is.na(df))){
cell = do.smt(cell)
temp = list(Row = get.row(cell), Col = get.col(cell))
changes = rbind(changes,temp)
}
}
Example of what I need:
df = data.frame(A = c(1,2,3), B = c(4,5,6), C = c(7,8,9))
rownames(df) = c('a','b','c')
changes = data.frame(Row = NA, Col = NA)
for (i in rownames(df)){
for (j in colnames(df)) {
if (df[i,j] > 5) {
df[i,j] = 0
temp = list(Row = i, Col = j)
changes = rbind(changes, temp)
}
}
}
This gets rid of both loops
df = data.frame(A = c(1,2,3), B = c(4,5,6), C = c(7,8,9))
rownames(df) = c('a','b','c')
changes <- which(df > 5, arr.ind=TRUE)
df[changes] <- 0
If you want the format exactly as specified you can sort that out with
changes <- data.frame(changes,row.names=NULL)
changes$row <- rownames(df)[changes$row]
changes$col <- colnames(df)[changes$col]
and its a simple matter of sorting if you're concerned that the order of the rows matches your example output

How to do calculations on elements from a sublist in R

my code is as follows:
x <- data.frame(matrix(rnorm(20), nrow=10))
colnames(x) <- c("z", "m")
n_boot<-4
bs <- list()
for (i in 1:n_boot) {
bs[[i]] <- x[sample(nrow(x), 10, replace = TRUE), ]
}
bt<-matrix(unlist(bs), ncol = 2*n_boot, byrow = FALSE)
colnames(bt) <- rep(c("z","m"),times=n_boot)
M_to_boot <- bt[,seq(2,8,by=2)]
funct<-function(M_boot_max) {
od<-(1/((10*((10^((16-M_boot_max-25)/5))^3)/3)*((max(M_boot_max)-min(M_boot_max))/50)))
}
V_boot<-apply(M_to_boot,2,funct)
rows.combined <- nrow(M_to_boot)
cols.combined <- ncol(M_to_boot) + ncol(V_boot)
matrix.combined <- matrix(NA, nrow=rows.combined, ncol=cols.combined)
matrix.combined[, seq(1, cols.combined, 2)] <- M_to_boot
matrix.combined[, seq(2, cols.combined, 2)] <- V_boot
colnames(matrix.combined) <- rep(c("M_boot","V_boot"),times=n_boot)
df<-as.data.frame(matrix.combined)
start0 <- seq(1, by = 2, length = ncol(df) / 2)
start <- lapply(start0, function(i, df) df[i:(i+1)], df = df)
tests<-lapply(start, function(xy) split(xy, cut(xy$M_boot,breaks=5)))
Now I want to prepare some calculations on values V_boot from a sublists. To be specific I want to for each subsample calculate the sum of V_boot. So, for example I want for a bin M_boot "[[4]]$(0.811,1.25]" to have a value of sum(V_boot) for that bin. But I cannot figure out how to get to that each V_boot values.
Please help me.

Divide vector with grouping vector

I have two vectors, which I would like to combine in one dataframe. One of the vectors values needs to be divided into two columns. The second vector nc informs about the number of values for each observation. If nc is 1, only one value is given in values (which goes into val1) and 999 is to be written in the second column (val2).
What is an r-ish way to divide vector value and populate the two columns of df? I suspect I miss something very obvious, but can't proceed at the moment...Many thanks!
set.seed(123)
nc <- sample(1:2, 10, replace = TRUE)
value <- sample(1:6, sum(nc), replace = TRUE)
# result by hand
df <- data.frame(nc = nc,
val1 = c(6, 3, 4, 1, 2, 2, 6, 5, 6, 5),
val2 = c(999, 5, 999, 6, 1, 999, 6, 4, 4, 999))
Here's an approach based on this answer:
set.seed(123)
nc <- sample(1:2, 10, replace = TRUE)
value <- sample(1:6, sum(nc), replace = TRUE)
splitUsing <- function(x, pos) {
unname(split(x, cumsum(seq_along(x) %in% cumsum(replace(pos, 1, pos[1] + 1)))))
}
combineValues <- function(vals, nums) {
mydf <- data.frame(cbind(nums, do.call(rbind, splitUsing(vals, nums))))
mydf$V3[mydf$nums == 1] <- 999
return(mydf)
}
df <- combineValues(value, nc)
I think this is what you are looking for. I'm not sure it is the fastest way, but it should do the trick.
count <- 0
for (i in 1:length(nc)) {
count <- count + nc[i]
if(nc[i]==1) {
df$val1[i] <- value[count]
df$val2[i] <- 999
} else {
df$val1[i] <- value[count-1]
df$val2[i] <- value[count]
}
}

Resources