【问题标题】:R - Create list of vectors for all combinations combined based on threshold valueR - 为基于阈值组合的所有组合创建向量列表
【发布时间】:2025-12-06 16:10:01
【问题描述】:

问题: 我有一个数据框(参见示例数据),其中包含空间点('siteA'和'siteB')之间的距离以及它们是否彼此太近('close')。我需要一种将彼此靠近的站点组合成一个向量的方法。在示例数据中:站点 1 靠近站点 3 但远离站点 2。但是,站点 3 靠近站点 2。因此,我需要一种方法将它们组合成一个列表中的一个向量(对于每个组),并且有一个输出,其中站点 1、2、3 在一个向量中;位点 4 和 5 在一个向量中。然后将所有向量组合成一个列表。

# ----------------------------- #
# --- Example table of data --- #
# ----------------------------- #
   siteA siteB     distance close
1      1     2   2913.35364 FALSE
2      1     3   1894.23651  TRUE
3      1     4  96487.01697 FALSE
4      1     5  96485.33550 FALSE
5      2     3   1642.27932  TRUE
6      2     4  93185.78766 FALSE
7      2     5  93183.73986 FALSE
8      3     4 102445.53187 FALSE
9      3     5 102448.58978 FALSE
10     4     5      3.47365  TRUE
# ----------------------------- #


# Example console output for expected results:
> expected_results
[[1]]
[1] 1 2 3

[[2]]
[1] 4 5

此表已包含站点对之间的所有组合,但我需要所有重叠对的组合(如果 close = TRUE)作为每个组的一个向量(例如上面的预期结果)。

在示例数据中,只有 5 个站点,但这些站点可以从 2 到 20+ 不等,并且在示例中,距离是在 2500 处取得的,低于该距离的任何地方都被认为是接近的,但是,这个值也可能会有所不同,具体取决于用户输入。

# Example dataset
df <- data.frame(
  siteA = c(1, 1, 1, 1, 2, 2, 2, 3, 3, 4),
  siteB = c(2, 3, 4, 5, 3, 4, 5, 4, 5, 5),
  distance = c(2913.35364, 1894.23651, 96487.01697, 96485.33550, 1642.27932,  93185.78766, 93183.73986, 102445.53187, 102448.58978, 3.47365),
  close = c(FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE)
)

我正在努力寻找解决方案,我们将不胜感激任何指导。很抱歉没有提供示例代码,我尝试了多种循环方法,但都以惨淡的方式结束。

谢谢!

【问题讨论】:

  • 如果 1 接近 2 并且 2 接近 3 但 1 不接近 3 会发生什么情况(例如,如果它们在一条直线上,并且每个都相隔 ​​2000 个单位的距离?

标签: r list vector combinations


【解决方案1】:

只需稍加改进,就可以以更好的方式完成。

代码

library(tidyverse)

df <- data.frame(
  siteA = c(1,1,1,1,2,2,2,3,3,4),
  siteB = c(2,3,4,5,3,4,5,4,5,5),
  close = c(F,T,F,F,T,F,F,F,F,T)
)

unvisited_sites <- df %>%
  select(contains("site")) %>%
  unlist() %>%
  unique()

site_groups <- list()
i <- 1
while(length(unvisited_sites) > 0){
  
  visited_sites <- NULL
  S <- unvisited_sites[[1]]
  while(length(S) > 0){
    
    u <- S[[1]]
    
    sites <- df %>%
      filter(siteA == u | siteB == u) %>%
      filter(close == TRUE) %>%
      select(siteA, siteB) %>%
      unlist() %>%
      unique() %>%
      intersect(unvisited_sites)
    
    visited_sites <- union(visited_sites, sites)
    unvisited_sites <- setdiff(unvisited_sites, u)
    S <- union(S, intersect(sites, unvisited_sites)) %>% setdiff(u)
  }
  
  site_groups[[i]] <- visited_sites %>% sort()
  i <- i + 1
}

输出

site_groups
[[1]]
[1] 1 2 3

[[2]]
[1] 4 5

【讨论】:

    【解决方案2】:

    我不完全确定这会扩展到更复杂的网络,但它适用于上述数据。

    aggregate(siteA ~ siteB, df[df$close == T,], paste)
    
      siteB siteA
    1     3  1, 2
    2     5     4
    

    【讨论】: