Как мне прочитать текстовый файл в R, когда каждая запись является абзацем, и некоторые записи имеют 4 поля, а другие 6 - PullRequest
7 голосов
/ 10 декабря 2011

Как можно читать в текстовом файле, в котором каждая запись является абзацем, а каждая новая строка обозначает отдельное поле. Сложность состоит в том, что некоторые записи имеют 4 строки, а некоторые - 6. @DWin прибил мои вопросы, когда разница в количестве полей была 1, но все это распалось, когда было два. Вы можете посмотреть его ответ здесь .

Итак, вот моя последняя симуляция начального текста

TheInstitute 5467
  telephone line 4125526987 x 4567
  datetime 2011110516 12:56
  blay blay blah who knows what, but anyway it may have a comma

TheInstitute 5467
  telephone line 4125526987 x 4567
  datetime 2011110516 12:58
  blay blay blah who knows what

TheInstitute 5467
  telephone line 412552999 x 4999
  bump phone line 4125527777
  bump pony pony oops 4125527777
  datetime 2011110516 12:59
  blay blay blah who knows what

TheInstitute 5467
  telephone line 4125526987 x 4567
  bump phone line 4125527777
  bump pony pony oops 4125527777
  datetime 2011110516 13:51
  blay blay blah who knows what, but anyway it may have a comma

TheInstitute 5467
  telephone line 4125526987 x 4567
  datetime 2011110516 14:56
  blay blay blah who knows what  

Вот как должен выглядеть вывод. На самом деле это один шаг от того, что мне нужно. Я помещаю текстовое представление ASCII R data.frame ниже. Вы увидите, что все находится во фрейме данных, но значения полей смещены на два столбца, поскольку некоторые записи имеют два дополнительных поля.

structure(list(institution = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "TheInstitute 5467", class = "factor"), 
    telephoneline = structure(c(1L, 1L, 2L, 1L, 1L), .Label = c("telephone line 4125526987 x 4567", 
    "telephone line 412552999 x 4999"), class = "factor"), date.or.bump = structure(c(2L, 
    3L, 1L, 1L, 4L), .Label = c("bump phone line 4125527777", 
    "datetime 2011110516 12:56", "datetime 2011110516 12:58", 
    "datetime 2011110516 14:56"), class = "factor"), field4 = structure(c(2L, 
    1L, 3L, 3L, 1L), .Label = c("blay blay blah who knows what", 
    "blay blay blah who knows what, but anyway it may have a comma", 
    "bump pony pony oops 4125527777"), class = "factor"), field5 = structure(c(1L, 
    1L, 2L, 3L, 1L), .Label = c("", "datetime 2011110516 12:59", 
    "datetime 2011110516 13:51"), class = "factor"), field6 = structure(c(1L, 
    1L, 2L, 3L, 1L), .Label = c("", "blay blay blah who knows what", 
    "blay blay blah who knows what, but anyway it may have a comma"
    ), class = "factor")), .Names = c("institution", "telephoneline", 
"date.or.bump", "field4", "field5", "field6"), class = "data.frame", row.names = c(NA, 
-5L))

PS: Правильно ли я считаю, что кто-то отправляет фрейм данных с помощью dput или можно сохранить директорию файла .Rdata здесь.

Ответы [ 3 ]

9 голосов
/ 10 декабря 2011

Возможно, есть более элегантный способ, но он должен выполнить работу.

x <- readLines("foo.txt")  # read data with readLines
nx <- !nchar(x)            # locate lines with only empty strings
# create a list (split by empty lines, with empty lines removed)
y <- split(x[!nx], cumsum(nx)[!nx])
# determine largest number of columns
maxLength <- max(sapply(y,length))
# pad each list element with empty strings
z <- lapply(y, function(x) c(x,rep("",maxLength-length(x))))
# create final matrix
out <- do.call(rbind, z)

Обновление:

Вот еще одно решение, использующее plyr::rbind.fill:

x <- readLines("foo.txt")  # read data with readLines
nx <- !nchar(x)            # locate lines with only empty strings
# create final data.frame
out <- rbind.fill(lapply(split(x[!nx], cumsum(nx)[!nx]),
                    function(x) data.frame(t(x))))
5 голосов
/ 10 декабря 2011

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

Затем можно использовать двараунды от strsplit до сначала пробивают записи, а затем пробивают поля в записях.(Записи будут разделены двумя последовательными EOL с, в то время как поля будут разделены одним EOL).

EOL <- "!@"  # (for instance)
x <- readLines("filename.R")
x <- paste(x, collapse=EOL)[[1]]

x <- strsplit(x, paste(EOL, EOL, sep=""))         # Split apart records
lapply(x, FUN=function(X) strsplit(X, EOL))[[1]]  # Split apart fields w/in records

Этот метод мне нравится, потому что он близок к тому, что я как делать, когда я вначале читаю файл (т. е. использовать "\n\n" в качестве символа sep), но не могу ничего сделать ни с scan, ни с readLines.

2 голосов
/ 10 декабря 2011

Чтение данных в. dat <- readLines ("filename.txt") </p>

Разделение данных по записям (на основе решения Джоша О'Брайена)

dat_rec <- lapply(strsplit(paste(dat,collapse="\n"),split="\n\n")[[1]],
                  function(x) strsplit(x,split="\n")[[1]])

Преобразовать данные в именованные векторы (предположим, что последним полем является комментарий, а данные начинаются с числового значения)

dat_rec_vn <- lapply(dat_rec,function(x) {
                           vn <- gsub(" ","_",sub("  ","",
                                        gsub("^(\\D*) \\d.*$","\\1", x[-length(x)])))
                           y <- gsub("^(\\D*) (\\d.*)$","\\2",x[-length(x)])
                           names(y) <- vn
                           return(y)})

Получить уникальные имена полей в данных.

 vn <- unique(unlist(lapply(dat_rec_vn,names),use.names=FALSE))

Объединить поле в матрицу и дать ему имена.

 dat_mat <- do.call(rbind,lapply(dat_rec_vn,function(x) {
                     y <- vector(mode="character",length=length(vn))
                     y[match(names(x),vn)] <- x
                     return(y)}))

colnames(dat_mat) <- vn

ВТОРОЙ раствор (с использованием gawk)

gawk_cmd <- "gawk 'BEGIN{FS=\"\\n\";RS=\"\";OFS=\"\\t\";ORS=\"\\n\"} 
                        {$1=$1; print $0}' test_multi.txt"
dat <- strsplit(system(gawk_cmd,intern=TRUE),split="\t")
NF <- do.call(max,lapply(dat,length))
M <- do.call(rbind,lapply(dat,"[",seq(NF)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...