2015-01-16 2 views
9

Mit R data.table Paket,R data.table ': =' Arbeiten in direktem Aufruf, aber die gleiche Funktion in einem Paket nicht

Dies funktioniert:

instruction = "a = data.table(name=1:3, value=1:3, blah=1:3); a[,c('value', 'blah'):=NULL]" 
eval(parse(text=instruction)) 
# name 
#1: 1 
#2: 2 
#3: 3 

Dies funktioniert:

myFunc = function(instruction) { 
eval(parse(text=instruction)) 
} 
myFunc(instruction) 
# name 
#1: 1 
#2: 2 
#3: 3 

Legen Sie nun diese Funktion in ein Paket, laden Sie es und versuchen Sie es aufzurufen. Dies funktioniert nicht:

myFuncInPackage(instruction) 
#Error in `:=`(c("value", "blah"), NULL) : 
# Check that is.data.table(DT) == TRUE. Otherwise, := and `:=`(...) are defined for use in j, once only and in particular ways. See help(":="). 

Warum?


EDIT: @Roland weist darauf hin, dass das Hinzufügen von data.table im Paket Depends Feld macht es Arbeit. Ich denke jedoch nicht, dass dies eine großartige Lösung ist, da das Paket nicht wirklich von data.table abhängig ist, sie benötigt oder verwendet. Ich möchte nur data.table mit dem Paket verwenden können.

Darüber hinaus funktioniert alles andere mit data.table gut in der Funktion, nur nicht der := Operator.

Also könnte ich eine Folgefrage sein: sollte ich data.table zu den Depends jedes Pakets hinzufügen, das ich schreibe, so dass data.tables innerhalb der Funktionen dieses Pakets wie erwartet funktionieren? Das scheint nicht richtig zu sein ... Was ist der richtige Weg, um das zu erreichen?

+2

Haben Sie den Ratschlag in [FAQ 6.9] (http://cran.r-project.org/web/packages/data.table/vignettes/datatable-faq.pdf) befolgt? Außerdem wird von 'eval (parse())' abgeraten. – Roland

+0

@Roland data.table zu Depends hinzufügen löst es ... aber führt zu einem Problem: mein Paket hängt nicht wirklich von data.table ab; in der Tat, es ist völlig unabhängig. Wie in diesem Beispiel, hat es nur eine Funktion, 'myFunc' - keine data.table nichts. Aber es kann nicht mit data.table verwendet werden, ohne es zu Depends hinzuzufügen ... – nsheff

+0

@Roland, ich weiß, 'eval (parse())' wird abgeraten, und dies ist ein sinnloses Beispiel, aber die Frage steht immer noch. ..in einigen Fällen kann ich es nicht umgehen. – nsheff

Antwort

0

Ich habe endlich die Antwort auf diese Frage (nach mehreren Jahren) herausgefunden. Alle Kommentare und Antworten vorgeschlagen data.table zu Depends oder Imports hinzufügen, aber das ist falsch; Das Paket hängt nicht von data.table und das könnte jedes Paket hypothetisch sein, nicht nur data.table, was bedeutet, logische Schlussfolgerung, würde der Vorschlag erfordern alle möglichen Pakete zu Depends hinzufügen - da diese Abhängigkeit vom Benutzer zur Verfügung gestellt wird instruction, nicht durch die Funktion, die durch das Paket zur Verfügung gestellt wird.

Stattdessen, im Grunde ist es, weil Aufruf an eval innerhalb des Namespace des Pakets erfolgt, und dies enthält nicht die Funktionen von anderen Paketen zur Verfügung gestellt. Ich löste schließlich die durch die globale Umwelt im eval Aufruf spezifiziert:

myFunc = function(instruction) { 
eval(parse(text=instruction), envir=globalenv()) 
} 

Warum das funktioniert

Dies bewirkt, dass die eval Funktion in der Umgebung durchgeführt werden, dass die erforderlichen Pakete in der Suche enthalten wird Pfad.

Im Fall data.table ist es wegen der Komplexität der Funktionsüberlastung besonders schwierig zu debuggen. In diesem Fall ist der Täter nicht die := Funktion, sondern die Funktion. Der := Fehler ist ein Ablenkungsmanöver.Zum Zeitpunkt des Schreibens, die := Funktion in data.table ist wie folgt definiert:

https://github.com/Rdatatable/data.table/blob/348c0c7fdb4987aa6da99fc989431d8837877ce4/R/data.table.R#L2561

":=" <- function(...) stop('Check that is.data.table(DT) == TRUE. Otherwise, := and `:=`(...) are defined for use in j, once only and in particular ways. See help(":=").')

Das ist es. Was das heißt: Jeder Aufruf an := als Funktion wird mit einer Fehlermeldung gestoppt, weil die Autoren nicht beabsichtigen, := zu verwenden. Stattdessen ist := wirklich nur ein Schlüsselwort, das von der [-Funktion in data.table interpretiert wird.

Aber was hier geschieht: Wenn die [ Funktion nicht korrekt an die von data.table angegebenen Version abgebildet wird, und stattdessen auf die [ Basis zugeordnet ist, dann haben wir ein Problem - da es nicht := verarbeiten kann und so Es wird als eine Funktion behandelt und löst die Fehlermeldung aus. Die Täterfunktion ist also [.data.table - der überladene Klammeroperator.

Was geschieht ist in meinem neuen Paket (das hält myFuncInPackage), wenn es um den Code zu bewerten geht, es löst die [ Funktion auf die Funktion Basis [ statt auf data.table ‚s [ Funktion. Es versucht := als eine Funktion auszuwerten, die von der [ nicht konsumiert wird, da es nicht die richtige [ ist, also := wird als Funktion statt als data.table 's übergeben, da sich data.table nicht im Namespace befindet (oder niedriger in der search() Hierarchie. in dieser Einstellung wird := nicht verstanden und so wird es wird als Funktion ausgewertet, so dass die Auslösung der Fehlermeldung im data.table Code oben.

Wenn Sie die eval angeben, um im globalen passieren Umgebung wird die [-Funktion korrekt in [.data.table aufgelöst und die := wird richtig interpretiert.

Im Übrigen können Sie auch diese verwenden, wenn Sie nicht eine Zeichenfolge durchzulassen, aber einen Codeblock (besser) zu eval() in einem Paket:

eval(substitute(instruction), envir=globalenv())

Hier verhindert substitute die instruction entfernt, Wird (inkorrekt) im Paket-Namespace in der argent-eval-Phase analysiert, so dass es intakt zurück in den globlenv-Code gelangt, wo es mit den erforderlichen Funktionen korrekt ausgewertet werden kann.

5

Ich hatte das gleiche Problem und ich löste es data.table zu Imports und Depends: hinzufügen. Meine data.table Version ist

+0

Können Sie ein Beispiel geben? - - Ich habe ein Skript, das eine Funktion liefert, die 'data.table' verwendet. Ich bekomme den Fehler hier. Ich schließe 'library (data.table)' im Skript und/oder in der Funktion selbst ein. - - Können Sie hier auch ein Beispiel geben, wie Sie 'Imports' und' Depends: 'hier anwenden, um das Problem zu lösen. Meine Daten.Tabelle ist 1.10.4. –

+2

Es funktionierte für mich im R-Paket Kontext - nicht rohes Skript. Aber beantworten Sie Ihre Frage - Sie können es in 'DESCRIPTION' Datei anwenden: ' Imports: data.table (> = 1.9.6) Hängt ab: data.table (> = 1.9.6) ', zB: https: // pastebin.com/uy10Devh – Taz

+0

Können Sie verhindern, dass Pakete von solchen Spezifikationen geladen werden? Etc 'importiert data.table', verhindert aber, dass' reshape2' als eigenes Paket geladen wird. –