2016-04-06 2 views
4

Was die effizienteste (Zeit und Raum gleichermaßen) Art und Weise ist die folgende TabelleWie teilt man eine große data.table nach einer Regel mit zwei Spalten effizient in zwei Teile auf?

dt = data.table(x=c(1,3,5,4,6,2), y=c(4,7,1,1,2,6)) 
> dt 
    x y 
1: 1 4 
2: 3 7 
3: 5 1 
4: 4 1 
5: 6 2 
6: 2 6 

in zwei getrennte Tabellen, DT1 und DT2, so dass DT1 enthält alle (x, y) Reihen iff (y aufzuteilen , x) ist auch eine Reihe in dt, während dt2 die anderen Zeilen enthält:

> dt1 
    x y 
1: 1 4 
2: 4 1 
3: 6 2 
4: 2 6 

> dt2 
    x y 
1: 3 7 
2: 5 1 

Effizienz ist entscheidend, die vollständige Tabelle fast 200M Reihen

Antwort

5

Eine weitere Option ist eine vorwärts-

indx <- sort.int(dt[unique(dt), on = c(x = "y", y = "x"), which = TRUE, nomatch = 0L]) 

dt[indx] 
# x y 
# 1: 1 4 
# 2: 4 1 
# 3: 6 2 
# 4: 2 6 

dt[-indx] 
# x y 
# 1: 3 7 
# 2: 5 1 

Benchmark sich verbinden ausführen - Wenn Sie nicht über die Reihenfolge egal , meine Lösung scheint für 200MM Reihen schneller zu sein (beide Lösungen sind ungeordnet)

set.seed(123) 
bigdt <- data.table(x = sample(1e3, 2e8, replace = TRUE), 
        y = sample(1e3, 2e8, replace = TRUE)) 

system.time(i1 <- bigdt[, .I[.N>1] ,.(X=pmax(x,y), Y=pmin(y,x))]$V1) 
# user system elapsed 
# 21.81 0.82 22.97 

system.time(indx <- bigdt[unique(bigdt), on = c(x = "y", y = "x"), which = TRUE, nomatch = 0L]) 
# user system elapsed 
# 17.74 0.90 18.80 

# Checking if both unsorted and if identical when sorted 
is.unsorted(i1) 
# [1] TRUE 
is.unsorted(indx) 
# [1] TRUE 

identical(sort.int(i1), sort.int(indx)) 
# [1] TRUE 

Und hier ist ein nicht-entarteter Fall (wo indx != bigdt[, .I]):

set.seed(123) 
n = 1e7 
nv = 1e4 
DT <- data.table(x = sample(nv, n, replace = TRUE), y = sample(nv, n, replace = TRUE)) 

library(microbenchmark) 
microbenchmark(
    akrun = { 
    idx = DT[, .I[.N > 1], by=.(pmax(x,y), pmin(x,y))]$V1 
    list(DT[idx], DT[-idx]) 
    }, 
    akrun2 = { 
    idx = DT[,{ 
     x1 <- paste(pmin(x,y), pmax(x,y)) 
     duplicated(x1)|duplicated(x1, fromLast=TRUE) 
    }] 
    list(DT[idx], DT[!idx]) 
    }, 
    davida = { 
    idx = DT[unique(DT), on = c(x = "y", y = "x"), which = TRUE, nomatch = 0L] 
    list(DT[idx], DT[-idx]) 
    }, 
    akrun3 = { 
    n = DT[, N := .N, by = .(pmax(x,y), pmin(x,y))]$N 
    DT[, N := NULL] 
    split(DT, n > 1L) 
    }, times = 1) 

Unit: seconds 
    expr  min  lq  mean median  uq  max neval 
    akrun 7.056609 7.056609 7.056609 7.056609 7.056609 7.056609  1 
akrun2 22.810844 22.810844 22.810844 22.810844 22.810844 22.810844  1 
davida 2.738918 2.738918 2.738918 2.738918 2.738918 2.738918  1 
akrun3 5.662700 5.662700 5.662700 5.662700 5.662700 5.662700  1 
+0

Ich denke, Sie sollten mit einem Beispiel testen, das nicht identisch (Sortierung (Indx), Bigdt [, .I]) # TRUE' – Frank

+1

Ich habe eine, wird bearbeiten. Ihr entpuppt sich in meinem Beispiel zu gewinnen. – Frank

+0

Vielen Dank David. Nur auf eine Randnotiz (was nicht der Fall ist, ich interessiere mich), Arkun Lösung ist erweiterbar Triplets (oder Tupel im Allgemeinen), anstatt Paare. Wechseln Sie einfach pmin(), pmax() mit sort(). Ihre Lösung verlangt, dass ich mich in der on = c() Phase nur an eine mögliche Permutation der Werte in jeder Zeile halte. – Amitai

4

hat konnten wir versuchen

i1 <- dt[, .I[.N>1] ,.(X=pmax(x,y), Y=pmin(y,x))]$V1 
dt[i1] 
# x y 
#1: 1 4 
#2: 4 1 
#3: 6 2 
#4: 2 6 

dt[-i1] 
# x y 
#1: 3 7 
#2: 5 1 

Oder eine andere Option duplicated

i1 <- dt[,{x1 <- paste(pmin(x,y), pmax(x,y)) 
     duplicated(x1)|duplicated(x1, fromLast=TRUE) }] 
dt[i1] 
dt[!i1] 
+1

Brilliant gezählt Sortierung! Obwohl ich mit David Arenburg Lösung wegen der etwas besseren Leistung gehen werde (mein Datensatz hat einzigartige Zeilen, so dass ich sogar die einzigartige() Phase verschone), was ich an dieser Lösung mag ist, dass es zu Triplets und Tupeln erweiterbar ist Allgemeines. Einfach pmin(), pmax() in sortierte Zeile umschalten! – Amitai

2

Gerade @ David Arenburg und @akrun Antworten (auf keinen Fall versuchen, einen neuen zu schreiben, das ist nur zu lang für ein folgen Kommentar), habe ich auch Funktionen zeitgleich mit Sortierung:

library(microbenchmark) 
library(data.table) 
library(dplyr) 

set.seed(123) 
bigdt <- data.table(x = sample(1e3, 2e8, replace = TRUE), 
        y = sample(1e3, 2e8, replace = TRUE)) 

f1 <- function() bigdt[, .I[.N>1] ,.(X=pmax(x,y), Y=pmin(y,x))]$V1 
f2 <- function() bigdt[, .I[.N>1] ,.(X=pmax(x,y), Y=pmin(y,x))] %>% setorder(V1) %>% .[, V1] 
f3 <- function() bigdt[unique(bigdt), on = c(x = "y", y = "x"), which = TRUE, nomatch = 0L] 
f4 <- function() sort.int(bigdt[unique(bigdt), on = c(x = "y", y = "x"), which = TRUE, nomatch = 0L]) 

res <- microbenchmark(
    i1 <- f1(), 
    i2 <- f2(), 
    i3 <- f3(), 
    i4 <- f4(), 
    times = 2L) 

print(res) 

mit:

is.unsorted(i1) # TRUE 
is.unsorted(i2) # FALSE 
is.unsorted(i3) # TRUE 
is.unsorted(i4) # FALSE 

identical(sort.int(i1), i2) # TRUE 
identical(sort.int(i3), i4) # TRUE 
identical(i2, i4)   # TRUE 

Und die Ergebnisse sind wie folgt:

Unit: seconds 
     expr  min  lq  mean median  uq  max neval cld 
i1 <- f1() 21.18695 21.18695 21.42634 21.42634 21.66572 21.66572  2 a 
i2 <- f2() 47.16270 47.16270 47.79535 47.79535 48.42799 48.42799  2 b 
i3 <- f3() 19.67623 19.67623 20.11365 20.11365 20.55108 20.55108  2 a 
i4 <- f4() 57.21732 57.21732 57.78666 57.78666 58.35600 58.35600  2 c 

Zusammengefasst:

  • f3() ist falser für unsortierte Ergebnis;
  • f2() ist schneller, wenn in.
Verwandte Themen