Первый экземпляр нужен только при объединении двух таблиц с использованием data.table's: = - PullRequest
0 голосов
/ 24 сентября 2018

У меня есть policyData, который является моим очень большим набором данных (миллионы строк), и я хочу добавить к нему некоторую информацию с помощью таблицы сопоставления (десятки тысяч строк).

Пример:

policyData <- data.table(plan=c("c","b","b","d"),v=c(8,7,5,6),foo=c(4,2,8,3))
mapping <- data.table(plan=c("b","b","a","a","c","c"),a=c(1,2,4,5,7,8),b=c(9,8,6,5,3,2))

policyData:

   plan v foo
1:    c 8   4
2:    b 7   2
3:    b 5   8
4:    d 6   3

mapping:

   plan a b
1:    b 1 9
2:    b 2 8
3:    a 4 6
4:    a 5 5
5:    c 7 3
6:    c 8 2

Проблема состоит в том, что отображение имеет несколько экземпляров, и я желаючтобы получить только первый матч.И мне нужно объединить два, используя эффективный способ памяти, используя :=.

. Желаемый вывод:

   plan v foo  a  b
1:    c 8   4  7  3
2:    b 7   2  1  9
3:    b 5   8  1  9
4:    d 6   3 NA NA

Я пробовал:

policyData[mapping, on="plan", `:=`(a=i.a, b=i.b)] 

, которыйдает последний экземпляр в таблице сопоставления:

   plan v foo  a  b
1:    c 8   4  8  2
2:    b 7   2  2  8
3:    b 5   8  2  8
4:    d 6   3 NA NA

Я также попытался:

policyData[mapping, on="plan", `:=`(a=i.a, b=i.b), mult="first"]

, что дает странный результат (второй «b» не может соответствовать сопоставлению):

   plan v foo  a  b
1:    c 8   4  8  2
2:    b 7   2  2  8
3:    b 5   8 NA NA
4:    d 6   3 NA NA

Любое понимание будет полезно.Я уже сделал много поисков.

Ответы [ 2 ]

0 голосов
/ 24 сентября 2018

Предлагая другую альтернативу:

policyData[, c("a", "b") := mapping[.SD, on="plan", .(a, b), mult="first"]]

выборка данных для соответствия размерам OP:

library(data.table)
set.seed(0L)
nrDS <- 100e6
nrMap <- 90e3
policyData <- data.table(plan=sample(letters,nrDS,TRUE),v=rnorm(nrDS),foo=rnorm(nrDS))
mapping <- data.table(plan=sample(letters,nrMap,TRUE),a=rnorm(nrMap),b=rnorm(nrMap))

профилирование памяти:

library(bench)
mark(mtd1=policyData[mapping[mapping[, .I[1L], by = plan]$V1], on = .(plan), `:=` (a = i.a, b = i.b)],
    mtd2=policyData[, c("a", "b") := mapping[.SD, on="plan", .(a, b), mult="first"]],
    mtd3=policyData[unique(mapping, by="plan"), on=.(plan), `:=` (a=i.a, b=i.b)])

выход профилирования памяти:

# A tibble: 3 x 14
  expression      min     mean   median      max `itr/sec` mem_alloc  n_gc n_itr total_time result                       memory                  time    gc             
  <chr>      <bch:tm> <bch:tm> <bch:tm> <bch:tm>     <dbl> <bch:byt> <dbl> <int>   <bch:tm> <list>                       <list>                  <list>  <list>         
1 mtd1          7.07s    7.07s    7.07s    7.07s     0.141    4.74GB     0     1      7.07s <data.table [90,000,000 x 5~ <Rprofmem [31,589 x 3]> <bch:t~ <tibble [1 x 3~
2 mtd2          6.73s    6.73s    6.73s    6.73s     0.149    5.03GB     1     1      6.73s <data.table [90,000,000 x 5~ <Rprofmem [20 x 3]>     <bch:t~ <tibble [1 x 3~
3 mtd3          7.68s    7.68s    7.68s    7.68s     0.130    3.35GB     1     1      7.68s <data.table [90,000,000 x 5~ <Rprofmem [23 x 3]>     <bch:t~ <tibble [1 x 3~

Хью-метод наиболее эффективен при использовании памяти, а mtd2 - самый быстрый.Как и с большинством вещей в жизни, вы должны сделать компромисс.

0 голосов
/ 24 сентября 2018

Просто суммируйте mapping с mapping[, .SD[1], by = plan] и используйте это для объединения:

policyData[mapping[, .SD[1], by = plan]
           , on = .(plan)
           , `:=` (a = i.a, b = i.b)]

, что дает желаемый результат:

> policyData
   plan v foo  a  b
1:    c 8   4  7  3
2:    b 7   2  1  9
3:    b 5   8  1  9
4:    d 6   3 NA NA
...