Трюки для управления доступной памятью в сеансе R
Какие приемы люди используют для управления доступной памятью интерактивного сеанса 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)
}
28 ответов
Чтобы дополнительно проиллюстрировать общую стратегию частых перезапусков, мы можем использовать 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).
Убедитесь, что вы записали свою работу в воспроизводимом сценарии. Время от времени снова открывайте R, затем source()
твой сценарий Вы очистите все, что больше не используете, и в качестве дополнительного преимущества протестируете ваш код.
Я использую пакет data.table. С этими :=
Оператор вы можете:
- Добавить столбцы по ссылке
- Изменить подмножества существующих столбцов по ссылке и по группам по ссылке
- Удалить столбцы по ссылке
Ни одна из этих операций не копирует (потенциально большой) data.table
даже не один раз.
- Агрегация также особенно быстро, потому что
data.table
использует гораздо меньше рабочей памяти.
Ссылки по теме:
Видел это в твиттере и думаю, что это потрясающая функция от Дирка! Исходя из ответа Д.Д. Лонга, я бы сделал это для удобного чтения:
# 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") })
Я активно использую 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
был характерным вектором, который суммировал предварительное и подтверждающее тестирование на ВИЧ.
Мне нравится сценарий Дирка.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
}
Это хороший трюк.
Еще одно предложение состоит в том, чтобы по возможности использовать объекты с эффективным использованием памяти: например, использовать матрицу вместо data.frame.
На самом деле это не относится к управлению памятью, но одна важная функция, которая широко не известна, - memory.limit(). Вы можете увеличить значение по умолчанию с помощью этой команды memory.limit(size=2500), где размер указан в МБ. Как упоминал Дирк, вам нужно использовать 64-битную версию, чтобы воспользоваться этим преимуществом.
Мне очень нравится улучшенная функция объектов, разработанная Дирком. Хотя в большинстве случаев мне достаточно более простого вывода с именем и размером объекта. Вот более простая функция с аналогичной целью. Использование памяти может быть упорядочено по алфавиту или по размеру, может быть ограничено определенным количеством объектов и может быть упорядочено по возрастанию или по убыванию. Кроме того, я часто работаю с данными размером более 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
Я никогда не сохраняю рабочее пространство R. Я использую сценарии импорта и сценарии данных и выводю любые особенно большие объекты данных, которые я не хочу часто воссоздавать, в файлы. Таким образом, я всегда начинаю со свежей рабочей области и мне не нужно убирать большие объекты. Это очень хорошая функция, хотя.
К сожалению, у меня не было времени тщательно его протестировать, но вот совет по памяти, которого я раньше не видел. Для меня требуемая память была уменьшена более чем на 50%. Когда вы читаете вещи в R, например, с помощью read.csv, они требуют определенного объема памяти. После этого вы можете сохранить их с save("Destinationfile",list=ls())
В следующий раз, когда вы откроете R, вы можете использовать load("Destinationfile")
Теперь использование памяти могло уменьшиться. Было бы хорошо, если бы кто-нибудь мог подтвердить, дает ли это аналогичные результаты с другим набором данных.
И с точки зрения скорости, и с точки зрения памяти, при построении большого фрейма данных с помощью некоторой сложной серии шагов я буду периодически сбрасывать его (создаваемый набор данных) на диск, добавлять все, что было до, и затем перезагружать его., Таким образом, промежуточные шаги работают только с небольшими фреймами данных (что хорошо, например, если rbind значительно замедляется с большими объектами). Весь набор данных может быть считан обратно в конце процесса, когда все промежуточные объекты были удалены.
dfinal <- NULL
first <- TRUE
tempfile <- "dfinal_temp.csv"
for( i in bigloop ) {
if( !i %% 10000 ) {
print( i, "; flushing to disk..." )
write.table( dfinal, file=tempfile, append=!first, col.names=first )
first <- FALSE
dfinal <- NULL # nuke it
}
# ... complex operations here that add data to 'dfinal' data frame
}
print( "Loop done; flushing to disk and re-reading entire data set..." )
write.table( dfinal, file=tempfile, append=TRUE, col.names=FALSE )
dfinal <- read.table( tempfile )
Просто отметить, что data.table
пакет-х tables()
кажется, довольно хорошая замена для Дирка .ls.objects()
Пользовательская функция (подробно описано в предыдущих ответах), хотя только для data.frames/ таблиц, а не, например, для матриц, массивов, списков.
Мне повезло, и мои большие наборы данных сохраняются инструментом в виде "кусочков" (подмножеств) размером примерно 100 МБ (32-разрядный двоичный код). Таким образом, я могу последовательно выполнить этапы предварительной обработки (удаление неинформативных частей, уменьшение частоты дискретизации) перед объединением набора данных.
призвание
gc ()
"от руки" может помочь, если размер данных приближается к доступной памяти.Иногда другому алгоритму требуется гораздо меньше памяти.
Иногда есть компромисс между векторизацией и использованием памяти.
Для сравнения:split
&lapply
противfor
петля.Для быстрого и легкого анализа данных я часто сначала работаю с небольшим случайным подмножеством (
sample ()
) данных. После того, как скрипт анализа данных /.Rnw закончил, код анализа данных и полные данные отправляются на сервер вычислений для расчета в течение ночи / в выходные дни / ....
Использование сред вместо списков для обработки коллекций объектов, занимающих значительный объем рабочей памяти.
Причина: каждый раз элемент list
Структура изменена, весь список временно продублирован. Это становится проблемой, если требование хранения списка составляет примерно половину доступной рабочей памяти, потому что тогда данные должны быть перенесены на медленный жесткий диск. Среды, с другой стороны, не подвержены такому поведению и могут рассматриваться как списки.
Вот пример:
get.data <- function(x)
{
# get some data based on x
return(paste("data from",x))
}
collect.data <- function(i,x,env)
{
# get some data
data <- get.data(x[[i]])
# store data into environment
element.name <- paste("V",i,sep="")
env[[element.name]] <- data
return(NULL)
}
better.list <- new.env()
filenames <- c("file1","file2","file3")
lapply(seq_along(filenames),collect.data,x=filenames,env=better.list)
# read/write access
print(better.list[["V1"]])
better.list[["V2"]] <- "testdata"
# number of list elements
length(ls(better.list))
В сочетании с такими структурами, как big.matrix
или же data.table
которые позволяют изменять их содержимое на месте, можно добиться очень эффективного использования памяти.
ll
функция в gData
Пакет может также показать использование памяти каждого объекта.
gdata::ll(unit='MB')
Если вы действительно хотите избежать утечек, вам следует избегать создания больших объектов в глобальной среде.
Обычно я использую функцию, которая выполняет работу и возвращает NULL
- все данные читаются и обрабатываются в этой или других функциях, которые она вызывает.
Имея только 4 ГБ ОЗУ (под управлением Windows 10, так что примерно 2 или более реально это 1 ГБ), я должен был быть очень осторожным с распределением.
Я использую data.table почти исключительно.
Функция 'fread' позволяет вам импортировать информацию по именам полей при импорте; импортируйте только те поля, которые действительно нужны для начала. Если вы используете базовое чтение R, обнуляйте ложные столбцы сразу после импорта.
Как следует из 42-й, по возможности, я буду размещать их в столбцах сразу после импорта информации.
Я часто rm() объекты из среды, как только они больше не нужны, например, на следующей строке после использования их для поднабора чего-то еще, и вызываю gc ().
'fread' и 'fwrite' из data.table могут быть очень быстрыми по сравнению с основанием R для чтения и записи.
Как подсказывает kpierce8, я почти всегда пишу все из среды и копирую все обратно, даже с тысячами / сотнями тысяч крошечных файлов. Это не только обеспечивает чистоту среды и низкое распределение памяти, но, возможно, из-за серьезного недостатка доступной оперативной памяти, R имеет склонность к частым сбоям на моем компьютере; действительно часто. Резервное копирование информации на самом диске в процессе выполнения кода на разных этапах означает, что мне не нужно начинать с самого начала, если он падает.
Начиная с 2017 года, я думаю, что самые быстрые твердотельные накопители работают со скоростью несколько ГБ в секунду через порт M2. У меня действительно базовый твердотельный накопитель Kingston V300 (550 МБ / с) емкостью 50 ГБ, который я использую в качестве основного (на нем установлены Windows и R). Я храню всю основную информацию на дешевом диске WD емкостью 500 ГБ. Я перемещаю наборы данных в 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 года). Я понимаю, что это не будет хорошо с некоторыми пользователями Linux, но некоторые из пользовательских дистрибутивов не имеют смысла, кроме новизны (я провел годы, используя только Linux).
Надеюсь, что-то из этого может помочь другим.
Это более новый ответ на этот отличный старый вопрос. От продвинутого R Хэдли:
install.packages("pryr")
library(pryr)
object_size(1:10)
## 88 B
object_size(mean)
## 832 B
object_size(mtcars)
## 6.74 kB
Это ничего не добавляет к вышесказанному, но написано в простом и сильно комментированном стиле, который мне нравится. В результате получается таблица с упорядоченными по размеру объектами, но без некоторых деталей, приведенных в примерах выше:
#Find the objects
MemoryObjects = ls()
#Create an array
MemoryAssessmentTable=array(NA,dim=c(length(MemoryObjects),2))
#Name the columns
colnames(MemoryAssessmentTable)=c("object","bytes")
#Define the first column as the objects
MemoryAssessmentTable[,1]=MemoryObjects
#Define a function to determine size
MemoryAssessmentFunction=function(x){object.size(get(x))}
#Apply the function to the objects
MemoryAssessmentTable[,2]=t(t(sapply(MemoryAssessmentTable[,1],MemoryAssessmentFunction)))
#Produce a table with the largest objects first
noquote(MemoryAssessmentTable[rev(order(as.numeric(MemoryAssessmentTable[,2]))),])
Помимо более общих методов управления памятью, приведенных в ответах выше, я всегда стараюсь максимально уменьшить размер своих объектов. Например, я работаю с очень большими, но очень разреженными матрицами, другими словами, с матрицами, где большинство значений равны нулю. Используя пакет "Матрица" (важно использовать заглавные буквы), я смог уменьшить свой средний размер объекта с ~2 ГБ до ~200 МБ просто:
my.matrix <- Matrix(my.matrix)
Пакет Matrix включает форматы данных, которые можно использовать точно так же, как обычную матрицу (не нужно менять другой код), но которые могут намного более эффективно хранить разреженные данные, независимо от того, загружены ли они в память или сохранены на диск.
Кроме того, я получаю необработанные файлы в "длинном" формате, где каждая точка данных имеет переменные x, y, z, i
, Гораздо эффективнее превратить данные в x * y * z
размерный массив только с переменной i
,
Знайте свои данные и используйте немного здравого смысла.
Если вы работаете в Linux и хотите использовать несколько процессов и должны выполнять операции чтения только для одного или нескольких крупных объектов, используйте makeForkCluster
вместо makePSOCKcluster
, Это также экономит время на отправку большого объекта другим процессам.
Совет для работы с объектами, требующими сложных промежуточных вычислений: при использовании объектов, для создания которых требуется много тяжелых вычислений и промежуточных шагов, я часто нахожу полезным написать фрагмент кода с функцией для создания объекта, а затем отдельный фрагмент кода, который дает мне возможность либо создать и сохранить объект как 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
обходит использование моей сложной функции и избегает всех тяжелых вычислений в ней. Этот метод все еще требует достаточно памяти для хранения интересующего вас объекта, но он избавляет вас от необходимости вычислять его каждый раз, когда вы запускаете свой код. Для объектов, которые требуют большого количества сложных вычислений промежуточных шагов (например, для вычислений, включающих циклы над большими массивами), это может сэкономить значительное количество времени и вычислений.
Я действительно ценю некоторые из ответов выше, после @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 снова открывается и память освобождается.
Надеюсь, поможет.
Вы также можете получить некоторую выгоду, используя knitr и помещая свой скрипт в Rmd chuncks.
Я обычно делю код на разные куски и выбираю, какой из них будет сохранять контрольную точку в кеше или в файле 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)
```
Как побочный эффект, это также может избавить вас от головной боли с точки зрения воспроизводимости:)
Бег
for (i in 1:10)
gc(reset = T)
время от времени также помогает R освободить неиспользованную, но все еще не освобожденную память.
Основываясь на ответах @ Дирка и @ Тони, я сделал небольшое обновление. Результатом был вывод [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()
Я стараюсь, чтобы количество объектов было небольшим при работе над большим проектом с большим количеством промежуточных шагов. Поэтому вместо создания множества уникальных объектов
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
...
rm(list=ls())
- отличный способ быть честным и воспроизводимым.