34

最近关于使用 require 与 :: 的问题提出了在 R 中编程时使用哪种编程风格以及它们的优点/缺点是什么的问题。浏览源代码或上网浏览,您会看到很多不同的样式显示。

我的代码中的主要趋势:

  • 重向量化我经常使用索引(和嵌套索引),这有时会导致代码相当模糊,但通常比其他解决方案快得多。例如:x[x < 5] <- 0而不是x <- ifelse(x < 5, x, 0)

  • 我倾向于嵌套函数以避免因需要清理的临时对象而使内存过载。特别是对于处理大型数据集的函数,这可能是一个真正的负担。例如:y <- cbind(x,as.numeric(factor(x)))而不是y <- as.numeric(factor(x)) ; z <- cbind(x,y)

  • 我编写了很多自定义函数,即使我在例如只使用了一次代码。一个sapply。我相信它可以使它更具可读性,而不会创建可以留在周围的对象。

  • 不惜一切代价避免循环,因为我认为矢量化更干净(更快)

然而,我注意到对此的看法不同,有些人倾向于放弃他们所谓的“Perl”编程方式(甚至是“Lisp”,所有这些括号都在我的代码中飞来飞去。我不会不过不要走那么远)。

您认为 R 中的良好编码实践是什么?

你的编程风格是什么,你如何看待它的优点和缺点?

4

4 回答 4

21

我所做的将取决于我编写代码的原因。如果我正在为我的研究(日常工作)编写数据分析脚本,我想要一些有效的东西,但几个月甚至几年后仍然可以阅读和理解。我不太关心计算时间。lapply与等人矢量化。可能会导致混淆,我想避免这种情况。

lapply在这种情况下,如果让我跳过箍来构造适当的匿名函数,我会使用循环来进行重复过程。我会ifelse()在你的第一个项目符号中使用,因为至少在我看来,该调用的意图比子集+替换版本更容易理解。在我的数据分析中,我更关心的是让事情变得正确,而不是计算时间——总是有周末和晚上我不在办公室的时候,我可以做大工作。

对于你的其他子弹;我倾向于内联/嵌套调用,除非它们非常微不足道。如果我明确说明这些步骤,我会发现代码更易于阅读,因此不太可能包含错误。

我一直在编写自定义函数,尤其是当我要在循环或类似的情况下重复调用函数的等效代码时。这样,我将主数据分析脚本中的代码封装到它自己的.R文件中,这有助于将分析的意图与分析的完成方式分开。如果该功能有用,我可以将其用于其他项目等。

如果我正在为一个包编写代码,我可能会以与我的数据分析(熟悉)相同的态度开始,以获得我所知道的有效的东西,然后才在我想改善计算时间时进行优化。

我尽量避免做的一件事是,我在编码时过于聪明,无论我在编码什么。最终,我从来没有像我想象的那样聪明,如果我保持简单,我往往不会像我试图变得聪明时那样经常摔倒在脸上。

于 2010-12-10T09:44:25.297 回答
11

.R我为概念上做一件事的各种代码块编写函数(在独立文件中)。这使事情变得简短而甜蜜。我发现调试稍微容易一些,因为traceback()它会告诉你哪个函数产生了错误。

我也倾向于避免循环,除非它绝对必要。如果我使用for()循环,我会觉得有点脏。:) 我非常努力地做所有矢量化或应用家庭的事情。这并不总是最佳实践,尤其是当您需要向其他不熟悉应用或矢量化的人解释代码时。

关于requirevs的使用::,我倾向于两者都使用。如果我只需要某个包中的一个函数,我会通过 使用它::,但如果我需要多个函数,我会加载整个包。如果包之间的函数名有冲突,我会尽量记住并使用::.

我尝试为我要完成的每项任务找到一个功能。我相信在我之前的某个人已经想到了它并制作了一个比我能想出的任何东西都更好的功能。这有时会奏效,有时不会。

我尝试编写我的代码以便我能理解它。这意味着我会发表大量评论并构建代码块,以便它们以某种方式遵循我想要实现的目标。我经常在函数进行时覆盖对象。我认为这可以保持任务的透明度,尤其是当您稍后在函数中引用这些对象时。当计算时间超过我的耐心时,我会考虑速度。如果一个功能需要很长时间才能完成,以至于我开始浏览 SO,我看看我是否可以改进它。

我发现具有代码折叠和语法着色功能的优秀语法编辑器(我使用 Eclipse + StatET)为我省去了很多麻烦。

根据 VitoshKa 的帖子,我补充说我使用大写字词(sensu Java)作为函数名称,使用 fullstop.delimited 作为变量。我看到我可以有另一种风格的函数参数。

于 2010-12-10T10:15:19.667 回答
8

命名约定对于代码的可读性非常重要。受 R 的 S4 内部风格的启发,我使用的是:

  • camelCase 用于全局函数和对象(如 doSomething、getXyyy、upperLimit)
  • 函数以动词开头
  • 未导出且辅助函数始终以“.”开头
  • 局部变量和函数都用小写字母和“_”语法(do_something,get_xyyy),这使得区分局部和全局变得容易,因此代码更清晰。
于 2010-12-12T09:57:35.863 回答
4

对于数据处理,我尝试尽可能多地使用 SQL,至少对于 GROUP BY 平均值之类的基本内容。我非常喜欢 R,但有时意识到您的研究策略还不足以找到隐藏在另一个包中的另一个功能,这不仅很有趣。对于我的情况,SQL 方言差别不大,代码非常透明。大多数情况下,阈值(何时开始使用 R 语法)很容易发现。例如

require(RMySQL)
# selection of variables alongside conditions in SQL is really transparent
# even if conditional variables are not part of the selection
statement = "SELECT id,v1,v2,v3,v4,v5 FROM mytable
             WHERE this=5
             AND that != 6" 
mydf <- dbGetQuery(con,statement)
# some simple things get really tricky (at least in MySQL), but simple in R
# standard deviation of table rows
dframe$rowsd <- sd(t(dframe))

所以我认为这是一种很好的做法,并且真的建议在大多数用例中为您的数据使用 SQL 数据库。我也在研究 TSdbi 并在关系数据库中保存时间序列,但还不能真正判断。

于 2010-12-10T10:27:38.293 回答