Непоследовательные результаты dist () foreach - PullRequest
0 голосов
/ 27 февраля 2020

У меня есть данные, которые примерно в следующем формате, но очень большие, но разбиты по группам, используя переменную class и uniqueId. Где каждая локация является парной строкой (x, y).

df <- 
  data.frame(
    x = c(1, 2, 3, 4, 5, 6, 8, 9, 10), 
    y = c(1, 2, 3, 4, 5, 6, 8, 9, 10), 
    class = c(0, 0, 0, 0, 0, 1, 0, 1, 0), 
    uniqueId = c("1-2-3", "1-2-3", "1-2-3", "1-2-4", "1-2-4", "1-2-4", "1-3-2", "1-3-2", "1-3-2"),
    partialId = c("1.2", "1.2", "1.2", "1.2", "1.2", "1.2", "1.3", "1.3", 1.3") 
  )

Используемая мной функция должна go пройти через фрейм данных и вычислить наименьшее расстояние до другого объекта в пределах того же уникального идентификатора, но другого класса, что и текущая строка. Для этого я разбил свои данные на куски следующим образом:

indexes <-
  df %>%
  select(partialId) %>%
  unique()

j <- 1

library(doParallel)

class_separation <- c()

cl <- makePSOCKcluster(24)

registerDoParallel(cl)


while(j <= nrow(indexes)) {

  test <- df %>% filter(partialId == indexes$partialId[j])
  n <- nrow(test)
  vec <- numeric(n)
  vec <- foreach(k = 1:n, .combine = 'c', .multicombine = F) %dopar% {
    c(
      min(
        apply(
          test[test$uniqueId == test$uniqueId[k] & test$class != test$class[k], c("x","y")],
          1,
          function(x) dist(rbind(c(test$x[k],test$y[k]), c(x[1], x[2])))
        )
      )
    )
  }
  class_separation <- c(class_separation, vec)
  j <- j + 1
}
endtime <- Sys.time()
stopwatch <- endtime - starttime
closeAllConnections()
registerDoSEQ()
gc()
df <- cbind(df, class_separation)

При обработке одиночных или небольших партий этот код работает нормально. Однако при обработке полного набора данных я получаю результаты, которые явно неверны. Я знаю, что у меня должен быть недостаток в том, как я вычисляю эти расстояния, так как есть очень небольшая вероятность, что сама функция dist () или% dopar% ошибочна. Я изменил на% do%, и мои результаты не изменились.

В качестве примера несоответствия на следующем рисунке показан столбец class_separation с момента, когда выполняется полный цикл данных, и когда я передаю его небольшой пример. Как видите, результаты сильно отличаются, но я не уверен, почему.

results image

1 Ответ

0 голосов
/ 28 февраля 2020

После дня размышлений об этом проблема заключается в том, как я отправлял свой df в dist ().

Например, если мы намеревались передать

dist(rbind(c(1, 1), c(6, 6)))

dist(rbind(c(1, 1), c(9, 9)))

Что мы на самом деле передаем это dist(rbind(c(1, 1), c(6, 6, 9, 9)))

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

foreach(i = 1:nrow(df), .combine = 'c', .multicombine = F, .packages = c('tidyverse', 
  'rdist')) %dopar% {
    min(
      cdist(
        df[df$class != df$class[i] & df$uniqueId == df$uniqueId[i], ] %>% select(x, y), 
        df %>% select(x, y) %>% slice(i)
      )
    )
}

Для наших тестовых данных это возвращает вектор

Inf Inf Inf 2.828427 1.414214 1.414214 1.414214 1.414214 1.414214

Что именно то, что мне было нужно. Первые три записи, не имеющие параметров class == 1 для их уникального идентификатора, должны возвращать Inf, строка 4 вдвое дальше от строки 6, чем строка 5, при этом все имеют одинаковый уникальный идентификатор, в то время как строка 9 находится на одинаковом расстоянии от строк 8 и 10. это решение будет достаточно быстрым, я опробую.

...