2015-07-17 17 views
5

Sono nuovo a R e sto cercando di sostituire alcuni loop con le fuctions della famiglia apply. ho ancora Non tiratevi capire completamente come funzionano, ma sono riuscito a produrre un pezzo di lavoro di codice:restituisce più valori da sapply/lapply

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

       }) 

L'idea è quella di "loop" attraverso le colonne del data.frame "calore" e eseguire alcune calcoli con i valori da "heat" data.frame. Per questo motivo utilizzo la prima funzione fasulla per ottenere le corrispondenti caratteristiche per ciascuna delle piante nella tabella di calore dalla tabella tecnica. Il secondo sapply esegue quindi i calcoli . L'output "risultato" è esattamente ciò che volevo.

Ora voglio calcolare più del valore di ogni riga in "calore" (pel ed epr). Ma non ho idea di come estrarre questi valori dall'interno delle simpatiche fuctions. Ho provato quanto segue con un elenco ma questo estrae i valori come un'unica grande matrice con 20 righe. Il risultato perfetto sarebbe qualcosa di simile a un elenco con due oggetti matrice o data.frame che hanno ciascuno 10 righe e 4 colonne con i valori 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) 
       }) 

Apprezzerei qualsiasi aiuto o commento.

risposta

6

Suggerisco di riordinare i dati prima. see the tidyr package for more information

Quindi si uniscono i due frame di dati e non sono necessari loop o * applica funzioni. Il tuo semplicemente fare i vostri calcoli all'interno di questa nuova dataframe, ad esempio utilizzando il pacchetto dplyr:

library(tidyr) 
library(dplyr) 

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

grazie mille per il tuo suggerimento. Capisco che non è necessario in questo caso utilizzare una funzione * apply. ma i dati reali sono 8760 righe /> 300 colonne e dovrò fare calcoli più complessi su di esso rispetto alla moltiplicazione nell'esempio – derdepe

+0

@derdepe Se i dati sono organizzati in un database è ancora più interessante usare dplyr. Poiché le operazioni fornite da questo pacchetto verranno eseguite direttamente sulle tabelle DB. [vedi dplyr vignette] (https://cran.rstudio.com/web/packages/dplyr/vignettes/introduction.html). Anche questo pacchetto contiene molte funzioni di riepilogo e finestra. – MarkusN

3
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 
+1

Oups scusa non ho visto la tua risposta, eliminerò il mio. –

2

un'opzione possibile utilizzare data.table (approccio simile a quello di @ user2992199 metodo dplyr). Convertiamo "data.frame" in "data.table" (setDT(heat)), passiamo dal formato "largo" a "lungo" con melt, impostiamo la chiave come "id" (setkey(..., id)), ci uniamo con "tech" e creiamo le colonne 'a' e '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)][] 
Problemi correlati