4

考虑以下来自Stata .dct 文件的几行,该文件为 Stata 定义了如何读取这个固定宽度的 ASCII 文件(可以使用任何平台上的任何 ZIP 软件解压缩):

start             type                            varname width  description
_column(24)       long                               rfv1   %5f  Patient's Reason for Visit #1            
_column(29)       long                               rfv2   %5f  Patient's Reason for Visit #2             
_column(34)       long                               rfv3   %5f  Patient's Reason for Visit #3             
_column(24)       long                             rfv13d   %4f  Patient's Reason for Visit #1 - broad     
_column(29)       long                             rfv23d   %4f  Patient's Reason for Visit #2 - broad     
_column(34)       long                             rfv33d   %4f  Patient's Reason for Visit #3 - broad     

基本上,这个 ASCII 文件每一行中的第 24 到第 39 个字符如下所示:

AAAAaBBBBbCCCCc

第一个广义代码在哪里AAAA,出于同样原因的较窄代码是AAAAa,等等。

换句话说,由于代码本身具有层次结构,因此每行中的相同字符被读取两次以创建两个不同的变量。

read.fwf相比之下,它只接受一个widths参数,从而排除了这种类型的双重阅读。

scan有没有一种标准的方法来处理这个问题,而不是通过在整个文件中重新创建轮子并手动解析它?

(start, width)这里的背景是我正在编写一个函数来解析这些 .DCT 文件,采用 SAScii 的风格,如果我可以为每个变量指定对,而不仅仅是.DCT 文件,我的工作会简单得多widths

4

2 回答 2

6

我已经开始研究 .DCT 解析器,但失去了动力。我的预期使用场景实际上是简单地解析文件并创建一个csvkit 模式文件,以允许我使用 csvkit 将文件从固定宽度转换为 csv。为此,该软件包是成功的,但它非常未完善,并且仅经过了很少的测试。

需要注意的几个问题包括 (1) 并非所有 DCT 文件都有相同的列;(2) 一些 DCT 文件有隐含小数位的说明,我从来没有想出处理这些类型文件的方法。

您可以在此处找到有关该包的初始工作。

主要功能有:

  • dct.parser-- 做你所期望的。在前几行中有一个“预览”参数,可让您确定 DCT 文件是否包含您期望的所有列。
  • csvkit.schema-- 使用从 中提取的信息,创建一个 csv 文件,其中包含 csvkitdct.parser所需的相关列。in2csv
  • csvkit.fwf2csv-- 基本上是system对 csvkit 的调用。也可以在 R 之外完成。

对于您的特定示例,我使用以下方法成功阅读了它:

## The extracted data file and the DCT file are in my downloads directory
setwd("~/Downloads/") 
dct.parser("ed02.dct", preview=TRUE) ## It seems that everything is there
temp <- dct.parser("ed02.dct")       ## Can be used as a lookup table later

## The next line automatically creates a csv schema file in your 
##   working directory named, by default, "your-dct-filename.csv"
csvkit.schema(temp) 
csvkit.fwf2csv(datafile = "ED02", schema="ed02.dct.csv", output="ED02.csv")

## I haven't set up any mechanism to check on progress...
## Just check the directory and see when the file stops growing :)
ED02 <- read.csv("ED02.csv")

我打算研究(但从未做过)的另一个替代方法是使用paste构建substr命令,这些命令可用于sqldf读取列包含重叠数据的数据。请参阅此博客文章以获取入门示例。


更新:一个sqldf例子

如上所述,sqldf可以很好地利用dct.parser数据的输出和读入substr。以下是您将如何执行此操作的示例:

## The extracted data file and the DCT file are in my downloads directory
setwd("~/Downloads/") 
temp <- dct.parser("ed02.dct")       ## Can be used as a lookup table later

## Construct your "substr" command
GetMe <- paste("select", 
               paste("substr(V1, ", temp$StartPos, ", ",
                     temp$ColWidth, ") `", temp$ColName, "`", 
                     sep = "", collapse = ", "), 
               "from fixed", sep = " ")

## Load "sqldf"
library(sqldf)

fixed <- file("ED02")
ED02 <- sqldf(GetMe, file.format = list(sep = "_"))
dim(ED02)
# [1] 37337   260

可以看出,该sqldf行需要进行一些修改。特别是,由于sqldfuses read.csv.sql,它会将数据中的任何逗号字符视为分隔符。您可以将其更改为您在数据中不期望的内容。

于 2013-04-23T16:28:09.043 回答
1

这只是刚刚用 Stata 标记(感谢@Metrics),所以可能很多 Stata 爱好者都没有注意到。

从纯Stata的角度来看,读取每个5位变量似乎很简单long,然后通过例如提取前4位数字

. gen rvf13d = floor(rvf13/10) 

或将这些代码作为字符串读入,然后

. gen rvf13d = substr(rvf13, 1, 4) 

因此,您永远不需要两次读取相同的数据。

就是说,这似乎与问题无关,其中给出了字典文件,而您不想手动编辑几个文件中的每一个。

于 2013-08-22T08:02:37.030 回答