Return multiple values ​​from sapply / lapply

I am new to R and trying to replace some of the loops with fuctions from the apply family. I still don’t understand how they work, but I managed to create working code:

#create some input data tech<-data.frame(cbind(c("p1","p2","p3","p4"),c(15,15,15,100),c(10,8,18,100))) colnames(tech)=c("id","capacity.el","capacity.th") tech$capacity.el<-as.numeric(tech$capacity.el) tech$capacity.th<-as.numeric(tech$capacity.th) heat<-data.frame(cbind(c(2,12,6,20,32,21,25,16,34,0),c(31,18,3,27,30,31,18,4,24,7),c(2,12,6,20,32,21,25,16,34,0),c(31,18,3,27,30,31,18,4,24,7))) colnames(heat)=c("p1","p2","p3","p4") > tech id capacity.el capacity.th 1 p1 2 1 2 p2 2 4 3 p3 2 3 4 p4 1 2 > heat p1 p2 p3 p4 1 2 31 2 31 2 12 18 12 18 3 6 3 6 3 4 20 27 20 27 5 32 30 32 30 6 21 31 21 31 7 25 18 25 18 8 16 4 16 4 9 34 24 34 24 10 0 7 0 7 #the result should be a matrix/list pel=matrix(,nrow=nrow(heat),ncol=ncol(heat)) epr=matrix(,nrow=nrow(heat),ncol=ncol(heat)) result<-list() #main code result<-sapply(colnames(heat),function(x) { a<-tech$capacity.th[match(x,tech$id)] b<-tech$capacity.el[match(x,tech$id)] sapply(heat[,x],function(y) { pel<-a*y return(pel) }) }) 

The idea is to loop around the “heat” columns of data.frame and do some calculations using the values ​​from the “heat” data frame. For this reason, I use the first sapply fuction to obtain the appropriate characteristics for each of the plants in the heat table from the technological table. Then the second sapply performs the calculations. The result "result" is exactly what I wanted.

Now I want to calculate more than the value from each row in "heat" (pel and epr). But I do not know how to extract these values ​​from sapply fuctions. I tried the following with a list, but this retrieves the values ​​as one large matrix with 20 rows. An ideal result would be like a list with two matrix or data.frame objects, each of which has 10 rows and 4 columns with pel / epr values.

 result<-sapply(colnames(heat),function(x) { a<-tech$capacity.th[match(x,tech$id)] b<-tech$capacity.el[match(x,tech$id)] sapply(heat[,x],function(y) { pel<-a*y epr<-b*y }) new<-list(pel,epr) return(new) }) 

I would appreciate any help or comment.

+5
source share
3 answers

I suggest you first tidy up your data. see tidyr package for more information

Then you combine the two data frames and you won’t need any cycles or * apply functions. You just do your calculations in this new data framework, for example, using the dplyr package:

 library(tidyr) library(dplyr) heat %>% gather(id, value) %>% left_join(tech, by="id") %>% mutate(a = value * capacity.el, b = value * capacity.th) 
+6
source
 o <- match(tech$id,names(heat)); ## precompute tech row order to match heat column order ms <- names(tech[-1]); ## store multiplier column names from tech setNames(lapply(ms,function(m) t(t(heat)*tech[o,m])),ms); ## $capacity.el ## p1 p2 p3 p4 ## [1,] 4 62 4 31 ## [2,] 24 36 24 18 ## [3,] 12 6 12 3 ## [4,] 40 54 40 27 ## [5,] 64 60 64 30 ## [6,] 42 62 42 31 ## [7,] 50 36 50 18 ## [8,] 32 8 32 4 ## [9,] 68 48 68 24 ## [10,] 0 14 0 7 ## ## $capacity.th ## p1 p2 p3 p4 ## [1,] 2 124 6 62 ## [2,] 12 72 36 36 ## [3,] 6 12 18 6 ## [4,] 20 108 60 54 ## [5,] 32 120 96 60 ## [6,] 21 124 63 62 ## [7,] 25 72 75 36 ## [8,] 16 16 48 8 ## [9,] 34 96 102 48 ## [10,] 0 28 0 14 
+3
source

A possible option using data.table (a similar approach as the @ user2992199 dplyr method). We convert "data.frame" to "data.table" ( setDT(heat) ), switch from wide to long format with melt , set the key as "id" ( setkey(..., id) ) , connect to "tech" and create the columns "a" and "b".

 library(data.table)#v1.9.5+ setkey(melt(setDT(heat), variable.name='id'), id)[tech ][, c('a', 'b') := list(value*capacity.el, value*capacity.th)][] 
+2
source

All Articles