请原谅我问了一个简单的问题,也许我误解了花括号{}
在R中的具体工作方式,但是我看到了一些奇怪的行为-可能是由于我自己的误解-并且想要接触到社区,这样我就可以更好地理解我的编程。我也不确定为什么我看到is.na
调用返回一个不适当的结果。
我有几列数据,在一个或多个列中有许多na。在删除一列中包含na的行之后,我想检查数据以确保我知道还剩下多少行,并记录所有na都被删除了。我可以在3个单独的行中做到这一点,但我试图使用管道操作符来简化。
library(magrittr)
df <- data.frame(a=rnorm(10, 3, 5), #create a quick data frame without any na values
b=rnorm(10, -3, 5))
df %>% head() #works
df %>% count() #works
df %>% sum(is.na()) #doesn't work - error
#Error in is.na() : 0 arguments passed to 'is.na' which requires 1
df %>% sum(is.na(.)) #returns random number (perhaps sum of all values) instead of zero??
可能是一个单独的问题,但是为什么第一个不能工作,为什么第二个不能计算'is '。na的论点吗?如果我在第三个参数周围加上花括号,它将返回正确的值:
df %>% { #works, but why is this different?
sum(is.na(.))
}
#[1] 0
现在,当我试着计算所有3时,我不理解我看到的行为:
df %>% { #doesn't work - error
head()
count()
sum(is.na())
}
# Error in checkHT(n, dx <- dim(x)) :
# argument "x" is missing, with no default
df %>% { #returns appropriate na count of zero, but nothing else is evaluated
head(.)
count(.)
sum(is.na(.))
}
# [1] 0
df %>% { #returns first and third result, but not count(.)
print(head(.))
count(.)
sum(is.na(.))
}
# a b
# 1 0.3555877 -7.29064483
# 2 -2.6278037 4.30943634
# 3 5.6163705 -10.31436769
# 4 -2.8920773 -4.83949384
# 5 9.0941861 -0.09287319
# 6 2.6118720 -11.86665105
# [1] 0
df %>% { #returns all three like I want
print(head(.))
print(count(.))
sum(is.na(.))
}
# a b
# 1 0.3555877 -7.29064483
# 2 -2.6278037 4.30943634
# 3 5.6163705 -10.31436769
# 4 -2.8920773 -4.83949384
# 5 9.0941861 -0.09287319
# 6 2.6118720 -11.86665105
# n
# 1 10
# [1] 0
感谢您对如何解释此行为的任何建议,以便我下次可以改进我的代码。
这源于大括号在磁力和基数r中的行为。
首先,为什么df %>% sum(is.na(.))
返回一个出乎意料的大数字,而df %>% {sum(is.na(.))}
则像您期望的那样工作?默认情况下,%>%
将左侧传递给右侧函数的第一个参数。所以df %>% sum(is.na(.))
等于sum(df, is.na(df))
,这应该能让你明白为什么它会产生一个大的数。然而,根据magrittr文档,这种行为可以通过用大括号括住右侧来推翻。当rhs用大括号括起来时,lhs仅在显式添加.
占位符的地方插入。所以df %>% {sum(is.na(.))}
等于sum(is.na(df))
。
在其次,
df %>% {
print(head(.))
print(count(.))
sum(is.na(.))
}
为什么你必须在print()
中包装head(.)
和count(.)
,而不是sum()
?这是因为,根据R文档,用{
包装的表达式返回"最后一个表达式计算的结果"。因此,返回并自动打印sum(is.na(.))
的结果,但不返回前面表达式的结果,因此必须显式地为print()
ed。
最后,您可能会对nakedpipe包感兴趣,它为在包含函数块的管道中使用管道增加了更多的灵活性。
%>%
管道将左侧传递到右侧,因此可以这样考虑:
head(df)
# is the same as
df %>% head()
然而,如果你传递多个东西,你可能会遇到一个问题:
head(df)
count(df)
# is not the same as
df %>% head() %>% count()
在上面,R首先处理head
,然后计算head(df)
中的值,因此返回值为6。
这就是为什么你的管道没有返回你期望的结果。
此外,您的df %>% sum(is.na(.))
返回0,因为它将所有内容评估为FALSE
(因为没有NA
值),当您将布尔值FALSE == 0
和TRUE == 1
相加时
is.na(df)
# a b
# [1,] FALSE FALSE
# [2,] FALSE FALSE
# [3,] FALSE FALSE
# [4,] FALSE FALSE
# [5,] FALSE FALSE
# [6,] FALSE FALSE
# [7,] FALSE FALSE
# [8,] FALSE FALSE
# [9,] FALSE FALSE
# [10,] FALSE FALSE
# so
sum(is.na(df))
# [1] 0
如果你把你想要的东西包装在函数中,并将所有东西存储在一个列表中,你可能是最有效的:
example_function <- function(x){
list(head(x), count(x), sum(is.na(x)))
}
example_function(df)
# [[1]]
# a b
# 1 0.1976218 3.1204090
# 2 1.8491126 -1.2009309
# 3 10.7935416 -0.9961427
# 4 3.3525420 -2.4465864
# 5 3.6464387 -5.7792057
# 6 11.5753249 5.9345657
#
# [[2]]
# n
# 1 10
#
# [[3]]
# [1] 0