。 R编码风格:如何定义一个新的转换变量?

时间:2017-06-25 18:03:00

标签: r

我们假设我们有一个包含两个变量的数据库,ab ...

RawData <- data.frame( a = rnorm( 10 ), b = rnorm( 10 ) )

...我们想要定义一个新变量c,它是ab的总和。

我可以想到四种方法(至少在基础R中,没有任何库):

  1. RawData$c1 <- RawData$a + RawData$b或(参见@alistaire的评论和@ 42-的答案)RawData[[ "c1" ]] <- RawData[[ "a" ]] + RawData[[ "b" ]]
  2. RawData <- transform( RawData, c2 = a + b )
  3. RawData <- within( RawData, { c3 = a + b } )
  4. RawData$c4 <- with( RawData, a + b )
  5. 当然identical( RawData$c1, RawData$c2, RawData$c3, RawData$c4 )TRUE,所以问题是是否有任何客观理由偏爱其他人,或者纯粹是品味问题......?

    解决方案#1有点多余,因为RawData写了三次,但它仍然是最容易用自动完成键入的(例如在RStudio中),特别是如果变量名很长。

2 个答案:

答案 0 :(得分:1)

我同意@alistaire在与控制台交互时几乎没有什么区别,但是在将这些代码放入程序中时存在差异,在这种情况下,他建议使用“[[”应该理解和我认为首选超过所引用的4种方法中的任何一种。原因是:您可以使用“[[”替换要评估的名称,并且使用“$”或其他方法不能成功。示例代码:

 my_name1 <- "a"
 my_name2 <- "b"

> RawData$c1 <- RawData$my_name1 + RawData$my_name2   # Fails
Error in `$<-.data.frame`(`*tmp*`, c1, value = integer(0)) : 
  replacement has 0 rows, data has 10                 # Success
> RawData$c1 <- RawData[[my_name1]] + RawData[[my_name2]]

您也可以使用“[[”使新列的名称成为运行时规范,与使用“$”不同:

> my_new_name <-  "xyz"
>     RawData[[my_new_name]] <- RawData[[my_name1]] + RawData[[my_name2]]

> names(RawData)
[1] "a"   "b"   "c1"  "xyz"

其他三个也有同样的缺陷:

> RawData$c1 <- with( RawData,  my_name1 + my_name2)
Error in my_name1 + my_name2 : non-numeric argument to binary operator

需要采取的教训是“$”只是“[[”的残缺版本。另一课(我没有演示)是withwithintransform中的所有三个都只是“认证安全”才能在控制台上使用,不应该使用在编程中,要么。这是一个更微妙的教训,因为可能会或可能不会导致的错误不会立即显现出来。其他三个都受到非标准评估问题的困扰,这些问题在未引用的符号开始传递时开始出现,特别是当它们没有以程序员使用单个字母标记时可能出现的独特方式命名时。请参阅此高度赞赏的SO答案,其中涉及另一个使用非标准评估的常用函数:Why is [ better than subset?

答案 1 :(得分:1)

从务实的角度来看,这并不重要,他们都以与你使用它们相同的方式完成工作。 (虽然如果在函数或循环中使用这些方法可能会失败,但是在脚本中它们看起来是相同的)

从计算的角度来看,它们的效率略高或低,当数据变大时,它们变得有意义。

你可以测试一下。

因为10行在计算上无关紧要,所以我将data.frame扩展了一下,如下所示:

df<- cbind(a=rnorm(1000000), b= rnorm(1000000))
RawData<-data.frame(df)

使用system.time运行每个,您将获得以下内容:

 system.time(RawData$c1 <- RawData$a + RawData$b , gcFirst = TRUE)
   user  system elapsed 
  0.008   0.001   0.009 
 system.time(RawData <- transform( RawData, c2 = a + b ),gcFirst = TRUE)
   user  system elapsed 
  0.008   0.001   0.009 
 system.time(RawData <- within( RawData, { c3 = a + b } ),gcFirst = TRUE)
   user  system elapsed 
  0.010   0.005   0.014 
 system.time(RawData$c4 <- with( RawData, a + b ), gcFirst = TRUE)
   user  system elapsed 
  0.006   0.004   0.010 

然后我又添加了两个零。

df<- cbind(a=rnorm(100000000), b= rnorm(100000000))
RawData<-data.frame(df)

然后重新计算:并且等待很长时间...非常非常长的时间..我发送这一系列任务在一台非常快的机器上工作,然后今天早上在这里发布任何答案。查看已用时间,系统时间和用户时间。

显然,当数据变大时,不同的方法会产生计算结果,我们正在研究简单的任务。

#The fastest method
system.time(RawData$c1 <- RawData$a + RawData$b , gcFirst = TRUE)
    user   system  elapsed 
   5.542  244.188 3271.741 
# The slowest method
system.time(RawData <- within( RawData, { c3 = a + b } ),gcFirst = TRUE)
    user   system  elapsed 
   9.031  207.036 3794.536 

这些时间是关闭所有其他应用程序,清晰的环境和事件之间的垃圾收集!

显然有多重要。问题变成你在什么时候担心这种效率?对于每次简单的加法,添加两个零将计算从小数秒到经过时间的54和63分钟。想象一下,如果数学更复杂吗?

我怀疑你是否可以使用[]获得42的建议,甚至可以提高性能......