Обработка больших наборов данных в R - PullRequest
2 голосов
/ 06 февраля 2020

У меня есть набор данных из ~ 5 мм рядов предприятий с контактной информацией (ID (int), Email (текст), BusinessPhone (текст), WorkPhone (текст), CellPhone (текст)) - более 3 миллионов из этих строк содержать дубликаты данных. Но они не являются точными, например, могут быть телефонные номера в нескольких строках с разными адресами электронной почты.

Я хочу, чтобы в каждой строке была уникальная информация, чтобы у меня не было дубликатов телефона. номера или электронные письма в моем файле данных. Я планирую сделать это путем объединения столбцов в списки по новому столбцу. Этот столбец (мы назовем ROWID) должен быть объединением всех идентификаторов, которые содержат 1 или более точек контактных данных (электронная почта, BusinessPhone, WorkPhone, CellPhone), которые появляются в этой строке.

У меня есть написанный код, который работает для небольших выборок, но я не могу понять, как его масштабировать.

Примечание: строки с отсутствующим номером телефона (любой из 3-х столбцов) имеют заполнитель текста 'NA'. Пример строки:

before:
ID         Email BusinessPhone   WorkPhone    CellPhone
1  test@mail.com    5555555555          NA   9998887777
2             NA    5555555555   873998898           NA

Desired After:
ID         Email BusinessPhone   WorkPhone    CellPhone ROWIDs
1  test@mail.com    5555555555          NA   9998887777    1,2
2             NA    5555555555   873998898           NA    1,2
library(foreach)
library(doParallel)

registerDoParallel(cores = detectCores())
getDoParWorkers() # (4)

#################### GET MATCHING ROW IDs ######################################################
d = ID(int), Email(char), BusinessPhone(char), WorkPhone(char), CellPhone(char), ROWIDs(all values are '0', col is character vector)

row = function(d) {

foreach(i = 1:nrow(d),.packages = c('dplyr','data.table','tidyverse')) %dopar% {

# 1. IDENTIFY LIST OF ROW IDS THAT CONTAIN CONTACT DATA FROM THE GIVEN ROW:
rowIDList = d[(emailp == emailp[i] & emailp != '') | 
              (BusinessPhone %in% c(BusinessPhone[i],WorkPhone[i],CellPhone[i]) & BusinessPhone != 0) | 
              (WorkPhone %in% c(BusinessPhone[i],WorkPhone[i],CellPhone[i]) & WorkPhone != 0) |
              (CellPhone %in% c(BusinessPhone[i],WorkPhone[i],CellPhone[i]) & CellPhone != 0),
            paste(ID, sep = ',')] %>% as.integer()

# 2. GET THE ROW IDS INTO CHARACTER FORM TO LIST THEM IN THE NEW COLUMN:
rowIDs = paste(rowIDList, collapse = ',') %>% as.character()

# 3. EDIT THE NEW COLUMN FOR THE SUBSET OF ROWS THAT CONTAIN DATA FROM THE ROW IN THE LOOP ITERATION: 
d[ID %in% rowIDList,
  try := rep(rowIDs,
             length(rowIDList))]


}
}

Для случайной выборки из 1000 строк system.time следует: Пользователь: 0,75 Система: 0,12 Истекла: 1,35

Увеличивается экспоненциально при 5000 строк: пользователь: 12,55 система: 1,50 истек: 16,72

и 10 000: пользователь: 50,97 система: 16,77 истек: 71,88

Это далеко от того, с чего я начал, но это насколько я могу возьми это с моими текущими навыками. Любая помощь или руководство приветствуется.

1 Ответ

1 голос
/ 06 февраля 2020

Не уверен, что это достаточно быстро для вашего набора данных, вы можете использовать igraph для идентификации ваших кластеров идентификаторов, которые относятся к одному и тому же человеку:

library(igraph)
edges <- melt(DT[, (names(DT)) := lapply(.SD, as.character)], id.vars="ID", na.rm=TRUE)[, 
    if (.N > 1L) transpose(combn(ID, 2L, simplify=FALSE)), value][, (1) := NULL]
g <- graph_from_data_frame(edges, FALSE)
mem <- setDT(stack(clusters(g)$membership))[, ROWIDs := toString(ind), values]
DT[mem, on=.(ID=ind), ROWIDs := ROWIDs]
DT

вывод:

   ID         Email BusinessPhone WorkPhone CellPhone ROWIDs
1:  1 test@mail.com             5      <NA>         7   1, 2
2:  2          <NA>             5         6      <NA>   1, 2
3:  3 aaaa@mail.com          <NA>      <NA>      <NA>   3, 4
4:  4 aaaa@mail.com          <NA>         1      <NA>   3, 4
5:  5 bbbb@mail.com          <NA>         3      <NA>   5, 6
6:  6          <NA>          <NA>         3      <NA>   5, 6
7:  7 cccc@mail.com          <NA>      <NA>         4   7, 8
8:  8          <NA>          <NA>      <NA>         4   7, 8

данные:

library(data.table)
DT <- fread("
ID         Email BusinessPhone   WorkPhone    CellPhone
1  test@mail.com             5          NA            7
2             NA             5           6           NA
3  aaaa@mail.com            NA          NA           NA
4  aaaa@mail.com            NA           1           NA
5  bbbb@mail.com            NA           3           NA
6             NA            NA           3           NA
7  cccc@mail.com            NA          NA            4
8             NA            NA          NA            4
")
...