【问题标题】:dplyr expression summing sum(!is.na(Field1) + !is.na(Field2)...) giving wrong numberdplyr 表达式求和 sum(!is.na(Field1) + !is.na(Field2)...) 给出错误的数字
【发布时间】:2014-04-11 00:46:13
【问题描述】:

我正在尝试通过每行中非 NA 的计数在 dplyr 中总结(/mutate)...不断给出错误的答案。

sum(FALSE + TRUE + FALSE + TRUE + TRUE) 这样的布尔值的算术确实加起来是3,那么问题出在哪里?为什么 dplyr 没有捕捉到错误?

N = 9
set.seed(1234)
df <- data.frame(id=c(1,1,1,2,2,2,3,3,3), date=c('2005','2006','2007'),
                 Field1 = ifelse(runif(N)>.5, runif(N, 5,30), NA),
                 Field2 = ifelse(runif(N)>.5, runif(N, 4,22), NA),
                 Field3 = ifelse(runif(N)>.5, runif(N, 7,18), NA),
                 Field4 = ifelse(runif(N)>.5, runif(N, 9,25), NA),
                 Field5 = ifelse(runif(N)>.5, runif(N, 3,30), NA) )

# > df
# id date   Field1    Field2    Field3    Field4    Field5
# 1  1 2005       NA        NA        NA        NA        NA
# 2  1 2006 22.33978        NA        NA 12.824412  6.850614
# 3  1 2007 18.62437        NA 12.334904        NA        NA
# 4  2 2005 12.06834        NA  9.683217 13.929516  8.296716
# 5  2 2006 28.08584        NA 15.420058        NA        NA
# 6  2 2007 12.30790        NA  7.811579  9.826346        NA
# 7  3 2005       NA        NA        NA 18.033117        NA
# 8  3 2006       NA  7.259732 14.889989        NA  7.320774
# 9  3 2007 11.67052 17.674071        NA        NA 27.197018


# Trying to summarize by the count of non-NAs in each row...!
df %.% regroup(list(quote(id),quote(date))) %.%
    summarize(nna_count = sum(!is.na(Field1) + !is.na(Field2) + !is.na(Field3) + !is.na(Field4) + !is.na(Field5)))

# TOTALLY WRONG?!

# Source: local data frame [9 x 3]
# Groups: id
# 
# id date nna_count
# 1  1 2005        0
# 2  1 2006        1
# 3  1 2007        1
# 4  2 2005        1
# 5  2 2006        1
# 6  2 2007        1
# 7  3 2005        0
# 8  3 2006        0
# 9  3 2007        0

通过使用格雷码进行调试,我看到除了 Field1 之外的所有 !is.na()s 都表现得很奇怪:

mutate(na_count = sum(16*!is.na(Field1) + 8*!is.na(Field2) + 4*!is.na(Field3) + 2*!is.na(Field4) + !is.na(Field5))) 

只给出 16 或 0

【问题讨论】:

  • 通过格雷码调试,我看到除了 Field1 之外的所有 !is.na()s 都表现得很奇怪:mutate(na_count = sum(16*!is.na(Field1) + 8*!is.na(Field2) + 4*!is.na(Field3) + 2*!is.na(Field4) + !is.na(Field5))) 只给出 16 或 0
  • 在 dplyr 0.1.2, 0.1.3 中都损坏了; R版本是3.0.3
  • 根据@thelatemail 的链接,这是一个具有运算符优先级的通用 R 陷阱。但我认为无论如何留下dplyr 的标签很有用,因为这似乎是用户可能会做的常见事情。

标签: r dplyr


【解决方案1】:

我暗自怀疑这与 !+ 运算符的优先级有关,而与 dplyr 本身几乎没有关系。请参阅此之前的帖子:Behavior of summing is.na results

因此,我可以通过添加一些额外的括号来使用 summarise 使其工作:

df %.% 
 group_by(id,date) %.%
 summarise(new=
   (!is.na(Field1)) + (!is.na(Field2)) + (!is.na(Field3)) + 
   (!is.na(Field4)) + (!is.na(Field5)) 
 )  %.%
 arrange(id,date)


#Source: local data frame [9 x 3]
#Groups: id
#
#  id date new
#1  1 2005   0
#2  1 2006   3
#3  1 2007   2
#4  2 2005   4
#5  2 2006   2
#6  2 2007   3
#7  3 2005   1
#8  3 2006   3
#9  3 2007   3

【讨论】:

  • @hadley 也是这么说的。所以我们有多种解决方法。但这是一个彻头彻尾的错误,值得记录 - 直到修复。
  • @smci - 我不认为这是 dplyr 特定问题 - 请参阅此处:Behavior of summing is.na results
  • ^ 哇。谢谢。那是 f#$%ed。
【解决方案2】:

由于某些奇怪的原因,当我们向 dplyr 传递一个包含多个子表达式的表达式时,它的行为很奇怪,每个子表达式都包含对 Field[1-5] 的引用。只有第一个引用似乎有效。

一种解决方法是将所有Field[1-5] 引用与c() 连接,然后执行is.na()sum() 向量。 但这似乎是一个 dplyr 错误。任何人都可以确认/否认/解释吗?

> df %.% regroup(list(quote(id),quote(date))) %.%
+   summarize(na_count = sum(!is.na(c(Field1,Field2,Field3,Field4,Field5))))
Source: local data frame [9 x 3]
Groups: id

  id date na_count
1  1 2005        0
2  1 2006        3
3  1 2007        2
4  2 2005        4
5  2 2006        2
6  2 2007        3
7  3 2005        1
8  3 2006        3
9  3 2007        3

【讨论】:

  • 您能提交一份错误报告吗?看起来我们对 + 的内部实现做错了。
  • @hadley - 看起来像 !+ 的运算符优先级 - 像 (!is.na(Field1)) 这样封装每个比较允许它使用 mutate 按预期工作。
  • Closed Won't-Fix as a generic R language wart.
猜你喜欢
  • 2023-03-19
  • 2015-04-02
  • 2018-10-21
  • 1970-01-01
  • 2013-07-13
  • 1970-01-01
  • 1970-01-01
  • 2017-11-16
  • 2017-03-17
相关资源
最近更新 更多