Трюки, чтобы управлять доступной памятью в сеансе 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 ]

186 голосов
/ 31 августа 2009

Убедитесь, что вы записали свою работу в воспроизводимый сценарий. Время от времени снова открывайте R, затем source() ваш скрипт. Вы удалите все, что больше не используете, и в качестве дополнительного преимущества протестируете ваш код.

153 голосов
/ 10 августа 2012

Я использую пакет data.table . С оператором := вы можете:

  • Добавить столбцы по ссылке
  • Изменить подмножества существующих столбцов по ссылке и по группе по ссылке
  • Удалить столбцы по ссылке

Ни одна из этих операций не копирует (потенциально большой) data.table, даже один раз.

  • Агрегация также особенно быстра, поскольку data.table использует гораздо меньше рабочей памяти.

Ссылки по теме:

106 голосов
/ 28 января 2011

Увидел это в твиттере и подумал, что это потрясающая функция от Дирка! Исходя из ответа Д.Д. Лонга, я бы сделал это для удобного чтения:

# 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.prettysize <- napply(names, function(x) {
                           format(utils::object.size(x), units = "auto") })
    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.prettysize, obj.dim)
    names(out) <- c("Type", "Size", "PrettySize", "Length/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)
}

lsos()

В результате получается что-то вроде следующего:

                      Type   Size PrettySize Length/Rows Columns
pca.res                 PCA 790128   771.6 Kb          7      NA
DF               data.frame 271040   264.7 Kb        669      50
factor.AgeGender   factanal  12888    12.6 Kb         12      NA
dates            data.frame   9016     8.8 Kb        669       2
sd.                 numeric   3808     3.7 Kb         51      NA
napply             function   2256     2.2 Kb         NA      NA
lsos               function   1944     1.9 Kb         NA      NA
load               loadings   1768     1.7 Kb         12       2
ind.sup             integer    448  448 bytes        102      NA
x                 character     96   96 bytes          1      NA

ПРИМЕЧАНИЕ: Основная часть, которую я добавил, была (опять же, адаптирована из ответа JD):

obj.prettysize <- napply(names, function(x) {
                           print(object.size(x), units = "auto") })
48 голосов
/ 05 декабря 2010

Я активно использую параметр subset с выбором только обязательных переменных при передаче фреймов данных в аргумент data= функций регрессии. Это приводит к некоторым ошибкам, если я забываю добавить переменные как к формуле, так и к вектору select=, но все равно экономит много времени из-за уменьшения копирования объектов и значительного сокращения объема памяти. Скажем, у меня 4 миллиона записей со 110 переменными (и я делаю.) Пример:

# library(rms); library(Hmisc) for the cph,and rcs functions
Mayo.PrCr.rbc.mdl <- 
cph(formula = Surv(surv.yr, death) ~ age + Sex + nsmkr + rcs(Mayo, 4) + 
                                     rcs(PrCr.rat, 3) +  rbc.cat * Sex, 
     data = subset(set1HLI,  gdlab2 & HIVfinal == "Negative", 
                           select = c("surv.yr", "death", "PrCr.rat", "Mayo", 
                                      "age", "Sex", "nsmkr", "rbc.cat")
   )            )

В порядке задания контекста и стратегии: переменная gdlab2 представляет собой логический вектор, который был создан для субъектов в наборе данных, которые имели все нормальные или почти нормальные значения для группы лабораторных тестов, а HIVfinal был персонаж вектор, суммирующий предварительное и подтверждающее тестирование на ВИЧ.

48 голосов
/ 09 марта 2010

Мне нравится сценарий Дирка .ls.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.prettysize <- sapply(obj.size, function(r) prettyNum(r, big.mark = ",") )
    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), ]
        out <- out[c("Type", "PrettySize", "Rows", "Columns")]
        names(out) <- c("Type", "Size", "Rows", "Columns")
    if (head)
        out <- head(out, n)
    out
}
33 голосов
/ 31 августа 2009

Это хороший трюк.

Еще одно предложение - по возможности использовать объекты с эффективным использованием памяти: например, использовать матрицу вместо data.frame.

Это на самом деле не относится к управлению памятью, но одна важная функция, которая не широко известна, - memory.limit (). Вы можете увеличить значение по умолчанию с помощью этой команды memory.limit (size = 2500), где размер указан в МБ. Как упоминал Дирк, вам нужно использовать 64-битную версию, чтобы воспользоваться этим преимуществом.

31 голосов
/ 23 марта 2012

Мне очень нравится улучшенная функция объектов, разработанная Дирком. Хотя в большинстве случаев мне достаточно более простого вывода с именем и размером объекта. Вот более простая функция с аналогичной целью. Использование памяти может быть упорядочено по алфавиту или по размеру, может быть ограничено определенным количеством объектов и может быть упорядочено по возрастанию или по убыванию. Кроме того, я часто работаю с данными размером более 1 ГБ, поэтому функция соответствующим образом меняет единицы измерения.

showMemoryUse <- function(sort="size", decreasing=FALSE, limit) {

  objectList <- ls(parent.frame())

  oneKB <- 1024
  oneMB <- 1048576
  oneGB <- 1073741824

  memoryUse <- sapply(objectList, function(x) as.numeric(object.size(eval(parse(text=x)))))

  memListing <- sapply(memoryUse, function(size) {
        if (size >= oneGB) return(paste(round(size/oneGB,2), "GB"))
        else if (size >= oneMB) return(paste(round(size/oneMB,2), "MB"))
        else if (size >= oneKB) return(paste(round(size/oneKB,2), "kB"))
        else return(paste(size, "bytes"))
      })

  memListing <- data.frame(objectName=names(memListing),memorySize=memListing,row.names=NULL)

  if (sort=="alphabetical") memListing <- memListing[order(memListing$objectName,decreasing=decreasing),] 
  else memListing <- memListing[order(memoryUse,decreasing=decreasing),] #will run if sort not specified or "size"

  if(!missing(limit)) memListing <- memListing[1:limit,]

  print(memListing, row.names=FALSE)
  return(invisible(memListing))
}

А вот пример вывода:

> showMemoryUse(decreasing=TRUE, limit=5)
      objectName memorySize
       coherData  713.75 MB
 spec.pgram_mine  149.63 kB
       stoch.reg  145.88 kB
      describeBy    82.5 kB
      lmBandpass   68.41 kB
30 голосов
/ 07 октября 2011

К сожалению, у меня не было времени, чтобы протестировать его всесторонне, но вот совет памяти, который я не видел раньше Для меня требуемая память была уменьшена более чем на 50%. Когда вы читаете вещи в R, например, с помощью read.csv, они требуют определенного объема памяти. После этого вы можете сохранить их с помощью save("Destinationfile",list=ls()) В следующий раз, когда вы откроете R, вы можете использовать load("Destinationfile") Теперь использование памяти могло уменьшиться. Было бы хорошо, если бы кто-нибудь мог подтвердить, дает ли это аналогичные результаты с другим набором данных.

29 голосов
/ 01 сентября 2009

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

25 голосов
/ 01 сентября 2009

Чтобы дополнительно проиллюстрировать общую стратегию частых перезапусков, мы можем использовать littler , которая позволяет нам запускать простые выражения непосредственно из командной строки. Вот пример, который я иногда использую для определения времени различных BLAS для простого кросс-процесса.

 r -e'N<-3*10^3; M<-matrix(rnorm(N*N),ncol=N); print(system.time(crossprod(M)))'

Аналогично,

 r -lMatrix -e'example(spMatrix)'

загружает пакет Matrix (через ключ --packages | -l) и запускает примеры функции spMatrix. Поскольку r всегда запускается «заново», этот метод также является хорошим тестом при разработке пакета.

И последнее, но не менее важное: r также отлично подходит для автоматического пакетного режима в сценариях, использующих заголовок shebang '#! / Usr / bin / r'. Rscript - это альтернатива, где littler недоступен (например, в Windows).

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