3

我正在尝试使用美国劳工统计局的所有美国县失业数据创建一个 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>标签中,我认为该工具的表格中没有足够的 HTML 结构。

然后我尝试了download.fileread.table。但同样,这些工具的数据格式似乎不正确 - 顶部和底部有多余的行,“分隔符”只是一个空格,当县名包含空格时,这会使 R 混淆。

归根结底,我只需要一个包含来自该文件的 3 条数据的 data.frame:州 FIPS 代码、县 FIPS 代码和失业率。

我现在在想,创建这个 data.frame 最简单的方法可能是下载 excel 文件,删除我不需要的列,删除顶部和底部的多余文本,导出为 CSV,然后阅读它进入 R。

我当然可以在这 14 年的每一年中做到这一点。但是我因此失去了一些可重复性 - 其他人将无法轻松验证我在导入过程中没有犯错。

有没有人看到更简单的方法来创建这个 data.frame?

4

3 回答 3

6

那只是一个固定宽度的数据文件。我没有时间给你完美的代码,但调整它应该会给你你需要的东西:

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)
于 2015-01-03T18:50:05.550 回答
3

这是一个使用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 行,因为它们包含标题,我们删除第 6 列,因为它是空白的。然后我们删除包含NA在第 2 列中的结果中的任何行(最后几行是注释)。最后,我们使用lapply(...)创建所有提取文件的列表,do.call(rbind,...)并将它们按行组合。

请注意,所有列都是字符。您仍然需要进行一些清理工作。与这些数十年数据集的典型情况一样,一些数据丢失了,“丢失”的代码并不总是相同的(有时"NA",有时"N.A.",等等)。

于 2015-01-04T01:33:10.097 回答
3

需要一个“标尺”来确定要拆分的列:

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”来改善

于 2015-01-03T19:15:21.663 回答