Как заставить R читать несколько таблиц в одном текстовом файле, когда в первой таблице меньше столбцов, чем в других таблицах - PullRequest
0 голосов
/ 26 апреля 2018

Набор данных, который мне дали, огромен, поэтому я сделал выборку.

text    bool
H1  H2
exTable1    0
text    num num text
HEAD1   HEAD2   HEAD3   HEAD4
exTable2    098 987 exText1
text    bool    text
HEADER1 HEADER2 HEADER3
exTable3    1   exText2

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

table1 <- read.table("tables.txt", sep="\t", skip=1, header=TRUE)

Я получил эту ошибку:

Error in read.table("tables.txt", sep = "\t",  : 
more columns than column names

Именно тогда обратите внимание, что было несколько таблиц и в первой таблице меньше столбцов, чем в остальных.

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

Хорошо, я справился, так как заметил 3 вещи: (1) первый столбец описывает, что содержит каждая строка; (2) первая строка каждой таблицы описывает, что содержит каждый столбец этой таблицы и начинается со слова TYPE; и (3) строка после каждой таблицы содержит только * в первом столбце, за исключением последней таблицы, которая не имеет ничего после нее. Я добавил строку в конце с *, чтобы каждая таблица следовала одному и тому же шаблону, и поэтому я мог получить правильные индексы.

Код обходного пути, измененный для набора тестовых данных (он дает те же результаты):

#Step 1: Read full data set

tables.df <- read.table("tablesTest2SampleDataSet.txt", header=FALSE, fill = TRUE, stringsAsFactors = FALSE)

#Append a row that starts with an * to the end of the file

tables.df <- rbind(tables.df, c("*"))

#Step 2: Establish identifier for the start and ending of each table in the data set

#Gets row names of the rows that start with the name TYPE

typeRows <- which(tables.df$V1 == "TYPE")

#Gets row names of the rows that start with *

starRows <- which(tables.df$V1 == "*")

#Gets column names of the slots in the TYPE rows that are empty
#Therefore i can use the first item in each of these to get the last column with data

for (i in 1:length(typeRows))
{
  assign(paste("emptyColumnsT", i, sep = ""), which(tables.df[typeRows[i],] == ""))
}

#Step 3: Create the tables

for (i in 1:length(typeRows))#One table per typeRows value
{
  if(length(get(paste("emptyColumnsT", i, sep = ""))) == 0)
  {
    #New frame with length = to original and height = to space between typeRows 
    #and starRows/end of file.

    istar <- starRows[i]-1 

    #If I use starRows[i]-1 instead of istar in the 
    #statement below it doesn't divide the table properly

    assign(paste("tables.df_table", i, sep = ""), tables.df[c(typeRows[i]:
        istar),c(1:length(tables.df))])        
  }else
  {
    #New frame with length = one slot prior to the first value of each emptyColumnT 
    #and height = to space between typeRows and starRows/end of file.

    istar <- starRows[i]-1 

    #If I use starRows[i]-1 instead of istar in the 
    #statement below it doesn't divide the table properly

    assign(paste("tables.df_table", i, sep = ""), tables.df[c(typeRows[i]:
        istar),c(1:get(paste("emptyColumnsT", i, sep = ""))[1]-1)])
  }
}

Вот пример набора данных, который я использовал для этого теста:

TYPE    text    bool    num num
HEADERS HEAD1   HEAD2   HEAD3   HEAD4
DATA    abcd    1   123 456
*
TYPE    text    num num num num num num num num bool
HEADERS2    HT1 HN1 HN2 HN3 HN4 HN5 HN6 HN7 HN8 HB
DATA    efgh    789 098 765 432 112 358 132 134 0
*
TYPE    text    text    text    num num num
HEADERS3    H1  H2  H3  H4  H5  H6
DATA    ijkl    mnop    qrst    558 914 400

В конце я хочу разделить файл на столько таблиц, сколько в нем содержится; в этом случае 3. Строки каждой из таблиц должны начинаться в строке ТИПА и заканчиваться строкой перед строкой *. Что касается столбца, у каждого не должно быть пустых слотов в конце. Поэтому все 3 таблицы в этом тесте имеют разную длину.

0 голосов
/ 26 апреля 2018

Решение не так тривиально.

ШАГ 1 Прочитать весь файл tables.txt, используя readLines

con <- file("tables.txt", "r")
tables<-readLines(con)
close(con)

ШАГ 2 Очистите его, используя специальную функцию

clean<-function(row)
{
  out<-unlist(strsplit(row,split=" "))
  return(out[nchar(out)>0])
}

tables_cleaned<-lapply(tables,clean)

ШАГ 3 Найти строки, которые идентифицируют типы переменных и соответственно разные таблицы в файле

find_header<-function(row,possible_types)
{
  return(as.logical(min(row %in% possible_types)))
}

possible_types<-c("text","num","bool")
is_header<-unlist(lapply(tables_cleaned,find_header,possible_types=possible_types))

n_files<-which(is_header==1

)

ШАГ 4 Используя эту информацию, загрузите шаг за шагом каждую таблицу

tab<-NULL
for (i in 1:length(n_files))
{
  con <- file("tables.txt", "r")
  if(i<length(n_files))
  {
    tab[[i]]<-read.table(con,skip=n_files[i],nrow=(n_files[i+1]-n_files[i])-2, sep="\t", header=TRUE)
  } else
  {
    tab[[i]]<-read.table(con,skip=n_files[i],nrow=length(tables), sep="\t", header=TRUE)
  }
    close(con)
}

ВЫХОД

tab
[[1]]
         H1 H2
1 exTable11  0

[[2]]
     HEAD1 HEAD2 HEAD3   HEAD4
1 exTable2    98   987 exText1

[[3]]
   HEADER1 HEADER2 HEADER3
1 exTable3       1 exText2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...