lapply & sapply on data.frame 测试每列中的所有元素以获得单个逻辑

lapply & sapply on data.frame to test all elements in each column to get a single logical

library(tidyverse)
df = data.frame(dates1 = c(20120631,NA,20130504,20161211),
                dates2 = c(201604,201503,NA,201201))
sapply(df,function(x) x %>% na.omit %>% as.character %>% nchar==8 %>% all)
lapply(df,function(x) x %>% na.omit %>% as.character %>% nchar==8 %>% all)
sapply(df,function(x) x %>% na.omit %>% as.character %>% nchar==8 %>% any)
lapply(df,function(x) x %>% na.omit %>% as.character %>% nchar==8 %>% any)

如果我对 sapplylapply 的工作方式有任何线索(而且我很确定这在昨天有效),这应该会返回一个 TRUEFALSE。不是。我正在找回真假矩阵。这不是 any()all() 应该做的。

应用结果:

     dates1 dates2
[1,]  FALSE  FALSE
[2,]  FALSE  FALSE
[3,]  FALSE  FALSE

lapply 结果:

$dates1
[1] FALSE FALSE FALSE

$dates2
[1] FALSE FALSE FALSE

WTH是怎么回事??

x %>% nchar == 8 %>% any等同于nchar(x) == any(8),所以不会等同于any(nchar(x) == 8)

我想这就是你想要的

sapply(df,function(x) x %>% na.omit %>% as.character %>% (function(x) nchar(x) == 8) %>% all)
# dates1 dates2 
#   TRUE  FALSE 
sapply(df,function(x) x %>% na.omit %>% as.character %>% (function(x) nchar(x) == 8) %>% any)
# dates1 dates2 
#   TRUE  FALSE

等价于:

sapply(df,function(x) x %>% na.omit %>% as.character %>% nchar %>% `==`(8) %>% all)
# dates1 dates2 
#   TRUE  FALSE 
sapply(df,function(x) x %>% na.omit %>% as.character %>% nchar %>% `==`(8) %>% any)
# dates1 dates2 
#   TRUE  FALSE

首先请注意,代码的问题在于操作顺序。 %>%== 之前执行,但我们希望 == 在最后一个 %>% 之前执行,因此使用括号强制执行此操作。这里显示的最里面的括号实际上是不需要的,因为默认的操作顺序已经适用于那些;但是,除了为清楚起见所需的内容之外,我们还添加了它们。请参阅 ?Syntax 以获得完整的 table 给出的操作顺序。

sapply(df,function(x) ((x %>% na.omit %>% as.character %>% nchar) == 8) %>% all)
## dates1 dates2 
##   TRUE  FALSE 

但是,使用以下事实可能会更好:

  • nchar 已经将其参数强制转换为字符,因此我们可以消除 as.character
  • . %>% whatever 可用于定义一个函数 wjere whatever 被替换为假设单个参数为点 (.)
  • 的函数体
  • {...} 可用于防止自动 .插入:

给予:

df %>% sapply(. %>% na.omit %>% { nchar(.) == 8 } %>% all)
## dates1 dates2 
##   TRUE  FALSE 

或者如果需要的是所有列的单一逻辑则:

p <- df %>% sapply(na.omit) %>% { nchar(.) == 8 } 

p %>% all
## [1] FALSE

p %>% any
## [1] TRUE

另一种摆脱循环的方法是使用 nchar

的向量化特性
 p <- colMeans(nchar(as.matrix(df)),na.rm = T)==8
 any(p)
[1] TRUE
 all(p)
[1] FALSE

或使用管道:

p<- df %>% as.matrix %>% nchar %>% colMeans(na.rm = T) %>% {. == 8}

p %>% any
[1] TRUE

 p %>% all
[1] FALSE