从 SQL 服务器读取非常大的固定(ish)宽度格式的 txt 文件导出到 R data.tables 或类似
Reading very large fixed(ish) width format txt files from SQL Server Export into R data.tables or likewise
我正在尝试读入(并最终 merge/link/manipulate)一系列大的 (~300M) 和非常大的 (~4G) 固定宽度文件,用于最终回归、可视化等,并且我遇到一些障碍。
首先,文件本身的格式很奇怪 - 我猜是 SQL-y。文件格式参考这里:
https://msdn.microsoft.com/en-us/library/ms191479.aspx
.它是固定宽度,但最后一列似乎(有时?)在该列经历完全固定宽度之前用 \r\n 切断。为了阅读它,我尝试了 laf_open_fwf 和 data.table::fread,但他们似乎都感到困惑。示例文件和关联的非 XML 格式描述符是 here。我什至无法正确阅读最后那篇愚蠢的专栏文章。这是文件示例:
1 1 7 7 ER
2 2 9 8 OI
3 54016 1988006 1953409 OI
4 54017 1988014 1953415 ER
5 54017 1988014 1953415 OB
(但请注意 CR/LF 在这里是不可见的,问题在于它们的奇怪位置。请参阅上面的 link 到 .txt 文件或 png 文件(我可以' t link, low rep) notepad++ 数据视图以演示该字段的问题。)
其次,文件大小是个问题。我知道我有很多 table 操作要做,所以我很想看看 data.table... 但我也相信 data.table 将整个对象存储在 RAM 中,那就是会出问题的。 LaF 或 ffdf 或 sqlite 似乎是选项,虽然我是新手,需要先处理这个文件格式问题。
一些问题得到了这个总体思路,建议 LaF、ffbase 或 data.table 在下面...
Reading big data with fixed width
Quickly reading very large tables as dataframes in R
Speed up import of fixed width format table in R
... 但是 none 似乎(1)处理这种奇怪的固定宽度格式或(2)最终将数据移动到 data.tables,这似乎我会喜欢先试试。我考虑过尝试将它们打开并重写为格式良好的 CSV,以便 data.table 可以处理它们(我通过 data.frames 并返回到 csv 的愚蠢黑客感觉荒谬且不可扩展,如下所示)。 CSV 导出表明文件变得多么混乱,因为 laf reader 严格按照字段长度进行,而不是根据 /r/n 的位置进行调整...
目前我正在为初学者尝试类似下面的内容。如果可能,请帮忙?
require("data.table", "LaF", "ffbase")
searchbasis.laf = laf_open_fwf("SEARCHBASIS.txt",
column_widths = c(12, 12, 12, 12, 10),
column_names = c("SearchBasisID", "SearchID", "PersonID", "StopID", "Basis"),
column_types = rep("string",5),
trim = T)
# ^ The laf_open_fwf quietly "fails" because the last column doesn't always
# have 10 chars, but sometimes ends short with /r/n after the element.
searchbasis.dt = as.data.table(as.data.frame(laf_to_ffdf(searchbasis.laf)))
write.csv(searchbasis.dt, file="SEARCHBASIS.csv")
# ^ To take a look at the file. Confirms that the read from laf, transfer
# to data.table is failing because of the last column issue.
对于这个特定的文件:
form <- read.table("SEARCHBASIS_format.txt", as.is = TRUE, skip = 2)
x <- read.table("SEARCHBASIS.txt", col.names = form$V7, as.is = TRUE)
如果您有时有包含空格的字符串,您几乎肯定需要先在外部处理文件。
如果您打算读取非常大的文件,我建议(假设您的路径上有 awk):
x <- setNames(data.table::fread("awk '{=}1' SEARCHBASIS.txt"), form$V7)
如果您想使用固定宽度,您可以使用:
x <- setNames(fread("gawk 'BEGIN {OFS = \"\t\"; FIELDWIDTHS = \"12 12 12 12 12\"} {for (i = 1; i<= NF; i++) {gsub(/ +$/, \"\", $i);}}1' SEARCHBASIS.txt"), form$V7)
您还可以从格式文件中提取宽度:
x <- setNames(fread(paste0("gawk 'BEGIN {OFS = \"\t\"; FIELDWIDTHS = \"", paste(form$V4, collapse = " "), "\"} {for (i = 1; i<= NF; i++) {gsub(/ +$/, \"\", $i);}}1' SEARCHBASIS.txt")), form$V7)
注意 =
强制 awk 重新评估字段,末尾的 1 实际上是 shorthand print
。我还假设您想从每个字段中去除尾随空格。
在 Windows 上,您需要在 R 中使用单引号并将命令中的单引号替换为“,将嵌套的双引号替换为”。因此上面的最后一个变为:
x <- setNames(fread(paste0('gawk \"BEGIN {OFS = ""\t""; FIELDWIDTHS = ""', paste(form$V4, collapse = " "), '""} {for (i = 1; i<= NF; i++) {gsub(/ +$/, """", $i);}}1" SEARCHBASIS.txt')), form$V7)
对于跨平台解决方案,您需要将 awk 脚本放在外部文件中:
stripSpace.awk
BEGIN {OFS="\t"} {for (i = 1; i<= NF; i++) {gsub(/ +$/, "", $i);}}1
R码
x <- setNames(fread(paste0('gawk -v FIELDWIDTHS="', paste(form$V4, collapse = " "), '" -f stripSpace.awk SEARCHBASIS.txt')), form$V7)
在科学 Linux 6 和 Windows 8.1
上测试
通过最近的修复,fread()
现在可以读取具有多个空格的行而没有任何问题(v1.9.5+ 开发),它的 strip.white
参数(=TRUE
默认):
require(data.table) # v1.9.5+
fread("1 1 7 7 ER
2 2 9 8 OI
3 54016 1988006 1953409 OI
4 54017 1988014 1953415 ER
5 54017 1988014 1953415 OB
")
# V1 V2 V3 V4 V5
# 1: 1 1 7 7 ER
# 2: 2 2 9 8 OI
# 3: 3 54016 1988006 1953409 OI
# 4: 4 54017 1988014 1953415 ER
# 5: 5 54017 1988014 1953415 OB
我希望这对你的情况有用。如果没有,请告诉我们,我们会看看能否在 fread()
内完成。升级到开发版本(请参阅我们项目页面上的安装说明)或等待下一个 CRAN 版本(如 v1.9.6)。
我正在尝试读入(并最终 merge/link/manipulate)一系列大的 (~300M) 和非常大的 (~4G) 固定宽度文件,用于最终回归、可视化等,并且我遇到一些障碍。
首先,文件本身的格式很奇怪 - 我猜是 SQL-y。文件格式参考这里: https://msdn.microsoft.com/en-us/library/ms191479.aspx .它是固定宽度,但最后一列似乎(有时?)在该列经历完全固定宽度之前用 \r\n 切断。为了阅读它,我尝试了 laf_open_fwf 和 data.table::fread,但他们似乎都感到困惑。示例文件和关联的非 XML 格式描述符是 here。我什至无法正确阅读最后那篇愚蠢的专栏文章。这是文件示例:
1 1 7 7 ER
2 2 9 8 OI
3 54016 1988006 1953409 OI
4 54017 1988014 1953415 ER
5 54017 1988014 1953415 OB
(但请注意 CR/LF 在这里是不可见的,问题在于它们的奇怪位置。请参阅上面的 link 到 .txt 文件或 png 文件(我可以' t link, low rep) notepad++ 数据视图以演示该字段的问题。)
其次,文件大小是个问题。我知道我有很多 table 操作要做,所以我很想看看 data.table... 但我也相信 data.table 将整个对象存储在 RAM 中,那就是会出问题的。 LaF 或 ffdf 或 sqlite 似乎是选项,虽然我是新手,需要先处理这个文件格式问题。
一些问题得到了这个总体思路,建议 LaF、ffbase 或 data.table 在下面...
Reading big data with fixed width
Quickly reading very large tables as dataframes in R
Speed up import of fixed width format table in R
... 但是 none 似乎(1)处理这种奇怪的固定宽度格式或(2)最终将数据移动到 data.tables,这似乎我会喜欢先试试。我考虑过尝试将它们打开并重写为格式良好的 CSV,以便 data.table 可以处理它们(我通过 data.frames 并返回到 csv 的愚蠢黑客感觉荒谬且不可扩展,如下所示)。 CSV 导出表明文件变得多么混乱,因为 laf reader 严格按照字段长度进行,而不是根据 /r/n 的位置进行调整...
目前我正在为初学者尝试类似下面的内容。如果可能,请帮忙?
require("data.table", "LaF", "ffbase")
searchbasis.laf = laf_open_fwf("SEARCHBASIS.txt",
column_widths = c(12, 12, 12, 12, 10),
column_names = c("SearchBasisID", "SearchID", "PersonID", "StopID", "Basis"),
column_types = rep("string",5),
trim = T)
# ^ The laf_open_fwf quietly "fails" because the last column doesn't always
# have 10 chars, but sometimes ends short with /r/n after the element.
searchbasis.dt = as.data.table(as.data.frame(laf_to_ffdf(searchbasis.laf)))
write.csv(searchbasis.dt, file="SEARCHBASIS.csv")
# ^ To take a look at the file. Confirms that the read from laf, transfer
# to data.table is failing because of the last column issue.
对于这个特定的文件:
form <- read.table("SEARCHBASIS_format.txt", as.is = TRUE, skip = 2)
x <- read.table("SEARCHBASIS.txt", col.names = form$V7, as.is = TRUE)
如果您有时有包含空格的字符串,您几乎肯定需要先在外部处理文件。
如果您打算读取非常大的文件,我建议(假设您的路径上有 awk):
x <- setNames(data.table::fread("awk '{=}1' SEARCHBASIS.txt"), form$V7)
如果您想使用固定宽度,您可以使用:
x <- setNames(fread("gawk 'BEGIN {OFS = \"\t\"; FIELDWIDTHS = \"12 12 12 12 12\"} {for (i = 1; i<= NF; i++) {gsub(/ +$/, \"\", $i);}}1' SEARCHBASIS.txt"), form$V7)
您还可以从格式文件中提取宽度:
x <- setNames(fread(paste0("gawk 'BEGIN {OFS = \"\t\"; FIELDWIDTHS = \"", paste(form$V4, collapse = " "), "\"} {for (i = 1; i<= NF; i++) {gsub(/ +$/, \"\", $i);}}1' SEARCHBASIS.txt")), form$V7)
注意 =
强制 awk 重新评估字段,末尾的 1 实际上是 shorthand print
。我还假设您想从每个字段中去除尾随空格。
在 Windows 上,您需要在 R 中使用单引号并将命令中的单引号替换为“,将嵌套的双引号替换为”。因此上面的最后一个变为:
x <- setNames(fread(paste0('gawk \"BEGIN {OFS = ""\t""; FIELDWIDTHS = ""', paste(form$V4, collapse = " "), '""} {for (i = 1; i<= NF; i++) {gsub(/ +$/, """", $i);}}1" SEARCHBASIS.txt')), form$V7)
对于跨平台解决方案,您需要将 awk 脚本放在外部文件中:
stripSpace.awk
BEGIN {OFS="\t"} {for (i = 1; i<= NF; i++) {gsub(/ +$/, "", $i);}}1
R码
x <- setNames(fread(paste0('gawk -v FIELDWIDTHS="', paste(form$V4, collapse = " "), '" -f stripSpace.awk SEARCHBASIS.txt')), form$V7)
在科学 Linux 6 和 Windows 8.1
上测试通过最近的修复,fread()
现在可以读取具有多个空格的行而没有任何问题(v1.9.5+ 开发),它的 strip.white
参数(=TRUE
默认):
require(data.table) # v1.9.5+
fread("1 1 7 7 ER
2 2 9 8 OI
3 54016 1988006 1953409 OI
4 54017 1988014 1953415 ER
5 54017 1988014 1953415 OB
")
# V1 V2 V3 V4 V5
# 1: 1 1 7 7 ER
# 2: 2 2 9 8 OI
# 3: 3 54016 1988006 1953409 OI
# 4: 4 54017 1988014 1953415 ER
# 5: 5 54017 1988014 1953415 OB
我希望这对你的情况有用。如果没有,请告诉我们,我们会看看能否在 fread()
内完成。升级到开发版本(请参阅我们项目页面上的安装说明)或等待下一个 CRAN 版本(如 v1.9.6)。