问题描述
如果您有完整的数据框,则可以很容易地根据逻辑条件将值相乘:
df = data.frame(
var1 = c(1,2,3,4,5),var2 = c(1,1),var3 = c(5,5)
)
> df
var1 var2 var3
1 1 1 5
2 2 2 4
3 3 3 3
4 4 2 4
5 5 1 5
> df[df > 2] <- df[df > 2] * 10
> df
var1 var2 var3
1 1 1 50
2 2 2 40
3 30 30 30
4 40 2 40
5 50 1 50
但是,如果数据框中包含NA值,则操作将失败:
> df_na = data.frame(
var1 = c(NA,1,NA),NA,5)
)
> df_na
var1 var2 var3
1 NA 1 5
2 2 2 NA
3 3 3 3
4 4 1 4
5 5 NA 5
> df_na[df_na > 2] <- df_na[df_na > 2] * 10
Error in `[<-.data.frame`(`*tmP*`,df_na > 2,value = c(NA,30,40,50,:
'value' is the wrong length
例如,我尝试了一些na.omit()
策略,但无法使其起作用。在堆栈溢出中,我也找不到合适的问题。
那我该怎么办?
解决方法
您可以通过以下方式将!is.na()
作为附加逻辑参数添加到子集:
df_na[df_na > 2 & !is.na(df_na)] <- df_na[df_na > 2 & !is.na(df_na)] * 10
# > df_na
# var1 var2 var3
# 1 NA 1 50
# 2 2 2 NA
# 3 30 30 30
# 4 40 1 40
# 5 50 NA 50
或者,dplyr
/ tidyverse
解决方案是:
library(dplyr)
df_na %>%
mutate_all(.funs = ~ ifelse(!is.na(.x) & .x > 2,.x * 10,.x))
根据OP评论添加:
如果要基于%in%
运算符对值进行子集化,请选择dplyr
解决方案(%in%
运算符在这里的工作方式与{{ 3}}帖子):
df_na %>%
mutate_all(.funs = ~ ifelse(!is.na(.x) & .x %in% c(3,4),.x))
# var1 var2 var3
# 1 NA 1 5
# 2 2 2 NA
# 3 30 30 30
# 4 40 1 40
# 5 5 NA 5
通常,这种方法适合进行更复杂的操作任务。例如,您也可以在dplyr::case_when()
的帮助下定义其他条件,而不是一个替代的ifelse
。
使用基数R完成这项工作:
df_na[] <- lapply(df_na,function(x) ifelse(!is.na(x) & x > 2,x * 10,x))
df_na
var1 var2 var3
1 NA 1 50
2 2 2 NA
3 30 30 30
4 40 1 40
5 50 NA 50
,
问题不在于乘法,而是数组索引。
(df_na > 2
返回NA)。
如果愿意,您可以将下面的行转换为一行,
inds <- which(df_na > 2,arr.ind = TRUE)
df_na[inds] <- df_na[inds] * 10