Какие приемы люди используют для управления доступной памятью интерактивного сеанса R? Я использую функции ниже [основанные на сообщениях Петра Пикала и Дэвида Хиндса в список r-help в 2004 году], чтобы перечислять (и / или сортировать) самые большие объекты и rm()
иногда некоторые из них. Но, безусловно, наиболее эффективным решением было ... работать под 64-битным Linux с достаточным объемом памяти.
Любые другие хорошие уловки люди хотят поделиться? Один на пост, пожалуйста.
# improved list of objects
.ls.objects <- function (pos = 1, pattern, order.by,
decreasing=FALSE, head=FALSE, n=5) {
napply <- function(names, fn) sapply(names, function(x)
fn(get(x, pos = pos)))
names <- ls(pos = pos, pattern = pattern)
obj.class <- napply(names, function(x) as.character(class(x))[1])
obj.mode <- napply(names, mode)
obj.type <- ifelse(is.na(obj.class), obj.mode, obj.class)
obj.size <- napply(names, object.size)
obj.dim <- t(napply(names, function(x)
as.numeric(dim(x))[1:2]))
vec <- is.na(obj.dim)[, 1] & (obj.type != "function")
obj.dim[vec, 1] <- napply(names, length)[vec]
out <- data.frame(obj.type, obj.size, obj.dim)
names(out) <- c("Type", "Size", "Rows", "Columns")
if (!missing(order.by))
out <- out[order(out[[order.by]], decreasing=decreasing), ]
if (head)
out <- head(out, n)
out
}
# shorthand
lsos <- function(..., n=10) {
.ls.objects(..., order.by="Size", decreasing=TRUE, head=TRUE, n=n)
}
memory-management
r
Дирк Эддельбюттель
источник
источник
multilevelPSA
пакет . Пакет предназначен для чего-то другого, но вы можете использовать функцию оттуда, не загружая пакет, говоряrequireNamespace(multilevelPSA); multilevelPSA::lsos(...)
. Или вDmisc
упаковке (не на CRAN).Ответы:
Убедитесь, что вы записали свою работу в воспроизводимом сценарии. Время от времени снова открывайте R, затем
source()
ваш скрипт. Вы удалите все, что больше не используете, и в качестве дополнительного преимущества протестируете ваш код.источник
1-load.r
,2-explore.r
,3-model.r
- таким образом , это очевидно для других , что есть какой - то порядок присутствует.Я использую пакет data.table . С его
:=
оператором вы можете:Ни одна из этих операций
data.table
вообще не копирует (потенциально большие) , даже один раз.data.table
использует гораздо меньше рабочей памяти.Ссылки по теме :
:=
оператор в data.table?источник
Видел это в твиттере и думаю, что это потрясающая функция от Дирка! Исходя из ответа JD Long, я бы сделал это для удобного чтения:
Что приводит к чему-то вроде следующего:
ПРИМЕЧАНИЕ: Основная часть, которую я добавил, была (опять же, адаптирована из ответа JD):
источник
capture.output
больше не нужно, иobj.prettysize <- napply(names, function(x) {format(utils::object.size(x), units = "auto") })
выдает чистый результат. Фактически, не удаляя его, вы получите нежелательные кавычки в выводе, то есть[1] "792.5 Mb"
вместо792.5 Mb
.obj.class <- napply(names, function(x) as.character(class(x))[1])
на,obj.class <- napply(names, function(x) class(x)[1])
такclass
как теперь всегда возвращаю вектор символов (base-3.5.0).Я активно использую
subset
параметр с выбором только обязательных переменных при передаче фреймов данных вdata=
аргумент функций регрессии. Это приводит к некоторым ошибкам, если я забываю добавлять переменные как в формулу, так и вselect=
вектор, но это все же экономит много времени из-за уменьшенного копирования объектов и значительно уменьшает объем памяти. Скажем, у меня есть 4 миллиона записей со 110 переменными (и я делаю.) Пример:Посредством установки контекста и стратегии:
gdlab2
переменная представляет собой логический вектор, который был сконструирован для субъектов в наборе данных, который имел все нормальные или почти нормальные значения для группы лабораторных тестов иHIVfinal
представлял собой вектор символов, который суммировал предварительное и подтверждающее тестирование на ВИЧ ,источник
Мне нравится сценарий Дирка .ls.objects (), но я продолжал щуриться, чтобы подсчитать количество символов в столбце размера. Поэтому я сделал несколько уродливых хаков, чтобы сделать это с красивым форматированием для размера:
источник
Это хороший трюк.
Еще одно предложение состоит в том, чтобы по возможности использовать объекты с эффективным использованием памяти: например, использовать матрицу вместо data.frame.
На самом деле это не относится к управлению памятью, но одна важная функция, которая широко не известна, - memory.limit (). Вы можете увеличить значение по умолчанию с помощью этой команды memory.limit (size = 2500), где размер указан в МБ. Как упоминал Дирк, вам нужно использовать 64-битную версию, чтобы воспользоваться этим преимуществом.
источник
Мне очень нравится улучшенная функция объектов, разработанная Дирком. Хотя в большинстве случаев мне достаточно более простого вывода с именем и размером объекта. Вот более простая функция с аналогичной целью. Использование памяти может быть упорядочено по алфавиту или по размеру, может быть ограничено определенным количеством объектов и может быть упорядочено по возрастанию или по убыванию. Кроме того, я часто работаю с данными размером более 1 ГБ, поэтому функция соответствующим образом меняет единицы измерения.
И вот пример вывода:
источник
Я никогда не сохраняю рабочее пространство R. Я использую сценарии импорта и сценарии данных и выводю любые особенно большие объекты данных, которые я не хочу часто воссоздавать, в файлы. Таким образом, я всегда начинаю со свежего рабочего пространства и мне не нужно убирать большие объекты. Это очень хорошая функция.
источник
К сожалению, у меня не было времени тщательно его протестировать, но вот совет по памяти, которого я раньше не видел. Для меня требуемая память была уменьшена более чем на 50%. Когда вы читаете вещи в R, например, с помощью read.csv, они требуют определенного объема памяти. После этого вы можете сохранить их с помощью.
save("Destinationfile",list=ls())
В следующий раз, когда вы откроете R, вы можете использоватьload("Destinationfile")
Теперь использование памяти могло уменьшиться. Было бы хорошо, если бы кто-нибудь мог подтвердить, дает ли это аналогичные результаты с другим набором данных.источник
fread
, а затем сохранены в .RData. Файлы RData действительно были примерно на 70% меньше, но после перезагрузки используемая память была точно такой же. Хотелось надеяться, что этот трюк уменьшит объем памяти ... я что-то упустил?Чтобы дополнительно проиллюстрировать общую стратегию частых перезапусков, мы можем использовать littler, который позволяет нам запускать простые выражения непосредственно из командной строки. Вот пример, который я иногда использую для определения времени различных BLAS для простого кросс-процесса.
Точно так же,
загружает пакет Matrix (через ключ --packages | -l) и запускает примеры функции spMatrix. Поскольку r всегда запускается «заново», этот метод также является хорошим тестом при разработке пакета.
И последнее, но не менее важное: r также прекрасно работает для автоматического пакетного режима в сценариях, использующих заголовок shebang '#! / Usr / bin / r'. Rscript - это альтернатива, где littler недоступен (например, в Windows).
источник
И с точки зрения скорости, и с точки зрения памяти, при построении большого фрейма данных с помощью некоторой сложной серии шагов я буду периодически сбрасывать его (создаваемый набор данных) на диск, добавлять все, что было до, и затем перезагружать его. , Таким образом, промежуточные шаги работают только с небольшими фреймами данных (что хорошо, например, если rbind значительно замедляется с большими объектами). Весь набор данных может быть считан обратно в конце процесса, когда все промежуточные объекты были удалены.
источник
Просто отметим, что
data.table
пакет,tables()
кажется, является довольно хорошей заменой.ls.objects()
пользовательской функции Дирка (подробно описано в предыдущих ответах), хотя только для data.frames / таблиц, а не, например, для матриц, массивов, списков.источник
Мне повезло, и мои большие наборы данных сохраняются прибором в виде «кусков» (подмножеств) размером примерно 100 МБ (32-разрядный двоичный код). Таким образом, я могу последовательно выполнить этапы предварительной обработки (удаление неинформативных частей, уменьшение частоты дискретизации) перед объединением набора данных.
Вызов
gc ()
«вручную» может помочь, если размер данных приблизится к доступной памяти.Иногда другому алгоритму требуется гораздо меньше памяти.
Иногда есть компромисс между векторизацией и использованием памяти.
сравните:
split
&lapply
противfor
цикла.Для быстрого и легкого анализа данных я часто сначала работаю с небольшим случайным подмножеством (
sample ()
) данных. После того, как скрипт анализа данных / .Rnw закончил, код анализа данных и полные данные отправляются на сервер вычислений для расчета в течение ночи / за выходные / ....источник
Использование сред вместо списков для обработки коллекций объектов, занимающих значительный объем рабочей памяти.
Причина: каждый раз, когда
list
изменяется элемент структуры, весь список временно дублируется. Это становится проблемой, если требования к хранилищу списка составляют примерно половину доступной рабочей памяти, потому что тогда данные должны быть перенесены на медленный жесткий диск. Среды, с другой стороны, не подвержены такому поведению и могут рассматриваться как списки.Вот пример:
В сочетании со структурами, такими как
big.matrix
илиdata.table
которые позволяют изменять их содержимое на месте, может быть достигнуто очень эффективное использование памяти.источник
ll
Функция вgData
пакете может показать использование памяти каждого объекта , а также.источник
Если вы действительно хотите избежать утечек, вам следует избегать создания больших объектов в глобальной среде.
Обычно я использую функцию, которая выполняет работу и возвращает ее
NULL
- все данные читаются и обрабатываются в этой или других функциях, которые она вызывает.источник
Только с 4 ГБ ОЗУ (под управлением Windows 10, так что примерно 2 или более реально 1 ГБ) я должен был быть очень осторожным с распределением.
Я использую data.table почти исключительно.
Функция 'fread' позволяет вам импортировать информацию по именам полей при импорте; импортируйте только те поля, которые действительно нужны для начала. Если вы используете базовое чтение R, обнуляйте ложные столбцы сразу после импорта.
Как следует из 42- , когда это возможно, я буду размещать их в столбцах сразу после импорта информации.
Я часто rm () объекты из среды, как только они больше не нужны, например, на следующей строке после использования их для поднабора чего-то еще, и вызываю gc ().
'fread' и 'fwrite' из data.table могут быть очень быстрыми по сравнению с основанием R для чтения и записи.
Как kpierce8 подсказывает , я почти всегда пишу все из окружения и копирую его обратно, даже с тысячами / сотнями тысяч крошечных файлов, через которые можно пройти. Это не только обеспечивает чистоту среды и низкое распределение памяти, но, возможно, из-за серьезного недостатка доступной оперативной памяти, R имеет склонность к частым сбоям на моем компьютере; действительно часто. Резервное копирование информации на сам диск по мере прохождения кода на разных этапах означает, что мне не нужно начинать с самого начала, если он падает.
Начиная с 2017 года, я думаю, что самые быстрые твердотельные накопители работают со скоростью несколько ГБ в секунду через порт M2. У меня действительно базовый SSD-накопитель Kingston V300 (550 МБ / с) емкостью 50 ГБ, который я использую в качестве основного (на нем установлены Windows и R). Я храню всю основную информацию на дешевом 500-гигабайтном диске WD. Я перемещаю наборы данных в SSD, когда начинаю над ними работать. Это, в сочетании с «fread» и «fwrite» все работало замечательно. Я пытался использовать 'FF', но предпочитаю первое. Скорость чтения / записи 4K может создать проблемы с этим; Резервное копирование четверти миллиона файлов размером 1 КБ (стоимостью 250 МБ) с SSD на диск может занять несколько часов. Насколько я знаю, еще нет доступных пакетов R, которые могли бы автоматически оптимизировать процесс «чанкификации»; например, посмотрите, сколько у пользователя оперативной памяти, проверьте скорость чтения / записи ОЗУ / всех подключенных дисков, а затем предложите оптимальный протокол «чанкификации». Это может привести к значительным улучшениям рабочего процесса / оптимизации ресурсов; например, разделить его на ... МБ для оперативной памяти -> разделить на ... МБ для SSD -> разделить на ... МБ на блюде -> разделить на ... МБ на ленте. Он мог бы забрать наборы данных заранее, чтобы дать ему более реалистичный измерительный стержень для работы.
Многие проблемы, над которыми я работал в R, включают в себя формирование пар комбинаций и перестановок, троек и т. Д., Что делает ограничение ОЗУ только ограничением, поскольку в некоторой точке они часто по меньшей мере экспоненциально расширяются. Это заставило меня сосредоточить много внимания на качестве, а не на количестве информации, поступающей в них с самого начала, а не пытаться очистить ее впоследствии, и на последовательности операций при подготовке информации для начала (начиная с простейшая операция и увеличение сложности); например, подмножество, затем объединить / объединить, затем сформировать комбинации / перестановки и т. д.
Кажется, что в некоторых случаях использование чтения и записи базы R имеет некоторые преимущества. Например, обнаружение ошибок в 'fread' настолько хорошо, что может быть трудно попытаться получить действительно грязную информацию в R для начала, чтобы очистить ее. Base R также кажется намного проще, если вы используете Linux. Кажется, что Base R отлично работает в Linux, Windows 10 использует ~ 20 ГБ дискового пространства, тогда как Ubuntu требуется всего несколько ГБ, а оперативной памяти, необходимой для Ubuntu, немного меньше. Но я заметил большое количество предупреждений и ошибок при установке сторонних пакетов в (L) Ubuntu. Я бы не рекомендовал уходить слишком далеко от (L) Ubuntu или других стандартных дистрибутивов с Linux, так как вы можете потерять столько общей совместимости, что делает процесс практически бессмысленным (я думаю, что единство должно быть отменено в Ubuntu с 2017 года ).
Надеюсь, что-то из этого может помочь другим.
источник
Это ничего не добавляет к вышесказанному, но написано в простом и сильно комментированном стиле, который мне нравится. В результате получается таблица с упорядоченными по размеру объектами, но без некоторых деталей, приведенных в примерах выше:
источник
Это более новый ответ на этот отличный старый вопрос. От продвинутого R Хэдли:
( http://adv-r.had.co.nz/memory.html )
источник
Если вы работаете в Linux и хотите использовать несколько процессов и должны выполнять операции чтения только для одного или нескольких крупных объектов, используйте
makeForkCluster
вместо amakePSOCKcluster
. Это также экономит ваше время на отправку большого объекта другим процессам.источник
Я действительно ценю некоторые из приведенных выше ответов. После @hadley и @Dirk, которые предлагают закрыть R, выдать
source
и использовать командную строку, я нашел решение, которое мне очень помогло . Мне пришлось иметь дело с сотнями масс-спектров, каждый из которых занимает около 20 Мб памяти, поэтому я использовал два сценария R, как показано ниже:Сначала обертка:
с помощью этого сценария я в основном контролирую, что делает мой основной сценарий
runConsensus.r
, и записываю ответ данных для вывода. При этом каждый раз, когда обертка вызывает скрипт, кажется, что R снова открывается и память освобождается.Надеюсь, поможет.
источник
Помимо более общих методов управления памятью, приведенных в ответах выше, я всегда стараюсь максимально уменьшить размер своих объектов. Например, я работаю с очень большими, но очень разреженными матрицами, другими словами, с матрицами, где большинство значений равны нулю. Используя пакет «Матрица» (важно использовать заглавные буквы), я смог уменьшить свой средний размер объекта с ~ 2 ГБ до ~ 200 МБ просто:
Пакет Matrix включает форматы данных, которые могут использоваться точно так же, как обычная матрица (нет необходимости изменять другой код), но способны гораздо более эффективно хранить разреженные данные, независимо от того, загружены ли они в память или сохранены на диск.
Кроме того, необработанные файлы, которые я получаю, имеют «длинный» формат, в котором каждая точка данных имеет переменные
x, y, z, i
. Гораздо эффективнее преобразовать данные вx * y * z
массив измерений только с переменнойi
.Знайте свои данные и используйте немного здравого смысла.
источник
Совет по работе с объектами, требующими сложных промежуточных вычислений: при использовании объектов, для создания которых требуется много тяжелых вычислений и промежуточных шагов, я часто нахожу полезным написать фрагмент кода с функцией для создания объекта, а затем отдельный фрагмент кода, который дает мне возможность либо сгенерировать и сохранить объект в виде
rmd
файла, либо загрузить его извне изrmd
файла, который я уже ранее сохранил. Это особенно легко сделать,R Markdown
используя следующую структуру фрагмента кода.С этой структурой кода все, что мне нужно сделать, это изменить в
LOAD
зависимости от того, хочу ли я сгенерировать и сохранить объект, или загрузить его непосредственно из существующего сохраненного файла. (Конечно, я должен сгенерировать и сохранить его в первый раз, но после этого у меня есть возможность загрузить его.) НастройкаLOAD = TRUE
обходит использование моей сложной функции и избегает всех тяжелых вычислений в ней. Этот метод все еще требует достаточно памяти для хранения интересующего вас объекта, но он избавляет вас от необходимости вычислять его каждый раз, когда вы запускаете свой код. Для объектов, которые требуют большого количества сложных вычислений промежуточных шагов (например, для вычислений, включающих циклы над большими массивами), это может сэкономить значительное количество времени и вычислений.источник
Бег
время от времени также помогает R освободить неиспользованную, но все еще не освобожденную память.
источник
for
цикл делает здесь? Там нетi
вgc
вызове.gc(reset = T)
девять разВы также можете получить некоторую выгоду, используя knitr и помещая свой скрипт в Rmd chuncks.
Я обычно делю код на разные куски и выбираю, какой из них будет сохранять контрольную точку в кеше или в файле RDS, и
Там вы можете установить чанк для сохранения в «кэш», или вы можете решить, запускать или нет конкретный чанк. Таким образом, при первом запуске вы можете обработать только «часть 1», при другом выполнении вы можете выбрать только «часть 2» и т. Д.
Пример:
Как побочный эффект, это также может избавить вас от головной боли с точки зрения воспроизводимости :)
источник
Основываясь на ответах @ Дирка и @ Тони, я сделал небольшое обновление. Результат выводился
[1]
до значений симпатичного размера, поэтому я вынул тот,capture.output
который решил проблему:источник
Я стараюсь держать количество объектов небольшим при работе в большом проекте с большим количеством промежуточных шагов. Поэтому вместо создания множества уникальных объектов
dataframe
->step1
->step2
->step3
->result
raster
->multipliedRast
->meanRastF
->sqrtRast
->resultRast
Я работаю с временными объектами, которые я называю
temp
.dataframe
->temp
->temp
->temp
->result
Что оставляет мне меньше промежуточных файлов и больше обзора.
Чтобы сохранить больше памяти, я могу просто удалить,
temp
когда больше не нужен.Если мне нужно несколько промежуточных файлов, я использую
temp1
,temp2
,temp3
.Для тестирования я использую
test
,test2
...источник