Verwenden des data.table-Pakets in meinem eigenen Paket

75

Ich versuche, das Paket data.table in meinem eigenen Paket zu verwenden. MWE ist wie folgt:

Ich erstelle eine Funktion, test.fun, die einfach ein kleines data.table-Objekt erstellt und dann die Spaltengruppierung "Val" durch die Spalte "A" summiert. Der Code ist

test.fun<-function ()
{
    library(data.table)
    testdata<-data.table(A=rep(seq(1,5), 5), Val=rnorm(25))
    setkey(testdata, A)
    res<-testdata[,{list(Ct=length(Val),Total=sum(Val),Avg=mean(Val))},"A"]
    return(res)
}

Wenn ich diese Funktion in einer regulären R-Sitzung erstelle und dann die Funktion ausführe, funktioniert sie wie erwartet.

> res<-test.fun()
data.table 1.8.0  For help type: help("data.table")
> res
     A Ct      Total        Avg
[1,] 1  5 -0.5326444 -0.1065289
[2,] 2  5 -4.0832062 -0.8166412
[3,] 3  5  0.9458251  0.1891650
[4,] 4  5  2.0474791  0.4094958
[5,] 5  5  2.3609443  0.4721889

Wenn ich diese Funktion in ein Paket einfüge, das Paket installiere, das Paket lade und dann die Funktion ausführe, wird eine Fehlermeldung angezeigt.

> library(testpackage)
> res<-test.fun()
data.table 1.8.0  For help type: help("data.table")
Error in `[.data.frame`(x, i, j) : object 'Val' not found

Kann mir jemand erklären, warum dies geschieht und was ich tun kann, um es zu beheben. Jede Hilfe wird sehr geschätzt.

Ruser
quelle
15
Ich vermute, dass Sie keine Abhängigkeit deklariert haben. Sie sollten library(data.table)aus Ihrer Funktion entfernen und depends:data.tablein Ihrem Namespace und in DESCRIPTION deklarieren .
Andrie

Antworten:

91

Andries Vermutung ist richtig, +1. Es gibt eine FAQ (siehe vignette("datatable-faq")) sowie eine neue Vignette zum Importieren data.table:

FAQ 6.9: Ich habe ein Paket erstellt, das von data.table abhängt. Wie stelle ich sicher, dass mein Paket data.table-fähig ist, damit die Vererbung von data.frame funktioniert?

Entweder i) data.tablein das Depends:Feld Ihrer DESCRIPTION-Datei aufnehmen oder ii) data.tablein das Imports:Feld Ihrer DESCRIPTION-Datei UND import(data.table)in Ihre NAMESPACE-Datei aufnehmen.

Weiterer Hintergrund ... oben in [.data.table(und anderen data.tableFunktionen) sehen Sie einen Schalter, der vom Ergebnis eines Anrufs an abhängt cedta(). Dies steht für Calling Environment Data Table Aware. Das Tippen data.table:::cedtazeigt, wie es gemacht wird. Es setzt voraus, dass das aufrufende Paket einen Namespace hat und dass dieser Namespace importiert oder davon abhängt data.table. Auf diese Weise data.tablekann an nicht data.table-fähige Pakete (wie z. B. Funktionen in base) übergeben werden, und diese Pakete können die absolut standardmäßige [.data.frameSyntax auf dem verwenden data.table, ohne dass dies data.frame is()a bewusst data.tableist.

Dies ist auch der Grund, warum die data.tableVererbung früher nicht mit namenlosen Paketen kompatibel war und warum wir auf Benutzeranforderung die Autoren solcher Pakete bitten mussten, ihrem Paket einen Namespace hinzuzufügen, um kompatibel zu sein. Glücklicherweise ist dieses Problem behoben, nachdem R einen Standard-Namespace für fehlende Pakete (ab Version 2.14.0) hinzugefügt hat:

ÄNDERUNGEN IN R VERSION 2.14.0
* Alle Pakete müssen einen Namespace haben, und einer wird bei der Installation erstellt, wenn er nicht in den Quellen angegeben ist.

Matt Dowle
quelle
(Tut mir leid, das wiederzubeleben, aber ...) Matthew, können Sie klären, wie dies von einem interaktiven Standpunkt aus funktionieren würde? Wenn mein Paket data.tableeinem Benutzer in einer interaktiven Sitzung eine zurückgibt , muss er dann die data.tableSemantik verwenden, oder gibt es eine Möglichkeit, die bekannte data.frameSyntax zu unterstützen?
Jeff Allen
1
@ JeffAllen Das ist neu ... nicht sicher. Wenn Ihr Paket von data.table abhängt, wird dies den Benutzer data.table darauf aufmerksam machen, denke ich. Vielleicht würde das Importieren von data.table nicht (und vielleicht möchten Sie das auch).
Matt Dowle
Danke Matt! Dies löste mein Problem nach einem halben Tag voller Fehler und Durchsuchen des Netzes. Ich hatte data.table nur in die Importe eingefügt. Der Code funktionierte gut in R, aber nicht innerhalb des Pakets. Verschoben nach Depends und es funktioniert!
Oskar Hansson
4
@OskarHansson Glad Depends funktioniert, aber Import sollte funktionieren, solange Sie beide Importe in DESCRIPTION und auch import(data.table) in NAMESPACE hatten?
Matt Dowle
3
@ MattDowle Du hast recht. Ich habe einen HINWEIS bei der Verwendung von Depends erhalten. Ich habe wieder zu Imports + gewechselt, das @import data.tableim Code hinzugefügt wurde, damit Roxygen es import(data.table)im NAMESPACE hinzufügt .
Oskar Hansson
29

Hier ist das komplette Rezept:

1) Fügen Sie data.tablezu ImportsIhrer DESCRIPTIONDatei.

2) Fügen Sie @import data.tableIhrer jeweiligen .R-Datei hinzu (dh die .R-Datei, in der sich Ihre Funktion befindet, die den Fehler auslöst Error in [.data.frame(x, i, j) : object 'Val' not found).

3) Geben Sie library(devtools)Ihr Arbeitsverzeichnis ein und stellen Sie es so ein, dass es auf das Hauptverzeichnis Ihres R-Pakets zeigt.

4) Typ document(). Dadurch wird sichergestellt, dass Ihre NAMESPACEDatei eine import(data.table)Zeile enthält.

5) Typ build()

6) Typ install()

Eine gute Einführung in was build()und install()was gibt es unter: http://kbroman.org/pkg_primer/ .

Sobald Sie Ihre R-Sitzung geschlossen und sich das nächste Mal angemeldet haben, können Sie sofort mit folgenden Funktionen einspringen:

1) Typ library("my_R_package")

2) Geben Sie den Namen Ihrer Funktion ein, die in der oben genannten .R-Datei enthalten ist.

3) Viel Spaß! Sie sollten die gefürchteten nicht mehr erhaltenError in [.data.frame(x, i, j) : object 'Val' not found

Kriegsschiff
quelle
Ich habe diese Anweisungen befolgt und bekomme function not found. Ich konnte nichts Ähnliches finden, also habe ich eine Frage erstellt stackoverflow.com/questions/56720520/…
Kill3rbee Lee Mtoti