将 SAS sas7bdat 数据读入 R

Posted

技术标签:

【中文标题】将 SAS sas7bdat 数据读入 R【英文标题】:Read SAS sas7bdat data into R 【发布时间】:2015-07-12 11:06:40 【问题描述】:

R 有哪些选项可以将本机 SAS 格式 sas7bdat 的文件读入 R?

例如,NCES Common Core 包含以这种格式保存的大量数据文件的存储库。具体而言,让我们专注于尝试读取 1997-98 年来自 LEA Universe 的 this 文件,其中包含从 A 到 I 的所有州的实体的教育机构级人口统计数据。

这是来自 SAS 的数据预览:

将这些数据带入我的 R 环境的最简单方法是什么?我没有任何可用的 SAS 版本,也不愿意付费,所以简单地将其转换为 .csv 会很麻烦。

【问题讨论】:

当然,我已经用了好几年了,它们总是看起来很挑剔或缺少我需要的一些功能,而且有几个可供选择(并且不断出现更多),所以它会是很高兴有一个 wiki 来解决这样一个常见的问题。我几乎放弃了“读取 sas 数据集”包——我从来不知道如何让sas7bdat 应用格式,我只是再次尝试haven,它给了我一个错误。如果必须,我使用 Hmisc::sas.get 的包装器来读取 sas 数据集目录并返回数据帧列表,尽管它需要一个工作 sas,但它一直对我有用 @rawr 如果找到时间和文件的公开,请添加一个答案来举例说明haven 的不足之处:) 在这种情况下,虽然Hmisc 需要一个工作的 SAS,但知道替代方案是有帮助的. haven 可以很好地读取文件。我还需要这些格式,因为我从 sas 获得的大量数据基本上没有格式化。当haven 没有给我一个模糊的错误时,它并没有真正应用这些格式——只将它们保留为需要little more user legwork 的属性——不多,不难,但有错误的余地。 Hmisc::sas.get(和我使用的包装器 fn)在 sas 中完成所有这些(可选)并返回格式化的数据帧 我遇到的另一个问题是,如果您尝试使用在 windows 上的 unix/linux 上创建的目录(反之亦然),您会遇到更多错误。但是,如果您有 proc 格式代码,则可以使用 sas 创建平台原生的格式目录。由于have需要目录,如果你只有proc格式的代码,你似乎是SOL 【参考方案1】:

sas7bdat 除了我正在查看的文件之一(特别是this one)外,其他所有文件都可以正常工作;在向sas7bdat 开发人员 Matthew Shotwell 报告错误时,他还指出了 Hadley 在 R 中的 haven 包的方向,该包也有一个 read_sas 方法。

这种方法优越有两个原因:

1) 读取上述链接文件没有任何问题 2) 它比read.sas7bdatmuch(我说的是much)。这是一个快速基准测试(在this 文件上,比其他文件小)作为证据:

microbenchmark(times=10L,
               read.sas7bdat("psu97ai.sas7bdat"),
               read_sas("psu97ai.sas7bdat"))

Unit: milliseconds
                              expr        min         lq       mean     median         uq        max neval cld
 read.sas7bdat("psu97ai.sas7bdat") 66696.2955 67587.7061 71939.7025 68331.9600 77225.1979 82836.8152    10   b
      read_sas("psu97ai.sas7bdat")   397.9955   402.2627   410.4015   408.5038   418.1059   425.2762    10  a 

没错——haven::read_sassas7bdat::read.sas7bdat 花费(平均)99.5% 的时间

小更新

我之前无法弄清楚这两种方法是否产生相同的数据(即,两者在读取数据方面具有相同的保真度),但最终做到了:

# Keep as data.tables
sas7bdat <- setDT(read.sas7bdat("psu97ai.sas7bdat"))
haven <- setDT(read_sas("psu97ai.sas7bdat"))

# read.sas7bdat prefers strings as factors,
#   and as of now has no stringsAsFactors argument
#   with which to prevent this
idj_factor <- sapply(haven, is.factor)

# Reset all factor columns as characters
sas7bdat[ , (idj_factor) := lapply(.SD, as.character), .SDcols = idj_factor]

# Check equality of the tables
all.equal(sas7bdat, haven, check.attributes = FALSE)
# [1] TRUE

但是,请注意read.sas7bdat 为该文件保留了大量属性列表,可能是 SAS 保留的:

str(sas7bdat)
# ...
# - attr(*, "column.info")=List of 70
#   ..$ :List of 12
#   .. ..$ name  : chr "NCESSCH"
#   .. ..$ offset: int 200
#   .. ..$ length: int 12
#   .. ..$ type  : chr "character"
#   .. ..$ format: chr "$"
#   .. ..$ fhdr  : int 0
#   .. ..$ foff  : int 76
#   .. ..$ flen  : int 1
#   .. ..$ label : chr "UNIQUE SCHOOL ID (NCES ASSIGNED)"
#   .. ..$ lhdr  : int 0
#   .. ..$ loff  : int 44
#   .. ..$ llen  : int 32
# ...

所以,如果您有任何机会需要这些属性(例如,我知道有些人特别热衷于labels),也许read.sas7bdat 是您的选择.

【讨论】:

haven (v. 2.1.1) 似乎保留了“标签”属性。来自?haven::read_sas“变量标签存储在每个变量的“标签”属性中。它不会打印在控制台上,但RStudio查看器会显示它。”【参考方案2】:

从 2018 年 1 月 18 日起,haven R 库会将 sas 和 stata 数据集加载到 R 环境中。在 R 中,简单地说:

library(haven)
data <- read_sas("C:/temp/mysasdataset.sas7bdat")
View(data)

您还可以在 R Studio 中手动加载数据。在环境窗格中,选择

导入数据集 > 从 SAS...

选择文件位置并点击“导入”

【讨论】:

您能否说明一下 2018 年的新情况?我在下面的答案中广泛介绍了 read_sas。如果您认为需要澄清,请随时编辑该回复,因为它是一个社区 wiki。【参考方案3】:

问题

问题似乎是您尝试使用的文件格式不正确。具体来说,空白单元格没有编码(R 使用NA),而只是留空。当尝试加载制表符分隔的文件时,这会给 R 带来问题,它认为列数不正确。

使用 SAS 文件的解决方法

我找到了一种解决方法,即使用 sas7bdat 包加载 SAS 文件,然后将空白单元格 ("") 重新编码为 NA:

install.packages("sas7bdat")
require("sas7bdat")
download.file("http://nces.ed.gov/ccd/Data/zip/ag121a_supp_sas.zip",
              destfile = "sas.zip")
unzip("sas.zip")
sas <- read.sas7bdat(file = "ag121a_supp.sas7bdat", debug = FALSE)
sas[sas == ""] <- NA

不过,这种方法有两个问题需要注意:

    速度很慢(参见 cmets) sas7bdat 包目前在作者撰写本文时被认为是实验性的。因此它可能不会加载所有 sas 文件,我会在使用前彻底检查它所做的不一致。

非 R 解决方案

它并不完全规范,但您也可以下载制表符分隔的文件,在 LibreOffice Calc 中打开它们(Microsoft Excel 似乎搞砸了),然后通过搜索 "" 并替换为 @987654328 来查找和替换所有文件@。

【讨论】:

这当然有效;你觉得它非常慢吗?读取一个文件大约需要 3 分钟——在 data.table 用户的 18,000 行中基本上闻所未闻!好的部分是,我只需要加载它们一次,就可以将它们从 R 保存到 csv 我确实发现它很慢,是的。此外,一旦输入,我会仔细检查数据帧,因为sas7bdat 在撰写此评论时被其作者认为是实验性的。但是,如果它有效... 再次听到Shotwell教授的消息,他指出haven基本上是C端口到R包,而sas7bdat完全写在R中,解释了呆滞。 就您的非 R 解决方案而言:非常好,您可以在命令行中使用 localc,加上 sed,无需 gui 即可实现相同的结果。【参考方案4】:

另一个选择可能是我的readsas 包。语法类似于foreign 包中的一个和 read-series 中的其他包。导入的数据以带有属性的data.frame() 形式返回。该软件包是从头开始编写的,并且具有对未压缩和压缩 sas7bdat 文件的读取支持。

尽管经过大量测试,该软件包仍处于早期开发阶段。

library(readsas)
dat <- read.sas("psu97ai.sas7bdat")

【讨论】:

以上是关于将 SAS sas7bdat 数据读入 R的主要内容,如果未能解决你的问题,请参考以下文章

在读取SAS文件时,Pandas以正确的数据类型失败

有啥方法可以尝试使用 JAVA 读取后缀为“.sas7bdat”、“.dta”、“.sav”和“.xpt”的文件?

SAS笔记 PDV与数据读入

R读取含多位数的数据

将数据读入 SAS,列未对齐

将SAS读入文件转换为SQL