2015-04-23 3 views
7

Ich habe zwei data.tables: samples, resourcesStaggered Leveln/Neugruppierung/join in R mit data.table der X [Y] Syntax

resources ist mit samples über primary und secondary ids. Ich möchte die Informationen von den Ressourcen mit der Beispieltabelle zuerst über die primäre ID kombinieren, und nur wenn dies NA erzeugt, dann möchte ich auf die sekundären Ressourcen aus der gleichen Tabelle zurückgreifen (innerhalb einer data.table Befehlskette) .

# resources: 
    primary secondary info 
1:  17  42 "I" 
2:  18  NA "J" 
3:  19  43 "K" 

# samples: 
    name primary secondary 
1: "a"  17  55 
2: "b"  0  42 
3 "c"  18  42 

Das gewünschte Ergebnis wäre:

# joined tables: 
    name info # primary secondary 
1: "a" "I" 
2: "b" "I" 
3: "c" "J" 

Die über primary beitreten erste ist einfach, es produziert

# Update: 
samples <- data.table(name = letters[1:3], 
         primary = c(17, 0, 18), 
         secondary = c(55, 42, 42)) 
resources <- data.table(primary = 17:19, 
         secondary = c(42, NA, 43), 
         info = LETTERS[9:11]) 
# first join: 
setkey(samples, primary) 
setkey(resources, primary) 
samples[resources] 

    name info # primary secondary 
1: "a" "I" 
2: "b" NA 
3: "c" "J" 

Aber dann? Ich muss Proben erneut mit setkey(samples, secondary), oder? Und dann Teilmenge nur zu jenen Zeilen, die NAs erzeugen. Aber all das ist innerhalb einer Befehlskette nicht wirklich möglich (und stellen Sie sich vor, dass es mehr als zwei Kriterien gibt ...). Wie kann ich das prägnanter erreichen?

... mit Code für die data.tables aktualisiert.

+6

Vielleicht leicht reproduzierbar machen, indem man Code einbezieht, der 'samples' und' resources' konstruiert? –

+0

nicht "data.table" freundlich, aber nur für den Fall, dass es hilfreich ist: http: // stackoverflow.com/questions/11369837/how-do-you-do-bedingte-links-join-in-r – npjc

+2

es in einer Befehlskette zu tun ist fehlgeleitet – eddi

Antwort

5

Während Sie es in einer einzigen Zeile tun könnten, ich denke, dass die Bedeutung dessen verdummt, was Sie tun, macht Dinge unglaublich schwer zu lesen/verstehen/debuggen/erinnern, was zur Hölle Sie in einem Monat getan haben, und ist einfach ein schlechte Idee.

Kleinere, viel leichter verdaulich Brocken sind die Art und Weise imo zu gehen:

setkey(samples, primary) 
setkey(resources, primary) 
samples[resources, info := i.info] 

setkey(samples, secondary) 
setkey(resources, secondary) 
samples[resources, info := ifelse(is.na(info), i.info, info)] 

samples 
# name primary secondary info 
#1: b  0  42 I 
#2: c  18  42 J 
#3: a  17  55 I 

# keep going with tertiary and so on if you like 

Wie @nachti in den Kommentaren darauf hingewiesen, müssen Sie möglicherweise allow.cartesian=TRUE für Versionen vor 1.9.5 hinzufügen abhängig von Ihren Daten .

+3

Ich verstehe, dass es cool ist, wenn man zuerst Chaining/Piping entdeckt, eine Menge Dinge in einer Zeile erledigt, aber nachdem die anfängliche Aufregung nachlässt, muss man zurück skalieren und realisieren, dass man eigentlich nicht alles will Skript in einer einzigen Zeile. – eddi

+0

Sie müssen hinzufügen 'by = .EACHI' seit dt 1.9.4:' samples [Ressourcen, info: = ifelse (is.na (info), i.info, info), by = .EACHI] 'Für weitere Informationen siehe https://github.com/Rdatatable/data.table/blob/master/README.md – nachti

+0

@nachti nein, das ist falsch - das obige wurde mit 1.9.5 ausgeführt (der "muss" Teil ist falsch - du * kann * es hinzufügen, aber das wird das Ergebnis nicht ändern und es kann oder auch nicht zu einem Leistungsunterschied führen - ich bin mir nicht sicher, auf welche Weise es gehen wird) – eddi

1

Ich denke, es ist zu schwierig ist es in einer Befehlskette zu tun, aber ich habe eine Lösung für Sie:

### First step 
samples[resources[samples, nomatch = 0], info := info] 
samples 

    name primary secondary info 
1: b  0  42 NA 
2: a  17  55 I 
3: c  18  42 J 

### Second step 
setkey(samples, secondary) 
setkey(resources, secondary) 
## create new column info1 
samples[resources[samples[is.na(info)], 
        list(info1 = unique(info)), by = .EACHI], 
     info1 := info1] 
## merge it to samples, where info is NA 
samples[is.na(info), info := info1] 
## remove info1 (and maybe other unused columns) 
samples[, info1 := NULL] 
## sort samples by name 
setkey(samples, name) 
samples 

    name primary secondary info 
1: a  17  55 I 
2: b  0  42 I 
3: c  18  42 J 

HTH
~ g

2

Diese eine Kette mit 2 Anrufe würden zu resources, einer von ihnen re-setkey hinter der Szene.

library(data.table) 
samples <- data.table(name = letters[1:3], 
         primary = c(17, 0, 18), 
         secondary = c(55, 42, 42)) 
resources <- data.table(primary = 17:19, 
         secondary = c(42, NA, 43), 
         info = LETTERS[9:11]) 
setkey(samples, primary) 
setkey(resources, primary) 
samples[resources, info := i.info 
     ][, .(name, info),, secondary 
      ][resources[, info,, secondary], info := ifelse(is.na(info), i.info, info) 
      ][, secondary := NULL] 

Wie Sie kompliziertere Beispiele fragen. Beachten Sie, dass die data.table-Abfragen problemlos als Module verwaltet werden können, indem Sie im Vorfeld Unterabfrageargumente vorbereiten. Sie können später leicht konditioniert verwaltet werden. Siehe folgendes Beispiel.

lkp2 <- quote(resources[, info,, secondary]) 
lkp2_formula <- quote(info := ifelse(is.na(info), i.info, info)) 
setkey(samples, primary) 
samples[resources, info := i.info 
     ][, .(name, info),, secondary 
      ][eval(lkp2), eval(lkp2_formula) 
      ][, secondary := NULL] 

Wenn Sie stark auf data.table Verkettungs verlassen Prozesse, die Sie dtq Paket nützlich finden können.

+1

Ich mag den Vorschlag, die 'i' und' j' Befehle separat vorzudefinieren, dies könnte helfen, den Code in komplizierteren Fällen leichter lesbar zu halten. Ich werde diese Strategie mit den Vorschlägen von @eddi und @nachti kombinieren. – Wordsmyth

Verwandte Themen