R:读取带有空格和列数不等的文本文件
R: Read text files with blanks and unequal number of columns
我正在尝试使用 read.table 将许多文本文件读入 R。大多数时候,我们都有定义了列的干净文本文件。
我尝试读取的数据来自ftp://ftp.cmegroup.com/delivery_reports/live_cattle_delivery/102317_livecattle.txt
您可以看到文本文件的空白和长度因报告而异。
ftp://ftp.cmegroup.com/delivery_reports/live_cattle_delivery/102317_livecattle.txt
ftp://ftp.cmegroup.com/delivery_reports/live_cattle_delivery/100917_livecattle.txt
我的 objective 是读取许多这些文本文件并将它们组合成一个数据集。
如果我能阅读其中的一篇,那么编译应该不是问题。但是,由于文本文件的格式,我 运行 遇到了几个问题:
1) 公司的数量因报告而异。例如,有时会有 3 行(即 3 家公司在该数据上开展业务)要导入的数据,有时可能有 10 行。
2) 正在识别空白。例如,在 FIRM 部分下应该有一列用于交付 (DEL) 和收据 (REC)。在本节中读取的数据应如下所示:
df <- data.frame("FIRM_#" = c(407, 685, 800, 905),
"FIRM_NAME" = c("STRAITS FIN LLC", "R.J.O'BRIEN ASSOC", "ROSENTHAL COLLINS LL", "ADM INVESTOR SERVICE"),
"DEL" = c(1,1,15,1), "REC"= c(NA,18,NA,NA))
然而,当我在格式中阅读此内容时,一切都搞砸了,并且没有将 NA 用于空白值
3) 以上问题适用于文本文件的 "YARDS" 和 "FUTURE DELIVERIES SCHEDULED" 部分。
我曾尝试阅读文本文件的各个部分,然后对其进行相应的格式化,但由于公司数量每天都在变化,因此代码无法概括。
如有任何帮助,我们将不胜感激。
这里是一个通过 rvest
从头开始的答案,用于下载数据并包含大量格式。一般的想法是确定可用于分隔列的固定宽度 - 为此我使用了 SO 的一些帮助 。
然后您可以将 read.fwf()
与 cat()
和 tempfile()
结合使用。在我的第一次尝试中,由于一些格式问题,这没有用,所以我添加了一些额外的行以获得最终的 table 格式。
也许有一些我监督过的更优雅的选项和快捷方式,但至少,我的回答应该能让你入门。当然,您必须根据需要的数据部分调整线的选择、分割宽度的识别 tables。解决此问题后,您可以遍历所有网站以收集数据。我希望这有助于...
library(rvest)
library(dplyr)
page <- read_html("ftp://ftp.cmegroup.com/delivery_reports/live_cattle_delivery/102317_livecattle.txt")
table <- page %>%
html_text("pre") %>%
#reformat by splitting on line breakes
{ unlist(strsplit(., "\n")) } %>%
#select range based on strings in specific lines
"["(.,(grep("FIRM #", .):(grep(" DELIVERIES SCHEDULED", .)-1))) %>%
#exclude empty rows
"["(., !grepl("^\s+$", .)) %>%
#fix width of table to the right
{ substring(., 1, nchar(gsub("\s+$", "" , .[1]))) } %>%
#strip white space on the left
{ gsub("^\s+", "", .) }
headline <- unlist(strsplit(table[1], "\s{2,}"))
get_split_position <- function(substring, string) {
nchar(string)-nchar(gsub(paste0("(^.*)(?=", substring, ")"), "", string , perl=T))
}
#exclude first element, no split before this element
split_positions <- sapply(headline[-1], function(x) {
get_split_position(x, table[1])
})
#exclude headline from split
table <- lapply(table[-1], function(x) {
substring(x, c(1, split_positions + 1), c(split_positions, nchar(x)))
})
table <- do.call(rbind, table)
colnames(table) <- headline
#strip whitespace
table <- gsub("\s+", "", table)
table <- as.data.frame(table, stringsAsFactors = FALSE)
#assign NA values
table[ table == "" ] <- NA
#change column type
table[ , c("FIRM #", "DEL", "REC")] <- apply(table[ , c("FIRM #", "DEL", "REC")], 2, as.numeric)
table
# FIRM # FIRM NAME DEL REC
# 1 407 STRAITSFINLLC 1 NA
# 2 685 R.J.O'BRIENASSOC 1 18
# 3 800 ROSENTHALCOLLINSLL 15 NA
# 4 905 ADMINVESTORSERVICE 1 NA
我正在尝试使用 read.table 将许多文本文件读入 R。大多数时候,我们都有定义了列的干净文本文件。
我尝试读取的数据来自ftp://ftp.cmegroup.com/delivery_reports/live_cattle_delivery/102317_livecattle.txt
您可以看到文本文件的空白和长度因报告而异。 ftp://ftp.cmegroup.com/delivery_reports/live_cattle_delivery/102317_livecattle.txt ftp://ftp.cmegroup.com/delivery_reports/live_cattle_delivery/100917_livecattle.txt
我的 objective 是读取许多这些文本文件并将它们组合成一个数据集。
如果我能阅读其中的一篇,那么编译应该不是问题。但是,由于文本文件的格式,我 运行 遇到了几个问题:
1) 公司的数量因报告而异。例如,有时会有 3 行(即 3 家公司在该数据上开展业务)要导入的数据,有时可能有 10 行。
2) 正在识别空白。例如,在 FIRM 部分下应该有一列用于交付 (DEL) 和收据 (REC)。在本节中读取的数据应如下所示:
df <- data.frame("FIRM_#" = c(407, 685, 800, 905),
"FIRM_NAME" = c("STRAITS FIN LLC", "R.J.O'BRIEN ASSOC", "ROSENTHAL COLLINS LL", "ADM INVESTOR SERVICE"),
"DEL" = c(1,1,15,1), "REC"= c(NA,18,NA,NA))
然而,当我在格式中阅读此内容时,一切都搞砸了,并且没有将 NA 用于空白值
3) 以上问题适用于文本文件的 "YARDS" 和 "FUTURE DELIVERIES SCHEDULED" 部分。
我曾尝试阅读文本文件的各个部分,然后对其进行相应的格式化,但由于公司数量每天都在变化,因此代码无法概括。
如有任何帮助,我们将不胜感激。
这里是一个通过 rvest
从头开始的答案,用于下载数据并包含大量格式。一般的想法是确定可用于分隔列的固定宽度 - 为此我使用了 SO 的一些帮助
然后您可以将 read.fwf()
与 cat()
和 tempfile()
结合使用。在我的第一次尝试中,由于一些格式问题,这没有用,所以我添加了一些额外的行以获得最终的 table 格式。
也许有一些我监督过的更优雅的选项和快捷方式,但至少,我的回答应该能让你入门。当然,您必须根据需要的数据部分调整线的选择、分割宽度的识别 tables。解决此问题后,您可以遍历所有网站以收集数据。我希望这有助于...
library(rvest)
library(dplyr)
page <- read_html("ftp://ftp.cmegroup.com/delivery_reports/live_cattle_delivery/102317_livecattle.txt")
table <- page %>%
html_text("pre") %>%
#reformat by splitting on line breakes
{ unlist(strsplit(., "\n")) } %>%
#select range based on strings in specific lines
"["(.,(grep("FIRM #", .):(grep(" DELIVERIES SCHEDULED", .)-1))) %>%
#exclude empty rows
"["(., !grepl("^\s+$", .)) %>%
#fix width of table to the right
{ substring(., 1, nchar(gsub("\s+$", "" , .[1]))) } %>%
#strip white space on the left
{ gsub("^\s+", "", .) }
headline <- unlist(strsplit(table[1], "\s{2,}"))
get_split_position <- function(substring, string) {
nchar(string)-nchar(gsub(paste0("(^.*)(?=", substring, ")"), "", string , perl=T))
}
#exclude first element, no split before this element
split_positions <- sapply(headline[-1], function(x) {
get_split_position(x, table[1])
})
#exclude headline from split
table <- lapply(table[-1], function(x) {
substring(x, c(1, split_positions + 1), c(split_positions, nchar(x)))
})
table <- do.call(rbind, table)
colnames(table) <- headline
#strip whitespace
table <- gsub("\s+", "", table)
table <- as.data.frame(table, stringsAsFactors = FALSE)
#assign NA values
table[ table == "" ] <- NA
#change column type
table[ , c("FIRM #", "DEL", "REC")] <- apply(table[ , c("FIRM #", "DEL", "REC")], 2, as.numeric)
table
# FIRM # FIRM NAME DEL REC
# 1 407 STRAITSFINLLC 1 NA
# 2 685 R.J.O'BRIENASSOC 1 18
# 3 800 ROSENTHALCOLLINSLL 15 NA
# 4 905 ADMINVESTORSERVICE 1 NA