Подтвердить что ты не робот

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

Как читать большие данные с фиксированной шириной? Я прочитал этот вопрос и попробовал несколько советов, но все ответы предназначены для данных с разделителями (как .csv), и это не мое дело. Данные имеют 558 МБ, и я не знаю, сколько строк.

Я использую:

dados <- read.fwf('TS_MATRICULA_RS.txt', width=c(5, 13, 14, 3, 3, 5, 4, 6, 6, 6, 1, 1, 1, 4, 3, 2, 9, 3, 2, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 11, 9, 2, 3, 9, 3, 2, 9, 9, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1), stringsAsFactors=FALSE, comment.char='', 
    colClasses=c('integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'character', 'character', 'character',
    'integer', 'integer', 'character', 'integer', 'integer', 'character', 'integer', 'character', 'character', 'character', 'character', 'character', 'character',
    'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character',
    'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'integer',
    'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'character', 'integer', 'integer', 'character', 'character', 'character',
    'character', 'integer', 'character', 'character', 'character', 'character', 'character', 'character', 'character', 'character'), buffersize=180000)

Но для чтения данных требуется 30 минут (и подсчет...). Любые новые предложения?

4b9b3361

Ответ 1

Без подробностей о ваших данных трудно дать конкретный ответ, но вот несколько идей, которые помогут вам начать:

Во-первых, если вы находитесь в системе Unix, вы можете получить некоторую информацию о своем файле с помощью команды wc. Например, wc -l TS_MATRICULA_RS.txt расскажет вам, сколько строк в вашем файле и wc -l TS_MATRICULA_RS.txt сообщит длину самой длинной строки в вашем файле. Это может быть полезно знать. Аналогично, head и tail позволяют вам проверять первую и последнюю 10 строк вашего текстового файла.

Во-вторых, некоторые предложения: поскольку кажется, что вы знаете ширину каждого поля, я бы рекомендовал один из двух подходов.

Вариант 1: csvkit + ваш любимый метод для быстрого чтения больших данных

csvkit - это набор инструментов Python для работы с файлами CSV. Одним из инструментов является in2csv, который берет файл с фиксированной шириной в сочетании с файлом "schema" для создания надлежащего CSV, который может использоваться с другими программами.

Файл схемы сам по себе представляет собой файл CSV с тремя столбцами: (1) имя переменной, (2) начальную позицию и (3) ширину. Пример (из страницы in2csv man):

    column,start,length
    name,0,30 
    birthday,30,10 
    age,40,3

Как только вы создали этот файл, вы сможете использовать что-то вроде:

in2csv -f fixed -s path/to/schemafile.csv path/to/TS_MATRICULA_RS.txt > TS_MATRICULA_RS.csv

Оттуда я бы предложил посмотреть данные с fread на "data.table" или с помощью sqldf.

Вариант 2: sqldf с помощью substr

Использование sqldf в файле с большими значениями, как ваш, должно быть довольно быстрым, и вы получаете возможность указать, что именно вы хотите прочитать при использовании substr.

Опять же, это будет означать, что у вас есть доступ к файлу схемы, как описано выше. После того, как у вас есть файл схемы, вы можете сделать следующее:

temp <- read.csv("mySchemaFile.csv")

## Construct your "substr" command
GetMe <- paste("select", 
               paste("substr(V1, ", temp$start, ", ",
                     temp$length, ") `", temp$column, "`", 
                     sep = "", collapse = ", "), 
               "from fixed", sep = " ")

## Load "sqldf"
library(sqldf)

## Connect to your file
fixed <- file("TS_MATRICULA_RS.txt")
myDF <- sqldf(GetMe, file.format = list(sep = "_"))

Поскольку вы знаете ширину, вы можете пропустить генерацию файла схемы. Из ширины это всего лишь небольшая работа с cumsum. Вот базовый пример, основанный на первом примере из read.fwf:

ff <- tempfile()
cat(file = ff, "123456", "987654", sep = "\n")
read.fwf(ff, widths = c(1, 2, 3))

widths <- c(1, 2, 3)
length <- cumsum(widths)
start <- length - widths + 1
column <- paste("V", seq_along(length), sep = "")

GetMe <- paste("select", 
               paste("substr(V1, ", start, ", ",
                     widths, ") `", column, "`", 
                     sep = "", collapse = ", "), 
               "from fixed", sep = " ")

library(sqldf)

## Connect to your file
fixed <- file(ff)
myDF <- sqldf(GetMe, file.format = list(sep = "_"))
myDF
unlink(ff)

Ответ 2

Пакет LaF очень хорош при чтении файлов с фиксированной шириной очень быстро. Я использую его ежедневно для загрузки файлов +/- 100Mio записей с 30 столбцами (не так много столбцов символов, как у вас - в основном числовые данные и некоторые факторы). И это довольно быстро. Так вот что я буду делать.

library(LaF)
library(ffbase)
my.data.laf <- laf_open_fwf('TS_MATRICULA_RS.txt', 
                  column_widths=c(5, 13, 14, 3, 3, 5, 4, 6, 6, 6, 1, 1, 1, 4, 3, 2, 9, 3, 2, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 11, 9, 2, 3, 9, 3, 2, 9, 9, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1), stringsAsFactors=FALSE, comment.char='', 
                  column_types=c('integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'categorical', 'categorical', 'categorical',
                               'integer', 'integer', 'categorical', 'integer', 'integer', 'categorical', 'integer', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical',
                               'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical',
                               'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'integer',
                               'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'integer', 'categorical', 'integer', 'integer', 'categorical', 'categorical', 'categorical',
                               'categorical', 'integer', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical', 'categorical'))
my.data <- laf_to_ffdf(my.data.laf, nrows=1000000)
my.data.in.ram <- as.data.frame(my.data)

PS. Я начал использовать пакет LaF, потому что меня раздражало медленность read.fwf, и потому что код PL/SQL PostgreSQL, с которым я работал с первоначально разобравшим данные, становился проблемой для поддержки.

Ответ 3

Вот чистое R-решение, использующее новый пакет readr, созданный Хэдли Уикхэмом и командой RStudio, выпущенный в апреле 2015 года. Подробнее здесь. Код такой же простой, как и этот:

library(readr)

my.data.frame <- read_fwf('TS_MATRICULA_RS.txt',
                      fwf_widths(c(5, 13, 14, 3, 3, 5, 4, 6, 6, 6, 1, 1, 1, 4, 3, 2, 9, 3, 2, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 11, 9, 2, 3, 9, 3, 2, 9, 9, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1)),
                      progress = interactive())

Преимущества read_fwf{readr}

  • readr находится в LaF, но на удивление быстрее. Он показал метод fasted для чтения файлов фиксированной ширины в R
  • проще, чем альтернативы. например вам не нужно беспокоиться о column_types, потому что они будут вменены из первых 30 строк на входе.
  • Он содержит индикатор выполнения;)