Eloquent根据一行值改变多行值的R解决方案
Eloquent R solution to change multiple row values based on one row value
我正在清理一个 200 行的调查数据集。该调查使用了相当多的分支,并且在参与者没有收到问题的情况下返回 NA,因此它放弃了我的缺失数据分析。我花了一天半的时间试图找出一个 eloquent 解决方案(for loops, if conditions, filter(dplyr), mutate(dplyr), case_when)。我选择了使用 mutate()
的解决方案,但我知道有更好的方法来做到这一点。
这里有一个可重现的数据框作为调查数据
df <- data.frame(attsess1 = c(1, 1, 1, -99, -99), attsess2 = c(-99, -99, 1, 1, 1), s1satis = c(1, 1, 1, NA, NA), s1time = c(1, 1, 1, NA, NA), s1qual = c(1, 1, NA, NA, NA), s2satis = c(NA, NA, NA, 1, 1), s2time = c(NA, NA, 1, 1, 1))
本质上,如果 attsess1 等于 -99,那么我希望 s1satis、s1time、s1qual 中的以下相应行将它们的 NA 更改为 -99。同样的逻辑适用于 attsess2 和 s2satis 和 s2time。
下面的代码是我用的。它可以工作,但需要太多行,这对于具有大量变量的大型数据集来说可能会有问题
library(dplyr)
df1 <- df %>% mutate(s1satis = case_when(attsess1 == -99 ~ -99)) %>% mutate(s1time = case_when(attsess1 == -99 ~ -99)) %>% mutate(s1qual = case_when(attsess1 == -99 ~ -99)) %>% mutate(s2satis = case_when(attsess2 == -99 ~ -99)) %>% mutate(s2time = case_when(attsess2 == -99 ~ -99))
我尝试使用 mutate_at
和 case_when
,但收到此错误消息:
must be a double vector, not an integer vector.
我也尝试过使用 if 条件嵌套的 for 循环,但我不记得收到的错误消息。我还遇到了几个论坛,在这些论坛上,作者提倡用 dplyr 函数替换 for 循环。
确保您的 dplyr
版本已更新并且这个想法应该可行:
df %>%
mutate(
across(starts_with("s1"), ~ case_when(attsess1 == -99 ~ -99, TRUE ~ .)),
across(starts_with("s2"), ~ case_when(attsess2 == -99 ~ -99, TRUE ~ .))
)
# attsess1 attsess2 s1satis s1time s1qual s2satis s2time
# 1 1 -99 1 1 1 -99 -99
# 2 1 -99 1 1 1 -99 -99
# 3 1 1 1 1 NA NA 1
# 4 -99 1 -99 -99 -99 1 1
# 5 -99 1 -99 -99 -99 1 1
虽然我不太确定你想要的结果,但请参阅我对你的问题的评论。
如果你想获取整个数据集并将所有 NA
替换为 -99,你可以使用:
df %>%
mutate_all(~replace(., is.na(.), -99))
我正在清理一个 200 行的调查数据集。该调查使用了相当多的分支,并且在参与者没有收到问题的情况下返回 NA,因此它放弃了我的缺失数据分析。我花了一天半的时间试图找出一个 eloquent 解决方案(for loops, if conditions, filter(dplyr), mutate(dplyr), case_when)。我选择了使用 mutate()
的解决方案,但我知道有更好的方法来做到这一点。
这里有一个可重现的数据框作为调查数据
df <- data.frame(attsess1 = c(1, 1, 1, -99, -99), attsess2 = c(-99, -99, 1, 1, 1), s1satis = c(1, 1, 1, NA, NA), s1time = c(1, 1, 1, NA, NA), s1qual = c(1, 1, NA, NA, NA), s2satis = c(NA, NA, NA, 1, 1), s2time = c(NA, NA, 1, 1, 1))
本质上,如果 attsess1 等于 -99,那么我希望 s1satis、s1time、s1qual 中的以下相应行将它们的 NA 更改为 -99。同样的逻辑适用于 attsess2 和 s2satis 和 s2time。
下面的代码是我用的。它可以工作,但需要太多行,这对于具有大量变量的大型数据集来说可能会有问题
library(dplyr)
df1 <- df %>% mutate(s1satis = case_when(attsess1 == -99 ~ -99)) %>% mutate(s1time = case_when(attsess1 == -99 ~ -99)) %>% mutate(s1qual = case_when(attsess1 == -99 ~ -99)) %>% mutate(s2satis = case_when(attsess2 == -99 ~ -99)) %>% mutate(s2time = case_when(attsess2 == -99 ~ -99))
我尝试使用 mutate_at
和 case_when
,但收到此错误消息:
must be a double vector, not an integer vector.
我也尝试过使用 if 条件嵌套的 for 循环,但我不记得收到的错误消息。我还遇到了几个论坛,在这些论坛上,作者提倡用 dplyr 函数替换 for 循环。
确保您的 dplyr
版本已更新并且这个想法应该可行:
df %>%
mutate(
across(starts_with("s1"), ~ case_when(attsess1 == -99 ~ -99, TRUE ~ .)),
across(starts_with("s2"), ~ case_when(attsess2 == -99 ~ -99, TRUE ~ .))
)
# attsess1 attsess2 s1satis s1time s1qual s2satis s2time
# 1 1 -99 1 1 1 -99 -99
# 2 1 -99 1 1 1 -99 -99
# 3 1 1 1 1 NA NA 1
# 4 -99 1 -99 -99 -99 1 1
# 5 -99 1 -99 -99 -99 1 1
虽然我不太确定你想要的结果,但请参阅我对你的问题的评论。
如果你想获取整个数据集并将所有 NA
替换为 -99,你可以使用:
df %>%
mutate_all(~replace(., is.na(.), -99))