return 来自 sapply/lapply 的多个值

return multiple values from sapply/lapply

我是 R 的新手,正在尝试用 apply 系列的函数替换一些 for 循环。 我仍然不完全理解它们是如何工作的,但我设法生成了一段有效的代码:

#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)
                })

              })

想法是 "loop" 通过 "heat" data.frame 的列并执行一些计算 来自 "heat" data.frame 的值。出于这个原因,我使用第一个 sapply 函数来获得相应的 来自技术 table 的热量 table 中每种植物的特征。第二个 sapply 然后执行 计算。输出 "result" 正是我想要的。

现在我想从 "heat"(pel 和 epr)中的每一行计算更多的值。 但我不知道如何从 sapply 函数中提取这些值。 我尝试了以下列表,但这将值提取为一个包含 20 行的大矩阵。 完美的结果应该是一个包含两个矩阵或 data.frame 对象的列表,每个对象有 10 行和 4 列 具有 pel/epr 个值。

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)
              })

如有任何帮助或评论,我将不胜感激。

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

我建议你先整理一下你的数据。 see the tidyr package for more information

然后合并两个数据帧,不需要任何循环或 *apply 函数。您只需在这个新数据框中进行计算,例如使用 dplyr 包:

library(tidyr)
library(dplyr)

heat %>%
  gather(id, value) %>%
  left_join(tech, by="id") %>%
  mutate(a = value * capacity.el,
         b = value * capacity.th)

使用 data.table 的可能选项(与 @user2992199 的 dplyr 方法类似的方法)。我们把'data.frame'转成'data.table'(setDT(heat)),把'wide'转成'long'格式,用melt,设置key为'id' (setkey(..., id)),加入 'tech',并创建列 'a' 和 '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)][]