简体   繁体   中英

R nested for loop structure for all combinations of two variables

I want to run a function on each level of a data.frame variable based on the condition of each level of another data.frame variable (or lists, if it's better to work with them for some reason).

If one of the variables achieves a certain condition (eg, > 15), I then want to run a simple function (eg, product) on each pair of variables and add the results to a new list. For the sake of my needs and other's future needs, I am hoping for a solution that is flexible for any condition and any function.

I am new to programming/R and do not know how to appropriate structure a for loop (or other method) in order to run the function for all combinations of elements in both data.frame variables. It seems like this should be really easy to achieve but I've been searching for hours and cannot find a solution.

This is the nested for loop code I am working on:

df1 <- data.frame(c(1, 2, 3))
df2 <- data.frame(c(10, 20, 30))

list1 <- list()
for (i in 1:length(df1)) {
  for (j in 1:length(df2)) {
    if (df2[j,] > 15) {
      list1[[i]] <-  df1[i,] * df2[j,]}
    }}
list1

When I run the current code I get and empty list results: list(). What I want returned is something like this:

[[1]]
[1] 20

[[2]]
[1] 30

[[3]]
[1] 40

[[4]]
[1] 60

[[5]]
[1] 60

[[6]]
[1] 90

Consider sapply with two inputs to iterate across nrow of both data frames with list conversion:

mat <- sapply(1:nrow(df2), function(i, j) ifelse(df2[j,] > 15, df1[i,]*df2[j,], NA),
              1:nrow(df1))

mat <- mat[!is.na(mat)]
mat
# [1] 20 30 40 60 60 90

as.list(mat)    
# [[1]]
# [1] 20
# 
# [[2]]
# [1] 30
# 
# [[3]]
# [1] 40
# 
# [[4]]
# [1] 60
# 
# [[5]]
# [1] 60
# 
# [[6]]
# [1] 90

There are many ways to do this, here are two of them: one is your for loop and another is vectorised.

for loop

There are few mistakes in your code, both df1 and df2 have length = 1. Therefore, i and j are only set as 1. This can be fixed by using nrow instead of length . Another thing is to create an index outside the loop to assign your results to list. Following code works

df1 <- data.frame(c(1, 2, 3))
df2 <- data.frame(c(10, 20, 30))

list1 <- list()
index=0
for (i in 1:nrow(df1)) {
  for (j in 1:nrow(df2)) {
    if (df2[j,] > 15) {
      index=index+1
      list1[[index]] <-  df1[i,] * df2[j,]}
  }}
list1

[[1]]
[1] 20

[[2]]
[1] 30

[[3]]
[1] 40

[[4]]
[1] 60

[[5]]
[1] 60

[[6]]
[1] 90

vectorized way

Using expand.grid to generate the required combinations and prod to find their products

dat=expand.grid(df1[,1], df2[df2 > 15,1])
dat=dat[order(dat$Var1),]
apply(dat, 1, prod)

 1  4  2  5  3  6 
20 30 40 60 60 90 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM