技巧以管理R会话中的可用内存


490

人们使用什么技巧来管理交互式R会话的可用内存?我使用下面的功能(基于Petr Pikal和David Hinds在2004年r-help列表中的发布)列出(和/或排序)最大的对象,并偶尔列出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)
}

请注意,我毫不怀疑,但这有什么用?我对R中的内存问题还很陌生,但是最近遇到了一些问题(这就是为什么我要搜索这篇文章的原因:) –我也是从这一切开始的。这对我的日常工作有什么帮助?
马特·班纳特

4
如果要查看函数中的对象,则必须使用:lsos(pos = environment()),否则它将仅显示全局变量。要写入标准错误:write.table(lsos(pos = pos(environment()),stderr(),quote = FALSE,sep ='\ t')
Michael Kuhn

为什么选择64位Linux,而不选择64位Windows?当我要使用32GB的ram时,操作系统的选择是否会有所不同?
亚瑟(Jase)2012年

3
@pepsimax:已包装在multilevelPSA包装中。该软件包是为其他目的设计的,但是您可以从那里使用该功能而无需说加载该软件包requireNamespace(multilevelPSA); multilevelPSA::lsos(...)。或在Dmisc软件包中(不在CRAN上)。
krlmlr

1
如果数据集的大小可以控制,我通常会转到R studio>环境>网格视图。在这里,您可以根据大小查看并排序当前环境中的所有项目。
kRazzy R

Answers:


196

确保以可复制的脚本记录您的工作。有时,请重新打开R,然后重新打开source()脚本。您将清理掉不再使用的所有内容,并且额外的好处是可以测试您的代码。


58
我的策略是按照load.R和do.R的方式分解脚本,其中load.R可能需要花费一些时间才能从文件或数据库中加载数据,并且会进行最少的预处理/合并该数据。load.R的最后一行是保存工作区状态的内容。然后do.R是我的便笺簿,通过它可以建立分析功能。我经常重新加载do.R(根据需要从或不从load.R重新加载工作区状态)。
乔什·赖希

32
那是个好技术。当文件被按照一定的顺序一样运行,我经常与一个号码前缀他们:1-load.r2-explore.r3-model.r-这种方式很明显对别人有一些顺序存在。
hadley

4
我不能足够支持这个想法。我已经向少数人讲授R,这是我首先说的一件事。这也适用于开发中结合了REPL和正在编辑的文件(即Python)的任何语言。rm(ls = list())和source()也可以,但是重新打开效果更好(也清除了软件包)。
文斯2010年

53
投票最多的答案涉及重新启动R的事实,是对R的最恶劣的批评。
2013年

7
@MartínBel仅删除在全局环境中创建的对象。它不会卸载软件包或S4对象或许多其他东西。
hadley 2013年


109

在Twitter帖子上看到了这一点,并认为这是Dirk的强大功能!根据JD Long的回答,我将这样做是为了便于用户阅读:

# 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") })

可以将此功能添加到dplyr或某些其他密钥包中。
userJT

1
值得一提的是(至少使用base-3.3.2)capture.output不再是必需的,并且可以obj.prettysize <- napply(names, function(x) {format(utils::object.size(x), units = "auto") })产生干净的输出。实际上,不删除它会在输出中产生不需要的引号,即[1] "792.5 Mb"代替 792.5 Mb
Nutle

@Nutle太好了,我已经相应地更新了代码:)
Tony Breyal

我也将更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)。
DeltaIV

49

subset在将数据框传递给data=回归函数的参数时,我仅通过选择必需变量来积极使用参数。如果我忘记在公式和select=向量中都添加变量,则确实会导致一些错误,但是由于减少了对象的复制,它仍然节省了大量时间,并显着减少了内存占用。假设我有400万条带有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是一个特征向量,概述了HIV的初步和确认性测试。


48

我喜欢Dirk的.ls.objects()脚本,但是我一直着眼睛来计算size列中的字符。因此,我做了一些丑陋的修改,使它以漂亮的格式显示出来:

.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
}

34

这是一个好把戏。

另一种建议是,尽可能使用内存有效的对象:例如,使用矩阵而不是data.frame。

这并没有真正解决内存管理问题,但是其中一个鲜为人知的重要功能是memory.limit()。您可以使用此命令memory.limit(size = 2500)增加默认值,其中大小以MB为单位。如Dirk所述,您需要使用64位才能真正利用此优势。


25
这不仅适用于Windows吗?
Christopher DuBois

4
> memory.limit()[1] Inf警告消息:“ memory.limit()”是Windows特定的
LJT

使用tibble代替data.frame是否可以更好地帮助我们节省内存?

32

我非常喜欢Dirk开发的改进的对象功能。不过,在大多数情况下,具有对象名称和大小的更基本的输出对我来说就足够了。这是一个具有相似目标的简单函数。内存使用可以按字母顺序或大小排序,可以限制为一定数量的对象,并且可以按升序或降序排序。另外,我经常使用大于1GB的数据,因此该功能会相应地更改单位。

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

我从不保存R工作区。我使用导入脚本和数据脚本,并将不想重新创建的任何特别大的数据对象输出到文件中。这样,我总是从一个新的工作区开始,不需要清理大对象。不过,这是一个非常好的功能。


30

不幸的是,我没有时间对其进行广泛的测试,但这是我之前从未见过的记忆技巧。对我来说,所需的内存减少了50%以上。当您使用例如read.csv将内容读入R时,它们需要一定数量的内存。之后,您可以使用保存它们save("Destinationfile",list=ls()) 。下次打开R时,可以使用load("Destinationfile") 现在内存使用量可能已减少。如果任何人都可以确认这是否会在不同的数据集上产生相似的结果,那就太好了。


4
是的,我也有同样的经历。在我的情况下,内存使用率甚至下降到30%。使用1.5GB内存,保存到.RData(〜30MB)。加载.RData之后的新会话使用少于500MB的内存。
f3lix 2012年

我尝试使用2个数据集(100MB和2.7GB)加载到data.table中fread,然后保存到.RData中。RData文件确实小了约70%,但重新加载后,所使用的内存完全相同。希望这个技巧可以减少内存占用...我是否缺少某些东西?
NoviceProg

@NoviceProg我不认为您缺少任何东西,但这是一个技巧,我想它不能在所有情况下都起作用。在我的情况下,重新加载后的内存实际上按照所述方式减少了。
丹尼斯·贾黑鲁丁

6
@NoviceProg有两件事。首先,按照data.table的信条进行读取,在读取文件时可能比read.csv更有效率。其次,人们在这里要注意的内存节省主要与R进程的内存大小有关(R进程可以扩展以容纳对象,而在进行垃圾回收时则可以缩回)。但是,垃圾回收并不总是将所有RAM释放回操作系统。停止R会话并从存储它的位置加载该项目将释放尽可能多的RAM ...但是,如果开销很小,那么...就没有收益。
russellpierce 2015年

27

为了进一步说明频繁重启的通用策略,我们可以使用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在使用'#!/ usr / bin / r'shebang-header的脚本中也非常适合自动批处理模式。Rscript是在littler不可用的情况下的替代方法(例如,在Windows上)。


23

出于速度和内存的目的,当通过一些复杂的步骤构建大型数据帧时,我将定期将其(正在构建的正在进行中的数据集)刷新到磁盘,追加到之前的任何内容之后,然后重新启动它。这样,中间步骤仅在较小的数据帧上起作用(这很好,例如,对于较大的对象,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 )

17

只是要注意,data.tabletables()似乎可以很好地替代Dirk的.ls.objects()自定义函数(在先前的答案中有详细介绍),尽管仅用于data.frames / tables而不是例如矩阵,数组,列表。


这没有列出任何data.frames,所以它不是很好
userJT

16
  1. 我很幸运,仪器将大数据集保存在大约100 MB(32位二进制)的“块”(子集)中。因此,在融合数据集之前,我可以依次进行预处理步骤(删除不具信息的部分,进行下采样)。

  2. gc ()如果数据大小接近可用内存,则调用“手工”将很有帮助。

  3. 有时,不同的算法需要更少的内存。
    有时,向量化和内存使用之间需要权衡取舍。
    比较:splitlapply对一个for循环。

  4. 为了快速,轻松地进行数据分析,我通常首先处理数据的一小部分随机子集(sample ())。数据分析脚本/.Rnw完成后,数据分析代码和完整的数据将进入计算服务器进行整夜/周末/ ...计算。


11

使用环境而不是列表来处理占用大量工作内存的对象的集合。

原因:每次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.matrixdata.table允许就地更改其内容的结构,可以实现非常有效的内存使用。


6
这不再是正确的:从Hadley的高级R语言开始,“对R 3.1.0的更改已使[环境]的使用不再那么重要了,因为修改列表不再构成深层副本。”
petrelharp

8

包中的ll函数gData还可以显示每个对象的内存使用情况。

gdata::ll(unit='MB')

不在我的系统上:R版本3.1.1(2014-07-10),x86_64-pc-linux-gnu(64位),gdata_2.13.3,gtools_3.4.1。
krlmlr 2014年

您是对的,一经订购便立即测试!
user1436187 2014年

1
请修改功能以使用Gb,Mb
userJT 2015年

7

如果您确实想避免泄漏,则应避免在全局环境中创建任何大对象。

我通常要做的是拥有一个可以完成工作并返回的函数NULL-所有数据都在此函数或它所调用的其他函数中读取和操作。


7

只有4GB的内存(运行Windows 10,因此使大约2或更多实际为1GB),我在分配时必须非常小心。

我几乎只使用data.table。

“读取”功能允许您在导入时按字段名称对信息进行子集设置;仅导入开始时实际需要的字段。如果您使用的是R读基数,请在导入后立即将虚假列置空。

正如42-所暗示的那样,在导入信息后,我将尽可能在列中立即子集化。

我经常从环境中删除不再需要的rm()对象,例如,使用它们对其他对象进行子集处理后在下一行,并调用gc()。

与基本R读写相比,data.table中的“ fread”和“ fwrite”可以非常快。

kpierce8建议的那样,我几乎总是将所有内容从环境中并重新读回,即使有成千上万的小文件可以通过。这不仅使环境保持“干净”,并使内存分配保持在较低水平,而且可能由于严重缺乏可用的RAM而使R经常在我的计算机上崩溃。真的很频繁。随着代码在各个阶段的进行,将信息备份到驱动器本身上意味着如果崩溃,我不必从头开始。

截至2017年,我认为最快的SSD通过M2端口以每秒几GB的速度运行。我有一个非常基本的50GB Kingston V300(550MB / s)SSD,可以将其用作主磁盘(具有Windows和R)。我将所有批量信息保存在便宜的500GB WD盘片上。开始处理数据集时,我将其移至SSD。结合“读取”和“ fwrite”所有内容,效果一直很好。我尝试使用'ff',但更喜欢前者。4K读写速度可能会为此带来问题;从固态硬盘将四分之一的一万个1000个文件(价值250MB)备份到磁盘上可能需要几个小时。据我所知,尚无任何R软件包可以自动优化“块化”流程;例如查看用户有多少RAM,测试RAM /所有连接的驱动器的读/写速度,然后建议最佳的“块化”协议。这可能会产生一些重大的工作流改进/资源优化;例如,将其拆分为RAM的... MB->将其拆分为SSD的... MB->将其拆分为...在磁盘上的MB->将其拆分为...在磁带上的MB。它可以事先对数据集进行采样,以使其更现实地适用于工作。

我在R中处理过的许多问题都涉及形成组合和置换对,三元组等,这仅使有限的RAM更具局限性,因为它们通常至少会在某个时候呈指数增长。这使我集中了大量的注意力放在质量而不是数量的信息进入他们开始,而不是试图事后清理,并在准备资料的操作顺序与(从开始最简单的操作并增加了复杂性);例如子集,然后合并/合并,然后形成组合/排列等。

在某些情况下,使用基本R读写似乎确实有一些好处。例如,“ fread”中的错误检测是如此之好,以至于很难将真正混乱的信息放入R中开始清理。如果您使用的是Linux,则Base R似乎也容易得多。Base R似乎在Linux上可以正常工作,Windows 10使用约20GB的磁盘空间,而Ubuntu仅需要几GB,而Ubuntu所需的RAM稍低。但是在(L)Ubuntu中安装第三方程序包时,我注意到大量警告和错误。我不建议与Linux的(L)Ubuntu或其他股票发行版本相距太远,因为您可能失去太多的总体兼容性,这使该过程几乎毫无意义(我认为``统一性''将于2017年在Ubuntu中取消) )。

希望其中一些可以帮助其他人。


5

上面没有添加任何内容,但是以我喜欢的简单且受大量评论的风格编写。它会产生一个表,其中的对象按大小排序,但没有上面示例中给出的某些详细信息:

#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]))),])


3

如果您在Linux上工作,并且想要使用多个进程,而只需要对一个或多个大对象进行读取操作,请使用而不是。这也节省了您将大对象发送到其他进程的时间。makeForkClustermakePSOCKcluster


2

在@hadley和@Dirk建议关闭R并发布source和使用命令行之后,我真的很感谢上面的一些回答,我提出了一个对我来说非常有效的解决方案。我必须处理数百个质谱图,每个质谱图占用约20 Mb的内存,因此我使用了两个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都会重新打开并且内存已释放。

希望能帮助到你。


2

以及以上答案中给出的更通用的内存管理技术,我总是尝试尽可能减小对象的大小。例如,我处理非常大但非常稀疏的矩阵,换句话说,大多数值为零的矩阵。使用“矩阵”程序包(重要的是大写),我能够将平均对象大小从〜2GB减小到〜200MB,方法很简单:

my.matrix <- Matrix(my.matrix)

Matrix软件包包括可以完全像常规矩阵一样使用的数据格式(无需更改您的其他代码),但是无论是加载到内存还是保存到磁盘,都能够更加有效地存储稀疏数据。

另外,我收到的原始文件为“长”格式,其中每个数据点都有变量x, y, z, i。将数据转换为x * y * z仅包含variable 的维度数组的效率要高得多i

了解您的数据并使用一些常识。


2

处理需要大量中间计算的对象的技巧:当使用需要大量繁重计算和中间步骤来创建的对象时,我经常发现用函数创建对象编写代码块然后再创建单独的块是很有用的的代码,使我可以选择将对象生成并保存为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绕过使用我的复杂函数,并避免其中所有繁重的计算。此方法仍然需要足够的内存来存储感兴趣的对象,但是它使您不必在每次运行代码时都进行计算。对于需要大量繁重的中间步骤计算的对象(例如,对于涉及大型数组上的循环的计算),这可以节省大量的时间和计算量。



1

使用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)
```

作为副作用,这也可以为您节省一些可重复性方面的麻烦:)


1

基于@Dirk和@Tony的回答,我做了一个小更新。结果是[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

在具有大量中间步骤的大型项目中,我尝试使对象数量保持较小。因此,与其创建许多称为

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)

如果我需要一些中间文件,我用的temp1temp2temp3

为了测试我使用testtest2...

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.