不一致的 dist() foreach 结果
Inconsistent dist() foreach results
我的数据大致采用以下格式,但非常大,但使用 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")
)
我正在使用的函数应该通过数据框并计算到与当前行相同的 uniqueId 但 class 不同的另一个对象的最小距离。为此,我按照以下方式将数据分成块。
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 列与我为其提供一个小示例时的对比。如您所见,结果大相径庭,但我不确定原因。
经过一天的思考,问题在于我如何将我的 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)))
这显然不是我想要的。我需要两个距离,然后 select 它们之间的最小值或添加其他条件。我发现的方法是使用 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)
)
)
}
对于我们的测试数据,这个 return 向量
Inf Inf Inf 2.828427 1.414214 1.414214 1.414214 1.414214 1.414214
这正是我所需要的。前三个条目的 uniqueId 没有 class == 1 选项应该 return Inf,第 4 行与第 6 行的距离是第 5 行的两倍,同时都具有相同的 uniqueId,而第 9 行同样到第 8 行和第 10 行的距离。这个解决方案是否足够快,我会测试一下。
我的数据大致采用以下格式,但非常大,但使用 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")
)
我正在使用的函数应该通过数据框并计算到与当前行相同的 uniqueId 但 class 不同的另一个对象的最小距离。为此,我按照以下方式将数据分成块。
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 列与我为其提供一个小示例时的对比。如您所见,结果大相径庭,但我不确定原因。
经过一天的思考,问题在于我如何将我的 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)))
这显然不是我想要的。我需要两个距离,然后 select 它们之间的最小值或添加其他条件。我发现的方法是使用 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)
)
)
}
对于我们的测试数据,这个 return 向量
Inf Inf Inf 2.828427 1.414214 1.414214 1.414214 1.414214 1.414214
这正是我所需要的。前三个条目的 uniqueId 没有 class == 1 选项应该 return Inf,第 4 行与第 6 行的距离是第 5 行的两倍,同时都具有相同的 uniqueId,而第 9 行同样到第 8 行和第 10 行的距离。这个解决方案是否足够快,我会测试一下。