2013-03-31 6 views
12

Blick auf die rcpp Dokumentation und Rcpp::DataFrame in der Galerie erkannte ich, dass ich nicht wusste, wie man einen DataFrame durch Referenz zu ändern. Etwas googelnd fand ich diesen Beitrag auf SO und diesen Beitrag im Archiv. Da ist nichts offensichtlich, also ich vermute, ich vermisse etwas Großes wie "Es ist schon der Fall, weil" oder "es macht keinen Sinn, weil".Passing durch Referenz ein data.frame und aktualisieren es mit rcpp

habe ich versucht, die folgende, die kompiliert, aber das data.frame Objekt updateDFByRef in R bestanden blieb unberührt

#include <Rcpp.h> 
using namespace Rcpp; 

// [[Rcpp::export]] 
void updateDFByRef(DataFrame& df) { 
    int N = df.nrows(); 
    NumericVector newCol(N,1.); 
    df["newCol"] = newCol; 
    return; 
} 
+6

Sie haben bereits auf der Liste gepostet. Warum repostest du hier? –

Antwort

12

Die Art und Weise DataFrame::operator[] implementiert ist in der Tat leeds auf eine Kopie, wenn Sie das tun:

df["newCol"] = newCol; 

zu tun, was Sie wollen, müssen Sie überlegen, was ein Datenrahmen ist, wird eine Liste von Vektoren, mit bestimmten Attributen . Dann können Sie Daten vom Original abrufen, indem Sie die Vektoren (die Zeiger, nicht ihren Inhalt) kopieren.

So etwas macht es. Es ist ein bisschen mehr Arbeit, aber nicht so schwer.

// [[Rcpp::export]] 
List updateDFByRef(DataFrame& df, std::string name) { 
    int nr = df.nrows(), nc= df.size() ; 
    NumericVector newCol(nr,1.); 
    List out(nc+1) ; 
    CharacterVector onames = df.attr("names") ; 
    CharacterVector names(nc + 1) ; 
    for(int i=0; i<nc; i++) { 
     out[i] = df[i] ; 
     names[i] = onames[i] ; 
    } 
    out[nc] = newCol ; 
    names[nc] = name ; 
    out.attr("class") = df.attr("class") ; 
    out.attr("row.names") = df.attr("row.names") ; 
    out.attr("names") = names ; 
    return out ; 
} 

Mit diesem Ansatz sind Probleme verbunden. Ihr ursprünglicher und der von Ihnen erstellte Datenrahmen teilen dieselben Vektoren und es können so schlimme Dinge passieren. Verwenden Sie das also nur, wenn Sie wissen, was Sie tun.

+0

Vielen Dank, das ist jetzt klarer, ich denke, ich hatte Grundkenntnisse wie die Tatsache, dass 'SEXP' schon Referenzen waren. Ich werde auf http://cran.r-project.org/doc/manuals/r-release/R-ints.pdf nachsehen. Im Moment habe ich die "data.table" in R vorbereitet, indem ich eine zusätzliche Spalte hinzugefügt und in Rcpp aktualisiert habe, so dass keine Kopie (glaube ich) gemacht wurde. Das ist viel besser, ich verstehe die Risiken, aber das ist gut für das, was ich tue. Merci Beaucoup. – statquant

+0

Noch einmal, Sie sind einfach nur falsch: _Ich denke, ich war Grundkenntnisse wie die Tatsache, dass SEXP bereits Referenzen waren. Nicht Verweise, sondern Zeiger. Versuchen Sie herauszufinden, wofür der letzte Buchstabe in SEXP steht. –

3

Die kurzen Antworten ist „weil es keinen Sinn macht“.

Eine data.frame ist im Wesentlichen eine Liste von Vektoren. Ein paar Sekunden Nachdenken machen deutlich, dass das Hinzufügen einer neuen Spalte zu dieser Liste eine Kopie nach sich zieht. Sie ändern also Ihre Variable df in dem Beispiel, geben sie nicht zurück und verlieren somit die Änderung.

Lediglich etwas zu wünschen, was auf eine bestimmte Art funktioniert, reicht nicht immer aus.

+0

So ersetzen 'void' durch' SEXP' zum Beispiel ein 'return df;' wird den Trick tun? – agstudy

+0

Ja, irgendeine von SEXP, Rcpp :: List oder Rcpp :: DataFrame wird tun. Momentan scheint es, als würde die Liste wieder erscheinen, also scheinen wir den Datenrahmen zu verlieren. –

+0

danke..ich teste es einfach und es funktioniert wie ein Charme! Wenn ich 'as.data.frame' zum Ergebnis hinzufüge, bekomme ich die gewünschten Daten. Frame-ness ... – agstudy