2015-07-17 11 views
5

Ich bin neu in R und versuche, einige for-Schleifen durch Funktionen aus der anwendungsfamilie zu ersetzen. ich nicht noch völlig verstehen, wie sie funktionieren, aber ich schaffte es, ein Arbeits Stück Code zu erzeugen:gibt mehrere Werte von sapply/lapply zurück

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

       }) 

Die Idee ist, „Schleife“ durch die Spalten des „Wärme“ data.frame und einige führen Berechnungen mit Werte von der "Wärme" data.frame. Aus diesem Grund verwende ich die erste Sapply-Funktion, um die entsprechenden Eigenschaften für jede der Pflanzen in der Heat-Tabelle aus der Tech-Tabelle zu erhalten. Der zweite Sapply führt dann die Berechnungen durch. Die Ausgabe "Ergebnis" ist genau das, was ich wollte.

Jetzt möchte ich mehr als Wert aus jeder Zeile in "Wärme" (Pel und EPR) berechnen. Aber ich habe keine Ahnung, wie man diese Werte aus den Sapply-Funktionen extrahiert. Ich habe Folgendes mit einer Liste versucht, aber das extrahiert die Werte als eine große Matrix mit 20 Zeilen. Das perfekte Ergebnis wäre etwa eine Liste mit zwei Matrix- oder data.frame-Objekten, die jeweils 10 Zeilen und 4 Spalten mit den pel/epr-Werten haben.

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

Ich würde mich über jede Hilfe oder Kommentar freuen.

Antwort

6

Ich schlage vor, dass Sie zuerst Ihre Daten aufräumen. see the tidyr package for more information

Dann fusionieren Sie die beiden Datenrahmen, und Sie brauchen keine Schleifen oder * Funktionen anwenden. Sie einfach tun, um Ihre Berechnungen in diesem neuen Datenrahmen, zum Beispiel durch das dplyr Paket mit:

library(tidyr) 
library(dplyr) 

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

vielen dank für ihren vorschlag. Ich verstehe, dass es in diesem Fall nicht notwendig ist, eine * apply-Funktion zu verwenden. aber die realen Daten sind 8760 Zeilen /> 300 Spalten und ich muss komplexere Berechnungen darauf durchführen als die Multiplikation im Beispiel – derdepe

+0

@derdepe Wenn Ihre Daten in einer Datenbank organisiert sind, ist es noch interessanter, dplyr zu verwenden. Da die von diesem Paket bereitgestellten Operationen direkt auf den db-Tabellen ausgeführt werden. [siehe dplyr vignette] (https://cran.rstudio.com/web/packages/dplyr/vignettes/introduction.html). Auch dieses Paket enthält viele Übersichts- und Fensterfunktionen. – 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 sorry ich habe deine Antwort nicht gesehen, ich werde meine löschen. –

2

Eine mögliche Option data.table (ähnlichen Ansatz wie @ user2992199 der dplyr Methode). Wir konvertieren den 'data.frame' in 'data.table' (setDT(heat)), ändern von 'wide' in 'long' mit melt, setzen den Schlüssel als 'id' (setkey(..., id)), verbinden mit 'tech', und erstellen die Spalten "a" und "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)][] 
Verwandte Themen