Чтение нескольких одинаковых столбцов в файле фиксированной ширины
Рассмотрим следующие несколько строк из файла.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)
Таким образом, вам никогда не придется читать одни и те же данные дважды.
Тем не менее, это кажется неуместным в вопросе, в котором даны файлы словарей, и вы не захотите вручную редактировать каждый из нескольких.