2016-05-09 11 views
4

Gegeben eine data.table mit drei Felder member_id, provider_id und srvc_dt. Ich muss die Anzahl der verschiedenen Mitglieder berechnen, die von einem Anbieterpaar gesehen werden. Ein Mitglied soll zwei Anbieter besucht haben, wenn die Besuche innerhalb von 180 Tagen stattgefunden haben. Dies wird verwendet, um ein ungerichtetes Diagramm zu erstellen, das einen Schwellenwert für # visits verwendet und nach verbundenen Komponenten sucht.Beschleunigung einer data.table kartesischen Produkt mit Filterung

Ich verwende die in Cartesian product with filter data.table vorgeschlagene Methode.

Die Instanz, die ich ausführen muss, hat über 3 Millionen Datensätze und es dauert mehr als 5 Minuten zu laufen. Gibt es eine Möglichkeit zum Umschreiben oder eine neue data.table-Funktion, so dass es schneller läuft?

require(data.table) 

nmem <- 5000 
data.dt <- data.table(member_id=sample(10000:1000000,nmem,replace=TRUE), provider_id=sample(1000:2000,nmem,replace=TRUE), 
    srvc_dt=sample(seq(as.Date('2014/01/01'), as.Date('2015/01/01'), by="day"), nmem, replace=TRUE)) 
setkey(data.dt, member_id) 

prov_pair.dt <- data.dt[data.dt, { 
     idx = provider_id<i.provider_id & abs(srvc_dt-i.srvc_dt)<180 
     list(provider_id1 = provider_id[idx], 
      srvc_dt1 = srvc_dt[idx], 
      provider_id2 = i.provider_id[any(idx)], 
      srvc_dt2 = i.srvc_dt[any(idx)] 
     ) 
    }, by=.EACHI, allow=TRUE] 

prov_pair_agg.dt <- prov_pair.dt[, .(weight=length(unique(member_id))), .(provider_id1,provider_id2)] 

Antwort

2

einfache links-join gefolgt von Filterung:

prov_pair.dt <- data.dt[data.dt,allow.cartesian=T][provider_id<i.provider_id & 
    abs(srvc_dt-i.srvc_dt)<180,] 

provider_id<i.provider_id wird eine Doppelzählung die gleichen Abfragen x, y und y, x.

auch, jetzt provider_id und i.provider_id statt provider_id1 und provider_id2prov_pair_agg.dt bei der Berechnung verwenden:

prov_pair_agg.dt <- prov_pair.dt[, .(weight=length(unique(member_id))), 
    .(provider_id,i.provider_id)] 

auf eine 16 GB Speicher Maschine mit Nmem = 1.000.000, nimmt diese 1.487s vs 106.034s von Ihrer aktuellen Methode.

+0

Bitte setzen Sie nmem auf 1000000 und versuchen Sie es. Ich erhalte den folgenden Fehler: "... Join Ergebnisse in 2009362 Zeilen; mehr als 2000000 = nrow (x) + nrow (i) ... '. Der Vorteil des anderen Ansatzes besteht darin, dass es speichereffizient ist (siehe die letzte Zeile in @ Aruns Post). – ironv

+0

mit nmem = 1.000.000 ist 'allow.cartesian = T' erforderlich, aber dieser Weg ist immer noch schnell, vorausgesetzt, genügend Speicher. – webb

+1

vielleicht heraus filtern Mitglieder, die nur einen einzigen Anbieter gesehen, dh beginnend mit 'data.dt [, wenn (. N> = 2) .SD, von = member_id]', lösen Speicherprobleme (hängt natürlich von Daten ab) – eddi

0

Zuerst die Daten filtern, um nur die Mitglieder umfassen, die mehr als einen Anbieter gesehen haben:

res = data.dt[, if (.N >= 2) .SD, by = member_id] 

Dann werden die Endpunkte hinzufügen, die Termine, und eine Kopie der Anbieter Spalte:

res[, `:=`(start.date = srvc_dt - 180, 
      end.date = srvc_dt + 180, 
      provider2 = provider_id)] 
Schließlich

, verwenden Sie die neue nicht-equi verbindet, in der development version:

res[res, on = .(member_id = member_id, provider2 < provider_id, 
       srvc_dt < end.date, srvc_dt > start.date) 
    , allow = T, nomatch = 0][, .N, by = .(provider1 = provider_id, provider2)] 

Eine Anmerkung - die Namen der Spalten im obigen Join sind zur Zeit leider etwas verwirrend und hoffentlich wird das bald aussortiert. Sie können zusätzliche Kopien der Spalten hinzufügen, um zu sehen, was gerade passiert, wenn das oben genannte zu unklar ist.

Verwandte Themen