2014-03-13 3 views
6

Gibt es bereits vorhandene Komfort-Funktion, die Zeilen in der data.table, Suchmuster, in allen Spalten Suche filtern würde?`data.table` globale Suche - Filter Zeilen gegeben Muster übereinstimmen in` any' Spalte

names(DT) 

[1] "Name" "LongName" "SomeOtherCol" "NumericCol" "bar" "foo" 

So etwas wie dies für eine beliebige Anzahl von Spalten verallgemeinern:

DT[Name %like% pattern | LongName %like% pattern | SomeOtherCol %like% pattern | bar %like% pattern | foo %like% pattern] 
+0

+1 versuchen Sie, die Datentabellen zu replizieren setzen? (Ich meine das jQuery-Plugin) – Michele

+0

@Michele nicht vertraut mit 'datatables', aber [Beispiel hier] (https://datatables.net/) hat" Suche "Texteingabefeld, das ziemlich genau das Gleiche tut über –

+0

... der Link, den Sie setzen, ist genau "Datatables" – Michele

Antwort

5

Eine Möglichkeit wäre, die Spalten durchzulaufen, Ihre Regex anzuwenden, die eine logische data.table zurückgeben. Sie können rowSums verwenden, um die Zeilen dann zu erhalten.

dt <- data.table(a=c("Aa1","bb","1c"),b=c("A1","a1","1C"), c=letters[1:3]) 
# "a1" is the pattern to search for 
ldt <- dt[, lapply(.SD, function(x) grepl("a1", x, perl=TRUE))] 
dt[rowSums(ldt)>0] 
#  a b c 
# 1: Aa1 A1 a 
# 2: bb a1 b 
+1

Wenn Sie zu viele Spalten haben, wäre ein schnellerer, aber weniger effizienter Speicher die 'data.table' in' matrix' umzuwandeln und dann 'grep' anzuwenden - da es direkt auf die ganze Matrix angewendet wird. – Arun

+2

Vielen Dank @Arun. Würdest du vernünftigerweise erwarten, dass dies verglichen mit dem Ansatz schneller ist, während ich zuerst Zeichenfolgen anfügen würde, um zu dem Ausdruck ähnlich wie "%% like% pattern |" zu gelangen b% like% pattern | ... '(oder sogar direkt' grepl') und dann 'DT [eval (combined.expression)]' '? Ich war dabei, diesen Ansatz zu entwickeln, aber ich würde eher Ihrer fundierten Meinung darüber vertrauen, ob es die Mühe wert ist –

+0

Ich schätze, Ihr wird schneller sein (wie es 'rowSums' vermeidet) .. zumindest auf größeren' Daten.Tabellen'. – Arun

2

I Wetten bin nicht, dass dies der beste Weg, es zu tun ist. Aber es dient dem Zweck:

> dt <- data.table(a=c("a1","bb","1c"),b=c("A1","BB","1C")) 
> dt 
    a b 
1: a1 A1 
2: bb BB 
3: 1c 1C 

> combined <- apply(dt,1,function(r) paste(r,collapse="/%/")) 
> combined 
[1] "a1/%/A1" "bb/%/BB" "1c/%/1C" 

> grepped <- grepl("[a-z][0-9]",apply(dt,1,function(r) paste(r,collapse="/"))) 
> grepped 
[1] TRUE FALSE FALSE 

> dt[grepped,] 
    a b 
1: a1 A1 

Die „/% /“ müsste etwas sein, das nicht relevant für das Muster und zuverlässig trennt Spalten.

Die Schritte können natürlich in einem einzigen Ausdruck kombiniert werden.

+0

danke für einige Inspiration, werde ich versuchen, mit Lösung native in 'data.table' für bessere Leistung zu kommen –

+1

ich don ' Ich denke, das ist eine gute Idee, was die Geschwindigkeit angeht. Abhängig von der Größe der 'data.table' könnte' paste' ziemlich zeitaufwendig sein. – Arun

+0

Ich konnte Ihre Lösung irgendwie nicht zum Laufen bringen, als ich versuchte, die Geschwindigkeit zu messen. Bitte schauen Sie sich die Implementierung (Funktion "Raffael") in meiner Antwort an. –

2

Lösung 3:

Zuerst bauen die logische grepexpression alle Spalten angehängt wird. Dann eval der Gesamtausdruck in einem Rutsch:

dt <- data.table(a=c("a1","bb","1c"),b=c("A1","BB","1C")) 

search.data.table <- function(x, pattern) { 
    nms <- names(x) 
    string <- eval(expression(paste0("grepl('", 
            pattern, 
            "', ", 
            nms,", 
            ignore.case=TRUE, perl=FALSE)", 
            collapse = " | "))) 
    x[eval(as.call(parse(text=string))[[1]])] 
} 

search.data.table(dt, "a1") 
#  a b c 
# 1: Aa1 A1 a 
# 2: bb a1 b 

Benchmarking

# functions 

Raffael <- function(x, pattern) { 
# unfortunately this implementation throws an error so I can't run the benchmark test. 
# Any help? 
    combined <- apply(x,1,function(r) paste(r,collapse="/%/")) 
    grepped <- grepl(pattern,apply(x,1,function(r) paste(r,collapse="/"))) 
    x[grepped,] 
} 

Arun <- function(x, pattern) { 
    ldt <- x[, lapply(.SD, function(x) grepl(pattern, x, perl=TRUE, ignore.case=TRUE))] 
    x[rowSums(ldt)>0] 
} 

DanielKrizian <- function(x, pattern) { 
    nms <- names(x) 
    string <- eval(expression(paste0("grepl('", pattern, "', ",nms,", ignore.case=TRUE,  perl=FALSE)",collapse = " | "))) 
    x[eval(as.call(parse(text=string))[[1]])] 
} 

# generate 1000 x 1000 benchmark data.table 

require(data.table) 
expr <- quote(paste0(sample(c(LETTERS,tolower(LETTERS),0:9),12, replace=T) 
       ,collapse="")) 
set.seed(1) 
BIGISH <- data.table(matrix(replicate(1000*1000,eval(expr)),nrow = 1000)) 
object.size(BIGISH) # 68520912 bytes 

# test 

benchmark(
    DK <- DanielKrizian(BIGISH,"qx"), 
    A <- Arun(BIGISH,"qx"), 
    replications=100) 

Ergebnisse

       test replications elapsed relative user.self sys.self user.child sys.child 
2   A <- Arun(BIGISH, "qx")   100 57.72 1.000  51.95  0.44   NA  NA 
1 DK <- DanielKrizian(BIGISH, "qx")   100 59.28 1.027  53.72  0.50   NA  NA 

identical(DK,A) 
[1] TRUE 
+1

Wenn Sie Benchmarks hinzufügen, fügen Sie Benchmark-Ergebnisse zu relativ größeren Daten hinzu. – Arun

+0

@Arun, bearbeitete die Testdaten und wartete darauf, nach Hause zu kommen und zu laufen. Vorschläge für bessere Daten begrüßen –

+0

@Arun, änderte die Datengröße auf 1000 Zeilen x 1000 Spalten –

Verwandte Themen