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

У меня есть папка, которая содержит 1900 наборов данных (.dat), это данные о потреблении пищи за 1 день за 2012-2017 годы.Они называются в соответствии с датой следующим образом:

 FC-20120204.dat 
 FC-20120205.dat 
 FC-20120206.dat

В каждом наборе данных содержится 1500 столбцов (1500 переменных), 1440 строк (данные за 1 минуту).

Мои проблемы заключаются в следующем:

  1. Большая часть набора данных не завершена, т.е. только 899 строк, 1101 рядов
  2. Нет отметки даты / времени, поэтому она может сбивать с толку
  3. Мне нужнотолько данные из отметки времени и столбца 25-го числа.
  4. Предполагается, что эти данные являются непрерывными, поэтому я должен в конечном итоге связать их вместе.

Но сначала я решил, что мне нужно сделать:

  1. найти способ стандартизировать все наборы данных, содержащие ровно 1440 строк.

До сих пор я пробовал это из моего предыдущего вопроса в stackoverflow:

files<-list.files(pattern="FC")
result <- sapply(files, function(file) {
temp <- read.csv(file) # adjustments may be needed for headers, etc.
temp[,25]
})

это работало хорошо, пока внезапно не упала R Studio.Я думаю, это потому, что у меня есть 1900 наборов данных (весь набор данных составляет около 9 ГБ. ОЗУ моего компьютера составляет всего 8 ГБ).Так что функция list.files не применима, и я полагаю, что sapply и lapply также не применимы.

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

После этого я могу импортировать все 1900 новых файлов (на этот раз намного меньше столько два столбца) и соедините их вместе.

Или есть более простой способ сделать это?

Обновление: три набора данных можно загрузить здесь: https://drive.google.com/drive/folders/17Rq1Vx21VqZhwYKWl9HLWZzxoZh2mxIh?usp=sharing.наиболее важные данные - это столбец C.

или здесь https://www.dropbox.com/sh/q6c9w8kryn2by5z/AAD3rPnBgP5CyRy7E5eautJGa?dl=0

1 Ответ

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

Работа с данными большого размера ^ 1 может быть решена несколькими способами.

  1. Я был бы упущен, если бы не предложил ("правильную") базу данных SQL.
  2. Загрузка / обработка только небольшого фрагмента за раз, агрегирование только в конце.То есть, сделайте некоторые из того, что я упоминаю ниже, пытаясь сократить ваши «используемые в настоящее время данные» до одного дня или нескольких дней за один раз.
  3. Если вы можете загрузить все данные одновременноно просто не можете загрузить инкрементные фрагменты и работать с ними, не превышая объем памяти, а затем попробуйте следующую методику.

Образец данных

(Это создает файлы в вашей работекаталог.)

x1 <- read.csv(header=TRUE, stringsAsFactors=FALSE, text='
X1,X2,X3
10,07:00,30
11,07:01,31
12,07:02,32
13,07:03,33
15,07:05,35
16,07:06,36
18,07:08,38
19,07:09,39')
write.csv(x1, file="20120204.dat", row.names=FALSE)
x2 <- read.csv(header=TRUE, stringsAsFactors=FALSE, text='
X1,X2,X3
20,07:00,40
22,07:02,42
23,07:03,43
24,07:04,44
25,07:05,45
26,07:06,46')
write.csv(x1, file="20120205.dat", row.names=FALSE)

Если вы можете сделать это с двумя файлами, вы можете сделать это с двумя тысячами.В этом случае второй столбец - «время», исходя из вашего вопроса, что единственный способ определить дату / время - это имя файла и это поле.(Обратите внимание, что в процессе, приведенном ниже, merge установит ключ присоединения в качестве первого столбца, поэтому порядок изменится . Вы можете, конечно, усилить это.)


Работа

fnames <- list.files(pattern=".*\\.dat", full.names=TRUE)
first <- TRUE
times <- c("00:00", "23:59")
for (fn in fnames) {
  thisdate <- gsub(".*(20[0-9]{6}).dat", "\\1", fn)
  twotimes <- as.POSIXct(paste(thisdate, c("00:00", "23:59")), format = "%Y%m%d %H:%M")
  allminutes <- data.frame(X2 = seq(twotimes[1], twotimes[2], by="min"))
  dat <- read.csv(fn, stringsAsFactors=FALSE)
  dat$X2 <- as.POSIXct(paste(thisdate, dat$X2), format = "%Y%m%d %H:%M")
  dat <- merge(dat, allminutes, by="X2", all=TRUE)
  write.table(dat, "alldata.csv", append=!first,
              col.names=first, row.names=FALSE, sep=",", na="")
  first <- FALSE
  rm(dat)
  gc() # optional, if you really want/need to control memory management *now*
}

Шаг:

  1. times, twotimes и allminutes используются для заполнения data.frame такчто у вас всегда есть как минимум 1440 рядов.Я говорю «по крайней мере», потому что это гарантирует, что у вас будет одно вхождение в «00» секунд каждой минуты.Если у вас есть что-то еще, вам нужно временно создать столбец времени «0 секунд» в каждом кадре или какой-то другой метод, чтобы включить слияние.Если вы посмотрите на allminutes, вы увидите, что это 1440 строк, 1 столбец, и это все, но его нужно создавать для каждого дня.
  2. thisdate: я извлекаю датукомпонент из имени файла;шаблон может отличаться для вас, но должно быть достаточно ресурсов для его формирования на основе ваших имен файлов.
  3. as.POSIXct(...): объединение thisdate и поля времени (X2), создание истинной даты /объект времени (для замены строк времени).
  4. merge() эффективно добавит строку для пропущенных времен со значениями NA для всех остальных столбцов.
  5. write.table(..., append=!first, col.names=first, ...) добавляет данныедля CSV, включая только строку заголовка при первом проходе через цикл.
  6. rm(dat) и gc() вызывает сборку мусора, которая обычно удаляет dat из памяти.Как правило, это неэффективно, необязательно и иногда нежелательно, но в вашем случае это принудительная гарантия.Вполне возможно, что это будет работать (автоматически собирая неиспользуемые данные) без этого, не стесняйтесь тестировать и сообщать.

Допущения

  1. Вы можете справиться со всемиданных в памяти за один раз (возможно, с использованием data.table), только не с загрузкой и изменением всего этого несколько раз.
  2. Кстати: если у вас будет 9 ГБ данных без заполнения отсутствующихстрок, то вы только увеличите размер файла, и, следовательно, вы, скорее всего, никогда не сможете загрузить этот один файл в свой экземпляр компьютера объемом 8 ГБ. Этот ответ не бесполезен: теперь у вас есть один файл лучшего формата дляданные, которые затем могут быть импортированы в базу данных или аналогичную.

База данных?

Как я упоминал ранее, эти большие объемы данных для локального использования действительно требуют увеличения объема ОЗУ (много) или, возможно, более элегантно, использование базы данных.Можно использовать SQLite (через RSQLite) для локальной базы данных без сервера, поскольку они могут обрабатывать такие большие данные.Однако, в зависимости от вашего мастерства, нетрудно раскрутить один докер-контейнер с postgres, mariadb или даже mssql-server-linux.


^ 1: «большие данные» могут быть классифицированы на основе того, сколько вы можете сделать на своем компьютере;если вы не можете загрузить его с учетом вашей оперативной памяти и языка / инструмента, то он «большой» для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...