【问题标题】:Reading big data with fixed width读取固定宽度的大数据
【发布时间】:2013-09-14 05:29:51
【问题描述】:

如何读取固定宽度格式的大数据?我阅读了this 问题并尝试了一些提示,但所有答案都是针对分隔数据(如 .csv),这不是我的情况。数据有558MB,不知道有多少行。

我正在使用:

dados <- read.fwf('TS_MATRICULA_RS.txt', width=c(5, 13, 14, 3, 3, 5, 4, 6, 6, 6, 1, 1, 1, 4, 3, 2, 9, 3, 2, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 11, 9, 2, 3, 9, 3, 2, 9, 9, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1), stringsAsFactors=FALSE, comment.char='', 
    colClasses=c('integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'character', 'character', 'character',
    'integer', 'integer', 'character', 'integer', 'integer', 'character', 'integer', 'character', 'character', 'character', 'character', 'character', 'character',
    'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character',
    'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'integer',
    'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'character', 'integer', 'integer', 'character', 'character', 'character',
    'character', 'integer', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character'), buffersize=180000)

但读取数据需要 30 分钟(而且还在继续……)。有什么新建议吗?

【问题讨论】:

  • 我不知道如何加快速度,但我也会在加载后将类似的大文件保存为 R 对象,这样我以后可以更快地加载它们。
  • 是的,我也是。但我需要从这个文件(现在)是一个简单的表,然后加载另一个大到:/
  • 我刚刚使用以下策略读取了 4GB FWF:使用“big ram”队列 (30GB) 在集群上加载。另存为 R 对象。花了一整夜。所以它与大数据有关。希望有人有更有效的策略。
  • 你有宽度索引吗?使用 substr 尝试 sqldf。或者创建一个 csvkit 架构文件并使用 csvkit 创建您的 CSV 并从 data.table 读取 CSV。
  • 我稍后会尝试更新我的答案,但与此同时,我想分享一个您可能感兴趣的包:iotools

标签: r bigdata


【解决方案1】:

这是一个纯 R 解决方案,使用新软件包 readr,由 Hadley Wickham 和 RStudio 团队创建,于 2015 年 4 月发布。更多信息 here。代码就这么简单:

library(readr)

my.data.frame <- read_fwf('TS_MATRICULA_RS.txt',
                      fwf_widths(c(5, 13, 14, 3, 3, 5, 4, 6, 6, 6, 1, 1, 1, 4, 3, 2, 9, 3, 2, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 11, 9, 2, 3, 9, 3, 2, 9, 9, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1)),
                      progress = interactive())

read_fwf{readr}的优势

  • readr 基于 LaF 但令人惊讶的是更快。显示为the fasted method to read fixed-width files in R
  • 它比其他替代方案更简单。例如您无需担心column_types,因为它们将根据输入的前 30 行进行估算。
  • 它带有一个进度条;)

【讨论】:

【解决方案2】:

LaF 包非常擅长快速读取固定宽度的文件。我每天都使用它来加载 +/- 100Mio 记录的文件,其中包含 30 列(没有你拥有的那么多字符列 - 主要是数字数据和一些因素)。而且速度非常快。所以这就是我要做的。

library(LaF)
library(ffbase)
my.data.laf <- laf_open_fwf('TS_MATRICULA_RS.txt', 
                  column_widths=c(5, 13, 14, 3, 3, 5, 4, 6, 6, 6, 1, 1, 1, 4, 3, 2, 9, 3, 2, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 11, 9, 2, 3, 9, 3, 2, 9, 9, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1), stringsAsFactors=FALSE, comment.char='', 
                  column_types=c('integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'categorical', 'categorical', 'categorical',
                               'integer', 'integer', 'categorical', 'integer', 'integer', 'categorical', 'integer', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical',
                               'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical',
                               'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'integer',
                               'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'categorical', 'integer', 'integer', 'categorical', 'categorical', 'categorical',
                               'categorical', 'integer', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical'))
my.data <- laf_to_ffdf(my.data.laf, nrows=1000000)
my.data.in.ram <- as.data.frame(my.data)

PS。我开始使用 LaF 包是因为我对 read.fwf 的缓慢感到恼火,而且我最初用来解析数据的 PL/SQL PostgreSQL 代码变得难以维护。

【讨论】:

  • 由于某种原因,它读取了有问题的第三个变量。 " 2012 8874432 110021407656 16 2 2004 8 240 180 0M11 76 43RS 4317400 43RS 4317400130 0000000000000000000000000 1 16 571764 0 0 43132715 43RS 4318002 512 00000100" 变为 -1647742040 而不是 110021407656。有什么想法吗?
  • 110021407656 不是整数。看看 as.integer(110021407656) 在 R 中给出了什么以及 as.double(110021407656) 给你什么?在上面的代码中将该列的列类型调整为“double”。
  • @Rcoster hmmmm.... 一个相减得到 2^33*13。你有没有机会在这里遇到 2^32 的限制? (也就是说你肯定是)
  • 试过这个但它崩溃了(RStudio/R 3.0.0)
  • @Ari 您是在使用 Rcoster 的数据上的确切代码,还是您有自己的代码和数据似乎给您带来麻烦?在后一种情况下,请分享代码和数据。
【解决方案3】:

如果没有足够的数据详细信息,很难给出具体答案,但这里有一些想法可以帮助您入门:

首先,如果您使用的是 Unix 系统,则可以使用 wc 命令获取有关文件的一些信息。例如wc -l TS_MATRICULA_RS.txt 将告诉您文件中有多少行,wc -L TS_MATRICULA_RS.txt 将报告文件中最长行的长度。知道这可能很有用。同样,headtail 可以让您检查文本文件的第一行和最后 10 行。

第二,一些建议:既然您似乎知道每个字段的宽度,我会推荐两种方法中的一种。

方案一:csvkit+你最喜欢的快速读取大数据的方法

csvkit 是一组用于处理 CSV 文件的 Python 工具。其中一个工具是in2csv,它采用一个固定宽度格式的文件和一个“模式”文件来创建一个可以与其他程序一起使用的适当的 CSV。

架构文件本身是一个包含三列的 CSV 文件:(1) 变量名称、(2) 起始位置和 (3) 宽度。一个例子(来自in2csv 手册页)是:

    column,start,length
    name,0,30 
    birthday,30,10 
    age,40,3

创建该文件后,您应该可以使用以下内容:

in2csv -f fixed -s path/to/schemafile.csv path/to/TS_MATRICULA_RS.txt > TS_MATRICULA_RS.csv

从那里,我建议研究使用“data.table”中的fread 或使用sqldf 读取数据。

选项 2:sqldf 使用 substr

在像您这样的大型数据文件上使用sqldf 实际上应该很快,并且您可以使用substr 准确指定要读取的内容。

同样,这将期望您有一个可用的架构文件,就像上面描述的那样。获得架构文件后,您可以执行以下操作:

temp <- read.csv("mySchemaFile.csv")

## Construct your "substr" command
GetMe <- paste("select", 
               paste("substr(V1, ", temp$start, ", ",
                     temp$length, ") `", temp$column, "`", 
                     sep = "", collapse = ", "), 
               "from fixed", sep = " ")

## Load "sqldf"
library(sqldf)

## Connect to your file
fixed <- file("TS_MATRICULA_RS.txt")
myDF <- sqldf(GetMe, file.format = list(sep = "_"))

由于您知道宽度,您可以跳过架构文件的生成。从宽度上看,cumsum 只需要一点点工作。这是一个基本示例,基于read.fwf 的第一个示例:

ff <- tempfile()
cat(file = ff, "123456", "987654", sep = "\n")
read.fwf(ff, widths = c(1, 2, 3))

widths <- c(1, 2, 3)
length <- cumsum(widths)
start <- length - widths + 1
column <- paste("V", seq_along(length), sep = "")

GetMe <- paste("select", 
               paste("substr(V1, ", start, ", ",
                     widths, ") `", column, "`", 
                     sep = "", collapse = ", "), 
               "from fixed", sep = " ")

library(sqldf)

## Connect to your file
fixed <- file(ff)
myDF <- sqldf(GetMe, file.format = list(sep = "_"))
myDF
unlink(ff)

【讨论】:

  • 查看here 了解一些基准。我无法让sqldf 版本工作(关于没有名为V1 的列的错误)所以我暂时排除了它。
猜你喜欢
  • 2012-03-16
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-01
  • 1970-01-01
  • 2016-01-18
  • 2017-05-19
相关资源
最近更新 更多