Трюки, чтобы управлять доступной памятью в сеансе R - PullRequest
474 голосов
/ 31 августа 2009

Какие приемы люди используют для управления доступной памятью интерактивного сеанса 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)
}

Ответы [ 27 ]

2 голосов
/ 14 января 2019

Совет для работы с объектами, требующими сложных промежуточных вычислений: При использовании объектов, для создания которых требуется много тяжелых вычислений и промежуточных шагов, я часто нахожу полезным написать кусок кода с функцией для создайте объект, а затем отдельный кусок кода, который дает мне возможность либо сгенерировать и сохранить объект как файл rmd, либо загрузить его извне из файла rmd, который я уже ранее сохранил. Это особенно легко сделать в R Markdown, используя следующую структуру фрагмента кода.

```{r Create OBJECT}

COMPLICATED.FUNCTION <- function(...) { Do heavy calculations needing lots of memory;
                                        Output OBJECT; }

```
```{r Generate or load OBJECT}

LOAD <- TRUE;
#NOTE: Set LOAD to TRUE if you want to load saved file
#NOTE: Set LOAD to FALSE if you want to generate and save

if(LOAD == TRUE) { OBJECT <- readRDS(file = 'MySavedObject.rds'); } else
                 { OBJECT <- COMPLICATED.FUNCTION(x, y, z);
                             saveRDS(file = 'MySavedObject.rds', object = OBJECT); }

```

При такой структуре кода все, что мне нужно сделать, это изменить LOAD в зависимости от того, хочу ли я сгенерировать и сохранить объект, или загрузить его непосредственно из существующего сохраненного файла. (Конечно, я должен сгенерировать его и сохранить в первый раз, но после этого у меня есть возможность загрузить его.) Установка LOAD = TRUE позволяет обойти использование моей сложной функции и избежать всех тяжелых вычислений в ней. Этот метод все еще требует достаточно памяти для хранения интересующего вас объекта, но он избавляет вас от необходимости вычислять его каждый раз, когда вы запускаете свой код. Для объектов, которые требуют большого количества сложных вычислений промежуточных шагов (например, для вычислений, включающих циклы над большими массивами), это может сэкономить значительное количество времени и вычислений.

2 голосов
/ 31 марта 2016

Помимо более общих методов управления памятью, приведенных в ответах выше, я всегда стараюсь максимально уменьшить размер своих объектов. Например, я работаю с очень большими, но очень разреженными матрицами, другими словами, с матрицами, где большинство значений равны нулю. Используя пакет «Матрица» (важно использовать заглавные буквы), я смог уменьшить свой средний размер объекта с ~ 2 ГБ до ~ 200 МБ, просто:

my.matrix <- Matrix(my.matrix)

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

Кроме того, я получаю необработанные файлы в «длинном» формате, где каждая точка данных имеет переменные x, y, z, i. Гораздо эффективнее преобразовать данные в массив измерений x * y * z только с переменной i.

Знайте свои данные и руководствуйтесь здравым смыслом.

2 голосов
/ 23 июля 2014

Я действительно ценю некоторые из ответов выше, после @hadley и @Dirk, которые предлагают закрыть R и выдать source, и с помощью командной строки я придумала решение, которое мне очень помогло. Мне приходилось иметь дело с сотнями масс-спектров, каждый из которых занимает около 20 Мб памяти, поэтому я использовал два сценария R, как показано ниже:

Первая обертка:

#!/usr/bin/Rscript --vanilla --default-packages=utils

for(l in 1:length(fdir)) {

   for(k in 1:length(fds)) {
     system(paste("Rscript runConsensus.r", l, k))
   }
}

с помощью этого сценария я в основном контролирую, что делает мой основной сценарий runConsensus.r, и записываю ответ данных для вывода. При этом каждый раз, когда обертка вызывает скрипт, кажется, что R снова открывается и память освобождается.

Надеюсь, это поможет.

1 голос
/ 29 октября 2017

Основываясь на ответах @ Дирка и @ Тони, я сделал небольшое обновление. Результатом был вывод [1] до значений довольно большого размера, поэтому я вынул capture.output, который решил проблему:

.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.prettysize <- napply(names, function(x) {
    format(utils::object.size(x),  units = "auto") })
obj.size <- napply(names, utils::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.prettysize, obj.dim)
names(out) <- c("Type", "Size", "PrettySize", "Rows", "Columns")
if (!missing(order.by))
    out <- out[order(out[[order.by]], decreasing=decreasing), ]
if (head)
    out <- head(out, n)

return(out)
}

# shorthand
lsos <- function(..., n=10) {
    .ls.objects(..., order.by="Size", decreasing=TRUE, head=TRUE, n=n)
}

lsos()
1 голос
/ 16 июня 2016

Вы также можете получить некоторую выгоду, используя knitr и помещая свой скрипт в чанки Rmd.

Я обычно делю код на разные куски и выбираю, какой из них будет сохранять контрольную точку в кэш или в файл RDS, и

Там вы можете установить чанк для сохранения в «кеш», или вы можете решить, запускать или нет конкретный чанк. Таким образом, при первом запуске вы можете обработать только «часть 1», при другом выполнении вы можете выбрать только «часть 2» и т. Д.

Пример:

part1
```{r corpus, warning=FALSE, cache=TRUE, message=FALSE, eval=TRUE}
corpusTw <- corpus(twitter)  # build the corpus
```
part2
```{r trigrams, warning=FALSE, cache=TRUE, message=FALSE, eval=FALSE}
dfmTw <- dfm(corpusTw, verbose=TRUE, removeTwitter=TRUE, ngrams=3)
```

В качестве побочного эффекта это также может избавить вас от головной боли с точки зрения воспроизводимости:)

0 голосов
/ 26 февраля 2019

Я стараюсь сохранять небольшое количество объектов при работе в большом проекте с большим количеством промежуточных шагов.Поэтому вместо создания множества уникальных объектов с именем

dataframe -> step1 -> step2 -> step3 -> result

raster -> multipliedRast -> meanRastF -> sqrtRast -> resultRast

Я работаю с временными объектами, которые я называю temp.

dataframe -> temp ->temp -> temp -> result

Что оставляет мне меньше промежуточных файлов и больше обзора.

raster  <- raster('file.tif')
temp <- raster * 10
temp <- mean(temp)
resultRast <- sqrt(temp)

Чтобы сэкономить больше памяти, я могу просто удалить tempкогда больше не нужен.

rm(temp)

Если мне нужно несколько промежуточных файлов, я использую temp1, temp2, temp3.

Для тестирования я использую test, test2, ...

0 голосов
/ 20 мая 2016

Запуск

for (i in 1:10) 
    gc(reset = T)

время от времени также помогает R освобождать неиспользованную, но все еще не освобожденную память.

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