数据 IO 是我在致力于学习 R 之前研究的功能之一。无论好坏,以下是我对这些问题的观察和解决方案/缓解措施:
1. That R 不处理大数据(>2 GB?)对我来说这是一个用词不当。默认情况下,常用数据输入函数将数据加载到 RAM 中。不是油嘴滑舌,但对我来说,这是一个功能而不是一个错误——只要我的数据适合我的可用 RAM,那就是我想要的地方。同样,SQLite 最受欢迎的功能之一是内存中选项——用户可以轻松选择将整个 dB 加载到 RAM 中。如果您的数据无法容纳在内存中,那么 R 可以通过连接到常见的 RDBMS 系统(RODBC、RSQLite、RMySQL 等)、通过简单的选项(如 filehash 包)以及通过当前技术/实践的系统(例如,我可以推荐ff http://ff.r-forge.r-project.org/)。换句话说,R 开发人员选择了一个合理的(可能也是最优的)默认值,很容易选择退出。
2、read.table的性能(read.csv、read.delim 等)是将数据导入 R 的最常见方法,只需选择退出 read.table 的一些默认参数即可将其改进 5 倍(根据我的经验,通常会提高很多) --R 的帮助 (?read.table) 中提到了对性能影响最大的那些。简而言之,R 开发人员告诉我们,如果您为参数“colClasses”、“nrows”、“sep”和“comment.char”提供值(特别是,如果您知道文件以 headers 或第 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. 使用扫描。只需多一点麻烦,您就可以通过使用“scan”而不是“read.table”(“read.table”实际上只是“scan”的包装器)做得更好(优化“read.table”)。再说一次,这很容易做到。我使用“scan”单独输入每一列,然后在 R 中构建我的 data.frame,即 df = data.frame(cbind(col1, col2,....))。
4.使用R的容器用于持久性代替普通文件格式(例如“txt”、“csv”)。 R 的本机数据文件“.RData”是一种二进制格式,比压缩的(“.gz”)txt 数据文件稍小。您使用以下命令创建它们save(,)。您可以使用以下命令将其加载回 R 命名空间load()。与“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 表达式中的数字被解释为双精度浮点,例如,> typeof(5) 返回“double. ”比较每个合理大小的数组的对象大小,您可以看到其重要性(使用 object.size())。因此,尽可能强制转换为整数。
最后,“apply”函数系列(以及其他函数)不是“隐藏循环”或循环包装器。它们是用 C 语言实现的循环——在性能方面差异很大。 [编辑:AWB 正确地指出,虽然 'sapply'、'tapply' 和 'mapply' 是用 C 实现的,但 'apply' 只是一个包装函数。