根据 R 中的查找 table 替换某些列和行中的 NA

Replace NA's in some columns and rows based on a lookup table in R

下面的可复制数据集。

让我设定场景:我有5个摄像头同时记录的3个物种的检测历史(V1:V10)(1=检测到,0=未检测到)。 摄像机 1 和 2 在第一天和最后一天没有记录,因此 NA 列在 V1 和 V10 列中。 摄像机 5 前两天和后两天没有记录,因此这些 NA。

因为摄像机 2 没有记录到狞猫,摄像机 5 也没有记录到豹子,所以这些行都充满了 NA。

不过,我知道摄像机 2 和 5 在此期间确实工作,因此摄像机 2 的 V2:V9 狞猫和摄像机 2 的豹子 V3:V8 应该有“0” 5.

所以我的问题是:如何用 0 而不是 NA 填充这些单元格?

当摄像机在第一天和最后几天不工作时,我需要维护 NA。

我的实际数据集有数百个物种、相机和日期,所以我无法手动执行此操作。

我一直在努力解决这个问题,但完全没有成功。 我想创建一个查询 table 每个摄像头何时工作但无法弄清楚语法。

感谢任何帮助

camera<-c(rep(1:5,each=3))
species_names<-c("baboon","caracal", "leopard")
species<-c(rep(species_names,5))
V1<-c(NA,NA,NA,NA,NA,NA,0,0,1,1,1,0,NA,NA,NA)
V2<-c(0,1,0,0,NA,0,0,0,1,0,0,1,NA,NA,NA)
V3<-c(1,0,1,0,NA,0,1,1,0,1,0,0,1,0,NA)
V4<-c(0,1,1,1,NA,0,0,0,0,1,1,0,0,0,NA)
V5<-c(1,1,1,0,NA,1,1,1,0,0,1,1,1,0,NA)
V6<-c(1,0,1,1,NA,1,1,1,1,0,0,1,1,1,NA)
V7<-c(0,0,1,0,NA,0,0,1,0,0,0,0,1,0,NA)
V8<-c(1,1,1,1,NA,1,0,0,0,0,1,0,0,0,NA)
V9<-c(0,0,1,0,NA,0,0,1,1,1,1,0,NA,NA,NA)
V10<-c(NA,NA,NA,NA,NA,NA,0,1,0,0,0,0,NA,NA,NA)

dataset<-data.frame(camera,species,V1,V2,V3,V4,V5,V6,V7,V8,V9,V10)
dataset

   camera species V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1       1  baboon NA  0  1  0  1  1  0  1  0  NA
2       1 caracal NA  1  0  1  1  0  0  1  0  NA
3       1 leopard NA  0  1  1  1  1  1  1  1  NA
4       2  baboon NA  0  0  1  0  1  0  1  0  NA
5       2 caracal NA NA NA NA NA NA NA NA NA  NA
6       2 leopard NA  0  0  0  1  1  0  1  0  NA
7       3  baboon  0  0  1  0  1  1  0  0  0   0
8       3 caracal  0  0  1  0  1  1  1  0  1   1
9       3 leopard  1  1  0  0  0  1  0  0  1   0
10      4  baboon  1  0  1  1  0  0  0  0  1   0
11      4 caracal  1  0  0  1  1  0  0  1  1   0
12      4 leopard  0  1  0  0  1  1  0  0  0   0
13      5  baboon NA NA  1  0  1  1  1  0 NA  NA
14      5 caracal NA NA  0  0  0  1  0  0 NA  NA
15      5 leopard NA NA NA NA NA NA NA NA NA  NA


我的数据集应该是这样的:

   camera species V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1       1  baboon NA  0  1  0  1  1  0  1  0  NA
2       1 caracal NA  1  0  1  1  0  0  1  0  NA
3       1 leopard NA  0  1  1  1  1  1  1  1  NA
4       2  baboon NA  0  0  1  0  1  0  1  0  NA
5       2 caracal NA  0  0  0  0  0  0  0  0  NA
6       2 leopard NA  0  0  0  1  1  0  1  0  NA
7       3  baboon  0  0  1  0  1  1  0  0  0   0
8       3 caracal  0  0  1  0  1  1  1  0  1   1
9       3 leopard  1  1  0  0  0  1  0  0  1   0
10      4  baboon  1  0  1  1  0  0  0  0  1   0
11      4 caracal  1  0  0  1  1  0  0  1  1   0
12      4 leopard  0  1  0  0  1  1  0  0  0   0
13      5  baboon NA NA  1  0  1  1  1  0 NA  NA
14      5 caracal NA NA  0  0  0  1  0  0 NA  NA
15      5 leopard NA NA  0  0  0  0  0  0 NA  NA

我们可以将 acrossifelse 语句一起使用:

library(dplyr)
dataset %>% 
    mutate(across(V2:V9, ~ifelse(camera==2 & species=="caracal", 0,.)),
           across(V3:V8, ~ifelse(camera==5 & species=="leopard", 0,.))
           )
           

输出:

   camera species V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1       1  baboon NA  0  1  0  1  1  0  1  0  NA
2       1 caracal NA  1  0  1  1  0  0  1  0  NA
3       1 leopard NA  0  1  1  1  1  1  1  1  NA
4       2  baboon NA  0  0  1  0  1  0  1  0  NA
5       2 caracal NA  0  0  0  0  0  0  0  0  NA
6       2 leopard NA  0  0  0  1  1  0  1  0  NA
7       3  baboon  0  0  1  0  1  1  0  0  0   0
8       3 caracal  0  0  1  0  1  1  1  0  1   1
9       3 leopard  1  1  0  0  0  1  0  0  1   0
10      4  baboon  1  0  1  1  0  0  0  0  1   0
11      4 caracal  1  0  0  1  1  0  0  1  1   0
12      4 leopard  0  1  0  0  1  1  0  0  0   0
13      5  baboon NA NA  1  0  1  1  1  0 NA  NA
14      5 caracal NA NA  0  0  0  1  0  0 NA  NA
15      5 leopard NA NA  0  0  0  0  0  0 NA  NA

也许你可以选择

library(dplyr)

dataset %>% 
  group_by(camera) %>% 
  mutate(across(V1:V10, ~ifelse(any(!is.na(.)) & is.na(.), 0, .))) %>%
  ungroup()

哪个returns

# A tibble: 15 x 12
   camera species    V1    V2    V3    V4    V5    V6    V7    V8    V9   V10
    <int> <chr>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1      1 baboon     NA     0     1     0     1     1     0     1     0    NA
 2      1 caracal    NA     1     0     1     1     0     0     1     0    NA
 3      1 leopard    NA     0     1     1     1     1     1     1     1    NA
 4      2 baboon     NA     0     0     1     0     1     0     1     0    NA
 5      2 caracal    NA     0     0     0     0     0     0     0     0    NA
 6      2 leopard    NA     0     0     0     1     1     0     1     0    NA
 7      3 baboon      0     0     1     0     1     1     0     0     0     0
 8      3 caracal     0     0     1     0     1     1     1     0     1     1
 9      3 leopard     1     1     0     0     0     1     0     0     1     0
10      4 baboon      1     0     1     1     0     0     0     0     1     0
11      4 caracal     1     0     0     1     1     0     0     1     1     0
12      4 leopard     0     1     0     0     1     1     0     0     0     0
13      5 baboon     NA    NA     1     0     1     1     1     0    NA    NA
14      5 caracal    NA    NA     0     0     0     1     0     0    NA    NA
15      5 leopard    NA    NA     0     0     0     0     0     0    NA    NA

主要思想是,如果一列中的所有观察值都是NA,则应保留NA,否则应将NA替换为0

这是一种方法。这使用 tidyverse 函数,因此加载该库。基本思想是首先有一个长数据集,指示相机在哪些天工作,哪些天不工作。像这样:

camera_data<-data.frame(
  camera=rep(c(1:5),each=10 ),
  Day=rep(paste0("V",1:10), times=5),
  Status=c(0,rep(1,8),0,0, rep(1,8),0, rep(1,20), 0,0, rep(1,6),0,0)
)

看起来像这样

   camera Day Status
1       1  V1      0
2       1  V2      1
3       1  V3      1
4       1  V4      1
5       1  V5      1
6       1  V6      1
7       1  V7      1
8       1  V8      1
9       1  V9      1
10      1 V10      0
11      2  V1      0

Status 为 1 表示相机正常工作,0 表示损坏。

然后,你需要将你的检测数据旋转得也很长,像这样:

dataset_long<-dataset %>% pivot_longer(cols=V1:V10, names_to="Day", values_to="Presence")

> dataset_long
# A tibble: 150 x 4
   camera species Day   Presence
    <int> <chr>   <chr>    <dbl>
 1      1 baboon  V1          NA
 2      1 baboon  V2           0
 3      1 baboon  V3           1
 4      1 baboon  V4           0
 5      1 baboon  V5           1
 6      1 baboon  V6           1
 7      1 baboon  V7           0
 8      1 baboon  V8           1
 9      1 baboon  V9           0
10      1 baboon  V10         NA
# ... with 140 more rows

现在你可以简单地 left_join 它们并使用 mutate 中的 if_else 找到应该为 0 的 NA 并替换它们:

dataset_long<-dataset_long %>% left_join(camera_data) %>%
mutate(Presence= if_else(is.na(Presence) & Status==1, 0, Presence))

最后,如果您需要以宽格式恢复数据,您可以使用 pivot_wider 来做到这一点并删除额外的 Status 列:

dataset_done<-dataset_long %>% 
pivot_wider(id_cols=c(camera,species), names_from=Day, values_from=Presence)

您的最终数据是:

> dataset_done
# A tibble: 15 x 12
   camera species    V1    V2    V3    V4    V5    V6    V7    V8    V9   V10
    <int> <chr>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1      1 baboon     NA     0     1     0     1     1     0     1     0    NA
 2      1 caracal    NA     1     0     1     1     0     0     1     0    NA
 3      1 leopard    NA     0     1     1     1     1     1     1     1    NA
 4      2 baboon     NA     0     0     1     0     1     0     1     0    NA
 5      2 caracal    NA     0     0     0     0     0     0     0     0    NA
 6      2 leopard    NA     0     0     0     1     1     0     1     0    NA
 7      3 baboon      0     0     1     0     1     1     0     0     0     0
 8      3 caracal     0     0     1     0     1     1     1     0     1     1
 9      3 leopard     1     1     0     0     0     1     0     0     1     0
10      4 baboon      1     0     1     1     0     0     0     0     1     0
11      4 caracal     1     0     0     1     1     0     0     1     1     0
12      4 leopard     0     1     0     0     1     1     0     0     0     0
13      5 baboon     NA    NA     1     0     1     1     1     0    NA    NA
14      5 caracal    NA    NA     0     0     0     1     0     0    NA    NA
15      5 leopard    NA    NA     0     0     0     0     0     0    NA    NA

一般来说,我发现处理长格式数据比处理宽格式数据容易得多 - 因此旋转通常是很好的第一步。

这确实需要您制作 camera_data table,但我看不出有任何解决办法。