将 NA 的行替换为满足特定列匹配的另一行

问题描述 投票:0回答:1

这是一个数据片段:

Tab1 <- read.table(text = "
  nodepair ES1 ES2 ++ -- +- -+ 0+ +0 0- -0 00
1     E_A6   3   3  0  0  0  0  0  0  0  0  1
2     E_A6   4   3 NA NA NA NA NA NA NA NA NA
3     E_A6   5   3 NA NA NA NA NA NA NA NA NA
4     E_AL   3   3  0  5  0  0  0  0  0  0  1
5     E_AL   4   3 NA NA NA NA NA NA NA NA NA
6     E_AL   5   3 NA NA NA NA NA NA NA NA NA   
", header = TRUE)

对于每个节点对组,我想将包含 NA 的行替换为 ES2 等于 ES1 的行中的值,前提是它与 NA 行的 ES2 匹配。然后我需要将 NA 分配给先前 NA 行的 ES1 列。

像这样:

Tab2 <- read.table(text = "
  nodepair ES1 ES2 ++ -- +- -+ 0+ +0 0- -0 00
1     E_A6   3   3  0  0  0  0  0  0  0  0  1
2     E_A6   NA  3  0  0  0  0  0  0  0  0  1
3     E_A6   NA  3  0  0  0  0  0  0  0  0  1
4     E_AL   3   3  0  5  0  0  0  0  0  0  1
5     E_AL   NA  3  0  5  0  0  0  0  0  0  1
6     E_AL   NA  3  0  5  0  0  0  0  0  0  1   
", header = TRUE)

我一直在尝试这种逻辑:

Tab2 <- Tab1  %>%
  rowwise %>%
  mutate(across(4:12, ~ifelse(is.na(rowsums), ???, .))))
r replace na matching pairwise
1个回答
0
投票

也许 for 循环会起作用?例如

Tab1 <- read.table(text = "
  nodepair ES1 ES2 ++ -- +- -+ 0+ +0 0- -0 00
1     E_A6   3   3  0  0  0  0  0  0  0  0  1
2     E_A6   4   3 NA NA NA NA NA NA NA NA NA
3     E_A6   5   3 NA NA NA NA NA NA NA NA NA
4     E_AL   3   3  0  5  0  0  0  0  0  0  1
5     E_AL   4   3 NA NA NA NA NA NA NA NA NA
6     E_AL   5   3 NA NA NA NA NA NA NA NA NA   
", header = TRUE,  check.names = FALSE)

for (i in 1:nrow(Tab1)) {
  if (Tab1[i,2] == Tab1[i,3]) {
    stored_line <- Tab1[i,4:12]
  }
  if (all(is.na(Tab1[i,4:12]))) {
    Tab1[i,4:12] <- stored_line
    Tab1[i,2] <- NA
  }
}

Tab1
#>   nodepair ES1 ES2 ++ -- +- -+ 0+ +0 0- -0 00
#> 1     E_A6   3   3  0  0  0  0  0  0  0  0  1
#> 2     E_A6  NA   3  0  0  0  0  0  0  0  0  1
#> 3     E_A6  NA   3  0  0  0  0  0  0  0  0  1
#> 4     E_AL   3   3  0  5  0  0  0  0  0  0  1
#> 5     E_AL  NA   3  0  5  0  0  0  0  0  0  1
#> 6     E_AL  NA   3  0  5  0  0  0  0  0  0  1

我尝试使用连接,但无法弄清楚边缘情况,例如如果一行有 NA 和值:

# add some sevens to line 2
Tab1 <- read.table(text = "
  nodepair ES1 ES2 ++ -- +- -+ 0+ +0 0- -0 00
1     E_A6   3   3  0  0  0  0  0  0  0  0  1
2     E_A6   4   3 NA NA NA NA NA NA NA  7  7
3     E_A6   5   3 NA NA NA NA NA NA NA NA NA
4     E_AL   3   3  0  5  0  0  0  0  0  0  1
5     E_AL   4   3 NA NA NA NA NA NA NA NA NA
6     E_AL   5   3 NA NA NA NA NA NA NA NA NA   
", header = TRUE,  check.names = FALSE)

# solution from @thelatemail's comment:
library(tidyverse)
Tab1 %>% select(nodepair,ES2) %>% left_join(Tab1 %>% filter(ES1 == ES2), by=c("nodepair","ES2"))
#>   nodepair ES2 ES1 ++ -- +- -+ 0+ +0 0- -0 00
#> 1     E_A6   3   3  0  0  0  0  0  0  0  0  1
#> 2     E_A6   3   3  0  0  0  0  0  0  0  0  1
#> 3     E_A6   3   3  0  0  0  0  0  0  0  0  1
#> 4     E_AL   3   3  0  5  0  0  0  0  0  0  1
#> 5     E_AL   3   3  0  5  0  0  0  0  0  0  1
#> 6     E_AL   3   3  0  5  0  0  0  0  0  0  1

# compared to the for-loop approach
for (i in 1:nrow(Tab1)) {
  if (Tab1[i,2] == Tab1[i,3]) {
    stored_line <- Tab1[i,4:12]
  }
  if (all(is.na(Tab1[i,4:12]))) {
    Tab1[i,4:12] <- stored_line
    Tab1[i,2] <- NA
  }
}
Tab1
#>   nodepair ES1 ES2 ++ -- +- -+ 0+ +0 0- -0 00
#> 1     E_A6   3   3  0  0  0  0  0  0  0  0  1
#> 2     E_A6   4   3 NA NA NA NA NA NA NA  7  7
#> 3     E_A6  NA   3  0  0  0  0  0  0  0  0  1
#> 4     E_AL   3   3  0  5  0  0  0  0  0  0  1
#> 5     E_AL  NA   3  0  5  0  0  0  0  0  0  1
#> 6     E_AL  NA   3  0  5  0  0  0  0  0  0  1

创建于 2024-02-06,使用 reprex v2.1.0

© www.soinside.com 2019 - 2024. All rights reserved.