R数据结构的操作效率

时间:2009-12-28 20:13:58

标签: r performance

我想知道是否有关于R中操作效率的任何文档,特别是与数据操作相关的文档。

例如:

  • 我认为将列添加到数据框是有效的,因为我猜你只是在链表中添加一个元素。
  • 我想添加行的速度较慢,因为向量保存在C level的数组中,你必须分配一个长度为n+1的新数组并复制所有元素。

开发人员可能不希望将自己绑定到特定的实现,但是有一些比猜测还要坚实的东西会很好。

另外,我知道主R性能提示是尽可能使用向量操作而不是loops

  • apply的各种风味怎么样?
  • 那些只是hidden loops
  • matricesdata frames的对比?

3 个答案:

答案 0 :(得分:28)

在我致力于学习R之前,数据IO是我所研究的功能之一。无论好坏,这是我对这些问题的观察和解决方案/姑息治疗:

1。 R无法处理大数据(> 2 GB?)对我来说这是用词不当。默认情况下,公共数据输入功能会将数据加载到RAM中。不要愚蠢,但对我来说,这是一个功能而不是一个错误 - 任何时候我的数据都适合我的可用内存,这就是我想要的地方。同样,SQLite最受欢迎的功能之一是内存中选项 - 用户可以轻松选择将整个dB加载到RAM中。如果你的数据不适合内存,那么通过连接到常见的RDBMS系统(RODBC,RSQLite,RMySQL等),通过像filehash包这样的简单选项,通过R,可以非常容易地保存它。当前技术/实践的系统(例如,我可以推荐ff)。换句话说,R开发人员选择了一个明智的(也可能是最佳的)默认值,从中很容易选择退出。

<强> 2。 read.table的性能(read.csv,read.delim等),这是将数据导入R的最常用方法,只需选择性就可以提高5倍(通常我的经验更多)在一些read.table的默认参数中 - 在R的帮助(?read.table)中提到了对性能影响最大的参数。简而言之,R开发人员告诉我们,如果您为参数'colClasses','nrows','sep'和'comment.char'提供值(特别是,如果您知道您的文件以标题开头,则传入''第1行的数据,你会看到显着的性能提升。我发现这是真的。

以下是我用于这些参数的片段:

要获取数据文件中的行数(在调用read.table时将此代码段作为参数的参数提供,'nrows'):

as.numeric((gsub("[^0-9]+", "", system(paste("wc -l ", file_name, sep=""), intern=T))))

获取每列的类:

function(fname){sapply(read.table(fname, header=T, nrows=5), class)}  

注意:您不能将此片段作为参数传递,您必须先调用它,然后传入返回的值 - 换句话说,调用函数,将返回的值绑定到变量,然后在调用read.table:

时,将变量作为值传递给参数'colClasses'

第3。使用扫描。只需稍微麻烦一点,你可以做得更好(优化'read.table')使用'scan'而不是'read.table'('read.table'实际上只是'scan'的包装)。再一次,这很容易做到。我使用'scan'分别输入每一列,然后在R中构建我的data.frame,即df = data.frame(cbind(col1,col2,....))。

<强> 4。使用R的容器来代替普通文件格式的持久性(例如,'txt','csv')。 R的原生数据文件'.RData'是一种二进制格式,比压缩('.gz')txt数据文件略小。您可以使用保存(,)创建它们。使用加载()将其加载回R命名空间。与“read.table”相比,加载时间的差异是巨大的。例如,w / 25 MB文件(未压缩大小)

system.time(read.table("tdata01.txt.gz", sep=","))
=>  user  system elapsed 
    6.173   0.245   **6.450** 

system.time(load("tdata01.RData"))
=> user  system elapsed 
    0.912   0.006   **0.912**   

<强> 5。注意数据类型通常可以提高性能并减少内存占用。这一点在从R中获取数据时可能更有用。这里要记住的关键点是默认情况下,R表达式中的数字被解释为双精度浮点,例如&gt; typeof(5)返回“double”。比较每个的合理大小的数组的对象大小,您可以看到重要性(使用object.size())。所以当你可以时强制转换为整数。

最后,'apply'系列函数(以及其他)不是“隐藏循环”或循环包装器。它们是用C实现的循环 - 性能差异很大。 [编辑:AWB正确地指出,虽然'sapply','tapply'和'mapply'是用C实现的,'apply'只是一个包装函数。

答案 1 :(得分:11)

这些东西会在列表中弹出,特别是在r-devel上。一个相当成熟的金块是例如matrix操作往往比data.frame操作更快。然后有一些很好的附加软件包--Matt的data.table软件包非常快,Jeff已经快速获得了xts索引。

但它“完全取决于” - 因此,您通常最好建议对您的特定代码进行配置R有很多分析支持,所以你应该使用它。我的Intro to HPC with R tutorials有很多分析示例。

答案 2 :(得分:6)

我会尝试回来提供更多细节。如果您对一项操作相对于另一项操作的效率有任何疑问,您最好对自己的代码进行分析(如Dirk建议的那样)。 system.time()函数是最简单的方法,尽管还有许多高级实用程序(例如Rprof,如文档here所述)。

对问题第二部分的快速回复:

  

各种口味的申请怎么样?那些只是隐藏的循环吗?

大多数情况下,apply函数只是循环,可能比for语句慢。他们的主要好处是更清晰的代码。我发现的主要例外是lapply,它可以更快,因为它直接用C编码。

  

那么矩阵与数据帧呢?

矩阵比数据帧更有效,因为它们需要更少的内存来存储。这是因为数据帧需要额外的属性数据。来自R Introduction

  

出于多种目的,数据框可以被视为具有可能具有不同模式和属性的列的矩阵