Чтение нескольких одинаковых столбцов в файле фиксированной ширины

Рассмотрим следующие несколько строк из файла.dct Stata, который определяет для 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     

В основном, символы с 24 по 39 в каждой строке этого файла ASCII выглядят так:

AAAAaBBBBbCCCCc

Где первый широкий код AAAAболее узкий код по той же причине AAAAa, так далее.

Другими словами, поскольку сами коды имеют иерархическую структуру, одни и те же символы в каждой строке читаются дважды, чтобы создать две разные переменные.

read.fwfнапротив, просто занимает widths аргумент, который исключает этот тип двойного чтения.

Есть ли стандартный способ справиться с этим, не воссоздавая колесо с нуля scanпоиск во всем файле и анализ его вручную?

Основой здесь является то, что я пишу функцию для анализа этих файлов.DCT в стиле SAScii, и моя работа была бы намного проще, если бы я мог указать (start, width) пары для каждой переменной, а не просто widths,

2 ответа

Я начал работать с парсером.DCT, но потерял пар. Мой предполагаемый сценарий использования состоял в том, чтобы фактически просто проанализировать файл и создать файл схемы csvkit, чтобы позволить мне использовать csvkit для преобразования файла с фиксированной ширины в csv. С этой целью пакет был успешным, но он очень не уточнен и только очень минимально протестирован.

Пара проблем, на которые стоит обратить внимание: (1) не все файлы DCT имеют одинаковые столбцы; (2) некоторые файлы DCT содержат инструкции для неявных десятичных разрядов, и я так и не смог придумать метод для работы с этими типами файлов.

Начальную работу над пакетом вы можете найти здесь.

Основными функциями являются:

  • dct.parser - Делает то, что вы ожидаете. Существует аргумент "Предварительный просмотр", который читает в первых нескольких строках, чтобы определить, есть ли в файле DCT все ожидаемые столбцы или нет.
  • csvkit.schema - Используя информацию, извлеченную из dct.parser создается CSV-файл с соответствующими столбцами, необходимыми для in2csv из csvkit.
  • 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 читать в данных, где столбцы содержат перекрывающиеся данные. Посмотрите этот пост в блоге для примера, чтобы начать.


Обновление: An 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 линия. В частности, так как sqldf использования read.csv.sql, он видел любые символы запятой в ваших данных в качестве разделителя. Вы можете просто изменить это на то, чего вы не ожидаете в данных.

Это было только отмечено тегом Stata (благодаря @Metrics), поэтому многие энтузиасты Stata могли его не заметить.

С чистой точки зрения Stata это кажется достаточно простым, чтобы прочитать в каждой 5-значный long переменная, а затем извлечь первые 4 цифры, например,

. gen rvf13d = floor(rvf13/10) 

или читать в этих кодах как строку, а затем

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

Таким образом, вам никогда не придется читать одни и те же данные дважды.

Тем не менее, это кажется неуместным в вопросе, в котором даны файлы словарей, и вы не захотите вручную редактировать каждый из нескольких.

Другие вопросы по тегам