Чтение 40-гигабайтного CSV файла в R с использованием bigmemory
Название здесь довольно понятно, но я расскажу следующее. Некоторые из моих нынешних методов борьбы с этой проблемой основаны на решениях, представленных в этом вопросе. Тем не менее, я столкнулся с несколькими проблемами и ограничениями, поэтому мне было интересно, может ли кто-нибудь попытаться предпринять удар по этой проблеме. Я пытаюсь выяснить проблему, используя bigmemory, но у меня возникли трудности.
Существующие ограничения:
- Использование Linux-сервера с 16 ГБ оперативной памяти
- Размер 40 GB CSV
- Нет строк: 67,194,126,114
Проблемы
- Необходимо иметь возможность случайным образом отображать меньшие массивы данных (5-10 миллионов строк) из большой или матричной структуры данных.
- Нужно уметь удалять любую строку с одним экземпляром NULL при разборе в массив big.matrix или эквивалентную структуру данных.
Пока результаты не очень хорошие. Очевидно, что я что-то проваливаю или, может быть, просто недостаточно понимаю документацию bigmemory. Итак, я подумал, что попрошу здесь посмотреть, использовал ли кто-нибудь
Любые советы, советы по этой линии атаки и т.д.? Или я должен перейти на что-то еще? Я прошу прощения, если этот вопрос очень похож на предыдущий, но я думал, что масштабы данных были примерно в 20 раз больше, чем предыдущие. Спасибо!
Ответы
Ответ 1
Я не знаю о bigmemory
, но чтобы удовлетворить ваши проблемы, вам не нужно читать файл. Просто подключите некоторые bash/awk/sed/python/любую обработку, чтобы выполнить нужные шаги, т.е. выбрасывать строки NULL
и произвольно выбирать строки N
, а затем читать это.
Вот пример использования awk (если вы хотите, чтобы 100 случайных строк из файла имели 1M строк).
read.csv(pipe('awk -F, \'BEGIN{srand(); m = 100; length = 1000000;}
!/NULL/{if (rand() < m/(length - NR + 1)) {
print; m--;
if (m == 0) exit;
}}\' filename'
)) -> df
Для меня не было очевидно, что вы имели в виду под NULL
, поэтому я использовал буквальное понимание этого, но его должно легко изменить в соответствии с вашими потребностями.
Ответ 2
Это чисто R-решение проблемы выборки из большого текстового файла; он имеет дополнительную ценность для рисования случайной выборки ровно n. Он не слишком неэффективен, хотя строки анализируются символьными векторами, и это относительно медленно.
Начнем с сигнатуры функции, где мы предоставляем имя файла, размер образца, который мы хотим нарисовать, семя для генератора случайных чисел (чтобы мы могли воспроизвести нашу случайную выборку!), указав, есть строка заголовка, а затем функция "читателя", которую мы будем использовать для синтаксического анализа образца в объект, видимый R, включая дополнительные аргументы ...
, которые могут потребоваться для функции чтения
fsample <-
function(fname, n, seed, header=FALSE, ..., reader=read.csv)
{
Функция засекает генератор случайных чисел, открывает соединение и читает в (необязательной) строке заголовка
set.seed(seed)
con <- file(fname, open="r")
hdr <- if (header) {
readLines(con, 1L)
} else character()
Следующий шаг - прочитать в куске n строк, инициализируя счетчик общего количества просмотренных строк
buf <- readLines(con, n)
n_tot <- length(buf)
Продолжайте читать в кусках n строк, останавливаясь, когда нет дополнительного ввода
repeat {
txt <- readLines(con, n)
if ((n_txt <- length(txt)) == 0L)
break
Для каждого фрагмента нарисуйте образец строк n_keep
с количеством строк, пропорциональным доле всех строк в текущем фрагменте. Это обеспечивает равномерное выборку строк по файлу. Если строк нет, перейдите к следующему фрагменту.
n_tot <- n_tot + n_txt
n_keep <- rbinom(1, n_txt, n_txt / n_tot)
if (n_keep == 0L)
next
Выберите строки, которые нужно сохранить, и строки, которые нужно заменить, и обновите буфер
keep <- sample(n_txt, n_keep)
drop <- sample(n, n_keep)
buf[drop] <- txt[keep]
}
Когда ввод данных выполняется, мы анализируем результат с помощью считывателя и возвращаем результат
reader(textConnection(c(hdr, buf), header=header, ...)
}
Решение может быть сделано более эффективным, но немного сложнее, используя readBin
и поиск разрывов строк, как предложил Саймон Урбанек на R-devel список рассылки.
Здесь полное решение
fsample <-
function(fname, n, seed, header=FALSE, ..., reader = read.csv)
{
set.seed(seed)
con <- file(fname, open="r")
hdr <- if (header) {
readLines(con, 1L)
} else character()
buf <- readLines(con, n)
n_tot <- length(buf)
repeat {
txt <- readLines(con, n)
if ((n_txt <- length(txt)) == 0L)
break
n_tot <- n_tot + n_txt
n_keep <- rbinom(1, n_txt, n_txt / n_tot)
if (n_keep == 0L)
next
keep <- sample(n_txt, n_keep)
drop <- sample(n, n_keep)
buf[drop] <- txt[keep]
}
reader(textConnection(c(hdr, buf)), header=header, ...)
}