2017-02-28 4 views
-1

Ich möchte eine Funktion schreiben, die einen Teil des Datensatzes mit dem data.table Paket auswählen würde. Die angegebenen Parameter der Funktion sind:data.table: Auswählen eines Teils eines Datensatzes unter Bedingung in einer benutzerdefinierten Funktion

  • Eingangsdatensatz (dset),
  • variable, auf dem der Datensatz subsetted würde (seg.var),
  • Wert der obigen Variablen (value) erklärt .

konnte ich arbeiten Funktion in der Basis R schreiben:

# Function without data.table 

data.select <- function(dset, seg.var, value){ 
    dset.out <- dset[dset[[seg.var]] == value,] 
    return(dset.out) 
} 

data.select(iris, "Species", "setosa") 

Allerdings habe ich es mit data.table Paket nicht neu schreiben kann: die Funktion unten funktioniert nicht.

# Function with data.table 

data.select.dt <- function(dset, seg.var, value){ 
    dset <- as.data.table(dset) 
    dset.out <- dset[seg.var == value,] 
    return(dset.out) 
} 

data.select.dt(iris, Species, "setosa") 

Fehler in eval (expr, Envir, enclos): Object 'Art' nicht gefunden

data.select.dt(iris, "Species", "setosa") 

Leer data.table (0 Zeilen) von 5 cols: Sepal .length, Sepal.Width, Petal.Length, Petal.Width, Species

der Eingabedatensatz ist in data.frame Format. Das Ziel des Überschreibens oberhalb einer gegebenen Funktion ist eine Leistungsverbesserung. Jede Hilfe wäre willkommen.

+3

Warum konvertieren Sie in die data.table innerhalb der Funktion? Sie erstellen eine Kopie des gesamten Datensatzes. Es wäre besser, bereits auf einer 'data.table' zu ​​operieren, indem man mit' setDT' in eine Eins konvertiert. In jedem Fall würde ich eine einfache binäre Verbindung machen. Etwas wie 'data.select.dt <- function (dset, seg.var, value) as.data.table (dset) [. (Wert), on = seg.var]' und dann als 'data.select 'ausführen .dt (Iris, "Species", "setosa") ' –

+0

Ich möchte sicher sein, dass der Rest des Codes funktioniert. Da ich mit einem Datensatz arbeite, der größer ist als "iris", möchte ich die Leistung der "Basis" -Untergruppe und der in "data.table" implementierten vergleichen, ohne den ganzen Code neu schreiben zu müssen. – kaksat

+0

@kaksat, siehe 'if (! Data.table :: is.data.table (dset))' in meiner Antwort, sollte etwas Zeit und RAM sparen, wenn 'dset' eine' data.table' wäre. –

Antwort

2

Es ist ein bisschen zu lang für einen Kommentar, so dass eine gesonderte Antwort:

zuerst die get() Funktion von mir als Kommentar erwähnt @ R, S. Antwort:

data.select.dt.V1 <- function(dset, seg.var, value){ 
    if(!data.table::is.data.table(dset)) dset <- data.table::as.data.table(dset) # To convert only if needed 
    dset[get(seg.var) == value,] 
} 

data.select.dt.V1(iris, 'Species', 'setosa') 

Und dann noch mehr data.table Funktion, wo Sie das zweite Argument als Ausdruck passieren kann (gut, in der data.table Art und Weise), kein String:

data.select.dt.V2 <- function(dset, seg.var, value){ 
    if(!data.table::is.data.table(dset)) dset <- data.table::as.data.table(dset) # To convert only if needed 
    sv <- substitute(seg.var) 
    dset[eval(sv) == value,] 
} 

data.select.dt.V2(iris, Species, 'setosa') 

Edit: Funktionen Vereinfachung und Test für die Konvertierung (dank @ David Arenburg Kommentar).

2. edit: über zwei Funktionen gebenchmarkt mit einem @ David Arenburg ist (mit und ohne is.data.table Scheck, V3 und V4 respectively) auf 515 MB data.table und data.frame:

data.select.dt.V3 <- function(dset, seg.var, value) data.table::as.data.table(dset)[.(value), on = seg.var] 

data.select.dt.V4 <- function(dset, seg.var, value) { 
    if(!data.table::is.data.table(dset)) dset <- data.table::as.data.table(dset) # To convert only if needed 
    dset[.(value), on = seg.var] 
} 

                expr  min  lq  mean median  uq  max neval cld 
1 res <- data.select.dt.V1(iris_df, "Species", "setosa") 3.804995 4.585763 4.150130 4.688093 5.320362 3.166503 10 c 
2 res <- data.select.dt.V2(iris_df, Species, "setosa") 3.713275 3.827180 3.865347 4.544968 4.753045 3.218075 10 c 
3 res <- data.select.dt.V3(iris_df, "Species", "setosa") 1.927947 1.942868 2.167127 2.328364 2.595420 2.159664 10 b 
4 res <- data.select.dt.V4(iris_df, "Species", "setosa") 1.987710 2.004497 2.011502 2.280117 2.856847 1.594249 10 b 

5 res <- data.select.dt.V1(iris_dt, "Species", "setosa") 2.771223 2.792428 2.501362 2.805796 3.056144 1.883520 10 b 
6 res <- data.select.dt.V2(iris_dt, Species, "setosa") 2.830161 2.970071 2.593192 3.123812 3.170884 1.752576 10 b 
7 res <- data.select.dt.V3(iris_dt, "Species", "setosa") 1.963530 2.116116 2.059718 2.203265 2.740949 1.768817 10 b 
8 res <- data.select.dt.V4(iris_dt, "Species", "setosa") 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 10 a 

V4 Klar ist das eine zu Gehen Sie, wenn Sie beide data.frame und data.table erwarten, wenn nur df möglich ist, wäre die schnellste Funktion V3.

1

Hier ist etwas Feinsinnig, meine Empfehlung ist es, dies in Schritte zu zerlegen. Schreiben Sie den Code gerade erst konvertieren dann zu einer Funktion:

Ihre ursprüngliche Code funktioniert außerhalb einer Funktion:

require(data.table) 

dset <- as.data.table(iris) 
dset.out <- dset[Species == "setosa",] 
dset.out 
> dset <- as.data.table(iris) 
> dset.out <- dset[Species == "setosa",] 
> dset.out 
Sepal.Length Sepal.Width Petal.Length Petal.Width Species 
1:   5.1   3.5   1.4   0.2 setosa 
2:   4.9   3.0   1.4   0.2 setosa 
... 

aber, wenn Sie es in einer Funktion wickeln ist nicht ...

> require(data.table) 
> data.select.dt <- function(dset, seg.var, value){ 
+ dset <- as.data.table(dset) 
+ dset.out <- dset[ seg.var == eval(value) ] 
+ return(dset.out) 
+ } 
> data.select.dt(iris, Species, "setosa") 
Show Traceback 

Rerun with Debug 
Error in eval(expr, envir, enclos) : object 'Species' not found 

OK, interessant, warum schlägt es im Funktionsaufruf fehl? Sie müssen die Variable "Species" korrekt referenzieren. Welche erfordert die Dereferenzierung in der Verbindung:

dset[dset[["Species"]] == "setosa",] 
> dset[dset[["Species"]] == "setosa",] 
    Sepal.Length Sepal.Width Petal.Length Petal.Width Species 
1:   5.1   3.5   1.4   0.2 setosa 
2:   4.9   3.0   1.4   0.2 setosa 
... 

nb. Was ich wirklich interessant finde, ist, dass RStudio im Debug die Funktion erlaubt, aber im Nicht-Debug-Modus einen Fehler auslöst.

Jetzt können Sie diese in einer Funktion wickeln:

data.select.dt <- function(dset, seg.var, value){ 
    dset <- as.data.table(dset) 
    dset.out <- dset[dset[[seg.var]] == value,] 
    return(dset.out) 
} 

Beachten Sie, dass die Arten in Anführungszeichen gewickelt "Species" ...

data.select.dt(iris, "Species", "setosa") 

data.select.dt(iris, "Species", "setosa") 
    Sepal.Length Sepal.Width Petal.Length Petal.Width Species 
1:   5.1   3.5   1.4   0.2 setosa 
2:   4.9   3.0   1.4   0.2 setosa 
3:   4.7   3.2   1.3   0.2 setosa 
+0

R. S. gab die richtige Antwort vor mir – Technophobe01

2

Überprüfen Sie den Code: dset.out <- dset[seg.var == value,] in der data.table Version sollte dset.out <- dset[dset[[seg.var]] == value,] sein, was Sie ursprünglich haben.

Species fehlt Anführungszeichen, sollte "Species" sein, wenn Sie die Funktion aufrufen.Aus diesem Grund lautet die Fehlermeldung in Ihrem Arbeitsbereich kein Objekt Species.

Das funktioniert.

Bearbeitet, um einen Tipp hinzuzufügen, Debug außerhalb der Funktion, so dass Sie sehen, wo Dinge brechen.

+1

Oder Sie können 'dset [get (seg.var) == Wert,]' verwenden, um etwas Zeit und Arbeitsspeicher zu sparen (Sie geben nicht 'dset [[seg.var]]'). –

Verwandte Themen