Bir R oturumunda kullanılabilir belleği yönetme hileleri


490

Kişiler etkileşimli bir R oturumunun kullanılabilir belleğini yönetmek için hangi hileleri kullanıyor? En büyük nesneleri listelemek (ve / veya sıralamak) ve rm()bazen de bazılarını listelemek için [Petr Pikal ve David Hinds'in 2004'teki r-yardım listesine gönderilerine dayanarak] aşağıdaki işlevleri kullanıyorum . Ama açık arayla en etkili çözüm ... 64-bit Linux altında geniş bellekle çalışmaktı.

Başka güzel hileler paylaşmak ister misiniz? Her gönderi için bir tane lütfen.

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

Not, şüphem yok, ama bunun ne faydası var? R'deki hafıza problemlerine oldukça yeniyim, ancak son zamanlarda biraz yaşıyorum (bu yüzden bu yazıyı arıyordum :) - bu yüzden tüm bunlarla başlıyorum. Bu günlük işlerime nasıl yardımcı olur?
Matt Bannert

4
bir işlev içindeki nesneleri görmek istiyorsanız, şunu kullanmanız gerekir: lsos (pos = çevre ()), aksi takdirde yalnızca global değişkenleri gösterir. Standart hataya yazmak için: write.table (lsos (pos = ortam ()), stderr (), alıntı = YANLIŞ, sep = '\ t')
Michael Kuhn

Neden 64 bit Windows değil 64 bit Linux? 32 GB RAM kullanacağımda işletim sistemi seçimi önemsiz bir fark yaratıyor mu?
Jase

3
@pepsimax: Bu multilevelPSApakette paketlenmiştir . Paket başka bir şey için tasarlanmıştır, ancak paketini yüklemeden oradan işlevi kullanabilirsiniz requireNamespace(multilevelPSA); multilevelPSA::lsos(...). Veya Dmiscpakette (CRAN'da değil).
krlmlr

1
Veri kümesi yönetilebilir boyuttaysa, genellikle R studio> Ortam> Izgara Görünümü'ne giderim. Burada mevcut ortamınızdaki tüm öğeleri boyutuna göre görebilir ve sıralayabilirsiniz.
kRazzy R

Yanıtlar:


197

Çalışmanızı tekrarlanabilir bir komut dosyasına kaydettiğinizden emin olun. Zaman zaman R'yi, sonra source()komut dosyanızı yeniden açın. Artık kullanmadığınız her şeyi temizleyeceksiniz ve ek bir avantaj olarak kodunuzu test etmiş olacaksınız.


58
Stratejim, scriptlerimi load.R ve do.R satırları boyunca ayırmaktır; burada load.R'nin dosyalardan veya veritabanından veri yüklemek oldukça uzun sürebilir ve herhangi bir minimum ön işleme / birleştirme yapar veri. Load.R dosyasının son satırı, çalışma alanı durumunu kaydetmek için bir şeydir. Öyleyse do.R, çizim fonksiyonumu oluşturduğum not defteri. Sık sık do.R'yi yeniden yüklüyorum (çalışma alanı durumunu load.R'den gerektiği gibi yeniden yükleyerek veya yüklemeden).
Josh Reich

32
Bu iyi bir teknik. Dosyalar böyle belirli bir sırayla çalıştırılır, ben sık sık bir dizi bunları önüne: 1-load.r, 2-explore.r, 3-model.r- başkalarına açıktır bu şekilde bazı düzen mevcut bulunmadığını söyledi.
hadley

4
Bu fikri yeterince destekleyemem. R'yi birkaç kişiye öğrettim ve bu ilk söylediğim şeylerden biri. Bu, geliştirmenin bir REPL ve düzenlenmiş bir dosyayı (Python) içerdiği her dil için de geçerlidir. rm (ls = list ()) ve source () da çalışır, ancak yeniden açma daha iyidir (paketler de temizlenir).
Vince

53
En çok oy alan cevabın R'nin yeniden başlatılmasını içermesi, R'nin en kötü eleştirisidir.
sds

7
@ MartínBel, yalnızca küresel ortamda oluşturulan nesneleri siler. Paketleri, S4 nesnelerini veya daha pek çok şeyi kaldırmaz.
hadley

160

Kullandığım data.table paketi. Onun sayesinde :=yapabilirsiniz operatörü:

  • Referansa göre sütun ekleme
  • Mevcut sütunların alt kümelerini başvuruya ve grup bazında başvuruya göre değiştirme
  • Referanslara göre sütunları silme

Bu işlemlerin hiçbiri (potansiyel olarak büyük) bir data.tablekez bile kopyalamaz .

  • Toplama da çok hızlıdır çünkü data.tableçok daha az çalışan bellek kullanır.

İlgili Bağlantılar :


109

Bunu bir twitter yazı üzerinde gördüm ve Dirk tarafından harika bir işlev olduğunu düşünüyorum! JD Long'un cevabından sonra, bunu kullanıcı dostu okuma için yaparım:

# 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()

Hangi aşağıdaki gibi bir şey ile sonuçlanır:

                      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

NOT: Eklediğim ana bölüm (yine JD'nin cevabından uyarlandı):

obj.prettysize <- napply(names, function(x) {
                           print(object.size(x), units = "auto") })

Bu işlev dplyr veya başka bir anahtar paketine eklenebilir.
userJT

1
(En azından baz-3.3.2 ile) capture.outputartık gerekli olmadığını ve obj.prettysize <- napply(names, function(x) {format(utils::object.size(x), units = "auto") })temiz çıktı ürettiğini belirtmek gerekir . Aslında, üretimdeki istenmeyen tırnak üreten çıkarmadan değil, yani [1] "792.5 Mb"yerine 792.5 Mb.
Nutle

@Nutle Excellent, kodu buna göre güncelledim :)
Tony Breyal

Ben de değiştirecek obj.class <- napply(names, function(x) as.character(class(x))[1])kadar obj.class <- napply(names, function(x) class(x)[1]) beri classdaima (baz-3.5.0) artık karakterlerden oluşan bir vektör döndürür.
DeltaIV

49

subsetVeri çerçevelerini data=regresyon fonksiyonlarının argümanına iletirken sadece gerekli değişkenleri seçerek parametrenin agresif kullanımını yaparım . Hem formüle hem de select=vektöre değişkenler eklemeyi unutursam bazı hatalara neden olur , ancak nesnelerin kopyalanmasının azalması ve bellek ayak izini önemli ölçüde azaltması nedeniyle hala çok zaman kazandırır. Diyelim ki 110 değişkenli 4 milyon kaydım var (ve var.) Örnek:

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

Bağlam ve strateji belirleyerek: gdlab2değişken, bir veri kümesindeki bir grup laboratuvar testi için tüm normal veya neredeyse normal değerlere sahip olan HIVfinalve HIV için ön ve doğrulayıcı testi özetleyen bir karakter vektörü olan mantıksal bir vektördür. .


48

Dirk'in .ls.objects () komut dosyasını seviyorum ama boyut sütunundaki karakterleri saymak için gözlerini kısmaya devam ettim. Bu yüzden boyutu için güzel biçimlendirme ile sunmak için bazı çirkin kesmek yaptım:

.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

Bu iyi bir numara.

Diğer bir öneri, mümkün olan yerlerde bellek tasarruflu nesneler kullanmaktır: örneğin, data.frame yerine bir matris kullanın.

Bu gerçekten bellek yönetimini ele almıyor, ancak yaygın olarak bilinmeyen önemli bir işlev memory.limit (). Boyutun MB cinsinden olduğu memory.limit (size = 2500) komutunu kullanarak varsayılanı artırabilirsiniz. Dirk'ten bahsedildiği gibi, bundan gerçek anlamda yararlanmak için 64 bit kullanmanız gerekir.


25
Bu yalnızca Windows için geçerli değil mi?
Christopher DuBois

4
> memory.limit () [1] Inf Uyarı mesajı: 'memory.limit ()' Windows'a özgü
LJT

Data.frame yerine tibble kullanmak, bellek tasarrufu yapmamıza yardımcı olur mu?

32

Dirk tarafından geliştirilen geliştirilmiş nesneler fonksiyonunu çok seviyorum. Ancak çoğu zaman, nesne adı ve boyutu ile daha temel bir çıktı benim için yeterli. İşte benzer bir amaca sahip daha basit bir işlev. Bellek kullanımı alfabetik olarak veya boyuta göre sıralanabilir, belirli sayıda nesne ile sınırlandırılabilir ve artan veya azalan şekilde sipariş edilebilir. Ayrıca, genellikle 1GB + olan verilerle çalışırım, bu nedenle işlev birimleri uygun şekilde değiştirir.

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

İşte bazı örnek çıktı:

> 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

Asla bir R çalışma alanını kaydetmedim. İçe aktarma komut dosyaları ve veri komut dosyaları kullanıyorum ve dosyalara sık sık yeniden oluşturmak istemediğim özellikle büyük veri nesnelerini çıkarıyorum. Bu şekilde her zaman yeni bir çalışma alanı ile başlıyorum ve büyük nesneleri temizlemem gerekmiyor. Yine de bu çok güzel bir işlev.


30

Ne yazık ki kapsamlı bir şekilde test etmek için zamanım yoktu ama burada daha önce görmediğim bir bellek ipucu. Benim için gerekli bellek% 50'den fazla azaltıldı. Örneğin read.csv ile R'ye bir şeyler okuduğunuzda belirli miktarda bellek gerektirirler. Bundan sonra bunları ile kaydedebilirsiniz save("Destinationfile",list=ls()) R'yi bir sonraki açışınızda kullanabilirsiniz load("Destinationfile") Artık bellek kullanımı azalmış olabilir. Herhangi birinin bunun farklı bir veri kümesiyle benzer sonuçlar üretip üretmediğini onaylaması güzel olurdu.


4
evet, ben de yaşadım. Benim durumumda bellek kullanımı% 30'a kadar düşüyor. 1.5GB bellek kullanıldı, .RData'ya kaydedildi (~ 30MB). .RData yüklendikten sonra yeni oturum 500MB'tan daha az bellek kullanır.
f3lix

2 veri kümesi (100MB ve 2.7GB) kullanarak data.table kullanarak yükledim fread, sonra .RData kaydedildi. RData dosyaları gerçekten yaklaşık% 70 daha küçüktü, ancak yeniden yüklendikten sonra kullanılan bellek tamamen aynıydı. Bu hilenin bellek ayak izini azaltacağını umuyordum ... bir şey mi kaçırıyorum?
NoviceProg 18:15

@NoviceProg Ben bir şey eksik olduğunu sanmıyorum, ama bu bir hile, sanırım tüm durumlar için işe yaramaz. Benim durumumda, yeniden yükleme sonrasındaki bellek açıklandığı gibi azaltıldı.
Dennis Jaheruddin

6
@NoviceProg Birkaç şey. İlk olarak, data.table'ın itibarı takiben, fread, muhtemelen dosya yüklemede read.csv'den daha fazla bellek verimlidir. İkincisi, insanların burada kaydettikleri bellek tasarrufları öncelikle R işleminin bellek boyutuyla (çöp toplama gerçekleştiğinde nesneleri tutmak ve geri çekilmek için genişler) yapmak zorunda. Ancak, çöp toplama her zaman tüm RAM'leri işletim sistemine geri bırakmaz. R oturumunun durdurulması ve öğenin depolandığı yerden yüklenmesi mümkün olduğunca fazla RAM bırakacaktır ... ancak ek yük küçükse ... kazanç olmaz.
russellpierce

27

Sık sık yeniden başlatmaların ortak stratejisini daha fazla göstermek için, basit ifadeleri doğrudan komut satırından çalıştırmamıza izin veren littler'ı kullanabiliriz . Basit bir çapraz kod için bazen farklı BLAS zamanlamak için kullandığım bir örnek.

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

Aynı şekilde,

 r -lMatrix -e'example(spMatrix)'

Matrix paketini yükler (--packages | -l anahtarı ile) ve spMatrix işlevinin örneklerini çalıştırır. R her zaman 'taze' olarak başladığı için, bu yöntem aynı zamanda paket geliştirme sırasında iyi bir testtir.

Son fakat en az değil de r '#! / Usr / bin / r' shebang-header kullanarak komut dosyalarında otomatik toplu iş modu için harika çalışıyor. Rscript, littler'ın kullanılamadığı bir alternatiftir (örn. Windows'ta).


23

Hem hız hem de bellek amaçları için, bazı karmaşık adımlar dizisi aracılığıyla büyük bir veri çerçevesi oluştururken, daha önce gelen herhangi bir şeye ekleyerek ve daha sonra yeniden başlatan düzenli olarak diske temizlerim (yapım aşamasında olan veri kümesi). . Bu şekilde ara adımlar yalnızca ufacık veri çerçeveleri üzerinde çalışır (örn. Rbind , daha büyük nesnelerle önemli ölçüde yavaşlar). Tüm ara nesneler kaldırıldığında, tüm veri seti işlemin sonunda tekrar okunabilir.

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

Sadece matrisler, diziler, listeler için değil sadece data.frames / tables için olsa da , data.tablepaketin tables()Dirk'ün .ls.objects()özel işlevi için oldukça iyi bir yedek gibi göründüğünü unutmayın .


Bu herhangi bir veri listeler.
çerçeveler

16
  1. Şanslıyım ve büyük veri setlerim enstrüman tarafından yaklaşık 100 MB'lık (alt kümeler) 100 MB'lık (32 bit ikili) kaydedilir. Böylece veri setini kaynaştırmadan önce sırayla ön işleme adımları (bilgilendirici olmayan parçaların silinmesi, altörnekleme) yapabilirim.

  2. Arayan gc ()veri boyutu yakın mevcut hafızaya alırsanız "elle" yardımcı olabilir.

  3. Bazen farklı bir algoritmanın çok daha az belleğe ihtiyacı vardır.
    Bazen vektörleştirme ve bellek kullanımı arasında bir denge vardır.
    karşılaştırmak: split& lapplyvs. bir fordöngü.

  4. Hızlı ve kolay veri analizi uğruna, genellikle önce verilerin küçük bir rastgele alt kümesiyle ( sample ()) çalışırım . Veri analiz komut dosyası / .Rnw bittikten sonra veri analiz kodu ve tüm veriler gece / hafta sonu / ... hesaplaması için hesaplama sunucusuna gider.


11

Önemli miktarda çalışma belleği kullanan nesne koleksiyonlarını işlemek için listeler yerine ortamların kullanılması.

Nedeni: Bir listyapının bir elemanı her değiştirildiğinde, tüm liste geçici olarak çoğaltılır. Bu, listenin depolama gereksinimi kullanılabilir çalışma belleğinin yaklaşık yarısı ise bir sorun haline gelir, çünkü verilerin yavaş sabit diske değiştirilmesi gerekir. Diğer yandan ortamlar bu davranışa tabi değildir ve listelere benzer şekilde işlenebilir.

İşte bir örnek:

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

İçeriğinin yerinde değiştirilmesine izin veren big.matrixveya buna data.tableizin veren yapılar ile birlikte çok verimli bellek kullanımı sağlanabilir.


6
Bu artık doğru değil: Hadley'in gelişmiş R'sinden , "R 3.1.0'daki değişiklikler [ortamların] kullanımını daha az önemli hale getirdi çünkü bir listeyi değiştirmek artık derin bir kopya oluşturmuyor."
petrelharp

8

llFonksiyon gDatapaketi gibi iyi her nesnenin hafıza kullanımını gösterebiliriz.

gdata::ll(unit='MB')

Sistemimde değil: R sürüm 3.1.1 (2014-07-10), x86_64-pc-linux-gnu (64 bit), gdata_2.13.3, gtools_3.4.1.
krlmlr

Haklısın, şans eseri sipariş edildiğinde test ediyorum!
user1436187

1
lütfen işlevi Gb, Mb kullanmak için değiştirin
userJT

7

Sızıntılardan gerçekten kaçınmak istiyorsanız, küresel ortamda büyük nesneler oluşturmaktan kaçınmalısınız.

Genelde yaptığım, işi yapan ve geri dönen bir işleve sahip olmaktır NULL- tüm veriler bu işlevde veya çağırdığı diğerlerinde okunur ve işlenir.


7

Sadece 4GB RAM (Windows 10 çalıştıran, bu yüzden yaklaşık 2 veya daha gerçekçi 1GB olun) ayırma konusunda gerçekten dikkatli olmak zorunda kaldım.

Data.table'ı neredeyse tamamen kullanıyorum.

'Fread' işlevi, içe aktarma sırasında bilgileri alan adlarına göre alt kümeye almanızı sağlar; yalnızca başlangıçta gerçekten gerekli olan alanları içe aktarın. Temel R okumasını kullanıyorsanız, içe aktardıktan hemen sonra sahte sütunları sıfırlayın.

As 42- anlaşılacağı, ben sonra hemen bilgi aktardıktan sonra sütunların içinde alt küme olacak hiç mümkün olduğunca.

Sık sık, artık gerekli olmadıkça nesneleri ortamdan rm (), örneğin başka bir şey alt kümesi için onları kullandıktan sonra sonraki satırda ve gc () çağırmak.

data.table'dan 'fread' ve 'fwrite' temel R okuma ve yazma işlemlerine kıyasla çok hızlı olabilir .

As kpierce8 ortamının dışarı, ben hemen hemen her zaman fwrite şeyi önerir ve hatta geçmek için minik binlerce dosya bin / yüzlerce tekrar içeri Fread. Bu sadece çevreyi 'temiz' tutmakla kalmaz aynı zamanda bellek tahsisini de düşük tutar, ancak büyük olasılıkla kullanılabilir RAM eksikliğinden dolayı, R bilgisayarımda sık sık çökme eğilimi gösterir; gerçekten sık. Kod çeşitli aşamalarda ilerledikçe sürücünün kendisinde yedeklenen bilgilere sahip olmak, çökerse en baştan başlamak zorunda kalmamam anlamına gelir.

2017 itibariyle, en hızlı SSD'lerin M2 portu üzerinden saniyede birkaç GB çalıştığını düşünüyorum. Birincil diskim olarak kullandığım gerçekten temel bir 50GB Kingston V300 (550MB / s) SSD'ye sahibim (üzerinde Windows ve R var). Tüm toplu bilgileri ucuz bir 500GB WD tablasında saklıyorum. Üzerinde çalıştığımda veri setlerini SSD'ye taşıyorum. Bu, 'korkma' ve 'fwrite' ile birlikte her şey harika çalışıyor. Ben 'ff' kullanmayı denedim ama eski tercih ederim. 4K okuma / yazma hızları bununla ilgili sorunlar yaratabilir; SSD'den tabağa çeyrek milyon 1k dosya (250MBs değerinde) yedeklemek saatler sürebilir. Bildiğim kadarıyla, 'chunkification' sürecini otomatik olarak optimize edebilen henüz bir R paketi yok; örneğin bir kullanıcının ne kadar RAM'e sahip olduğuna bakın, bağlı olan RAM / tüm sürücülerin okuma / yazma hızlarını test edin ve ardından en uygun 'tıklatma' protokolünü önerin. Bu, bazı önemli iş akışı iyileştirmeleri / kaynak optimizasyonları üretebilir; örneğin ram için ... MB için bölmek -> SSD için - MB için bölmek -> bölmek için ... bölmedeki MB -> bölmek için ... bantta MB. Çalışmak için daha gerçekçi bir ölçü çubuğu vermek için veri kümelerini önceden örnekleyebilir.

R'de üzerinde çalıştığım birçok sorun, kombinasyon ve permütasyon çiftleri, üçlüler vb.'nin oluşturulmasını içerir, bu da sınırlı RAM'in daha az bir sınırda olmasını sağlar çünkü genellikle en azından bir noktada genişlerler. Bu , daha sonra temizlemeye çalışmak yerine, kendileriyle başlayacak olan bilgi miktarının aksine kaliteye ve başlamak için bilgileri hazırlamaya yönelik işlem sırasına çok fazla dikkat çekti. en basit operasyon ve karmaşıklığı arttırmak); örneğin altküme, birleştirme / birleştirme, ardından kombinasyonlar / permütasyonlar vb.

Baz R okuma ve yazma bazı durumlarda kullanmanın bazı yararları var gibi görünüyor. Örneğin, 'fread' içindeki hata tespiti o kadar iyidir ki, temizlemeye başlamak için R'ye gerçekten dağınık bilgi almaya çalışmak zor olabilir. Linux kullanıyorsanız Base R de çok daha kolay görünüyor. Base R Linux'ta iyi çalışıyor gibi görünüyor, Windows 10 ~ 20GB disk alanı kullanıyor ancak Ubuntu'nun sadece birkaç GB'ye ihtiyacı var, Ubuntu ile ihtiyaç duyulan RAM biraz daha düşük. Ancak (L) Ubuntu'ya üçüncü taraf paketleri yüklerken büyük miktarlarda uyarı ve hata fark ettim. (L) Ubuntu veya Linux ile diğer hisse senedi dağıtımlarından çok uzakta sürüklenmenizi tavsiye etmem, çünkü süreci neredeyse anlamsız hale getiren çok fazla genel uyumluluğu kaybedebilirsiniz (bence 'birlik' 2017'den itibaren Ubuntu'da iptal edilecek ).

Umarım bunlardan bazıları başkalarına yardım edebilir.


5

Bu, yukarıdakilere hiçbir şey katmaz, ancak sevdiğim basit ve ağır yorumlanmış tarzda yazılır. Yukarıdaki örneklerde verilen ayrıntıların bir kısmı olmadan, boyut olarak sipariş edilen nesnelerle bir tablo verir:

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

5

Bu, bu mükemmel eski sorunun daha yeni bir cevabıdır. Hadley'nin Gelişmiş R'sinden:

install.packages("pryr")

library(pryr)

object_size(1:10)
## 88 B

object_size(mean)
## 832 B

object_size(mtcars)
## 6.74 kB

( http://adv-r.had.co.nz/memory.html )


3

Eğer çalışıyorsanız Linux ve kullanmak istediğiniz birkaç süreçleri ve sadece yapmak zorunda okuma bir veya daha fazla işlemleri büyük nesnelerin kullanmak makeForkClusteryerine ait makePSOCKcluster. Bu aynı zamanda büyük nesneyi diğer işlemlere gönderme zamanından tasarruf etmenizi sağlar.


2

Yukarıdaki cevaplardan bazılarını takdir ediyorum, @hadley ve @ Dirk'i takip ederek R'yi kapatmayı sourceve komut satırını yayınlamayı ve kullanmayı benim için çok iyi çalışan bir çözüm buluyorum . Yüzlerce kütle spektrumu ile uğraşmak zorunda kaldım, her biri yaklaşık 20 Mb bellek kaplıyor, bu yüzden aşağıdaki gibi iki R komut dosyası kullandım:

İlk önce bir sarıcı:

#!/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))
   }
}

Bu komut dosyası ile temel olarak ana komut dosyamın ne yaptığını kontrol runConsensus.rediyorum ve çıktı için veri yanıtını yazıyorum. Bununla, sarıcı komut dosyasını her çağırdığında, R yeniden açılmış ve bellek serbest bırakılmış gibi görünüyor.

Umarım yardımcı olur.


2

Yukarıdaki yanıtlarda verilen daha genel bellek yönetimi tekniklerinin yanı sıra, nesnelerimin boyutunu her zaman mümkün olduğunca azaltmaya çalışıyorum. Örneğin, çok büyük ama çok seyrek matrislerle, diğer bir deyişle çoğu değerin sıfır olduğu matrislerle çalışıyorum. 'Matrix' paketini kullanarak (büyük harf kullanımı önemlidir) ortalama nesne boyutumu ~ 2GB'dan ~ 200MB'ye kadar düşürdüm:

my.matrix <- Matrix(my.matrix)

Matrix paketi, normal bir matris gibi kullanılabilen (diğer kodunuzu değiştirmenize gerek yoktur) ancak belleğe yüklenen veya diske kaydedilen seyrek verileri çok daha verimli bir şekilde depolayabilen veri formatları içerir.

Ayrıca, aldığım ham dosyalar, her veri noktasının değişkenleri olduğu 'uzun' biçimindedir x, y, z, i. Verileri x * y * zsadece değişkenli bir boyut dizisine dönüştürmek için çok daha verimli i.

Verilerinizi tanıyın ve biraz sağduyunuzu kullanın.


2

Ağır ara hesaplama gerektiren nesnelerle uğraşmak için ipucu: Oluşturmak için çok fazla ağır hesaplama ve ara adım gerektiren nesneler kullanırken, genellikle nesneyi oluşturma işleviyle bir kod parçası ve sonra ayrı bir yığın yazmayı yararlı buluyorum nesneyi bir rmddosya olarak oluşturma ve kaydetme veya rmddaha önce kaydettiğim bir dosyadan harici olarak yükleme seçeneği sunan kodun . Bu, özellikle R Markdownaşağıdaki kod yığın yapısını kullanarak yapmak kolaydır .

```{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); }

```

Bu kod yapısı ile tek yapmam gereken LOAD, nesneyi oluşturmak ve kaydetmek isteyip istemediğime veya doğrudan kayıtlı bir dosyadan yüklemek isteyip istemediğime bağlı olarak değişmektir. (Tabii ki, onu ilk kez üretip kaydetmeliyim, ama bundan sonra yükleme seçeneğim var.) Ayarlamak LOAD = TRUEkarmaşık işlevimin kullanımını atlar ve içindeki tüm ağır hesaplamalardan kaçınır. Bu yöntem yine de ilgilenilen nesneyi depolamak için yeterli bellek gerektirir, ancak kodunuzu her çalıştırdığınızda bunu hesaplamaktan kurtarır. Ara adımların çok fazla hesaplanmasını gerektiren nesneler için (örneğin, büyük dizilerdeki döngüler içeren hesaplamalar için) bu önemli miktarda zaman ve hesaplama tasarrufu sağlayabilir.


1

Koşu

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

zaman zaman R'nin kullanılmayan ancak hala serbest bırakılmamış belleği boşaltmasına da yardımcı olur.


forDöngü burada ne yapıyor ? Hiçbir var iiçinde gcçağrı.
Umaomamaomao

@qqq gc(reset = T)dokuz kez kopyala yapıştırmayı önlemek için orada
Marcelo Ventura

14
Ama neden 9 kere koşasın ki? (meraklı, kritik değil)
Umaomamaomao

1

Ayrıca knitr kullanarak ve betiğinizi Rmd parçalarına koyarak da fayda sağlayabilirsiniz.

Genellikle kodu farklı parçalara bölerim ve hangisinin bir kontrol noktasını önbelleğe veya bir RDS dosyasına kaydedeceğini seçerim ve

Orada, bir önbelleği "önbellek" e kaydedilecek şekilde ayarlayabilir veya belirli bir yığını çalıştırmaya karar verebilirsiniz. Bu şekilde, ilk çalıştırmada sadece "bölüm 1" i işleyebilir, başka bir yürütme yalnızca "bölüm 2" vb. Seçebilirsiniz.

Misal:

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

Bir yan etki olarak, bu da tekrarlanabilirlik açısından size bazı baş ağrılarından kurtarabilir :)


1

@ Dirk's ve @ Tony'nin cevabına dayanarak hafif bir güncelleme yaptım. Sonuç [1]güzel boyut değerlerinden önce çıktı, capture.outputbu yüzden hangi sorunu çözdü çıkardı :

.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

Çok sayıda orta adımda daha büyük bir projede çalışırken nesne miktarını küçük tutmaya çalışıyorum. Yani, birçok benzersiz nesne oluşturmak yerine

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

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

Aradığım geçici nesnelerle çalışıyorum temp.

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

Bu da beni daha az ara dosya ve daha fazla genel bakışla bırakıyor.

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

Daha fazla bellek tasarrufu için tempartık gerekmediğinde kaldırabilirim .

rm(temp)

Birkaç ara dosyaları gerekiyorsa, kullandığım temp1, temp2, temp3.

Kullandığım test için test, test2...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.