处理 R 中的重复性任务
Posted
技术标签:
【中文标题】处理 R 中的重复性任务【英文标题】:Dealing with repetitive tasks in R 【发布时间】:2011-08-23 18:40:41 【问题描述】:我经常发现自己不得不在 R 中执行重复性任务。不得不一遍又一遍地在一个或多个数据结构上不断地运行相同的函数会让人非常沮丧。
例如,假设我在 R 中有三个单独的数据帧,我想删除每个数据帧中具有缺失值的行。对于三个数据帧,在每个 df 上运行 na.omit() 并不是那么困难,但它会变得非常低效 当一个人有一百个相似的数据结构需要相同的操作时。
df1 <- data.frame(Region=c("Asia","Africa","Europe","N.America","S.America",NA),
variable=c(2004,2004,2004,2004,2004,2004), value=c(35,20,20,50,30,NA))
df2 <- data.frame(Region=c("Asia","Africa","Europe","N.America","S.America",NA),
variable=c(2005,2005,2005,2005,2005,2005), value=c(55,350,40,90,99,NA))
df3 <- data.frame(Region=c("Asia","Africa","Europe","N.America","S.America",NA),
variable=c(2006,2006,2006,2006,2006,2006), value=c(300,200,200,500,300,NA))
tot04 <- na.omit(df1)
tot05 <- na.omit(df2)
tot06 <- na.omit(df3)
在 R 中处理重复性任务有哪些一般准则?
是的,我知道这个问题的答案是特定于一个人所面临的任务,但我只是询问用户在执行重复性任务时应该考虑的一般事项。
【问题讨论】:
【参考方案1】:作为一般准则,如果您有多个对象要对其应用相同的操作,则应将它们收集到一个数据结构中。然后您可以使用循环、[sl]apply 等一次性完成操作。在这种情况下,您可以将它们放入数据帧列表中,然后在所有数据帧上运行 na.omit
,而不是使用单独的数据帧 df1
、df2
等:
dflist <- list(df1, df2, <...>)
dflist <- lapply(dflist, na.omit)
【讨论】:
这样做的缺点是:当操作在最后一个数据帧上失败时,您会丢失所有结果(或者是否有人知道检索未失败结果的方法)?它也可能遭受资源(内存!)问题的困扰(尽管如果没有@Hong Ooi 的建议也很难避免这些问题)。根据我的经验,使用 R 之外的编辑器会有所帮助(例如 Tinn-R 或更新的 RStudio)。 @Nick:您可以使用tryCatch
来缓解操作失败的情况。如果您想要更完整的答案,请将此问题作为单独的问题。
有人不使用IDE吗?!我无法想象没有它的生活。
@Richie:不用了,谢谢。我知道 tryCatch (尽管我应该查一下它是否像大多数语言一样涉及性能损失)。是的:它会减轻我的担忧。尽管如此,这种工作方式使我无法在所有结果完成之前查看部分结果。请注意,我非常重视@Hong 的建议,但我自己也经常坐在“该死的,我开始了很多事情,我想知道到目前为止它是如何做的”椅子上 :-)。【参考方案2】:
除了@Hong Ooi 的回答,我建议查看plyr 和reshape 包。在您的情况下,以下可能有用:
df1$name <- "var1"
df2$name <- "var2"
df3$name <- "var3"
df <- rbind(df1,df2,df3)
df <- na.omit(df)
##Get various means:
> ddply(df,~name,summarise,AvgName=mean(value))
name AvgName
1 var1 31.0
2 var2 126.8
3 var3 300.0
> ddply(df,~Region,summarise,AvgRegion=mean(value))
Region AvgRegion
1 Africa 190.00000
2 Asia 130.00000
3 Europe 86.66667
4 N.America 213.33333
5 S.America 143.00000
> ddply(df,~variable,summarise,AvgVar=mean(value))
variable AvgVar
1 2004 31.0
2 2005 126.8
3 2006 300.0
##Transform the data.frame into another format
> cast(Region+variable~name,data=df)
Region variable var1 var2 var3
1 Africa 2004 20 NA NA
2 Africa 2005 NA 350 NA
3 Africa 2006 NA NA 200
4 Asia 2004 35 NA NA
5 Asia 2005 NA 55 NA
6 Asia 2006 NA NA 300
7 Europe 2004 20 NA NA
8 Europe 2005 NA 40 NA
9 Europe 2006 NA NA 200
10 N.America 2004 50 NA NA
11 N.America 2005 NA 90 NA
12 N.America 2006 NA NA 500
13 S.America 2004 30 NA NA
14 S.America 2005 NA 99 NA
15 S.America 2006 NA NA 300
【讨论】:
【参考方案3】:如果名称相似,您可以使用 pattern
参数对它们进行迭代:ls
:
for (i in ls(pattern="df"))
assign(paste("t",i,sep=""),na.omit(get(i)))
然而,一种更“R”的做法似乎是使用单独的环境和eapply
:
# setup environment
env <- new.env()
# copy dataframes across (using common pattern)
for (i in ls(pattern="df"))
asssign(i,get(i),envir=env)
# apply function on environment
eapply(env,na.omit)
产量:
$df3
Region variable value
1 Asia 2006 300
2 Africa 2006 200
3 Europe 2006 200
4 N.America 2006 500
5 S.America 2006 300
$df2
Region variable value
1 Asia 2005 55
2 Africa 2005 350
3 Europe 2005 40
4 N.America 2005 90
5 S.America 2005 99
$df1
Region variable value
1 Asia 2004 35
2 Africa 2004 20
3 Europe 2004 20
4 N.America 2004 50
5 S.America 2004 30
不幸的是,这是一个庞大的列表,因此将其作为单独的对象列出有点棘手。大概是这样的:
lapply(eapply(env,na.omit),function(x) assign(paste("t",substitute(x),sep=""),x,envir=.GlobalEnv))
应该可以,但是substitute
没有正确选择列表元素名称。
【讨论】:
以上是关于处理 R 中的重复性任务的主要内容,如果未能解决你的问题,请参考以下文章