2016-07-14 6 views
1

Ich versuche, eine Zeile in data.table anwenden und kann es nicht funktionieren. Wie mache ich das?Zeile gelten in data.table mit Spaltennummer Referenzen

library(data.table) 
data(diamonds, package= "ggplot2") 
dt <- data.table(diamonds) 

# what I want, but via data.table 
diamonds$sum1 <- apply(dt[,5:10, with=FALSE], 1, sum) 
diamonds$sd1 <- apply(dt[,5:10, with=FALSE], 1, sd) 

# why don't these work? 
dt[, `:=` (sum1= sum(.SD), 
      sd1= sd(.SD)), .SDcols= 5:10, by= .EACHI] 
dt[, `:=` (sum1= sum(dt[,5:10, with=FALSE]), 
      sd1= sd(dt[,5:10, with=FALSE])), by= .EACHI] 

Beide geben diesen Fehler:

Error in [.data.table (dt, , := (sum1 = sum(.SD), sd1 = sd(.SD)), .SDcols = 5:10, : object 'f__' not found

verwandt, aber nicht die gleichen Fragen: (1), (2)

+1

Es gibt eine FR irgendwo für 'by = .EACHI' zu tun, was Sie wollen, aber im Moment hat es nur Bedeutung beim Beitritt. Verwenden Sie 'by = 1: nrow (dt)' anstatt, wenn Sie müssen, aber vermeiden Sie es offensichtlich um jeden Preis. – eddi

+1

Probieren Sie es aus, im Allgemeinen zu vermeiden. Sie können einfach mit 'melt' in ein langes Format konvertieren und dann in einer einzigen Spalte arbeiten. Oder Sie könnten 'rowMeans' verwenden oder die' matrixStats' auschecken, die viele andere vektorisierte Zeilenoperationen haben. Oder schreiben Sie [Ihre eigene] (http://stackoverflow.com/a/25100036/3001626) vektorisierte Funktion. Oder benutze Rcpp. Meiner Ansicht nach ist R eine Sprache, die Sie immer wieder mit intelligenten Tricks ausstatten müssen, um Ihre Probleme effizient zu lösen, und zwar so, wie es auf der ersten Seite am sinnvollsten ist. –

+0

@DavidArenburg Fair genug Punkte. Aber die Dev-Zeit, um dies in Rcpp zu schreiben, ist es nicht wert, wenn ich nur das 'data.frame'-Framework verwenden kann –

Antwort

0

Dies verwendet die Rcpp Paket, um eine schnelle Funktion in C++ zu schreiben, die dann verfügbar, um von R anzurufen, aber ich denke, dass es ziemlich klar und wartbar ist.

library(Rcpp) 

cppFunction('Rcpp::NumericVector SDrowSums(Rcpp::DataFrame SD) { 
    Rcpp:: NumericVector sums; 
    for(int i = 0; i<SD.nrows(); ++i) { // each row of .SD 
     sums.push_back( 0.0 
      + as<NumericVector>(SD[4]) [i] 
      + as<NumericVector>(SD[5]) [i] 
      + as<IntegerVector>(SD[6]) [i] // IntegerVector, or will be slow! 
      + as<NumericVector>(SD[7]) [i] 
      + as<NumericVector>(SD[8]) [i] 
      + as<NumericVector>(SD[9]) [i] 
     ); 
    } 
    return sums; 
}'); 

dt[, "sumNew" := SDrowSums(.SD) ,by=seq_len(nrow(dt))] 

Die letzte Zeile ruft die Funktion SDrowSums einmal für jede Zeile der Tabelle (by=seq_len(nrow(dt))).

Für mich läuft das in etwa 0,15 Sekunden. Nicht so schnell wie rowSums (0,01s für mich), aber die gleiche Geschwindigkeit wie Ihr ursprünglicher Code: diamonds$sum1 <- apply(dt[,5:10, with=FALSE], 1, sum).

Sie können sogar die (auf null basierende) Spaltenverschiebungen ersetzen (4, 5, 6, 7, 8, 9) mit den Namen ("depth", "table", ...). Dies verlangsamt es ein wenig, ist aber besser lesbar.

In der Praxis wird SDrowSums eine für jede Zeile mit nrow(.SD)==1 aufgerufen werden, aber diese cpp-Funktion ist ein bisschen allgemeiner, mehrreihige SD zu erlauben.

+1

Danke! Ich denke, eine innere Schleife würde Ihre Lösung verbessern (generischer). '... für (int j = 0; n