В r, как вы можете прочитать X количество плоских файлов фиксированной ширины в Y фреймов данных на основе имени файла?

Итак, у меня есть 80 файлов в формате имени файла:

P.A3588.ACO.CCLF0.D00001.TO30000
P.A3588.ACO.CCLF0.D30001.TO60000
...
P.A3588.ACO.CCLF1.D30001.TO60000    
P.A3588.ACO.CCLF1.D30001.TO60000
...
P.A3588.ACO.CCLF9.D30001.TO60000    
P.A3588.ACO.CCLF9.D30001.TO60000

Существует 80 текстовых файлов фиксированной ширины: 8 частей для каждого из 10 номеров CCLF (CCLF0, CCLF1, ..., CCLF9). Я хочу иметь возможность группировать по номеру CCLF, применять вектор ширины столбца, добавлять имена столбцов и связывать строки частей CCLF.

Ниже то, что я пробовал до сих пор. Это не работает, но дает представление о том, что я пытаюсь сделать.

filenames <- list.files(dataPath)
names <- substr(filenames,13,17)

CCLF1_width <- c(13,6,11,2,10,10,1,1,7,7,2,17,1,2,2,4,1,10,10,10,10,10,2,10,10,10,11,2,2,1,1,1)
CCLF2_width <- c(13,10,11,2,10,10,4,10,5,11,6,10,10,24,17,2,2,2,2,2)
CCLF3_width <- c(13,11,2,2,7,10,11,6,10,10,1)
CCLF4_width <- c(13,11,2,1,2,7,11,6,10,10,7,1)
CCLF5_width <- c(13,10,11,2,10,10,3,2,2,1,2,10,10,5,15,1,7,10,10,2,2,2,10,10,40,11,17,24,2,2,2,2,2,2,7,7,7,7,7,7,7,7,1)
CCLF6_width <- c(13,10,11,2,10,10,1,2,10,10,5,15,1,10,10,2,2,2,10,10,40,11,17,2)
CCLF7_width <- c(13,11,11,2,10,2,20,1,1,24,9,2,20,13,2,10,10,12,9)
CCLF8_width <- c(11,2,3,5,10,1,1,3,2,2,10,10,10,30,15,40,1,1)
CCLF9_width <- c(11,11,10,10,12)
CCLF0_width <- c(11,11)

for (i in length(filenames)){
  assign(paste0(substr(filenames,13,17)),
  read_fwf(grepl("CCLF1",filenames),
  paste0(i,"_width")))
  }

person user3304359    schedule 12.09.2018    source источник
comment
не могли бы вы объяснить column width?   -  person Jimmy    schedule 12.09.2018
comment
пожалуйста, предоставьте также образец вывода   -  person Jimmy    schedule 12.09.2018
comment
Вместо текстового файла с разделителями столбцы разбиваются на определенное количество символов. Таким образом, в CCLF1_width первый столбец содержит 13 символов, второй столбец - 6 символов (позиции с 14 по 19), третий столбец содержит 11 символов (позиции с 20 по 31) и так далее.   -  person user3304359    schedule 12.09.2018
comment
Значит, вы имеете в виду, что в 8 файлах, содержащих CLF0, есть два столбца по 11 символов в каждом? Точно так же файлы CCLF9 имеют 5 столбцов с шириной символов 11, 11, 10, 10 и 12?   -  person ichbinallen    schedule 12.09.2018
comment
@ichbinallen, это правильно.   -  person user3304359    schedule 12.09.2018


Ответы (2)


Рассмотрим отображение через два списка одинаковой длины и поэлементно выполняем итерацию с Map (оболочка для mapply):

cclf_files <- paste0("CCLF", seq(0:9))

cclf_widths <- list(
  CCLF0_width = c(11,11)
  CCLF1_width = c(13,6,11,2,10,10,1,1,7,7,2,17,1,2,2,4,1,10,10,10,10,10,2,10,10,10,11,2,2,1,1,1)
  CCLF2_width = c(13,10,11,2,10,10,4,10,5,11,6,10,10,24,17,2,2,2,2,2)
  CCLF3_width = c(13,11,2,2,7,10,11,6,10,10,1)
  CCLF4_width = c(13,11,2,1,2,7,11,6,10,10,7,1)
  CCLF5_width = c(13,10,11,2,10,10,3,2,2,1,2,10,10,5,15,1,7,10,10,2,2,2,10,10,40,11,17,24,2,2,2,2,2,2,7,7,7,7,7,7,7,7,1)
  CCLF6_width = c(13,10,11,2,10,10,1,2,10,10,5,15,1,10,10,2,2,2,10,10,40,11,17,2)
  CCLF7_width = c(13,11,11,2,10,2,20,1,1,24,9,2,20,13,2,10,10,12,9)
  CCLF8_width = c(11,2,3,5,10,1,1,3,2,2,10,10,10,30,15,40,1,1)
  CCLF9_width = c(11,11,10,10,12)
)

proc_files <- function(f, w) {
    # RETRIEVE FILES WITH CURRENT CCF# IN NAME
    files <- list.files(path = "/path/to/cclf/files", pattern = f)
    print(files)

    # BUILD A LIST OF DFs FROM ALL FILES WITH CURRENT CCF#_width
    df_list <- lapply(files, function(x) {
                   tryCatch(read.fwf(x, widths=w), error = function(e) return(NA))
               })

    # ROW BIND ALL DFs TO FINAL FOR RETURN
    df <- do.call(rbind, df_list)
}

# BUILD A NAMED LIST OF DATA FRAMES FOR EACH CCLF#
df_list <- setNames(Map(proc_files, cclf_files, cclf_widths), cclf_files)

df_list$CCLF0
df_list$CCLF1
df_list$CCLF2
...
person Parfait    schedule 12.09.2018
comment
Спасибо! Я думаю, что это может сработать, но я получаю сообщение об ошибке, что мое использование стека C слишком близко к пределу. Некоторые из них представляют собой довольно большие файлы, поэтому мне, возможно, придется попробовать подмножество данных. Буду обновлять завтра. - person user3304359; 13.09.2018
comment
Это может быть моя ошибка. Для ccfl_files я использовал paste вместо paste0, чтобы избежать разделителя пробелов. Если проблема не исчезнет, ​​мы можем запустить tryCatch. - person Parfait; 13.09.2018
comment
Он определенно делает то, что я хочу, но из-за файлов возникают некоторые ошибки. Lapply не принял бы только w в качестве аргумента, поэтому изменил его на df_list ‹- lapply (files, function (x) read_fwf (x, fwf_widths (w))) Поскольку read_fwf использует тиббл, я должен использовать rbindlist из данных .table пакет вместо этого. Итак, внутри функции proc_files я изменил на df ‹- do.call (rbindlist, list (fill = TRUE), df_list) Когда я запускаю функцию, она начинает загружаться в файлы, но останавливается с ошибкой Ошибка в args‹ - lapply (args, enquote): аргумент не интерпретируется как логический, поэтому работаем над этим - person user3304359; 13.09.2018
comment
Что вы имеете в виду, lapply не примет w? В чем ошибка? С rbindlist вам не нужно do.call. Просто запустите его один раз rbindlist(df_list). Но чтобы оставаться в тидиверсе, используйте df <- dplyr::bind_rows(df_list). Я по ошибке забыл, что R имеет встроенный read.fwf (с точкой) vs. метод в readr (с подчеркиванием). Попробуйте использовать базовую функцию R, которая возвращает dfs, а не tibbles. Но из docs, я вижу, что функция readr действительно имеет аргумент widths. - person Parfait; 13.09.2018
comment
Я повторно запускаю его на подмножестве данных, используя стандартный read.fwf без tidyverse, просто он занимает намного больше времени и не показывает прогресса. Я получаю следующую ошибку: Ошибка в if (quote) args ‹- lapply (args, enquote): аргумент не интерпретируется как логический - person user3304359; 13.09.2018
comment
См. Обновление с tryCatch оболочкой и print файлов, чтобы узнать, какие файлы вызывают проблему. И чтобы do.call работал, colnames должен быть одинаковой и одинаковой длины. Насколько велики эти файлы? ГБ? Всего на 80 это не должно быть много времени. Я могу попросить показать образец файлов фиксированной ширины. - person Parfait; 13.09.2018
comment
Теперь появляется ошибка в is_closure (x): объектные файлы не найдены. Всего файлов около 1,8 ГБ. - person user3304359; 13.09.2018
comment
Ага! Файлы не считываются должным образом. Установлен ли в вашем текущем рабочем каталоге файлы CCLF? Отметьте getwd(). Если нет, передайте каталог в аргументе path list.files(). См. Редактировать. И снова, шаблон ищет ЛЮБОЙ файл в каталоге с CCLF # текущего цикла в его имени (все заглавные буквы). - person Parfait; 13.09.2018
comment
Я закончил тем, что все заработало! Думал, что обновил свой комментарий, но думаю, он не прошел. Я удалил функцию set_names вне функции proc_files, и она работала нормально. Спасибо за помощь! - person user3304359; 13.09.2018
comment
Большой! Рад, что это получилось. Фактически, вы все равно можете использовать setNames (без подчеркивания), но передать вектор символов, cclf_files, а не files. Трудно закодировать эти вещи без реальных данных! - person Parfait; 13.09.2018
comment
Ха-ха, вы точно справились! - person user3304359; 13.09.2018

Эту проблему можно решить с помощью цикла for и функции. Я написал функцию combine_fwf для объединения всех файлов фиксированной ширины с заданным номером CCLF в один фрейм данных. Строка list.files находит все файлы в текущем рабочем каталоге, содержащие CCLF, где - одно из ваших чисел (0-9). Затем используйте read.fwf, чтобы прочитать это имя файла в фрейм данных, cbind на номере CCLF и rbind на общем результате.

combine_fwf = function(CCLF_num, colwidths) {
  filenames = list.files(pattern = paste0("CCLF", CCLF_num))
  df_list = vector("list", length(filenames))
  for (i in 1:length(filenames)) {
   df_list[[i]] = cbind.data.frame(CCLF_num, read.fwf(filenames[[i]], 
                                   colwidths)) 
  }
  return(do.call(rbind, df_list))
}

combine_fwf(2, c(12,6))
>>  CCLF_num           V1     V2
1        2 adsfasdfadsf 123123
2        2 lkjhlkjhlkjh  98098
3        2 adsfasdfadsf 123123
4        2 lkjhlkjhlkjh  98098
5        2 adsfasdfadsf 123123
6        2 lkjhlkjhlkjh  98098
> combine_fwf(1, c(12,6))
  CCLF_num           V1     V2
1        1 adsfasdfadsf 123123
2        1 lkjhlkjhlkjh  98098
3        1 adsfasdfadsf 123123
4        1 lkjhlkjhlkjh  98098
5        1 adsfasdfadsf 123123
6        1 lkjhlkjhlkjh  98098
person ichbinallen    schedule 12.09.2018
comment
@Parfait, что ты делаешь вместо этого? - person ichbinallen; 12.09.2018