提问人:jaggedjava 提问时间:11/3/2023 最后编辑:jaggedjava 更新时间:11/4/2023 访问量:49
为什么 if 循环不能在 R 中的函数中正确捕获 NA 值?
Why does an if loop not catch an NA value correctly inside a function in R?
问:
我有一个相当复杂的函数,可以修改一些字符变量。在对函数进行编码时,我在处理 NA 值时遇到了一个奇怪的问题。我将为您省去复杂的函数,而是在下面的 MWE 中提出问题:
# Create an example data frame
df <- data.frame(noun = c("apple", NA, "banana"))
# Display the example data frame
df
#> noun
#> 1 apple
#> 2 <NA>
#> 3 banana
# Introduce the function
process_my_df <- function(input_data, my_var) {
# Create a new variable based on an existing variable
for (i in 1:nrow(input_data)) {
if (!is.na(input_data[[my_var]][i])) {
input_data[[paste0(my_var, "_result")]][i] <- "is a fruit"
}
}
return(input_data)
}
# Call the function to process the data frame
processed_df <- process_my_df(df, "noun")
# Display the resulting df
processed_df
#> noun noun_result
#> 1 apple is a fruit
#> 2 <NA> is a fruit
#> 3 banana is a fruit
创建于 2023-11-03 with reprex v2.0.2
我的问题:根据条件,我期望以下结果:if (!is.na(input_data[[my_var]][i])) {}
#> noun noun_result
#> 1 apple is a fruit
#> 2 <NA> <NA>
#> 3 banana is a fruit
这是怎么回事?
编辑:
由于下面公认的答案,我在函数中添加了一行简单的行,现在一切正常:
# Introduce the function
process_my_df <- function(input_data, my_var) {
# Create a new variable based on an existing variable
# But first, "prime" it with NA_character_
input_data[[paste0(my_var, "_result")]] = NA_character_
for (i in 1:nrow(input_data)) {
if (!is.na(input_data[[my_var]][i])) {
input_data[[paste0(my_var, "_result")]][i] <- "is a fruit"
}
}
return(input_data)
}
创建于 2023-11-03 with reprex v2.0.2
答:
2赞
Andrey Shabalin
11/3/2023
#1
当您隐式创建新列时,会出现此问题。如果显式执行此操作,则它可以正常工作:
# Call the function to process the data frame
df$noun_result = ""
processed_df <- process_my_df(df, "noun")
# Display the resulting df
processed_df
# noun noun_result
# 1 apple is a fruit
# 2 <NA>
# 3 banana is a fruit
评论
0赞
Dean MacGregor
11/3/2023
如果默认值应为 NA 而不是空字符串,则执行此操作以启动。df$noun_result = as.character(NA)
0赞
Andrey Shabalin
11/3/2023
好吧,那么如果我们迂腐。NA_character_
1赞
Dean MacGregor
11/4/2023
TIL 这就是获得 NA 字符的方法。我一直在做上述事情,同时发现这是不对的,但从不费心去寻找正确的方法。
1赞
Marcus
11/3/2023
#2
鉴于 @Andrey Shabalin 提供的解释,您需要一个条件else
process_my_df <- function(input_data, my_var) {
# Create a new variable based on an existing variable
for (i in 1:nrow(input_data)) {
if (!is.na(input_data[[my_var]][i])) {
input_data[[paste0(my_var, "_result")]][i] <- "is a fruit"
} else {
input_data[[paste0(my_var, "_result")]][i] <- NA
}
}
return(input_data)
}
评论
0赞
Andrey Shabalin
11/3/2023
或者只是只遍历非 NA 线路for(i in which(!is.na(input_data[[my_var]])))
0赞
jaggedjava
11/4/2023
@Andrey 这不就是用“回收”初始值来重现原来的问题吗?
0赞
jaggedjava
11/4/2023
@Marcus 谢谢你的解决方案,我自己想出了一个几乎相同的解决方案,但想知道为什么我的初始代码不起作用,因此决定将这个问题发布给 SO。
评论
for
input_data[[paste0(my_var, "_result")]] <- ifelse(!is.na(input_data[my_var]), "is a fruit", NA)
df[["new_col"]][1] <- "hello"
ifelse