使用plyr按类别计算最常见的级别

4
我希望使用plyr计算每个类别中最频繁的因子水平,使用下面的代码。数据框b显示了请求的结果。为什么c$mlevels只有"numeric"这个值?
require(plyr)
set.seed(0)
a <- data.frame(cat=round(runif(100, 1, 3)),
                levels=factor(round(runif(100, 1, 10))))
mode <- function(x) names(table(x))[which.max(table(x))]
b <- data.frame(cat=1:3,
                mlevels=c(mode(a$levels[a$cat==1]),
                       mode(a$levels[a$cat==2]),
                       mode(a$levels[a$cat==3])))
c <- ddply(a, .(cat), summarise,
           mlevels=mode(levels))
2个回答

5
当你使用summarise函数时,plyr似乎在检查base函数之前没有看到在全局环境中声明的函数。
我们可以使用Hadley方便的pryr包来检查这个问题。您可以通过以下命令安装它:
library(devtools)
install_github("pryr")


require(pryr)
require(plyr)
c <- ddply(a, .(cat), summarise, print(where("mode")))
# <environment: namespace:base>
# <environment: namespace:base>
# <environment: namespace:base>

基本上,它没有读取/知道/看到你的mode函数。有两个选择。第一个是@AnandaMahto建议的方法,我会这样做并建议你坚持使用它。另一个选择是不使用summarise并使用function(.)调用它,这样全局环境中的mode函数就会被“看到”。
c <- ddply(a, .(cat), function(x) mode(x$levels))
#   cat V1
# 1   1  6
# 2   2  5
# 3   3  9

为什么这个可以正常工作?
c <- ddply(a, .(cat), function(x) print(where("mode")))
# <environment: R_GlobalEnv>
# <environment: R_GlobalEnv>
# <environment: R_GlobalEnv>

因为正如你在上面看到的那样,它读取了你的函数,该函数位于“全局环境”中。
> mode # your function
# function(x)
#     names(table(x))[which.max(table(x))]
> environment(mode) # where it sits
# <environment: R_GlobalEnv>

与之相反:

> base::mode # base's mode function
# function (x) 
# {
#     some lines of code to compute mode
# }
# <bytecode: 0x7fa2f2bff878>
# <environment: namespace:base>

这里有一篇非常棒的维基文章,如果您对环境(environments)感兴趣并想进一步阅读/探索,请参考Hadley的文章。


1
+1,这个答案比我的好多了。我太懒了,没有去探索plyr在哪里寻找“mode”,所以我只是重命名并简化了它。 - A5C1D2H2I1M1N2O1R2T1
谢谢你的回答,现在它正常工作了。我试着总结一下:模式(Mode)已经存在于全局环境中,因此plyr正在使用这个而不是我提供的模式函数。 - naund
@user2126360,mode 存在于 base 中。 - A5C1D2H2I1M1N2O1R2T1
不行。你的函数存在于全局环境中。但是summarise看到的是默认在base中的不同mode。这就是为什么@AnandaMahto在他的编辑中解释说,使用已经在R中使用过的所有默认名称不明智,因为你的代码更容易出现错误。 - Arun
1
请参考here函数:ddply(a, .(cat), here(summarise), mlevels=mode(levels))。文档中的解释应该会有所帮助。 - hadley

2
你的示例中几乎只使用了现有的函数名称:levelscatmode。通常情况下,这不会造成太大问题——例如,将一个数据框命名为“df”并不会破坏 R 的 df() 函数。但这几乎总会导致更加模糊或令人困惑的代码,在 这个 示例中,它导致了问题的发生。Arun 的答案很好地解释了原因。
你可以通过重新命名你的“mode”函数来轻松解决问题。在下面的示例中,我除了重命名之外还对其进行了一些简化,它可以按照你的期望工作。
Mode <- function(x) names(which.max(table(x)))
ddply(a, .(cat), summarise,
      mlevels=Mode(levels))
#   cat mlevels
# 1   1       6
# 2   2       5
# 3   3       9

当然,有一个非常繁琐的解决办法:使用get并指定要搜索函数的位置。
> mode <- function(x) names(table(x))[which.max(table(x))]
> ddply(a, .(cat), summarise, mlevels = get("mode", ".GlobalEnv")(levels))
  cat mlevels
1   1       6
2   2       5
3   3       9

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接