2

我正在尝试编写一个“变量化” ddply 调用的函数:

december <- ddply(adk47, .(PeakName, Elevation), summarize, 
  needThese=if(sum(dec) == 0) "needThis" 
  else character(0), .progress='text')

df 中每个月有 3 个字母的列名。我正在尝试将函数编写为:

need.fr.month <- function(df, monthCol) {
    needThese <- ddply(df, .(PeakName, Elevation), 
                       summarize, 
                       needThese=if(sum(monthCol) == 0)
                           "needThis" else character(0)
    )
    return(needThese)
}

但是当我用

need.fr.month(adk47, oct)

或与

need.fr.month(adk47, "oct")

我收到这些错误消息:

eval 中的错误(expr,envir,enclos):找不到对象“monthCol”

或者

sum("monthCol") 中的错误:参数的“类型”(字符)无效

我知道我没有得到一些非常基本的东西,但我不知道是什么。

我正在使用这个 DF 来练习编写 R 函数。我的其他功能进展顺利;但是,这是我尝试对 df 列进行可变化的第一个函数。

帮助将不胜感激。

这是数据子集的可重现示例

PeakName    Elevation   jul aug sep oct nov dec
Algonquin   5114    0   0   1   0   0   0
Algonquin   5114    0   0   0   0   0   0
Algonquin   5114    0   0   0   1   0   0
Algonquin   5114    1   0   0   0   0   0
Allen   4340    0   0   0   0   0   0
Allen   4340    0   0   0   0   0   0
Allen   4340    0   0   1   0   0   0
Allen   4340    1   0   0   0   0   0
Allen   4340    0   0   0   0   1   0
Armstrong   4400    0   0   0   0   0   0
Armstrong   4400    0   0   0   0   0   0
Armstrong   4400    0   0   0   0   0   0
Armstrong   4400    0   0   0   0   0   0
Armstrong   4400    0   0   0   0   1   0
Armstrong   4400    0   0   0   0   0   0
Armstrong   4400    0   0   0   1   0   0
Basin   4827    1   0   0   0   0   0
Basin   4827    0   0   0   0   0   0
Basin   4827    0   0   0   0   0   0
Basin   4827    0   0   0   0   0   0
Basin   4827    0   0   0   0   0   0
Basin   4827    0   0   0   0   0   0
Basin   4827    0   0   0   0   1   0
Big.Slide   4240    0   0   0   0   0   0
Big.Slide   4240    0   0   0   1   0   0
Big.Slide   4240    0   0   0   0   0   0
Big.Slide   4240    0   0   1   0   0   0
Big.Slide   4240    0   0   0   0   0   0
Big.Slide   4240    0   0   0   0   0   0
Big.Slide   4240    0   0   0   0   0   0
Big.Slide   4240    1   0   0   0   0   0

我希望这就足够了。显然,这是数据的一个子集。形式是,每次“远足”都有一行月份列(此处截断为 7 月至 12 月),表示一个月为“1”,其他 11 个月为 0。

谢谢

韦恩

4

4 回答 4

3

你打电话时

need.fr.month(adk47, oct)

octR 查找在您的一般环境中命名的变量,但什么也没找到。因此它报告它没有找到。

如果你打电话:

need.fr.month(adk47, "oct")

R 尝试使用字符串"oct"代替monthCol. 但是获取sum字符串的 没有意义,因此会引发错误。

将参数传递给内部函数可能很困难。臭名昭著的 eval-parse 构造是一个快速的组合。虽然它可以完成工作,但通常不建议这样做,因为通常有更简单的方法可以完成相同的工作。

need.fr.month <- function(df, monthCol) {
    needThese <- eval(parse(text=paste0("ddply(df, .(PeakName, Elevation), 
                       summarize, 
                       needThese=if(sum(", monthCol, ") == 0)
                           "needThis" else character(0)
                 ")))
    )
    return(needThese)
}

在这里,你不需要 eval-parse 来得到你想要的。只是不要使用summarize和依赖基本的 R 提取函数:

need.fr.month <- function(df, monthCol) {
    needThese <- ddply(df, .(PeakName, Elevation), 
                       function(x) sum(x[[monthCol]]))
    return(needThese)
    #return(needThese[needThese[["V1"]] != 0,])
}

我认为这种方法可以做得更好,但如果不知道你想用这些信息做什么,我就无法进一步改进它。如果您想找到要子集化的行,我认为最好执行以下操作:

need.fr.month <- function(df, monthCol) {
ave(df[[monthCol]],df[["PeakName"]],df[["Elevation"]],FUN=sum)
}
adk47$need <- need.fr.month(adk47,"dec") == 0

然后,这会在数据框中为您提供一列,让您可以通过adk47$need == TRUE.

于 2013-04-21T03:32:56.823 回答
2

谢谢大家,这两个都很有用。

我使用了 Blue Magister 的第二个示例的修改版本:

need.fr.month <- function(df, monthCol) {
needThese <- ddply(df, .(PeakName, Elevation),
                   function(x) sum(x[[monthCol]]))
subsetNeedThese <- subset(needThese, V1 == 0, select=c(PeakName, Elevation))

}

因为它准确地返回了我需要的东西,并且我理解它在做什么。我之前没有处理过附加和分离环境,所以我感谢 croy111 提供的示例。我需要阅读这个!同样,Blue Magister 的 eval-parse 对我来说似乎是一种简单的方法来做一些我真的不明白的事情。

我很欣赏 Blue Magister 的评论:“将参数传递给内部函数可能很困难”。我现在会接受,如果你避免调用内部函数(例如“summarize”)并在下次遇到这样的问题时再考虑一下,这个问题就会消失!

于 2013-04-21T18:58:57.037 回答
2

看起来,summarize无法从调用ddply. 但是,您可以手动将此环境附加到搜索路径。调用后ddply,您可以分离环境。

这是一个简单的示例 - 类似的方法也应该适用于您。

test_fun=function(team_vec)
{
    attach(environment())
    tmp=ddply(baseball,
              "team",
              summarise,
              duration=(if (unique(team)%in%team_vec) max(year)-min(year) else 0)
             )
    detach(environment())
    tmp
}

test_fun(c("PIT","PHI"))
于 2013-04-21T03:42:20.943 回答
2

我认为创建一个您的指标变量将是指标变量的列(如描述优化:将数据框拆分为数据框列表,每行转换数据)然后从中提取子集会容易得多。

我会提倡data.tableddply + summarize使用效率(但也许这是一个长期目标)

data.table用于访问(适用于data.frames set

library(data.table)
adk47$monthCol <- character(nrow(adk47))
# data.table specific
# adk47 <- data.table(adk47)
# adk47[, monthCol := character(nrow(adk47))]

# find which columns are == 1
whiches <- lapply(adk47[c("jul", "aug", "sep", "oct", "nov", "dec")],
                  function(x) which(x==1))
# data.table approach would require 
#  adk47[c("jul", "aug", "sep", "oct", "nov", "dec"),with = TRUE]

for(val in names(whiches)){ 
  set(adk47, i = whiches[[val]], j = 'monthCol', value = val)
  }

head(adk47)


       PeakName Elevation jul aug sep oct nov dec monthCol
1 Algonquin      5114   0   0   1   0   0   0      sep
2 Algonquin      5114   0   0   0   0   0   0         
3 Algonquin      5114   0   0   0   1   0   0      oct
4 Algonquin      5114   1   0   0   0   0   0      jul
5     Allen      4340   0   0   0   0   0   0         
6     Allen      4340   0   0   0   0   0   0         

然后,您可以使用子集monthCol

于 2013-04-22T00:50:10.907 回答