如何根据其他变量/记录次数将NA更改为0
我还是 R 的新手,需要帮助。我想根据计数值将变量 x1,x2,x3 中的 NA 值更改为 0。Count 指定观察次数,x1,x2,x3 代表对站点的访问(或复制)。每个“X”变量中的值是找到的物种数。但是,并非所有网站都被访问了 3 次。变量计数告诉我们网站实际访问了多少次。我想确定实际的 NA 和真正的 0(这意味着没有找到物种)。如果实际访问了该站点,我想将 NA 更改为 0,如果未访问该站点,则将其保留为 NA。例如从虚拟数据中,'zhask'站点被访问了2次,那么zhask的x1中的NA需要被替换为0。
这是虚拟数据:
site x1 x2 x3 count
1 miya 1 2 1 3
2 zhask NA 1 NA 2
3 balmond 3 NA 2 3
4 layla NA 1 NA 2
5 angela NA 3 NA 2
因此,需要将表更改为:
site x1 x2 x3 count
1 miya 1 2 1 3
2 zhask 0 1 NA 2
3 balmond 3 0 2 3
4 layla 0 1 NA 2
5 angela 0 3 NA 2
我尝试了很多东西并尝试制作自己的功能,但是,它不起作用:
for(i in 1:nrow(df))
{
if( is.na(df$x1[i]) && (i < df$count[i]))
{df$x1[i]=0}
else
{df$x1[i]=df$x1[i]}
}
这是虚拟数据框的脚本:
x1= c(1,NA,3, NA, NA)
x2= c(2,1, NA, 1, 3)
x3 = c(1, NA, 2, NA, NA)
count=c(3,2,3,2,2)
site=c("miya", "zhask", "balmond", "layla", "angela")
df=data.frame(site,x1,x2,x3,count)
任何帮助将不胜感激!
回答
一种方法是对所有计数列应用函数。这是一种方法。
cols <- c("x1", "x2", "x3")
df[, cols] <- mapply(function(col, idx, count) {
ifelse(idx <=count & is.na(col), 0, col)
}, df[,cols], seq_along(cols), MoreArgs=list(count=df$count))
# site x1 x2 x3 count
# 1 miya 1 2 1 3
# 2 zhask 0 1 NA 2
# 3 balmond 3 0 2 3
# 4 layla 0 1 NA 2
# 5 angela 0 3 NA 2
我们mapply用来迭代列和列的索引。我们也count每次都传入值(因为它对所有列都是相同的,所以它进入了MoreArgs=参数)。这mapply将返回一个列表,我们可以使用它来用更新的值替换列。
如果您想使用dplyr,那可能看起来更像
library(dplyr)
cols <- c("x1"=1, "x2"=2, "x3"=3)
df %>%
mutate(across(starts_with("x"), ~if_else(cols[cur_column()]<count & is.na(.x), 0, .x)))
我使用cols向量来获取列的索引,当使用across().
但是解决这个问题的更“整洁”的方法是首先将您的数据转换为“整洁”的格式。然后您可以更轻松地清理数据并在必要时返回
library(dplyr)
library(tidyr)
df %>%
pivot_longer(cols=starts_with("x")) %>%
mutate(index=readr::parse_number(name)) %>%
mutate(value=if_else(index < count & is.na(value), 0, value)) %>%
select(-index) %>%
pivot_wider(names_from=name, values_from=value)
# site count x1 x2 x3
# <chr> <dbl> <dbl> <dbl> <dbl>
# 1 miya 3 1 2 1
# 2 zhask 2 0 1 NA
# 3 balmond 3 3 0 2
# 4 layla 2 0 1 NA
# 5 angela 2 0 3 NA