我有简单的代码可以创建任意示例数据:
library(assertr)
library(tidyverse)
set.seed(1)
df <- tibble(id = 1:10, value = rnorm(10, 0, 1)) %>%
mutate(value = if_else(abs(value) < 0.5, NA_real_, value))
数据如下:
> df
# A tibble: 10 x 2
id value
<int> <dbl>
1 1 -0.626
2 2 NA
3 3 -0.836
4 4 1.60
5 5 NA
6 6 -0.820
7 7 NA
8 8 0.738
9 9 0.576
10 10 NA
现在,我正在尝试编写一个函数来检查给定列(在这种情况下,value
列)中是否有任何行具有NA值,如果存在则抛出错误。如果没有,它将返回未经修改的原始数据,以便管道可以继续。这很简单,没有功能:
df %>% verify(sum(is.na(value)) == 0)
# Outputs "Error: assertr stopped execution"
将其包装在函数中会带来困难。我尝试使用lazyeval
:
verify_not_missing <- function(.data, v) {
.data %>% verify(sum(is.na(lazyeval::lazy(v))) == 0)
}
df %>% verify_not_missing(value)
但这不会引发任何错误或停止执行。它默默地继续执行。同样,从dplyr programming vignette,我认为以下方法会起作用:
verify_not_missing <- function(.data, v) {
.data %>% verify(sum(is.na(!! quo(v))) == 0)
}
df %>% verify_not_missing(value)
但这会引发错误:
Error in is_quosure(e2) : argument "e2" is missing, with no default
我搜索了一些文档和SO,包括this question,但是一些答案提到了dplyr
弃用的部分,并没有太大帮助(例如,调用{{1} }显示该小插图已不存在。
我在这里想念什么?
我正在x64 Linux系统上使用R v3.5.1,dplyr v0.7.7和asserter v2.5
答案 0 :(得分:1)
有三种方法可以实现这一目标:
第一种方法
将eval()
与substitute()
一起使用,如下所示:
verify_not_missing <- function(.data, v) {
v <- eval(substitute(v), .data)
.data %>%
verify(sum(is.na(v)) == 0)
}
第二种方法
将rlang::eval_tidy()
与enquo()
一起使用,如下所示:
verify_not_missing <- function(.data, v) {
v <- rlang::eval_tidy(enquo(v), .data)
.data %>%
verify(sum(is.na(v)) == 0)
}
第三种方法
在!!enquo()
内使用select()
(您需要colnames(.data)
才能获得其他列)
verify_not_missing <- function(.data, v) {
.data %>%
select(colnames(.data), v = !!enquo(v)) %>%
verify(sum(is.na(v)) == 0)
}
df %>% verify_not_missing(value)
所有这些都产生相同的结果,使用您的数据,结果如下所示:
#verification [sum(is.na(v)) == 0] failed! (1 failure)
# verb redux_fn predicate column index value
#1 verify NA sum(is.na(v)) == 0 NA 1 NA
#Error: assertr stopped execution
希望有帮助。
答案 1 :(得分:0)
如果您不必使用assertr
软件包,我认为可以考虑使用此解决方案。
library(tidyverse)
verify_not_missing <- function(.data) {
col_na <- colSums(is.na(.data)) > 0 # larger than zero, than na value in that column
if (any(col_na)) stop(gettextf("column %s is missing",
str_c(names(col_na)[col_na], collapse = ", ")))
}
通过使用colSums(is.na(.))
,您可以检测具有NA
值的列。如果有这样的列,则使用其列名打印错误消息可能很容易。
此外,对于多列情况,我折叠了names()
。
应用于您的数据集,我们可以获得结果:
df %>%
verify_not_missing()
#> Error in verify_not_missing(.): column value is missing
类似地,对于具有NA
值的其他列,
(mydf2 <- tibble(id = 1:10, value = rnorm(10, 0, 1)) %>%
mutate(value1 = if_else(abs(value) < 0.5, NA_real_, value),
value2 = if_else(abs(value) < 0.5, NA_real_, value)))
#> # A tibble: 10 x 4
#> id value value1 value2
#> <int> <dbl> <dbl> <dbl>
#> 1 1 1.51 1.51 1.51
#> 2 2 0.390 NA NA
#> 3 3 -0.621 -0.621 -0.621
#> 4 4 -2.21 -2.21 -2.21
#> 5 5 1.12 1.12 1.12
#> 6 6 -0.0449 NA NA
#> 7 7 -0.0162 NA NA
#> 8 8 0.944 0.944 0.944
#> 9 9 0.821 0.821 0.821
#> 10 10 0.594 0.594 0.594
mydf2 %>%
verify_not_missing()
#> Error in verify_not_missing(.): column value1, value2 is missing
它会打印value1, value2
,其中包括NA
。
您可以先enquo(v)
,然后再使用%>% select(!!v)
。然后,它返回v
的列。其余部分相同。
verify_not_missing2 <- function(.data, v) {
v <- enquo(v)
col_na <-
.data %>%
select(!!v) %>% # this returns v columns
is.na() %>%
colSums()
col_na <- col_na > 0
if (any(col_na)) stop(gettextf("column %s is missing",
str_c(names(col_na)[col_na], collapse = ", ")))
}
将此应用于示例
df %>%
verify_not_missing2(value)
#> Error in verify_not_missing2(., value): column value is missing
将value
指定为参数,可能会出错。另外,对于多个NA
列,
mydf2 %>%
verify_not_missing2(value)
#---------------------------
mydf2 %>%
verify_not_missing2(value1)
#> Error in verify_not_missing2(., value1): column value1 is missing
当您输入既不是value1
也不是value2
的列时,则不会打印任何内容。另一方面,指定value1
会出错。
此外,您可以使用c()
指定多个列。
mydf2 %>%
verify_not_missing2(v = c("value1", "value2"))
#> Error in verify_not_missing2(., v = c("value1", "value2")): column value1, value2 is missing
#----------------------------
mydf2 %>%
verify_not_missing2(v = c(value1, value2))
#> Error in verify_not_missing2(., v = c(value1, value2)): column value1, value2 is missing
verify_not_missing3 <- function(.data, v) {
v <- enquo(v)
col_na <-
.data %>%
select(!!v) %>%
is.na() %>%
colSums()
col_na <- col_na > 0
if (any(col_na)) {
stop(gettextf("column %s is missing",
str_c(names(col_na)[col_na], collapse = ", ")))
} else {
.data
}
}
在没有错误的情况下,其他else { .data }
语句可以返回。
如果您提供value
,
mydf2 %>%
verify_not_missing3(value)
#> # A tibble: 10 x 4
#> id value value1 value2
#> <int> <dbl> <dbl> <dbl>
#> 1 1 1.51 1.51 1.51
#> 2 2 0.390 NA NA
#> 3 3 -0.621 -0.621 -0.621
#> 4 4 -2.21 -2.21 -2.21
#> 5 5 1.12 1.12 1.12
#> 6 6 -0.0449 NA NA
#> 7 7 -0.0162 NA NA
#> 8 8 0.944 0.944 0.944
#> 9 9 0.821 0.821 0.821
#> 10 10 0.594 0.594 0.594
另一方面,
mydf2 %>%
verify_not_missing3(value1)
#> Error in verify_not_missing3(., value1): column value1 is missing
答案 2 :(得分:0)
这是在基数R中如何执行类似的操作:
verify_not_missing <- function(.data, v) {
!any(
is.na(
.data[[deparse(substitute(v))]]
)
)
}
verify_not_missing(df, value)
[1] FALSE