【问题标题】:Using tapply or by with non-default settings of a function使用 tapply 或 by 与函数的非默认设置
【发布时间】:2014-03-27 11:46:52
【问题描述】:

我已经在 Stackoverflow 上搜索了几个小时,希望能找到一些我猜想是不言而喻的东西,但似乎没有人问过(这可能意味着它确实是不言而喻的)。

我想使用tapplyby 来查找特定事件在数据帧中第一次发生的时间(第一个非零值)。我之前这样做的方式是通过

max.col(df, ties.method = c("first"))

但不知何故,这在与 tapply 或 by 结合使用时不起作用。这是一些示例数据

FIRM<-as.vector(sample(c("a","b","c","d"),100,replace=T))
MOMENT<-as.vector(sample((1990:1995),100,replace=T))
EVENT<-as.vector(sample(c("x12","x43","x35","y71","y81","xy1","xy67","yy123","xx901"),100,replace=T))
OCCURENCE<-as.vector(sample(c(0,1),100,replace=T))
m<-as.data.frame(cbind(FIRM,MOMENT,EVENT,OCCURENCE))

所以这是我尝试过但没有奏效的方法

  1. tapply(m[,4],m[,3],max.col) # 这为每个 EVENT 提供了 1,结果向量的长度等于数据集中提到的 EVENT 的数量
  2. tapply(m[,4],m[,3],max.col(m, ties.method=c("first"))) # match.fun(FUN) 中的错误: 'max.col(m, ties.method = c("first"))' 不是函数、字符或符号 另外:警告消息:在 max.col(m, ties.method = c("first")) 中:强制引入的 NAs

2 号确实是问题的症结所在。由于我不清楚的原因,一旦您将默认的打破平局方法(即“随机”)更改为我需要的方法(即“第一”),max.col 就不会被识别为函数。

此外,我希望能够找到出现非零的年份。 我认为一个明智的选择是将 MOMENT 列与 OCCURENCE 列相乘(称为该 ID)并在 ID 中查找第一个非零值(对于每个因素 EVENT)保持该 ID 值并将其他值变为零

m$MOMENT<-as.numeric(as.character(m$MOMENT))
m$OCCURENCE<-as.numeric(as.character(m$OCCURENCE))    
m[,"ID"]<-m$MOMENT * m$OCCURENCE

我尝试使用包含whenif 语句并使用break 的函数对此进行编码,但它不起作用

tapply(m$ID,m$EVENT, function(x) m$ID[i]<- while (m$ID[i] == 0) {m$ID[i]
                  if (m$ID[i]>0) {m$YEAR[i] && break }})

这里的想法是在 m$ID == 0 时在 EVENT 上迭代函数,然后更改值并在 m$ID > 0 时中断。没用...

关于如何解决这个问题(或更简单的解决方案)的任何想法?

【问题讨论】:

    标签: r if-statement lapply tapply


    【解决方案1】:

    tapplyFUN 参数必须是函数,但问题中的代码提供的是表达式,而不是函数。试试这个:

    tapply(m[,4], m[,3], max.col, ties.method =  "first")
    

    这将给出每个事件中第一行的逻辑指示符,其中 OCCURENCE 列中有 1,第二行将选择这些行:

    o <- order(m$EVENT, m$MOMENT) # omit this and next line if already ordered
    m <- m[o,]
    
    is.first <- ave(m$OCCURENCE == 1, m$EVENT, FUN = function(x) x & !duplicated(x))
    m[is.first, ]
    

    修订

    • 按事件和年份排序。

    • 请注意,如果可能存在只有零的事件,那么这些事件将从m[is.first, ] 中完全省略。

    【讨论】:

    • 谢谢 G.G 一旦我根据年份对变量进行排序,这就像一个魅力。不确定 ave 函数究竟是如何工作的,但它确实有效:)!干杯
    【解决方案2】:

    我不太确定您想要实现什么,所以这里只是一些编码建议。

    首先,您需要阅读help("tapply") 以了解如何将参数传递给传递给tapply 的函数:

    tapply(m[,4],m[,3],max.col, ties.method="first")
    

    但是,我怀疑这是否满足您的需求。也许这样的东西会很有用:

    m<-data.frame(FIRM,MOMENT,EVENT,OCCURENCE)
    #note how I create the data.frame in a different way 
    #in order to avoid coercing all columns to factors
    
    
    tapply(m[,4],m[,3],which.max)
    #  x12   x35   x43 xx901   xy1  xy67   y71   y81 yy123 
    #    2     1     2     3     1     1     3     1     1 
    
    tapply(m[,4],m[,3],function(x) m[which.max(x), "MOMENT"])
    #  x12   x35   x43 xx901   xy1  xy67   y71   y81 yy123 
    # 1995  1995  1995  1991  1995  1995  1991  1995  1995 
    

    【讨论】:

    • 感谢@Roland,之前我没有想到 which.max 函数。我认为它给出了最大数量而不是第一个最大值,所以这也很有效。
    • 嘿@Roland,我一直在努力让您的解决方案发挥作用,但它似乎会出错。结果因数据的顺序而异(当然可以修复),在您的示例中,它给出 xx901 作为 1991 例如这是错误的,它应该是 1992,x43 给出 1995 但它应该是 1990。 .. 这可能与 which.max 如何寻找第一个最大值有关,即由因子 m[,3] 确定的子组内的起始位置......不确定。无论如何,您的同事通过 ave 功能提出的建议非常有效。感谢您的帮助!
    • 当然这取决于顺序。我了解到您要求的是 data.frame 中的第一个位置,而不是第一年。如果您想要第一年,则需要订购 data.frame 或使用其他方法。
    • 嗨@Roland,我也是这么想的。我的问题应该更清楚。然而,即使我订购了 df,结果仍然不正确......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-29
    • 1970-01-01
    • 2013-04-25
    • 1970-01-01
    • 2021-04-16
    相关资源
    最近更新 更多