2017-02-10 3 views
2

У меня есть два больших наборов данных, d1 и d2, которые я хотел бы объединить на основе матчей обоего переменных idA и idB.эффективно объединить два набора данных, соответствующих одной переменной или другой

Оба они присутствуют в обоих наборах данных, но оба могут содержать ошибки и отсутствующие значения (NA), или имеют idA и idB указывают на различные наблюдения в другом наборе данных. Пример сверху.

Желаемый результат приведен ниже. В основном, совпадения находятся либо на idA OR idB, в случае дублированных матчей предпочтение должно быть отдано idA совпадениям по idB матчам.

Фактические наборы данных довольно большие (~ 10 миль).

Есть ли эффективный способ реализовать это в R?

Кроме того, существует ли технический термин для такого рода присоединения к SQL?

library(tidyverse) 
library(data.table) 

d1 <- read.table(text= 
"idA idB value1 
A 10 500 
B 1 111 
C 4 234 
D NA 400 
E 7 500 
NA 3 700 
Z 5 543 
Q 9 567 
U 23 723 
", 
header=T) %>% data.table 


d2 <- read.table(text= 
"idA idB value2 
A 10 11 
B 1 12 
L 21 15 
D 15 12 
E 8 17 
M 3 18 
N 5 13 
Z 25 17 
Q 23 12 
", 
header=T) %>% data.table 

Желаемый результат:

Out <- read.table(text= 
"d1.idA d2.idA d1.idB d2.idB d1.v1 d2.v2 
A A 10 10 500 11 # matched on idA and idB 
B B 1 1 111 12 # matched on idA and idB 
D D NA 15 400 12 # matched on idA. d2.idB had NAs 
E E 7 8 500 17 # matched on idA. idB had divergent values 
NA M 3 3 700 18 # matched on idB. d1.idA had NAs 
Z Z 5 25 543 13 # d1[7,] matched to d2[8,] on idA and d2[9,] on idB. Priority given to idA match. 
Q Q 9 23 657 17 # d2[9,] matched to d1[8,] on idA and d1[9,] on idB. Priority given to idA match. 
", 
header=T) %>% data.table 

#Non matched rows 
# d1[3,] 
# d2[3,] 

EDIT1:

  • добавлено желаемый результат
  • держали data.table (read.table) из-за легкости разборе читатели, фактические данные поступают из файла (файла)

EDIT2: удалить несоответствующие строки из желаемого результата.

+1

@akrun, я не вижу, как это дубликат. Я спрашиваю о том, как объединить две переменные id, требуя, чтобы только один из них соответствовал. (вопрос относится к внутренним, левым, жестким соединениям одной и той же переменной). – LucasMation

+0

Пожалуйста, заполните ваш пример желаемым результатом перед лоббированием для повторного открытия. «предпочтение должно быть направлено на совпадение idA над idB», на самом деле не совсем понятно. Кроме того, fyi, если массивы данных большие, вам нужно использовать 'fread' вместо' data.table (read.table (.)) ', Который является вдвойне медленным - медленнее читать и принимать ненужную копию, когда преобразование в DT. – Frank

+0

добавлены запрошенные функции. Тем не менее исходный вопрос полностью не связан с вопросом, указанным как дубликат – LucasMation

ответ

1

Я не знаю, какой изящный способ достичь желаемого результата (и я тоже не знаю технического термина для этого типа операций в SQL).

Поэтому я предлагаю сделать это в четыре этапа:

  1. Внутреннее объединение двух data.tables на idA и idB, определяют оставшиеся строки в каждой из data.tables.
  2. Внутреннее соединение остальных строк данных data.tables на idA, еще раз определите оставшиеся строки.
  3. Внутреннее соединение остальных строк данных data.tables на idB.
  4. Объедините результаты предыдущих шагов.

Код для всех 4-х этапов:.

library(data.table) 

# create index column in both data.tables 
d1[, idx := .I] 
d2[, idx := .I] 

# inner join on idA and idB 
j1 <- d1[d2, .(idx, i.idx), on = c("idA", "idB"), nomatch = 0L] 
m1 <- unique(j1$idx) 
m2 <- unique(j1$i.idx) 

# inner join on idA 
j2 <- d1[!(idx %in% m1)][d2[!(idx %in% m2)], .(idx, i.idx), on = c("idA"), nomatch = 0L] 
m1 <- append(m1, unique(j2$idx)) 
m2 <- append(m2, unique(j2$i.idx)) 

# inner join on idB 
j3 <- d1[!(idx %in% m1)][d2[!(idx %in% m2)], .(idx, i.idx), on = c("idB"), nomatch = 0L] 
m1 <- append(m1, unique(j3$idx)) 
m2 <- append(m2, unique(j3$i.idx)) 

# combine results 
rbindlist(
    list(
    AB = cbind(
     d1[idx %in% j1[, idx]], 
     d2[idx %in% j1[, i.idx]]), 
    A. = cbind(
     d1[idx %in% j2[, idx]], 
     d2[idx %in% j2[, i.idx]]), 
    .B = cbind(
     d1[idx %in% j3[, idx]], 
     d2[idx %in% j3[, i.idx]])), 
    fill = TRUE, 
    idcol = "match_on") 

, который дает

# match_on idA idB value1 idx idA idB value2 idx 
#1:  AB A 10 500 1 A 10  11 1 
#2:  AB B 1 111 2 B 1  12 2 
#3:  A. D NA 400 4 D 15  12 4 
#4:  A. E 7 500 5 E 8  17 5 
#5:  A. Z 5 543 7 Z 25  17 8 
#6:  A. Q 9 567 8 Q 23  12 9 
#7:  .B NA 3 700 6 M 3  18 6 

m1 и m2 используются, чтобы вспомнить строки идентификаторы строк в d1 и d2, соотв, которые уже были использованы в одной из предыдущих операций объединения.

Итак, наконец, остальные строки в d1 и d2, которые не нашли совпадения могут быть напечатаны:

d1[!(idx %in% m1)] 
# idA idB value1 idx 
#1: C 4 234 3 
#2: U 23 723 9 
d2[!(idx %in% m2)] 
# idA idB value2 idx 
#1: L 21  15 3 
#2: N 5  13 7 

Обратите внимание, что в каждой операции соединения только индексы строк сохраняются вместо того, чтобы все столбцы , Результаты различных операций объединения различаются по имени и положению столбцов.

На заключительном этапе объединения строки исходных данных. Таблицы d1 и d2 выбираются с использованием этих индексов для создания равномерной таблицы результатов.

+0

красивый, tks! – LucasMation

+0

Решен ли этот вопрос? Если это так, отметьте галочку, чтобы подтвердить разрешение. – Parfait

Смежные вопросы