使用所有美国县的失业数据创建 data.frame
Creating a data.frame with all USA County Unemployment Data
我正在尝试使用来自美国劳工统计局的所有美国县失业数据创建 data.frame:
http://www.bls.gov/lau/#cntyaa
数据从 1990 年到 2013 年每年有一个结果。
我原本计划使用 BLS API,但他们似乎认为每个县都是一个单独的查询,并且查询总数将超过他们的阈值。我现在认为从他们放在网上的 TXT 文件中简单地抓取数据可能更容易,但我在使用 R 解析数据时遇到了问题。这是一个包含数据的示例页面:
http://www.bls.gov/lau/laucnty90.txt#90=1990
我最初尝试用 rvest
包解析文件。但是因为数据都在一个 <p>
标签中,我认为 table 的 HTML 结构不足以用于该工具。
然后我尝试了 download.file
和 read.table
。但同样,对于这些工具,数据的格式似乎不正确 - 顶部和底部有额外的行,并且 "separating character" 只是一个空格,当县名包含空格时,这会使 R 感到困惑。
一天结束时,我只需要一个 data.frame,其中包含此文件中的 3 条数据:州 FIPS 代码、县 FIPS 代码和失业率。
我现在认为创建此 data.frame 的最简单方法可能是下载 excel 文件,删除我不需要的列,删除顶部的多余文本和底部,导出为 CSV,然后将其读入 R。
这14年的每一年我都一定能做到。但是我失去了一些重现性 - 其他人将无法轻松验证我在导入过程中没有犯错误。
有没有人看到更简单的方法来创建这个 data.frame?
那只是一个固定宽度的数据文件。我没有时间给你完美的代码,但调整一下应该可以满足你的需要:
url = 'http://www.bls.gov/lau/laucnty90.txt'
w = c(17, 8, 6, 50, 12, 13, 12, 11)
dat = read.fwf(url, w, skip=3)
需要 "ruler" 来确定要拆分的列:
cat(">",paste0(rep(c(1:9,"+"),14),collapse=""))
cat(">",paste0(sprintf("%08s0/",1:14),collapse=""))
> 123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+
cat(">",paste0(sprintf("%08s0/",1:14),collapse=""))
> 000000010/000000020/000000030/000000040/000000050/000000060/000000070/000000080/000000090/000000100/000000110/000000120/000000130/000000140/
# and paste in the first line of data
> CN0100100000000 01 001 Autauga County, AL 1990 16,875 15,853 1,022 6.1
这可以让你弄清楚在哪里放置拆分并取差值并移动一个值得到宽度。跳过前六行,然后将读入的数据处理为字符,以避免因素的麻烦。在强制转换为数字之前删除逗号。
> dat = read.fwf(url,
widths=diff(c(0,16,21,29,80,86,100,115,125,132)+1),
skip=6,colClasses="character")
> str(dat)
'data.frame': 3219 obs. of 9 variables:
$ V1: chr "CN0100100000000 " "CN0100300000000 " "CN0100500000000 " "CN0100700000000 " ...
$ V2: chr " 01 " " 01 " " 01 " " 01 " ...
$ V3: chr " 001 " " 003 " " 005 " " 007 " ...
$ V4: chr " Autauga County, AL " " Baldwin County, AL " " Barbour County, AL " " Bibb County, AL " ...
$ V5: chr " 1990 " " 1990 " " 1990 " " 1990 " ...
$ V6: chr " 16,875 " " 46,773 " " 11,458 " " 7,408 " ...
$ V7: chr " 15,853 " " 44,492 " " 10,619 " " 6,776 " ...
$ V8: chr " 1,022 " " 2,281 " " 839 " " 632 " ...
$ V9: chr " 6.1" " 4.9" " 7.3" " 8.5" ...
dat[6:8] <- lapply( dat[6:8],
function(col) as.numeric( gsub("[,]", "", col)) )
> str(dat)
'data.frame': 3219 obs. of 9 variables:
$ V1: chr "CN0100100000000 " "CN0100300000000 " "CN0100500000000 " "CN0100700000000 " ...
$ V2: chr " 01 " " 01 " " 01 " " 01 " ...
$ V3: chr " 001 " " 003 " " 005 " " 007 " ...
$ V4: chr " Autauga County, AL " " Baldwin County, AL " " Barbour County, AL " " Bibb County, AL " ...
$ V5: chr " 1990 " " 1990 " " 1990 " " 1990 " ...
$ V6: num 16875 46773 11458 7408 19130 ...
$ V7: num 15853 44492 10619 6776 18001 ...
$ V8: num 1022 2281 839 632 1129 ...
$ V9: chr " 6.1" " 4.9" " 7.3" " 8.5" ...
dat[[9]] <- as.numeric( dat[[9]])
这可能可以通过使用一些 "NULL"
来改善
这是一个使用 XLConnect
包直接读取电子表格的选项,避免了所有这些计算列边界的业务。
get.file <- function(url) {
require(XLConnect)
download.file(url,"temp.xlsx",mode="wb")
wb <- loadWorkbook("temp.xlsx")
ws <- readWorksheet(wb,1,startRow=7,header=FALSE,drop=list(6))
ws[!is.na(ws$Col2),] # remove empty rows at the end
}
pfx <- "http://www.bls.gov/lau/laucnty"
urls <- paste0(pfx,c(90:99,formatC(0:13,width=2,flag=0)),".xlsx")
result <- do.call(rbind,lapply(urls,get.file))
head(result)
# Col1 Col2 Col3 Col4 Col5 Col7 Col8 Col9 Col10
# 1 CN0100100000000 01 001 Autauga County, AL 1990 16875 15853 1022 6.1
# 2 CN0100300000000 01 003 Baldwin County, AL 1990 46773 44492 2281 4.9
# 3 CN0100500000000 01 005 Barbour County, AL 1990 11458 10619 839 7.3
# 4 CN0100700000000 01 007 Bibb County, AL 1990 7408 6776 632 8.5
# 5 CN0100900000000 01 009 Blount County, AL 1990 19130 18001 1129 5.9
# 6 CN0101100000000 01 011 Bullock County, AL 1990 4381 3869 512 11.7
在 readWorksheet(...)
调用中,我们跳过前 7 行,因为它们包含 headers,并且我们删除第 6 列,因为它是空白的。然后我们删除结果中第 2 列中包含 NA
的任何行(最后几行是注释)。最后我们使用 lapply(...)
创建所有提取文件的列表,并使用 do.call(rbind,...)
将它们全部组合 row-wise.
注意所有的列都是字符。您还需要做一些清理工作。正如这些 multi-decade 数据集的典型情况一样,一些数据丢失并且 "missing" 的代码并不总是相同的(有时 "NA"
,有时 "N.A."
,等等)。
我正在尝试使用来自美国劳工统计局的所有美国县失业数据创建 data.frame:
http://www.bls.gov/lau/#cntyaa
数据从 1990 年到 2013 年每年有一个结果。
我原本计划使用 BLS API,但他们似乎认为每个县都是一个单独的查询,并且查询总数将超过他们的阈值。我现在认为从他们放在网上的 TXT 文件中简单地抓取数据可能更容易,但我在使用 R 解析数据时遇到了问题。这是一个包含数据的示例页面:
http://www.bls.gov/lau/laucnty90.txt#90=1990
我最初尝试用 rvest
包解析文件。但是因为数据都在一个 <p>
标签中,我认为 table 的 HTML 结构不足以用于该工具。
然后我尝试了 download.file
和 read.table
。但同样,对于这些工具,数据的格式似乎不正确 - 顶部和底部有额外的行,并且 "separating character" 只是一个空格,当县名包含空格时,这会使 R 感到困惑。
一天结束时,我只需要一个 data.frame,其中包含此文件中的 3 条数据:州 FIPS 代码、县 FIPS 代码和失业率。
我现在认为创建此 data.frame 的最简单方法可能是下载 excel 文件,删除我不需要的列,删除顶部的多余文本和底部,导出为 CSV,然后将其读入 R。
这14年的每一年我都一定能做到。但是我失去了一些重现性 - 其他人将无法轻松验证我在导入过程中没有犯错误。
有没有人看到更简单的方法来创建这个 data.frame?
那只是一个固定宽度的数据文件。我没有时间给你完美的代码,但调整一下应该可以满足你的需要:
url = 'http://www.bls.gov/lau/laucnty90.txt'
w = c(17, 8, 6, 50, 12, 13, 12, 11)
dat = read.fwf(url, w, skip=3)
需要 "ruler" 来确定要拆分的列:
cat(">",paste0(rep(c(1:9,"+"),14),collapse=""))
cat(">",paste0(sprintf("%08s0/",1:14),collapse=""))
> 123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+
cat(">",paste0(sprintf("%08s0/",1:14),collapse=""))
> 000000010/000000020/000000030/000000040/000000050/000000060/000000070/000000080/000000090/000000100/000000110/000000120/000000130/000000140/
# and paste in the first line of data
> CN0100100000000 01 001 Autauga County, AL 1990 16,875 15,853 1,022 6.1
这可以让你弄清楚在哪里放置拆分并取差值并移动一个值得到宽度。跳过前六行,然后将读入的数据处理为字符,以避免因素的麻烦。在强制转换为数字之前删除逗号。
> dat = read.fwf(url,
widths=diff(c(0,16,21,29,80,86,100,115,125,132)+1),
skip=6,colClasses="character")
> str(dat)
'data.frame': 3219 obs. of 9 variables:
$ V1: chr "CN0100100000000 " "CN0100300000000 " "CN0100500000000 " "CN0100700000000 " ...
$ V2: chr " 01 " " 01 " " 01 " " 01 " ...
$ V3: chr " 001 " " 003 " " 005 " " 007 " ...
$ V4: chr " Autauga County, AL " " Baldwin County, AL " " Barbour County, AL " " Bibb County, AL " ...
$ V5: chr " 1990 " " 1990 " " 1990 " " 1990 " ...
$ V6: chr " 16,875 " " 46,773 " " 11,458 " " 7,408 " ...
$ V7: chr " 15,853 " " 44,492 " " 10,619 " " 6,776 " ...
$ V8: chr " 1,022 " " 2,281 " " 839 " " 632 " ...
$ V9: chr " 6.1" " 4.9" " 7.3" " 8.5" ...
dat[6:8] <- lapply( dat[6:8],
function(col) as.numeric( gsub("[,]", "", col)) )
> str(dat)
'data.frame': 3219 obs. of 9 variables:
$ V1: chr "CN0100100000000 " "CN0100300000000 " "CN0100500000000 " "CN0100700000000 " ...
$ V2: chr " 01 " " 01 " " 01 " " 01 " ...
$ V3: chr " 001 " " 003 " " 005 " " 007 " ...
$ V4: chr " Autauga County, AL " " Baldwin County, AL " " Barbour County, AL " " Bibb County, AL " ...
$ V5: chr " 1990 " " 1990 " " 1990 " " 1990 " ...
$ V6: num 16875 46773 11458 7408 19130 ...
$ V7: num 15853 44492 10619 6776 18001 ...
$ V8: num 1022 2281 839 632 1129 ...
$ V9: chr " 6.1" " 4.9" " 7.3" " 8.5" ...
dat[[9]] <- as.numeric( dat[[9]])
这可能可以通过使用一些 "NULL"
来改善这是一个使用 XLConnect
包直接读取电子表格的选项,避免了所有这些计算列边界的业务。
get.file <- function(url) {
require(XLConnect)
download.file(url,"temp.xlsx",mode="wb")
wb <- loadWorkbook("temp.xlsx")
ws <- readWorksheet(wb,1,startRow=7,header=FALSE,drop=list(6))
ws[!is.na(ws$Col2),] # remove empty rows at the end
}
pfx <- "http://www.bls.gov/lau/laucnty"
urls <- paste0(pfx,c(90:99,formatC(0:13,width=2,flag=0)),".xlsx")
result <- do.call(rbind,lapply(urls,get.file))
head(result)
# Col1 Col2 Col3 Col4 Col5 Col7 Col8 Col9 Col10
# 1 CN0100100000000 01 001 Autauga County, AL 1990 16875 15853 1022 6.1
# 2 CN0100300000000 01 003 Baldwin County, AL 1990 46773 44492 2281 4.9
# 3 CN0100500000000 01 005 Barbour County, AL 1990 11458 10619 839 7.3
# 4 CN0100700000000 01 007 Bibb County, AL 1990 7408 6776 632 8.5
# 5 CN0100900000000 01 009 Blount County, AL 1990 19130 18001 1129 5.9
# 6 CN0101100000000 01 011 Bullock County, AL 1990 4381 3869 512 11.7
在 readWorksheet(...)
调用中,我们跳过前 7 行,因为它们包含 headers,并且我们删除第 6 列,因为它是空白的。然后我们删除结果中第 2 列中包含 NA
的任何行(最后几行是注释)。最后我们使用 lapply(...)
创建所有提取文件的列表,并使用 do.call(rbind,...)
将它们全部组合 row-wise.
注意所有的列都是字符。您还需要做一些清理工作。正如这些 multi-decade 数据集的典型情况一样,一些数据丢失并且 "missing" 的代码并不总是相同的(有时 "NA"
,有时 "N.A."
,等等)。