2012-04-11 6 views
6

Mithilfe einer data.table, die die schnellste Möglichkeit wäre, eine Statistik über eine Auswahl von Spalten hinweg zu "fegen"?data.tables und Sweep-Funktion

Beginnend mit (deutlich größeren Versionen) DT

p <- 3 
DT <- data.table(id=c("A","B","C"),x1=c(10,20,30),x2=c(20,30,10)) 
DT.totals <- DT[, list(id,total = x1+x2) ] 

Ich mag folgendes data.table Ergebnis erhalten, indem Sie die Zielspalten Indizierung (2: p), um den Schlüssel zu überspringen:

id x1 x2 
[1,] A 0.33 0.67 
[2,] B 0.40 0.60 
[3,] C 0.75 0.25 

Antwort

4

ich glaube, dass etwas in der Nähe der folgenden (die die relativ neue set() Funktion verwendet) schnellste sein wird:

DT <- data.table(id = c("A","B","C"), x1 = c(10,20,30), x2 = c(20,30,10)) 
total <- DT[ , x1 + x2] 

rr <- seq_len(nrow(DT)) 
for(j in 2:3) set(DT, rr, j, DT[[j]]/total) 
DT 
#  id  x1  x2 
# [1,] A 0.3333333 0.6666667 
# [2,] B 0.4000000 0.6000000 
# [3,] C 0.7500000 0.2500000 

FWIW, ruft set() die folgende Form annimmt:

# set(x, i, j, value), where: 
#  x is a data.table 
#  i contains row indices 
#  j contains column indices 
#  value is the value to be assigned into the specified cells 

Mein Verdacht über die relative Geschwindigkeit dieses, im Vergleich zu anderen Lösungen ist, auf dieser Stelle aus data.table's NEWS file im Abschnitt basierend auf Änderungen in Version 1.8.0:

o New function set(DT,i,j,value) allows fast assignment to elements 
    of DT. Similar to := but avoids the overhead of [.data.table, so is 
    much faster inside a loop. Less flexible than :=, but as flexible 
    as matrix subassignment. Similar in spirit to setnames(), setcolorder(), 
    setkey() and setattr(); i.e., assigns by reference with no copy at all. 

     M = matrix(1,nrow=100000,ncol=100) 
     DF = as.data.frame(M) 
     DT = as.data.table(M) 
     system.time(for (i in 1:1000) DF[i,1L] <- i) # 591.000s 
     system.time(for (i in 1:1000) DT[i,V1:=i])  # 1.158s 
     system.time(for (i in 1:1000) M[i,1L] <- i) # 0.016s 
     system.time(for (i in 1:1000) set(DT,i,1L,i)) # 0.027s 
+0

Danke für die Antwort. Ich habe ein Upgrade auf data.table 1.8.0 durchgeführt und den obigen Testcode erfolgreich ausgeführt. Ich bekomme eine ausführliche Warnung (wird hier nicht passen) über den Zwang zu verdoppeln, wenn sowohl Zähler als auch Nenner ganzzahlige Spalten aus data.tables sind. Ich werde die Frage zu diesem Zweck bearbeiten. –

+0

Ich habe heute eine schwierige Zeit mit Änderungen: Kein Zeilenvorschub. Wie auch immer, hier ist der Code: für (j in 2: p) { gesetzt (dt, alle Zeilen, j, dt [[j]]/Nenn [[2]]) } und für beide dt und Nenn, Spalten 2 bis p sind ganze Zahlen. Die Warnung, die ich bekomme, ist –

+0

"Warnmeldung: In Satz (dt, allrows, j, dt [[j]]/Nenn [[2]]): Coerced" Doppel "RHS zu" Ganzzahl ", um den Typ der Spalte zu entsprechen , kann abgeschnittene Genauigkeit haben Entweder ändern Sie die Zielspalte zuerst 'double' (indem Sie eine neue 'doppelte' Vektorlänge 16863 (nrows der gesamten Tabelle) erstellen und diese zuweisen; dh 'replace' -Spalte) oder RHS zu 'integer '(zB 1L, NA_ [real | integer] _, as. *, usw.), um Ihre Absicht klar und schnell zu machen. Oder stellen Sie den Spaltentyp korrekt ein, wenn Sie den Tisch erstellen und sich daran halten. " –