R数据结构的操作效率

cba*_*are 24 performance r

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

例如:

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

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

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

  • 那各种口味apply怎么样?
  • 那些只是hidden loops
  • matrices对战data frames怎么样?

dou*_*oug 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))))
Run Code Online (Sandbox Code Playgroud)

获取每列的类:

function(fname){sapply(read.table(fname, header=T, nrows=5), class)}  
Run Code Online (Sandbox Code Playgroud)

注意:您不能将此片段作为参数传递,您必须先调用它,然后传入返回的值 - 换句话说,调用函数,将返回的值绑定到变量,然后传入变量作为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数据文件小一点.您可以使用save(,)创建它们.使用load()将其加载回R命名空间.与"read.table"相比,加载时间的差异是巨大的.例如,带有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**   
Run Code Online (Sandbox Code Playgroud)

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

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

  • 我想在doug(非常好的)帖子中纠正一个声明,并指出数据I/O速度的一个很好的参考.首先,并非所有'apply'函数都在C中实现.'lapply'在C中实现,就像'sapply'(包装'lapply')一样.'mapply'也在C.'apply'中实现,但是,它只是'for'的一个很好的包装器; 优秀的'plyr'包装中的功能也是如此.其次,请查看Revolutions博客上的此条目,了解有关IO效率的更多信息:http://blog.revolution-computing.com/2009/12/speedreading-files-revisited.html (4认同)

Dir*_*tel 11

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

但它"完全取决于" - 所以你通常最好建议你的特定代码.R有足够的分析支持,所以你应该使用它.我的带有R教程的HPC简介有很多分析示例.


Sha*_*ane 6

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

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

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

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

那么矩阵与数据帧呢?

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

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