简体   繁体   中英

Storing output from R multiple loops into a list

I'm trying to carry out the following action on the columns of a dataframe (df1):

term1+term2+term3*req_no

req_no is a range of numbers: 20:24

df1:

 ID     term1   term2   term3
X299    1.2 2.3 0.12
X300    1.4 0.6 2.4
X301    0.3 1.6 1.2
X302    0.9 0.6 0.4
X303    0.3 1.8 0.3
X304    1.3 0.3 2.1

I need help t get this output and here's my attempt:

Required output:
  ID    20  21  22  23  24
X299    5.9 6.02    6.14    6.26    6.38
X300    50  52.4    54.8    57.2    59.6
X301    25.9    27.1    28.3    29.5    30.7
X302    9.5 9.9 10.3    10.7    11.1
X303    8.1 8.4 8.7 9   9.3
X304    43.6    45.7    47.8    49.9    52

Here's:

results <- list()
req_no <- 20:25
for(i in 1:nrow(df1){
   for(j in rq_no){
      res <- term1+term2+term3*j
      results[j] <- res
   }
   results[[i]]
}
results2 <- do.call("rbind",result) 

Help will be appreciated.

Consider directly assigning new columns with sapply using your formula:

df[paste0(req_no)] <- sapply(req_no, function(r) with(df, term1 + term2 + term3 * r))
    
df
#     ID term1 term2 term3   20    21    22    23    24
# 1 X299   1.2   2.3  0.12  5.9  6.02  6.14  6.26  6.38
# 2 X300   1.4   0.6  2.40 50.0 52.40 54.80 57.20 59.60
# 3 X301   0.3   1.6  1.20 25.9 27.10 28.30 29.50 30.70
# 4 X302   0.9   0.6  0.40  9.5  9.90 10.30 10.70 11.10
# 5 X303   0.3   1.8  0.30  8.1  8.40  8.70  9.00  9.30
# 6 X304   1.3   0.3  2.10 43.6 45.70 47.80 49.90 52.00

Here are a couple different approaches, though neither as succinct as Parfait's. Sample data:

df <- data.frame(ID=c("X299", "X300"),
                 term1=c(1.2, 1.4),
                 term2=c(2.3, 0.6),
                 term3=c(0.12, 2.4))
req_no <- 20:25

Loop approach

Your initial approach is headed in the right direction, but in the future, it would help to specify exactly what your error or problem is. For an iterated and perhaps easier-to-read approach, here's one answer:

results <- matrix(data=NA, nrow=nrow(df), ncol=length(req_no))  # Empty matrix to store our results
colnames(results) <- req_no  # Optional; name columns based off of req_no values
for(i in 1:nrow(df)) {
    # Do the calculation we want; returns a vector length 6
    res <- df[i,]$term1 + df[i,]$term2 + (df[i,]$term3 * req_no)
    # Save results for row i of df into row i of results matrix
    results[i,] <- res
}
# Now bind the columns (named 20 through 25) to the respective rows of df
output <- cbind(df, results)
output

From your initial attempt, note:

  • We only do one loop, since it is easy to multiply by a vector in R
  • There are a few ways to subset data from a data frame in R. In this case, df[i,] gets everything in the i-th row, while $termX gets value in the column named termX
  • Using a results matrix instead of a list makes it very easy to copy the temporary computations (for each row) into rows of the matrix
  • Rather than rbind() (row bind), we want cbind() (column bind) to bind those results to new columns of the original rows.

Output:

    ID term1 term2 term3   20    21    22    23    24   25
1 X299   1.2   2.3  0.12  5.9  6.02  6.14  6.26  6.38  6.5
2 X300   1.4   0.6  2.40 50.0 52.40 54.80 57.20 59.60 62.0

Dplyr/purrr functions

This could also be solved using tidy functions. In essence it's a pretty similar approach to Parfait's answer, but I've made the steps a bit more verbose to see what's going on.

# Use purrr's map functions to do the computation we want
nested_df <- df %>%
    # Make new column holding term3 * req_no (stores a vector in each new cell)
    mutate(term3r = map(term3, ~ .x * req_no)) %>%
    # Make new column which sums the three columns of interest (stores a vector in each new cell)
    mutate(sum = pmap(list(term1, term2, term3r), ~ ..1 + ..2 + ..3))

# "Unnest" those vectors which store our sums, and keep only those and ID
output <- nested_df %>%
    # Creates six new columns (named ...1 to ...6) with the elements of each sum
    unnest_wider(sum) %>%
    # Keeps only the output data and IDs
    select(ID, ...1:...6)
output

Output:

# A tibble: 2 x 7
  ID     ...1  ...2  ...3  ...4  ...5  ...6
  <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 X299    5.9  6.02  6.14  6.26  6.38   6.5
2 X300   50   52.4  54.8  57.2  59.6   62

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