处理 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,而不是使用单独的数据帧 df1df2 等:

dflist <- list(df1, df2, <...>)
dflist <- lapply(dflist, na.omit)

【讨论】:

这样做的缺点是:当操作在最后一个数据帧上失败时,您会丢失所有结果(或者是否有人知道检索未失败结果的方法)?它也可能遭受资源(内存!)问题的困扰(尽管如果没有@Hong Ooi 的建议也很难避免这些问题)。根据我的经验,使用 R 之外的编辑器会有所帮助(例如 Tinn-R 或更新的 RStudio)。 @Nick:您可以使用tryCatch 来缓解操作失败的情况。如果您想要更完整的答案,请将此问题作为单独的问题。 有人不使用IDE吗?!我无法想象没有它的生活。 @Richie:不用了,谢谢。我知道 tryCatch (尽管我应该查一下它是否像大多数语言一样涉及性能损失)。是的:它会减轻我的担忧。尽管如此,这种工作方式使我无法在所有结果完成之前查看部分结果。请注意,我非常重视@Hong 的建议,但我自己也经常坐在“该死的,我开始了很多事情,我想知道到目前为止它是如何做的”椅子上 :-)。【参考方案2】:

除了@Hong Ooi 的回答,我建议查看plyrreshape 包。在您的情况下,以下可能有用:

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 中的重复性任务的主要内容,如果未能解决你的问题,请参考以下文章

不处理 CSV 中的第一行 [重复]

仅删除R中的空括号[重复]

R:从R中的大型数据集中根据列中的值删除行[重复]

foreach循环中的启动任务使用最后一项的值[重复]

在 Java Web 应用程序中处理重复性后台任务的策略?

【R去重】 保留第一个重复/去所有的重复