我正在尝试编写一个“变量化”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”)中的错误:参数
的'type'(字符)无效
我知道我没有得到一些非常基本的东西,但我不知道是什么。
我正在使用这个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”,另一个月为零。
由于
韦恩
答案 0 :(得分:3)
致电时
need.fr.month(adk47, oct)
R在您的常规环境中查找名为oct
的变量,但什么都没找到。因此它报告说找不到它。
如果你打电话:
need.fr.month(adk47, "oct")
R尝试使用字符串"oct"
代替monthCol
。但是,取一个字符串的sum
没有意义,所以它会抛出一个错误。
将参数传递给内部函数可能很困难。臭名昭着的eval-parse结构是一个快速的kludge。虽然它完成了工作,但它是generally not recommended,因为通常有更简单的方法来完成同样的工作。
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
为您提供所需数据的子集。
答案 1 :(得分: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"))
答案 2 :(得分: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的评论:“将参数传递给内部函数可能很困难”。我现在会接受,如果你避免调用内部函数(例如“汇总”)并在下次遇到像这样的问题时再考虑一下这个问题就会消失!!
答案 3 :(得分:2)
我认为创建一个您的指标变量为指标变量(如describeie Optimization: splitting dataframe into a list of dataframes, transforming data per row)然后从中进行子集的列会容易得多。
我主张使用data.table
而不是ddply + summarize
来提高效率(但这可能是一个长期目标)
使用data.table
访问set
(适用于data.frames)
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