Trik untuk mengelola memori yang tersedia dalam sesi R.

490

Trik apa yang digunakan orang untuk mengelola memori sesi R interaktif yang tersedia? Saya menggunakan fungsi-fungsi di bawah ini [berdasarkan pada posting oleh Petr Pikal dan David Hinds ke daftar r-help pada 2004] untuk membuat daftar (dan / atau mengurutkan) objek terbesar dan kadang-kadang rm()beberapa di antaranya. Tetapi sejauh ini solusi yang paling efektif adalah ... berjalan di bawah Linux 64-bit dengan memori yang cukup.

Adakah trik bagus lain yang ingin dibagikan orang? Tolong satu per posting.

# 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)
}
Dirk Eddelbuettel
sumber
Catatan, saya TIDAK meragukannya, tapi apa gunanya itu? Saya cukup baru dalam masalah memori di R, tetapi saya mengalami beberapa akhir-akhir ini (itu sebabnya saya mencari posting ini :) - jadi saya baru mulai dengan semua ini. Bagaimana ini membantu pekerjaan saya sehari-hari?
Matt Bannert
4
jika Anda ingin melihat objek dalam suatu fungsi, Anda harus menggunakan: lsos (pos = environment ()), jika tidak, ia hanya akan menampilkan variabel global. Untuk menulis ke standard error: write.table (lsos (pos = environment ()), stderr (), quote = FALSE, sep = '\ t')
Michael Kuhn
Mengapa 64-bit linux dan bukan 64-bit Windows? Apakah pilihan OS membuat perbedaan non-sepele ketika saya memiliki 32GB ram untuk digunakan?
Jase
3
@ pepsimax: Ini telah dikemas dalam multilevelPSApaket . Paket ini dirancang untuk sesuatu yang lain, tetapi Anda dapat menggunakan fungsi dari sana tanpa memuat paket dengan mengatakan requireNamespace(multilevelPSA); multilevelPSA::lsos(...). Atau dalam Dmiscpaket (bukan pada CRAN).
krlmlr
1
Jika kumpulan data memiliki ukuran yang dapat dikelola, saya biasanya pergi ke R studio> Environment> Grid View. Di sini Anda dapat melihat dan mengurutkan semua item di lingkungan Anda saat ini berdasarkan ukuran.
kRazzy R

Jawaban:

197

Pastikan Anda merekam pekerjaan Anda dalam skrip yang dapat direproduksi. Dari waktu ke waktu, buka kembali R, lalu source()skrip Anda. Anda akan membersihkan apa pun yang tidak lagi Anda gunakan, dan sebagai manfaat tambahan akan menguji kode Anda.

Hadley
sumber
58
Strategi saya adalah untuk memecah skrip saya di sepanjang garis load.R dan do.R, di mana load.R mungkin membutuhkan beberapa waktu untuk memuat data dari file atau database, dan melakukan minimum pra-pemrosesan / penggabungan dari data itu. Baris terakhir load.R adalah sesuatu untuk menyelamatkan kondisi ruang kerja. Lalu do.R adalah scratchpad saya di mana saya membangun fungsi analisis saya. Saya sering memuat ulang do.R (dengan atau tanpa memuat status workspace dari load.R sesuai kebutuhan).
Josh Reich
32
Itu teknik yang bagus. Ketika file dijalankan dalam urutan tertentu seperti itu, saya sering awalan mereka dengan nomor: 1-load.r, 2-explore.r, 3-model.r- dengan cara itu jelas kepada orang lain bahwa ada beberapa urutan hadir.
Hadley
4
Saya tidak bisa mendukung ide ini dengan cukup. Saya telah mengajar R kepada beberapa orang dan ini adalah salah satu hal pertama yang saya katakan. Ini juga berlaku untuk bahasa apa pun di mana pengembangan menggabungkan REPL dan file yang sedang diedit (yaitu Python). rm (ls = list ()) dan source () berfungsi juga, tetapi membuka kembali lebih baik (paket dibersihkan juga).
Vince
53
Fakta bahwa jawaban teratas melibatkan memulai kembali R adalah kritik terburuk dari R yang mungkin.
sds
7
@ MartínBel yang hanya menghapus objek yang dibuat di lingkungan global. Itu tidak membongkar paket atau objek S4 atau banyak hal lainnya.
Hadley
160

Saya menggunakan paket data.table . Dengan :=operatornya Anda dapat:

  • Tambahkan kolom dengan referensi
  • Ubah himpunan bagian dari kolom yang ada dengan referensi, dan dengan grup dengan referensi
  • Hapus kolom dengan referensi

Tak satu pun dari operasi ini menyalin (berpotensi besar) data.tablesama sekali, bahkan tidak sekali.

  • Agregasi juga sangat cepat karena data.tablemenggunakan memori yang bekerja jauh lebih sedikit.

Tautan yang berhubungan :

Matt Dowle
sumber
109

Lihat ini di posting twitter dan anggap ini fungsi luar biasa dari Dirk! Sebagai lanjutan dari jawaban JD Long, saya akan melakukan ini untuk membaca ramah pengguna:

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

Yang menghasilkan sesuatu seperti berikut:

                      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

CATATAN: Bagian utama yang saya tambahkan adalah (sekali lagi, diadaptasi dari jawaban JD):

obj.prettysize <- napply(names, function(x) {
                           print(object.size(x), units = "auto") })
Tony Breyal
sumber
dapat fungsi ini ditambahkan ke dplyr atau paket kunci lainnya.
userJT
1
Perlu dicatat bahwa (setidaknya dengan basis-3.3.2) capture.outputtidak perlu lagi, dan obj.prettysize <- napply(names, function(x) {format(utils::object.size(x), units = "auto") })menghasilkan keluaran bersih. Bahkan, tidak menghapusnya menghasilkan kutipan yang tidak diinginkan di output, yaitu [1] "792.5 Mb"bukannya 792.5 Mb.
Nutle
@ Nut Excellent, saya telah memperbarui kode yang sesuai :)
Tony Breyal
Saya juga berubah obj.class <- napply(names, function(x) as.character(class(x))[1])menjadi obj.class <- napply(names, function(x) class(x)[1]) karena classselalu mengembalikan vektor karakter sekarang (base-3.5.0).
DeltaIV
49

Saya menggunakan subsetparameter secara agresif dengan hanya memilih variabel yang diperlukan ketika meneruskan kerangka data ke data=argumen fungsi regresi. Itu memang menghasilkan beberapa kesalahan jika saya lupa menambahkan variabel ke rumus dan select=vektor, tetapi masih menghemat banyak waktu karena penurunan penyalinan objek dan mengurangi jejak memori secara signifikan. Katakanlah saya memiliki 4 juta catatan dengan 110 variabel (dan saya punya.) Contoh:

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

Dengan cara menetapkan konteks dan strategi: gdlab2variabel adalah vektor logis yang dibangun untuk subjek dalam dataset yang memiliki semua nilai normal atau hampir normal untuk sekelompok tes laboratorium dan HIVfinalmerupakan vektor karakter yang merangkum tes pendahuluan dan konfirmasi untuk HIV .

IRTFM
sumber
48

Saya suka skrip .ls.objects () dari Dirk, tetapi saya tetap menyipitkan mata untuk menghitung karakter di kolom ukuran. Jadi saya melakukan beberapa hacks jelek untuk membuatnya hadir dengan format yang cukup untuk ukuran:

.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
}
JD Long
sumber
34

Itu trik yang bagus.

Satu saran lain adalah untuk menggunakan objek yang efisien memori sedapat mungkin: misalnya, gunakan matriks, bukan data.frame.

Ini tidak benar-benar menangani manajemen memori, tetapi satu fungsi penting yang tidak banyak dikenal adalah memory.limit (). Anda dapat meningkatkan default menggunakan perintah ini, memory.limit (size = 2500), di mana ukurannya dalam MB. Seperti yang disebutkan Dirk, Anda harus menggunakan 64-bit untuk mengambil keuntungan nyata dari ini.

Shane
sumber
25
Bukankah ini hanya berlaku untuk Windows?
Christopher DuBois
4
> memory.limit () [1] Pesan Peringatan Inf: 'memory.limit ()' khusus untuk Windows
LJT
Apakah menggunakan tibble sebagai ganti data.frame membantu kita lebih baik untuk menghemat memori?
32

Saya sangat menyukai fungsi objek yang dikembangkan oleh Dirk. Namun, sebagian besar waktu, keluaran yang lebih mendasar dengan nama dan ukuran objek cukup bagi saya. Inilah fungsi yang lebih sederhana dengan tujuan yang serupa. Penggunaan memori dapat dipesan berdasarkan abjad atau berdasarkan ukuran, dapat dibatasi untuk sejumlah objek tertentu, dan dapat dipesan naik atau turun. Juga, saya sering bekerja dengan data yang 1GB +, jadi fungsinya berubah satuan.

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

Dan inilah beberapa contoh output:

> 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
Michael Hallquist
sumber
30

Saya tidak pernah menyimpan ruang kerja R. Saya menggunakan skrip impor dan skrip data dan menampilkan objek data besar apa pun yang tidak ingin sering saya buat ulang ke file. Dengan cara ini saya selalu memulai dengan ruang kerja baru dan tidak perlu membersihkan benda besar. Itu adalah fungsi yang sangat bagus.

kpierce8
sumber
30

Sayangnya saya tidak punya waktu untuk mengujinya secara ekstensif tetapi di sini ada tip memori yang belum pernah saya lihat sebelumnya. Bagi saya memori yang dibutuhkan berkurang dengan lebih dari 50%. Ketika Anda membaca barang-barang ke R dengan misalnya read.csv mereka memerlukan sejumlah memori. Setelah ini, Anda dapat menyimpannya dengan save("Destinationfile",list=ls()) lain kali Anda membuka R Anda dapat menggunakan load("Destinationfile") Sekarang penggunaan memori mungkin telah menurun. Alangkah baiknya jika ada yang bisa mengkonfirmasi apakah ini menghasilkan hasil yang sama dengan dataset yang berbeda.

Dennis Jaheruddin
sumber
4
ya, saya mengalami hal yang sama. Penggunaan memori turun hingga 30% dalam kasus saya. Memori 1,5GB digunakan, disimpan ke. Data (~ 30MB). Sesi baru setelah memuat .Rata menggunakan memori kurang dari 500MB.
f3lix
Saya mencoba dengan 2 dataset (100MB dan 2.7GB) dimuat ke data.table menggunakan fread, kemudian disimpan ke. Data. File RData memang sekitar 70% lebih kecil tetapi setelah memuat ulang, memori yang digunakan persis sama. Berharap trik ini akan mengurangi jejak memori ... apakah saya melewatkan sesuatu?
NoviceProg
@NoviceProg Saya tidak berpikir bahwa Anda kehilangan sesuatu, tetapi itu adalah trik, saya kira itu tidak akan berfungsi untuk semua situasi. Dalam kasus saya, memori setelah memuat ulang sebenarnya berkurang seperti yang dijelaskan.
Dennis Jaheruddin
6
@NoviceProg Ada beberapa hal. Pertama, takut, mengikuti kredo data.tabel mungkin lebih efisien dalam memuat file daripada read.csv. Kedua, penghematan memori yang dicatat oleh orang-orang di sini terutama berkaitan dengan ukuran memori dari proses R (yang mengembang untuk menampung benda dan menarik ketika pengumpulan sampah terjadi). Namun, pengumpulan sampah tidak selalu melepaskan semua RAM kembali ke OS. Menghentikan sesi R dan memuat item dari tempat penyimpanannya akan melepaskan RAM sebanyak mungkin ... tetapi jika overhead kecil untuk memulai dengan ... tidak ada keuntungan.
russellpierce
27

Untuk mengilustrasikan strategi umum restart yang sering, kita dapat menggunakan littler yang memungkinkan kita untuk menjalankan ekspresi sederhana langsung dari baris perintah. Berikut adalah contoh yang kadang saya gunakan untuk menentukan waktu BLAS berbeda untuk crossprod sederhana.

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

Juga,

 r -lMatrix -e'example(spMatrix)'

memuat paket Matrix (melalui saklar --packages | -l) dan menjalankan contoh fungsi spMatrix. Karena r selalu memulai 'fresh', metode ini juga merupakan tes yang baik selama pengembangan paket.

Last but not least r juga berfungsi baik untuk mode batch otomatis dalam skrip menggunakan shebang-header '#! / Usr / bin / r'. Rscript adalah alternatif di mana littler tidak tersedia (misalnya pada Windows).

Dirk Eddelbuettel
sumber
23

Untuk keperluan kecepatan dan memori, saat membangun bingkai data besar melalui serangkaian langkah yang kompleks, saya akan secara berkala menyiramnya (set data yang sedang dibuat sedang dibangun) ke disk, menambahkan ke apa pun yang datang sebelumnya, dan kemudian memulai kembali. . Dengan cara ini langkah-langkah perantara hanya bekerja pada frame data bertubuh kecil (yang bagus, misalnya, rbind melambat jauh dengan objek yang lebih besar). Seluruh kumpulan data dapat dibaca kembali di akhir proses, ketika semua objek perantara telah dihapus.

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 )
Ben BL
sumber
17

Hanya untuk dicatat bahwa data.tablepaket tables()tampaknya merupakan pengganti yang cukup bagus untuk .ls.objects()fungsi kustom Dirk (dirinci dalam jawaban sebelumnya), meskipun hanya untuk data.frame / tabel dan bukan misalnya matriks, array, daftar.

geotheory
sumber
ini tidak mencantumkan data.frame apa pun sehingga tidak terlalu bagus
userJT
16
  1. Saya beruntung dan set data saya yang besar disimpan oleh instrumen dalam "potongan" (himpunan bagian) sekitar 100 MB (biner 32bit). Jadi saya dapat melakukan langkah-langkah pra-pemrosesan (menghapus bagian yang tidak informatif, downsampling) secara berurutan sebelum menggabungkan set data.

  2. Memanggil gc ()"dengan tangan" dapat membantu jika ukuran data mendekati memori yang tersedia.

  3. Terkadang algoritma yang berbeda membutuhkan lebih sedikit memori.
    Terkadang ada trade off antara vektorisasi dan penggunaan memori.
    bandingkan: split& lapplyvs. satu forloop.

  4. Demi analisis data yang cepat & mudah, saya sering bekerja dulu dengan subset acak kecil ( sample ()) dari data. Setelah script analisis data / .Rnw selesai kode analisis data dan data lengkap pergi ke server perhitungan untuk perhitungan malam / akhir pekan / ...

cbeleites tidak senang dengan SX
sumber
11

Penggunaan lingkungan alih-alih daftar untuk menangani koleksi objek yang menempati sejumlah besar memori yang bekerja.

Alasannya: setiap kali elemen liststruktur diubah, seluruh daftar sementara digandakan. Ini menjadi masalah jika persyaratan penyimpanan daftar adalah sekitar setengah dari memori yang tersedia, karena data harus ditukar dengan hard disk yang lambat. Lingkungan, di sisi lain, tidak tunduk pada perilaku ini dan mereka dapat diperlakukan serupa dengan daftar.

Berikut ini sebuah contoh:

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

Dalam hubungannya dengan struktur seperti big.matrixatau data.tableyang memungkinkan untuk mengubah konten mereka di tempat, penggunaan memori yang sangat efisien dapat dicapai.

Georg Schnabel
sumber
6
Ini tidak lagi benar: dari R canggih Hadley , "Perubahan ke R 3.1.0 telah membuat penggunaan [lingkungan] ini secara substansial kurang penting karena memodifikasi daftar tidak lagi membuat salinan yang dalam."
petrelharp
8

The llfungsi dalam gDatapaket dapat menunjukkan penggunaan memori setiap objek juga.

gdata::ll(unit='MB')
pengguna1436187
sumber
Bukan pada sistem saya: R versi 3.1.1 (2014-07-10), x86_64-pc-linux-gnu (64-bit), gdata_2.13.3, gtools_3.4.1.
krlmlr
Anda benar, saya mengujinya begitu dipesan secara kebetulan!
user1436187
1
silakan modifikasi fungsi untuk menggunakan Gb, Mb
userJT
7

Jika Anda benar-benar ingin menghindari kebocoran, Anda harus menghindari membuat benda besar di lingkungan global.

Apa yang biasanya saya lakukan adalah memiliki fungsi yang melakukan pekerjaan dan mengembalikan NULL- semua data dibaca dan dimanipulasi dalam fungsi ini atau orang lain yang dipanggil.

Alexander Radev
sumber
7

Dengan hanya 4GB RAM (menjalankan Windows 10, jadi buatlah sekitar 2 atau lebih 1GB realistis) Saya harus benar-benar berhati-hati dengan alokasi.

Saya menggunakan data.tabel hampir secara eksklusif.

Fungsi 'ketakutan' memungkinkan Anda untuk mengelompokkan informasi menurut nama bidang saat impor; hanya mengimpor bidang yang benar-benar diperlukan untuk memulai. Jika Anda menggunakan basis R baca, null kolom palsu segera setelah impor.

Sebagai 42- disarankan oleh , jika memungkinkan saya kemudian akan mengelompokkan dalam kolom segera setelah mengimpor informasi.

Saya sering rm () objek dari lingkungan segera setelah mereka tidak lagi diperlukan, misalnya pada baris berikutnya setelah menggunakannya untuk mengelompokkan sesuatu yang lain, dan memanggil gc ().

'fread' dan 'fwrite' dari data.table bisa sangat cepat dibandingkan dengan base R membaca dan menulis.

Sebagai kpierce8 disarankan oleh , saya hampir selalu menulis semuanya dari lingkungan dan membuatnya takut, bahkan dengan ribuan / ratusan ribu file kecil yang harus dilalui. Ini tidak hanya menjaga lingkungan tetap 'bersih' dan membuat alokasi memori rendah tetapi, mungkin karena kurangnya RAM yang tersedia, R memiliki kecenderungan untuk sering crash di komputer saya; sangat sering. Memiliki informasi yang dicadangkan di drive itu sendiri ketika kode berlangsung melalui berbagai tahapan berarti saya tidak harus mulai dari awal jika crash.

Pada 2017, saya pikir SSD tercepat berjalan sekitar beberapa GB per detik melalui port M2. Saya memiliki 50GB Kingston V300 (550MB / s) SSD yang benar-benar dasar yang saya gunakan sebagai disk utama saya (memiliki Windows dan R di atasnya). Saya menyimpan semua informasi massal di piring WD 500GB yang murah. Saya memindahkan set data ke SSD ketika saya mulai mengerjakannya. Ini, dikombinasikan dengan 'menakut-nakuti dan' menulis 'semuanya telah bekerja dengan baik. Saya sudah mencoba menggunakan 'ff' tetapi lebih suka yang pertama. Kecepatan baca / tulis 4K dapat menimbulkan masalah dengan ini; mencadangkan seperempat juta file 1k (senilai 250MB) dari SSD ke piring dapat berlangsung berjam-jam. Sejauh yang saya ketahui, belum ada paket R yang tersedia yang dapat secara otomatis mengoptimalkan proses 'chunkification'; mis. lihat berapa banyak RAM yang dimiliki pengguna, uji kecepatan baca / tulis RAM / semua drive yang terhubung dan kemudian sarankan protokol 'chunkification' yang optimal. Ini dapat menghasilkan beberapa peningkatan alur kerja yang signifikan / optimisasi sumber daya; misalnya membaginya menjadi ... MB untuk ram -> membaginya menjadi ... MB untuk SSD -> membaginya menjadi ... MB di piring -> membaginya menjadi ... MB pada kaset. Ini bisa mengambil sampel set data sebelumnya untuk memberikan tongkat pengukur yang lebih realistis untuk bekerja.

Banyak masalah yang saya kerjakan di R melibatkan pembentukan kombinasi dan permutasi pasangan, tiga kali lipat dll, yang hanya membuat memiliki keterbatasan RAM lebih dari batasan karena mereka akan setidaknya setidaknya secara eksponensial berkembang di beberapa titik. Ini telah membuat saya memusatkan banyak perhatian pada kualitas daripada kuantitas informasi yang masuk ke mereka untuk memulai, daripada mencoba untuk membersihkannya setelah itu, dan pada urutan operasi dalam menyiapkan informasi untuk memulai (dimulai dengan operasi paling sederhana dan menambah kompleksitas); misal subset, lalu gabung / gabung, lalu bentuk kombinasi / permutasi dll.

Tampaknya ada beberapa manfaat untuk menggunakan basis R membaca dan menulis dalam beberapa kasus. Misalnya, deteksi kesalahan dalam 'fread' sangat bagus sehingga sulit untuk mencoba mendapatkan informasi yang benar-benar berantakan ke R untuk memulai dengan membersihkannya. Basis R juga tampaknya jauh lebih mudah jika Anda menggunakan Linux. Basis R tampaknya berfungsi dengan baik di Linux, Windows 10 menggunakan ~ 20GB ruang disk sedangkan Ubuntu hanya membutuhkan beberapa GB, RAM yang dibutuhkan dengan Ubuntu sedikit lebih rendah. Tetapi saya telah memperhatikan sejumlah besar peringatan dan kesalahan saat menginstal paket pihak ketiga di (L) Ubuntu. Saya tidak akan merekomendasikan melayang terlalu jauh dari (L) Ubuntu atau distribusi saham lainnya dengan Linux karena Anda dapat kehilangan begitu banyak kompatibilitas secara keseluruhan sehingga prosesnya hampir tidak ada gunanya (saya pikir 'unity' akan dibatalkan di Ubuntu pada 2017 ).

Semoga beberapa dari itu dapat membantu orang lain.

bg49ag
sumber
5

Ini tidak menambahkan apa pun di atas, tetapi ditulis dengan gaya sederhana dan sangat dikomentari yang saya sukai. Ini menghasilkan tabel dengan objek yang dipesan dalam ukuran, tetapi tanpa beberapa detail yang diberikan dalam contoh di atas:

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

Ini adalah jawaban yang lebih baru untuk pertanyaan lama yang luar biasa ini. Dari Hadley's Advanced R:

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 )

Chris Beeley
sumber
3

Jika Anda bekerja di Linux dan ingin menggunakan beberapa proses dan hanya perlu melakukan operasi baca pada satu atau lebih objek besar gunakan makeForkClustersebagai ganti a makePSOCKcluster. Ini juga menghemat waktu Anda mengirim objek besar ke proses lainnya.

gdkrmr
sumber
2

Saya benar-benar menghargai beberapa jawaban di atas, mengikuti @Hadley dan @Dirk yang menyarankan untuk menutup R dan mengeluarkan sourcedan menggunakan baris perintah saya datang dengan solusi yang bekerja sangat baik untuk saya. Saya harus berurusan dengan ratusan spektrum massa, masing-masing menempati sekitar 20 Mb memori jadi saya menggunakan dua skrip R, sebagai berikut:

Pertama pembungkus:

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

dengan skrip ini saya pada dasarnya mengontrol apa yang dilakukan skrip utama saya runConsensus.r, dan saya menulis jawaban data untuk hasilnya. Dengan ini, setiap kali wrapper memanggil skrip, tampaknya R dibuka kembali dan memori dibebaskan.

Semoga ini bisa membantu.

pengguna1265067
sumber
2

Selain teknik manajemen memori yang lebih umum yang diberikan dalam jawaban di atas, saya selalu berusaha mengurangi ukuran objek saya sejauh mungkin. Sebagai contoh, saya bekerja dengan matriks yang sangat besar tetapi sangat jarang, dengan kata lain matriks di mana sebagian besar nilai adalah nol. Menggunakan paket 'Matrix' (huruf besar penting), saya dapat mengurangi ukuran objek rata-rata dari ~ 2GB hingga ~ 200MB semudah:

my.matrix <- Matrix(my.matrix)

Paket Matrix mencakup format data yang dapat digunakan persis seperti matriks biasa (tidak perlu mengubah kode Anda yang lain) tetapi mampu menyimpan data jarang jauh lebih efisien, apakah dimuat ke dalam memori atau disimpan ke disk.

Selain itu, file mentah yang saya terima dalam format 'panjang' di mana setiap titik data memiliki variabel x, y, z, i. Jauh lebih efisien untuk mengubah data menjadi x * y * zarray dimensi dengan hanya variabel i.

Ketahui data Anda dan gunakan sedikit akal sehat.

D Greenwood
sumber
2

Kiat untuk berurusan dengan objek yang membutuhkan perhitungan menengah yang berat: Saat menggunakan objek yang membutuhkan banyak perhitungan berat dan langkah-langkah perantara untuk membuat, saya sering merasa berguna untuk menulis sepotong kode dengan fungsi untuk membuat objek, dan kemudian potongan terpisah kode yang memberi saya pilihan untuk membuat dan menyimpan objek sebagai rmdfile, atau memuatnya secara eksternal dari rmdfile yang sudah saya simpan sebelumnya. Ini sangat mudah dilakukan dalam R Markdownmenggunakan struktur kode-chunk berikut.

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

```

Dengan struktur kode ini, yang perlu saya lakukan adalah mengubah LOADtergantung pada apakah saya ingin membuat dan menyimpan objek, atau memuatnya langsung dari file tersimpan yang ada. (Tentu saja, saya harus membuat dan menyimpannya untuk pertama kali, tetapi setelah ini saya memiliki pilihan untuk memuatnya.) Pengaturan LOAD = TRUEmemotong penggunaan fungsi saya yang rumit dan menghindari semua perhitungan berat di dalamnya. Metode ini masih membutuhkan memori yang cukup untuk menyimpan objek yang menarik, tetapi ini menghemat Anda dari keharusan untuk menghitungnya setiap kali Anda menjalankan kode Anda. Untuk objek yang membutuhkan banyak perhitungan langkah menengah (mis., Untuk perhitungan yang melibatkan loop pada array besar) ini dapat menghemat banyak waktu dan perhitungan.

Ben - Pasang kembali Monica
sumber
1

Lari

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

dari waktu ke waktu juga membantu R untuk membebaskan memori yang tidak digunakan tetapi masih belum dirilis.

Marcelo Ventura
sumber
Apa yang dilakukan forloop di sini? Tidak ada idalam gcpanggilan.
Umaomamaomao
@qqq itu ada di sana hanya untuk menghindari salin-tempel gc(reset = T)sembilan kali
Marcelo Ventura
14
Tetapi mengapa Anda menjalankannya 9 kali? (penasaran, tidak kritis)
Umaomamaomao
1

Anda juga bisa mendapatkan manfaat menggunakan rajutan dan meletakkan skrip Anda di rmd chuncks.

Saya biasanya membagi kode dalam potongan yang berbeda dan memilih mana yang akan menyimpan pos pemeriksaan ke cache atau ke file RDS, dan

Di sana Anda dapat mengatur chunk untuk disimpan ke "cache", atau Anda dapat memutuskan untuk menjalankan atau tidak chunk tertentu. Dengan cara ini, dalam menjalankan pertama Anda hanya dapat memproses "bagian 1", eksekusi lain Anda hanya dapat memilih "bagian 2", dll.

Contoh:

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

Sebagai efek samping, ini juga bisa menyelamatkan Anda dari sakit kepala dalam hal reproduksibilitas :)

Matias Thayer
sumber
1

Berdasarkan jawaban @ Dirk dan @ Tony, saya telah melakukan sedikit pembaruan. Hasilnya adalah keluaran [1]sebelum nilai ukuran cantik, jadi saya mengambil capture.outputyang memecahkan masalah:

.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()
ilya
sumber
-1

Saya mencoba untuk menjaga jumlah objek kecil ketika bekerja di proyek yang lebih besar dengan banyak langkah perantara. Jadi alih-alih menciptakan banyak objek unik yang disebut

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

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

Saya bekerja dengan objek sementara yang saya panggil temp.

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

Yang membuat saya dengan file kurang menengah dan lebih banyak ikhtisar.

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

Untuk menghemat lebih banyak memori, saya cukup menghapusnya tempsaat tidak diperlukan lagi.

rm(temp)

Jika saya perlu beberapa file intermediate, saya menggunakan temp1, temp2, temp3.

Untuk pengujian saya menggunakan test, test2...

bunga pala
sumber