使用所有美国县的失业数据创建 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.fileread.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.",等等)。