2016-05-09 2 views
4

С учетом data.table с тремя полями member_id, provider_id и srvc_dt. Мне нужно вычислить количество отдельных членов, которых видит пара поставщиков. Говорят, что посетитель посетил двух поставщиков, если эти визиты произошли в течение 180 дней. Это используется для построения неориентированного графика с использованием порогового значения для #visits и поиска подключенных компонентов.ускорение данных. Картографический файл с фильтрацией

Я использую метод, предложенный в Cartesian product with filter data.table.

Экземпляр, который мне нужно запустить, имеет более 3 миллионов записей, и он занимает 5 минут для запуска. Есть ли способ перезаписи или новая функция data.table, чтобы она работала быстрее?

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)] 

ответ

2

простой левый-Join с последующей фильтрацией:

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 предотвращает двойного подсчета те же посещения х, у и у, х.

также, теперь использует provider_id и i.provider_id вместо provider_id1 и provider_id2 при вычислении prov_pair_agg.dt:

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

на 16gb памяти машины с nmem = 1,000,000, это занимает 1.487s против 106.034s вашего текущего метода.

+0

, пожалуйста, установите nmem на 1000000 и попробуйте. Я получаю следующую ошибку: ... Присоединяйтесь к результатам в 2009362 строках; более 2000000 = nrow (x) + nrow (i) ... '. Преимущество с другим подходом заключается в том, что он эффективен с точки зрения памяти (см. Последнюю строку в сообщении @ Arun). – ironv

+0

с nmem = 1,000,000, 'allow.cartesian = T' требуется, но этот способ все еще быстр, при условии достаточной памяти. – webb

+1

, возможно, отфильтровывают участников, которые видели только одного поставщика, то есть, начиная с 'data.dt [, if (.N> = 2) .SD, by = member_id]', будут решать проблемы с памятью (в зависимости от данных, конечно) – eddi

0

Во-первых, отфильтровать данные, чтобы включать только пользователей, которые видели более одного поставщика:

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

Затем добавить конечные точки для даты и копию столбца поставщика:

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

Наконец, используйте новые, не оборуды присоединяются, доступный в 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)] 

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

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