Rセッションで利用可能なメモリを管理するためのトリック


490

対話型Rセッションの使用可能なメモリを管理するために、どのようなトリックを使用しますか?以下の関数(2004年のPetr PikalとDavid Hindsによるr-helpリストへの投稿に基づく)を使用して、最大のオブジェクトをリスト(および/またはソート)し、場合rm()によってはそれらのいくつかをリストします。しかし、これまでで最も効果的な解決策は、十分なメモリを備えた64ビットLinuxで実行することでした。

他の人が共有したい素敵なトリックはありますか?投稿ごとに1つお願いします。

# 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のメモリの問題にかなり慣れていますが、最近、いくつかの問題が発生しています(そのため、この投稿を探していました:)。これは私の毎日の仕事にどのように役立ちますか?
Matt Bannert、

4
関数内のオブジェクトを表示するには、lsos(pos = environment())を使用する必要があります。それ以外の場合は、グローバル変数のみが表示されます。標準エラーに書き込むには:write.table(lsos(pos = environment())、stderr()、quote = FALSE、sep = '\ t')
Michael Kuhn

64ビットWindowsではなく64ビットLinuxを使用する理由 32GBのRAMを使用する場合、OSの選択によって大きな違いはありますか?
Jase

3
@pepsimax:これはパッケージにパッケージされていmultilevelPSAます。パッケージは別の目的で設計されていますが、と言うことで、パッケージをロードせずにそこから関数を使用できますrequireNamespace(multilevelPSA); multilevelPSA::lsos(...)。またはDmiscパッケージ内(CRANではありません)。
krlmlr 2013年

1
データセットが扱いやすいサイズである場合、通常はR studio>環境>グリッドビューに移動します。ここでは、現在の環境のすべてのアイテムをサイズに基づいて表示およびソートできます。
kRazzy R 2016

回答:


197

作業は再現可能なスクリプトで記録してください。時々、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-それは他の人に明らかだそのようにいくつかの順序は存在であること。
ハドリー2009

4
この考えを十分に裏付けることはできません。私は数人にRを教えましたが、これは私が最初に言うことの1つです。これは、開発にREPLと編集中のファイル(つまりPython)が組み込まれているすべての言語にも当てはまります。rm(ls = list())とsource()も機能しますが、再オープンの方が優れています(パッケージもクリアされます)。
Vince

53
トップ投票の回答がRの再起動を含むという事実は、Rの最悪の批判です。
sds

7
@MartínBelは、グローバル環境で作成されたオブジェクトのみを削除します。パッケージ、S4オブジェクト、またはその他の多くのものをアンロードしません。
ハドリー2013

160

data.tableパッケージを使用してます。その:=演算子を使用すると、次のことができます。

  • 参照により列を追加する
  • 参照による、および参照によるグループ化による既存の列のサブセットの変更
  • 参照により列を削除する

これらの操作はどれも、(潜在的に大きい)data.tableをまったくコピーしません。一度もコピーしません。

  • data.table使用する作業メモリがはるかに少ないため、集計も特に高速です。

関連リンク :


109

これをツイッターの投稿で見て、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 2017

@Nutleすばらしい、それに応じてコードを更新しました:)
Tony Breyal

私はまた、変更したいobj.class <- napply(names, function(x) as.character(class(x))[1])obj.class <- napply(names, function(x) class(x)[1]) ため、class常に(ベースは-3.5.0)になりました文字のベクトルを返します。
DeltaIV

49

subsetデータフレームをdata=回帰関数の引数に渡すときに、必要な変数のみを選択してパラメーターを積極的に使用します。数式とselect=ベクトルの両方に変数を追加し忘れた場合、エラーが発生しますが、オブジェクトのコピーが減少するため、時間を大幅に節約でき、メモリフットプリントを大幅に削減できます。たとえば、110個の変数を持つ400万件のレコードがあるとします(そうです)。例:

# 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()スクリプトは気に入っていますが、サイズ列の文字を数えるために目を細め続けました。だから私はいくつかの醜いハックをして、それをサイズのかなりのフォーマットで表示するようにしました:

.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

それは良いトリックです。

もう1つの提案は、可能な限りメモリ効率の高いオブジェクトを使用することです。たとえば、data.frameの代わりに行列を使用します。

これは実際にはメモリ管理に対処していませんが、広く知られていない重要な関数の1つはmemory.limit()です。このコマンド、memory.limit(size = 2500)を使用してデフォルトを増やすことができます。サイズはMB単位です。Dirkが述べたように、これを実際に利用するには64ビットを使用する必要があります。


25
これはWindowsにのみ適用されませんか?
クリストファーデュボワ

4
> memory.limit()[1] Inf警告メッセージ: 'memory.limit()'はWindows固有
LJT

data.frameの代わりにtibbleを使用すると、メモリを節約するのにさらに役立ちますか?

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

を使用してdata.tableに2つのデータセット(100MBと2.7GB)をロードし、.RDataにfread保存してみました。RDataファイルは確かに約70%小さくなりましたが、再ロード後、使用されるメモリはまったく同じでした。このトリックがメモリのフットプリントを減らすことを期待していた...私は何かが足りないのですか?
NoviceProg 2015年

@NoviceProg私はあなたが何かを見逃しているとは思いませんが、それはトリックです、私はそれがすべての状況でうまくいくとは思いません。私の場合、リロード後のメモリは、説明したように実際に減少しました。
Dennis Jaheruddin 2015年

6
@NoviceProgカップルのもの。まず、fread、data.tableのcredoの後に続くファイルは、おそらくread.csvよりもファイルのロードにおいてより効率的なメモリです。次に、ここで注意しているメモリの節約は、主にRプロセスのメモリサイズ(オブジェクトを保持するように拡張され、ガベージコレクションが行われると格納される)に関係していることです。ただし、ガベージコレクションは必ずしもすべてのRAMをOSに解放するわけではありません。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)'

(--packages | -lスイッチを介して)Matrixパッケージを読み込み、spMatrix関数の例を実行します。rは常に「新規」で開始されるため、この方法はパッケージ開発中の優れたテストでもあります。

最後に重要な点として、rは '#!/ usr / bin / r' shebang-headerを使用するスクリプトの自動化バッチモードにも最適です。Rscriptは、小さなものが利用できない場合の代替手段です(例: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.table、パッケージのは、tables()ダークのためのかなり良い代替のようです.ls.objects()が、ちょうどdata.frames /テーブル用ではなく例えば行列、配列、リスト、(以前の回答で詳述)カスタム関数。


これはdata.framesをリストしないので、それほど大きくありません
userJT

16
  1. 私は幸運であり、私の大きなデータセットは、約100 MB(32ビットバイナリ)の「チャンク」(サブセット)で測定器によって保存されます。したがって、データセットを融合する前に、前処理手順(情報のない部分の削除、ダウンサンプリング)を順次実行できます。

  2. gc ()「手動で」呼び出すと、データのサイズが使用可能なメモリに近づく場合に役立ちます。

  3. 時々、別のアルゴリズムははるかに少ないメモリを必要とします。
    時々、ベクトル化とメモリ使用の間にはトレードオフがあります。
    比較:splitlapplyforループ。

  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.matrixまたはdata.tableその場で自分のコンテンツを変更するため、非常に効率的なメモリ使用を達成することができる可能にします。


6
これはもう当てはまりません。Hadleyの高度なRから、「R 3.1.0への変更により、[環境の]この使用は、リストを変更しても深いコピーが作成されなくなったため、それほど重要ではなくなりました。」
petrelharp 2015

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

7

リークを本当に避けたい場合は、グローバル環境で大きなオブジェクトを作成しないようにする必要があります。

私が通常行うことは、ジョブを実行して返す関数を持つことです。NULLすべてのデータは、この関数またはそれが呼び出す他の関数で読み取られ、操作されます。


7

4GBのRAM(Windows 10を実行しているので、実際には約2GBまたは1GBにしてください)の場合、割り当てには十分注意する必要がありました。

私はほぼ排他的にdata.tableを使用しています。

'fread'関数を使用すると、インポート時にフィールド名で情報をサブセット化できます。最初に実際に必要なフィールドのみをインポートします。ベースRの読み取りを使用している場合は、インポート直後に偽の列をnullにします。

42-今までの可能な私は、すぐに情報をインポートした後、列の中にサブセットする場所を、示唆しています。

私は頻繁に、環境からオブジェクトをrm()する必要がなくなり次第、たとえば、次の行でそれらを使用して他のものをサブセット化し、gc()を呼び出します。

data.tableの「fread」と「fwrite」は、ベースRの読み取りと書き込みと比較すると非常に高速です。

以下のようkpierce8は環境のうち、私はほとんど常にfwriteのすべてを示唆しているとさえ介して取得する小さなファイルの数千人の千/数百人で、後ろにそれを関数fread。これは、環境を「クリーン」に保ち、メモリ割り当てを低く保つだけでなく、使用可能なRAMの深刻な不足が原因で、Rはコンピュータで頻繁にクラッシュする傾向があります。本当に頻繁に。コードがさまざまな段階を進むときにドライブ自体に情報がバックアップされるので、クラッシュした場合、最初から開始する必要はありません。

2017年現在、最速のSSDはM2ポートを介して毎秒数GBで実行されていると思います。私は、プライマリディスクとして使用する本当に基本的な50GB Kingston V300(550MB / s)SSDを持っています(WindowsとRを搭載しています)。私はすべての情報を安価な500GB WDプラッターに保管しています。作業を開始したら、データセットをSSDに移動します。これは、「fread」および「fwrite」と組み合わせると、すべてうまくいきました。私は「ff」を使ってみましたが、前者を好みます。ただし、4Kの読み取り/書き込み速度では、この問題が発生する可能性があります。SSDからプラッタへの25万個の1kファイル(250MB相当)のバックアップには、数時間かかる場合があります。私の知る限り、「チャンク化」プロセスを自動的に最適化できるRパッケージはまだありません。たとえば、ユーザーが持っているRAMの容量を確認します。RAM /接続されているすべてのドライブの読み取り/書き込み速度をテストし、最適な「チャンク化」プロトコルを提案します。これにより、ワークフローが大幅に改善され、リソースが最適化されます。たとえば、RAMを... MBに分割-> SSDを... MBに分割->プラッタで... MBに分割->テープで... MBに分割 データセットを事前にサンプリングして、より現実的なゲージスティックを作成することができます。

私がRで取り組んだ問題の多くは、組み合わせと順列のペア、トリプルなどの形成に関係しています。これらの問題は、少なくともある時点で指数関数的に拡張することが多いため、限られたRAMを制限するだけです。これにより、後で情報を整理しようとするのではなく、最初にそれらに入る情報の量とは対照的に、品質に多くの注意を集中させることができました。最も単純な操作と複雑さの増加); 例:サブセット、マージ/結合、フォームの組み合わせ/順列など

場合によっては、ベースRの読み取りと書き込みを使用することにはいくつかの利点があるようです。たとえば、 'fread'内のエラー検出は非常に優れているため、まず、乱雑な情報をRに取り込んでクリーンアップすることは困難です。Linuxを使用している場合は、Base Rの方がはるかに簡単なようです。LinuxでBase Rは正常に動作するようですが、Windows 10は約20 GBのディスク領域を使用しますが、Ubuntuは数GBしか必要とせず、Ubuntuで必要なRAMはわずかに少なくなります。しかし、(L)Ubuntuにサードパーティのパッケージをインストールするときに、大量の警告とエラーに気づきました。Linuxで(L)Ubuntuやその他の株式ディストリビューションから遠く離れすぎて、全体的な互換性が失われ、プロセスがほとんど無意味になる可能性があるため、お勧めしません( 'unity'は、Ubuntuで2017年の時点でキャンセルされる予定です) )。

うまくいけば、その一部が他の人を助けるかもしれません。


5

これは上記に追加するものではありませんが、私が好きなシンプルで強くコメントされたスタイルで書かれています。これは、オブジェクトがsize順に並べられたテーブルを生成しますが、上記の例で提供された詳細の一部はありません。

#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で作業していて、複数のプロセスを使用する必要があり、1つ以上の大きなオブジェクトに対して読み取り操作のみを実行する必要がある場合makeForkClusterは、の代わりにを使用しmakePSOCKclusterます。これにより、ラージオブジェクトを他のプロセスに送信する時間も節約できます。


2

上記の回答のいくつかに本当に感謝しています。Rを閉じsourceてコマンドラインを発行して使用することを提案する@hadleyと@Dirkに続いて、私にとって非常にうまく機能する解決策を考え出します。何百もの質量スペクトルを処理する必要があり、それぞれが約20 Mbのメモリを占有するため、次のように2つの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

上記の回答で示したより一般的なメモリ管理手法と同様に、私は常にオブジェクトのサイズをできるだけ小さくするようにしています。たとえば、私は非常に大きいが非常に疎な行列、つまりほとんどの値がゼロである行列で作業します。'Matrix'パッケージを使用すると(大文字と小文字を区別することが重要)、次のように単純に、平均オブジェクトサイズを〜2GBから〜200MBに減らすことができました。

my.matrix <- Matrix(my.matrix)

Matrixパッケージには、通常のマトリックスとまったく同じように使用できる(他のコードを変更する必要はない)データ形式が含まれていますが、メモリにロードされているかディスクに保存されているかにかかわらず、スパースデータをより効率的に格納できます。

さらに、受け取った生ファイルは「ロング」フォーマットで、各データポイントには変数がありますx, y, z, i。データをx * y * z変数のみの次元配列に変換する方がはるかに効率的です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

ランニング

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

時々は、Rが未使用であるが解放されていないメモリを解放するのにも役立ちます。


forループはここで何をしますか?通話iはありませんgc
Umaomamaomao 2017

@qqqそれはgc(reset = T)9回コピーペーストを避けるためだけにあります
マルセロベンチュラ

14
しかし、なぜそれを9回実行するのでしょうか。(好奇心が強い、重要ではない)
Umaomamaomao 2017

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.