【问题标题】:How to handle null values /NAs in network analysis如何在网络分析中处理空值/NA
【发布时间】:2021-12-27 09:14:46
【问题描述】:

这个问题基本上是我之前发布的问题here的扩展。
如何在这些类型的情况下处理空值/NA。 示例场景和数据

df1 <- data.frame(
  stringsAsFactors = FALSE,
                    id_1 = c("ABC","ABC","BCD",
                             "CDE","DEF","EFG","GHI","HIJ","IJK","JKL",
                             "GHI","KLM","LMN","MNO","NOP"),
                    id_2 = c("1A","2A","3A",
                             "1A","4A","5A","6A",NA,"9A","10A","7A",
                             "12A","13A",NA,"15A"),
                    id_3 = c("Z3","Z2","Z1",
                             "Z4","Z1","Z5","Z5","Z6","Z7","Z8","Z6","Z8",
                             "Z9","Z9","Z1"),
                    Name = c("StackOverflow1",
                             "StackOverflow2","StackOverflow3","StackOverflow4",
                             "StackOverflow5","StackOverflow6",
                             "StackOverflow7","StackOverflow8","StackOverflow9",
                             "StackOverflow10","StackOverflow11","StackOverflow12",
                             "StackOverflow13","StackOverflow14","StackOverflow15"),
          desired_output = c(1L,1L,2L,1L,2L,
                             3L,3L,3L,4L,5L,3L,5L,6L,6L,2L)
      )

df1
   id_1 id_2 id_3            Name desired_output
1   ABC   1A   Z3  StackOverflow1              1
2   ABC   2A   Z2  StackOverflow2              1
3   BCD   3A   Z1  StackOverflow3              2
4   CDE   1A   Z4  StackOverflow4              1
5   DEF   4A   Z1  StackOverflow5              2
6   EFG   5A   Z5  StackOverflow6              3
7   GHI   6A   Z5  StackOverflow7              3
8   HIJ <NA>   Z6  StackOverflow8              3
9   IJK   9A   Z7  StackOverflow9              4
10  JKL  10A   Z8 StackOverflow10              5
11  GHI   7A   Z6 StackOverflow11              3
12  KLM  12A   Z8 StackOverflow12              5
13  LMN  13A   Z9 StackOverflow13              6
14  MNO <NA>   Z9 StackOverflow14              6
15  NOP  15A   Z1 StackOverflow15              2

但是链接帖子中建议的三种方法不起作用并给我错误。

请提出建议。

【问题讨论】:

  • 你可以先把NA换成字符'"NA"',然后我想问题可以像上一个问题一样解决。
  • @ThomasIsCoding 会将所有记录与我不想要的文本 NA 链接起来!
  • 对不起,我的错。请参阅下面的答案。
  • 在这些情况下,您能用简单的英语解释一下这个问题吗?这和你之前的问题都不是很清楚。一个人必须做猜测。

标签: r igraph network-analysis


【解决方案1】:

附加说明

为了能够集群这个网络,我们需要一个ids 的边缘列表。在这个数据框中,我们实际上在每一行中有 3 个ids,表示一种三元组结构,或者通常它显示了三者之间的联系。所以

  • 我首先选择了 3 个目标变量,然后我使用 pmap 函数在这 3 个顶点之间创建长度为 2 的每个组合,并将结果逐行绑定在一起
  • 在下一步中,我们得到一个只有 2 个变量的数据框,这些变量构成了我们所需的边列表,其中包含原始顶点(变量)之间的所有现有边]
  • 然后我使用tidyr::drop_na 删除那些缺失值,假设在HIJ --- NA 这样的设置中,如果HIJ 与其他观察中的其他顶点之间有任何边,我们只能定义它的成员资格。所以在第一个代码块中删除它们是安全的
  • 最后我用membership函数提取了相关组件,也用groups提取了簇。这些集群的 id 是我们提取 desired_output 变量的地方,如何? 由于每个集群都与其他集群完全分开,我们假设原始数据集中的每个顶点或ids 只能是一个集群的一部分,所以我们通过第二个代码块检查了这一点,我只检查了id_1
library(tidyverse)
library(igraph)

df1 %>%
  select(starts_with("id")) %>%
  pmap_dfr(~ as.data.frame(t(combn(c(...), 2)))) %>%
  drop_na() %>%
  graph_from_data_frame(directed = TRUE) %>%
  components() %>% 
  groups() -> lst
  
df1 %>%
  rowwise() %>%
  mutate(grp = seq_len(length(lst))[map_lgl(lst, ~ id_1 %in% .x)])

# A tibble: 15 x 6
# Rowwise: 
   id_1  id_2  id_3  Name            desired_output   grp
   <chr> <chr> <chr> <chr>                    <int> <int>
 1 ABC   1A    Z3    StackOverflow1               1     1
 2 ABC   2A    Z2    StackOverflow2               1     1
 3 BCD   3A    Z1    StackOverflow3               2     2
 4 CDE   1A    Z4    StackOverflow4               1     1
 5 DEF   4A    Z1    StackOverflow5               2     2
 6 EFG   5A    Z5    StackOverflow6               3     3
 7 GHI   6A    Z5    StackOverflow7               3     3
 8 HIJ   NA    Z6    StackOverflow8               3     3
 9 IJK   9A    Z7    StackOverflow9               4     4
10 JKL   10A   Z8    StackOverflow10              5     5
11 GHI   7A    Z6    StackOverflow11              3     3
12 KLM   12A   Z8    StackOverflow12              5     5
13 LMN   13A   Z9    StackOverflow13              6     6
14 MNO   NA    Z9    StackOverflow14              6     6
15 NOP   15A   Z1    StackOverflow15              2     2

【讨论】:

  • 感谢@Anoushiravan 的回答。请添加更多有关语法的信息。
【解决方案2】:

更新

如果你在某一行有多个NA,你可以试试下面的代码

transform(
  df,
  GRP = membership(
    components(
      graph_from_data_frame(
        transform(
          reshape(
            df,
            direction = "long",
            idvar = c("id_1", "Name"),
            varying = 2:3,
            v.names = "to"
          )[c("id_1", "to")],
          to = ifelse(is.na(to), id_1, to)
        )
      )
    )
  )[id_1]
)

给了

   id_1 id_2 id_3            Name GRP
1   ABC   1A   Z3  StackOverflow1   1
2   ABC   2A   Z2  StackOverflow2   1
3   BCD   3A   Z1  StackOverflow3   2
4   CDE   1A   Z4  StackOverflow4   1
5   DEF   4A   Z1  StackOverflow5   2
6   EFG   5A   Z5  StackOverflow6   3
7   GHI   6A   Z5  StackOverflow7   3
8   HIJ <NA> <NA>  StackOverflow8   4
9   IJK   9A   Z7  StackOverflow9   5
10  JKL  10A   Z8 StackOverflow10   6
11  GHI   7A   Z6 StackOverflow11   3
12  KLM  12A   Z8 StackOverflow12   6
13  LMN  13A <NA> StackOverflow13   7
14  MNO <NA> <NA> StackOverflow14   8
15  NOP  15A   Z1 StackOverflow15   2

虚拟数据

> dput(df)
structure(list(id_1 = c("ABC", "ABC", "BCD", "CDE", "DEF", "EFG", 
"GHI", "HIJ", "IJK", "JKL", "GHI", "KLM", "LMN", "MNO", "NOP"
), id_2 = c("1A", "2A", "3A", "1A", "4A", "5A", "6A", NA, "9A",
"10A", "7A", "12A", "13A", NA, "15A"), id_3 = c("Z3", "Z2", "Z1",
"Z4", "Z1", "Z5", "Z5", NA, "Z7", "Z8", "Z6", "Z8", NA, NA, "Z1"
), Name = c("StackOverflow1", "StackOverflow2", "StackOverflow3",
"StackOverflow4", "StackOverflow5", "StackOverflow6", "StackOverflow7",
"StackOverflow8", "StackOverflow9", "StackOverflow10", "StackOverflow11",
"StackOverflow12", "StackOverflow13", "StackOverflow14", "StackOverflow15"
)), row.names = c(NA, -15L), class = "data.frame")

上一个答案

也许您可以将id_2 列中的NA 替换为id_1 中的值,然后按照前面问题中的答案进行操作。

你可以试试这个

transform(
  df,
  GRP = membership(
    components(
      graph_from_data_frame(
        reshape(
          transform(
            df,
            id_2 = ifelse(is.na(id_2), id_1, id_2)
          ),
          direction = "long",
          idvar = c("id_1", "Name"),
          varying = 2:3,
          v.names = "to"
        )[c("id_1", "to")]
      )
    )
  )[id_1]
)

给了

   id_1 id_2 id_3            Name GRP
1   ABC   1A   Z3  StackOverflow1   1
2   ABC   2A   Z2  StackOverflow2   1
3   BCD   3A   Z1  StackOverflow3   2
4   CDE   1A   Z4  StackOverflow4   1
5   DEF   4A   Z1  StackOverflow5   2
6   EFG   5A   Z5  StackOverflow6   3
7   GHI   6A   Z5  StackOverflow7   3
8   HIJ <NA>   Z6  StackOverflow8   3
9   IJK   9A   Z7  StackOverflow9   4
10  JKL  10A   Z8 StackOverflow10   5
11  GHI   7A   Z6 StackOverflow11   3
12  KLM  12A   Z8 StackOverflow12   5
13  LMN  13A   Z9 StackOverflow13   6
14  MNO <NA>   Z9 StackOverflow14   6
15  NOP  15A   Z1 StackOverflow15   2

【讨论】:

  • 谢谢。但我认为它只适用于至少一列具有空值!如果某些行在所有 id_columns 中都有空白值怎么办?这个可以修改吗?
  • @AnilGoyal 你能按照你的描述生成数据吗?我去看看
  • 感谢您的努力。这次我也接受另一个答案,但我会发布另一个问题,其中包含更具体的数据库示例。
【解决方案3】:

只需删除NA

df$desired_output <- df %>%
  select(matches("^id_[0-9]+$")) %>%
  mutate(row = row_number()) %>%
  pmap(~c(...) %>% .[!is.na(.)]) %>%
  map(f) %>%
  flatten() %>%
  reduce(rbind) %>%
  igraph::graph_from_edgelist() %>% 
  components() %>%
  membership() %>%
  .[as.character(seq_len(nrow(df)))]

【讨论】:

  • 感谢@det 的回答。已经投票了。这次接受另一个答案。
猜你喜欢
  • 2021-12-19
  • 2018-01-13
  • 2020-05-22
  • 2022-11-04
  • 2015-10-10
  • 1970-01-01
  • 2014-09-05
  • 2019-02-18
  • 2014-12-28
相关资源
最近更新 更多