R सत्र में उपलब्ध मेमोरी को प्रबंधित करने के लिए ट्रिक्स


490

इंटरेक्टिव आर सत्र की उपलब्ध मेमोरी को प्रबंधित करने के लिए लोग कौन से ट्रिक्स का उपयोग करते हैं? मैं सबसे बड़ी वस्तुओं को सूचीबद्ध करने के लिए (और / या सॉर्ट करने के लिए) 2004 में आर-हेल्प लिस्ट पर पेट्र पिकल और डेविड हिंड्स द्वारा पोस्टिंग के आधार पर नीचे दिए गए कार्यों का उपयोग करता हूं और rm()उनमें से कुछ को। लेकिन अब तक सबसे प्रभावी समाधान था ... 64-बिट लिनक्स के तहत पर्याप्त मेमोरी के साथ चलना।

किसी भी अन्य अच्छी चाल लोगों को साझा करना चाहते हैं? कृपया प्रति पोस्ट करें।

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

ध्यान दें, मुझे इसमें कोई संदेह नहीं है, लेकिन इसका क्या उपयोग है? मैं आर में मेमोरी समस्याओं के लिए बहुत नया हूं, लेकिन मैं हाल ही में कुछ अनुभव कर रहा हूं (इसीलिए मैं इस पोस्ट को खोज रहा था :) - तो क्या मैं अभी यह सब शुरू कर रहा हूं। यह मेरे दैनिक काम में कैसे मदद करता है?
मैट बन्नर्ट

4
यदि आप किसी फ़ंक्शन के भीतर ऑब्जेक्ट देखना चाहते हैं, तो आपको उपयोग करना होगा: lsos (pos = environment ()), अन्यथा यह केवल वैश्विक चर दिखाएगा। मानक त्रुटि को लिखने के लिए: write.table (lsos (pos = environment) (), stderr (), उद्धरण = FALSE, sep = '\ t')
माइकल कुह्न

64-बिट लिनक्स और 64-बिट विंडोज क्यों नहीं? जब मैं 32GB RAM का उपयोग करने के लिए OS का विकल्प एक गैर-तुच्छ अंतर बनाता हूं?
जस्सी

3
@ पेप्सिमैक्स: यह पैकेज में पैक किया गया multilevelPSAहै । पैकेज कुछ और के लिए डिज़ाइन किया गया है, लेकिन आप पैकेज को लोड किए बिना कह सकते हैं कि आप वहां से फ़ंक्शन का उपयोग कर सकते हैं requireNamespace(multilevelPSA); multilevelPSA::lsos(...)। या Dmiscपैकेज में (सीआरएएन पर नहीं)।
krlmlr

1
यदि डेटा सेट एक प्रबंधनीय आकार का है, तो मैं आमतौर पर आर स्टूडियो> पर्यावरण> ग्रिड व्यू पर जाता हूं। यहां आप आकार के आधार पर अपने वर्तमान परिवेश में सभी आइटम देख और सॉर्ट कर सकते हैं।
kRazzy आर

जवाबों:


197

सुनिश्चित करें कि आप अपने काम को एक प्रतिलिपि प्रस्तुत करने योग्य स्क्रिप्ट में रिकॉर्ड करें। समय-समय पर, फिर से खोलना आर, फिर source()आपकी स्क्रिप्ट। आप कुछ भी साफ कर लेंगे जिसका आप अब उपयोग नहीं कर रहे हैं, और एक अतिरिक्त लाभ के रूप में आपने अपने कोड का परीक्षण किया होगा।


58
मेरी रणनीति मेरी स्क्रिप्ट को लोड की पंक्तियों के साथ तोड़ना है। और do.R, जहाँ load.R फाइल या डेटाबेस से डेटा लोड करने में काफी समय ले सकता है, और कोई भी नंगे न्यूनतम पूर्व-प्रसंस्करण / विलय नहीं करता है वह डेटा। कार्यक्षेत्र स्थिति को बचाने के लिए load.R की अंतिम पंक्ति कुछ है। फिर do.R मेरा स्क्रैचपैड है जिससे मैं अपने विश्लेषण कार्यों का निर्माण करता हूं। मैं अक्सर do.R को लोड करता हूं (आवश्यकतानुसार लोड से कार्यक्षेत्र की स्थिति को फिर से लोड किए बिना या बिना)।
जोश रीच

32
यह एक अच्छी तकनीक है। जब फ़ाइलें जो की तरह एक निश्चित क्रम में चलाए जा रहे हैं, मैं अक्सर एक संख्या के साथ उन्हें उपसर्ग: 1-load.r, 2-explore.r, 3-model.r- इस तरह से दूसरों के लिए स्पष्ट है वहाँ कुछ क्रम मौजूद है कि।
13

4
मैं इस विचार को पर्याप्त रूप से वापस नहीं ले सकता। मैंने कुछ लोगों को आर सिखाया है और यह पहली चीजों में से एक है जो मैं कहता हूं। यह किसी भी भाषा पर भी लागू होता है जहाँ विकास में एक REPL और एक फ़ाइल शामिल होती है (यानी पायथन)। rm (ls = list ()) और source () भी काम करता है, लेकिन री-ओपनिंग बेहतर है (पैकेज भी क्लीयर हो गए हैं)।
विंस

53
तथ्य यह है कि शीर्ष मतदान जवाब में आर को पुनरारंभ करना आर की सबसे खराब आलोचना है।
एसडीएस

7
@ मार्टीनबेल जो केवल वैश्विक वातावरण में निर्मित वस्तुओं को हटाती है। यह पैकेज या S4 ऑब्जेक्ट या कई अन्य चीजों को अनलोड नहीं करता है।
हैडले

160

मैं data.table पैकेज का उपयोग करता हूं । इसके :=ऑपरेटर के साथ आप कर सकते हैं:

  • संदर्भ द्वारा कॉलम जोड़ें
  • संदर्भ द्वारा मौजूदा कॉलम के सबसेट को संशोधित करें और संदर्भ द्वारा समूह द्वारा
  • संदर्भ द्वारा कॉलम हटाएं

इनमें से कोई भी ऑपरेशन संभावित (संभावित बड़े) की नकल data.tableनहीं करता है, एक बार भी नहीं।

  • एकत्रीकरण भी विशेष रूप से तेज़ है क्योंकि data.tableबहुत कम काम करने वाली मेमोरी का उपयोग करता है।

सम्बंधित लिंक्स :


109

यह एक ट्विटर पोस्ट पर देखा और लगता है कि यह डिर्क द्वारा एक भयानक समारोह है! जेडी लॉन्ग के जवाब के बाद, मैं उपयोगकर्ता के अनुकूल पढ़ने के लिए ऐसा करूंगा:

# 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

नोट: मुख्य भाग जो मैंने जोड़ा था (फिर से, जेडी के उत्तर से अनुकूलित):

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

क्या इस फ़ंक्शन को dplyr या किसी अन्य कुंजी पैकेज में जोड़ा जा सकता है।
userJT

1
वर्थ नोटिंग (कम-से-कम आधार-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
नटले

@ उत्कृष्ट, मैंने कोड को तदनुसार अद्यतन किया है :)
टोनी ब्रील

मैं भी तब से बदल दूंगा obj.class <- napply(names, function(x) as.character(class(x))[1]), obj.class <- napply(names, function(x) class(x)[1]) जब classहमेशा एक वेक्टर अब वर्ण (आधार -3.0) लौटाता हूं ।
डेल्टा जिव

49

मैं प्रतिगमन कार्यों subsetके data=तर्क के लिए डेटाफ्रेम पास करते समय केवल आवश्यक चर के चयन के साथ पैरामीटर का आक्रामक उपयोग करता हूं । यह कुछ त्रुटियों के परिणामस्वरूप होता है यदि मैं सूत्र और select=वेक्टर दोनों में चर जोड़ना भूल जाता हूं , लेकिन वस्तुओं की प्रतिलिपि कम होने और स्मृति पदचिह्न को कम करने के कारण यह अभी भी बहुत समय बचाता है। कहो मेरे पास ११० चर के साथ ४ मिलियन रिकॉर्ड हैं (और मैं करता हूं।) उदाहरण:

# 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एक चरित्र वेक्टर था जो एचआईवी के लिए प्रारंभिक और पुष्टिकरण परीक्षण को संक्षेप में प्रस्तुत करता था। ।


48

मुझे डिर्क की .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

यह अच्छी चाल है।

एक अन्य सुझाव यह है कि जहाँ भी संभव हो मेमोरी मेमोरी ऑब्जेक्ट्स का उपयोग करें: उदाहरण के लिए, data.frame के बजाय मैट्रिक्स का उपयोग करें।

यह वास्तव में स्मृति प्रबंधन को संबोधित नहीं करता है, लेकिन एक महत्वपूर्ण कार्य जो व्यापक रूप से ज्ञात नहीं है, वह है मेमोरी। बिलिट ()। आप इस आदेश का उपयोग करके डिफ़ॉल्ट बढ़ा सकते हैं, memory.limit (आकार = 2500), जहां आकार MB में है। जैसा कि डिर्क ने उल्लेख किया है, इसका वास्तविक लाभ लेने के लिए आपको 64-बिट का उपयोग करने की आवश्यकता है।


25
क्या यह केवल विंडोज पर लागू नहीं है?
क्रिस्टोफर डुबोइस

4
> memory.limit () [1] Inf चेतावनी संदेश: 'memory.limit ()' विंडोज विशिष्ट है
LJT

डेटा के बजाय टिबबल का उपयोग करने से क्या मेमोरी को बचाने के लिए हमें बेहतर सहायता मिलती है?

32

मुझे डिर्क द्वारा विकसित बेहतर वस्तु समारोह पसंद है। हालांकि, ज्यादातर समय मेरे नाम और ऑब्जेक्ट के साथ एक अधिक बुनियादी आउटपुट के लिए पर्याप्त है। यहाँ एक समान उद्देश्य के साथ एक सरल कार्य किया गया है। मेमोरी का उपयोग वर्णानुक्रम या आकार से किया जा सकता है, एक निश्चित संख्या में वस्तुओं तक सीमित किया जा सकता है, और आरोही या अवरोही का आदेश दिया जा सकता है। इसके अलावा, मैं अक्सर 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% से अधिक कम हो गई थी। जब आप उदाहरण के लिए R. में सामान पढ़ते हैं। तो उन्हें मेमोरी की एक निश्चित मात्रा की आवश्यकता होती है। इसके बाद आप उन्हें save("Destinationfile",list=ls()) अगली बार जब आप R खोलते हैं, तो आप उनका उपयोग कर सकते हैं। load("Destinationfile") अब मेमोरी का उपयोग कम हो सकता है। यह अच्छा होगा यदि कोई भी पुष्टि कर सकता है कि क्या यह अलग डेटासेट के साथ समान परिणाम उत्पन्न करता है।


4
हां, मैंने वही अनुभव किया। स्मृति उपयोग मेरे मामले में भी 30% तक गिर जाता है। 1.5 जीबी मेमोरी का उपयोग किया गया, जिसे सहेजा गया है ।Rata (~ 30MB)। लोड होने के बाद नया सत्र ।Rata 500MB से कम मेमोरी का उपयोग करता है।
f3lix

मैंने 2 डेटासेट्स (100 एमबी और 2.7 जीबी) को डेटा में लोड freadकरने का प्रयास किया। RData फाइलें वास्तव में लगभग 70% छोटी थीं लेकिन फिर से लोड करने के बाद, उपयोग की जाने वाली मेमोरी बिल्कुल वैसी ही थी। उम्मीद कर रहा था कि यह चाल स्मृति पदचिह्न को कम कर देगी ... क्या मुझे कुछ याद आ रहा है?
NoviceProg

@ नौसिखिए मुझे नहीं लगता कि आप कुछ याद कर रहे हैं, लेकिन यह एक चाल है, मुझे लगता है कि यह सभी स्थितियों के लिए काम नहीं करेगा। मेरे मामले में पुनः लोड करने के बाद की मेमोरी वास्तव में वर्णित के रूप में कम हो गई थी।
डेनिस जहरुद्दीन

6
@ नौसिखिए एक दो बातें। Read.tcsv की तुलना में डेटा लोड करने में सबसे पहले, भय, निम्नलिखित डेटा। टायलो का श्रेय शायद अधिक मेमोरी कुशल है। दूसरा, स्मृति बचत करने वाले लोग यहां मुख्य रूप से आर प्रक्रिया की मेमोरी आकार (जो वस्तुओं को पकड़ना और कचरा संग्रह होने पर पीछे हटना पड़ता है) के साथ करना है। हालांकि, कचरा संग्रह हमेशा रैम के सभी ओएस पर वापस नहीं छोड़ता है। R सेशन को रोकना और जहाँ से स्टोर किया गया है उस आइटम को लोड करना जितना संभव हो उतना रैम जारी करेगा ... लेकिन अगर ओवरहेड शुरू करने के लिए छोटा था ... कोई लाभ नहीं।
रसेलपियरिएस

27

बार-बार पुनरारंभ की आम रणनीति को और स्पष्ट करने के लिए, हम लिटलर का उपयोग कर सकते हैं जो हमें कमांड-लाइन से सीधे सरल अभिव्यक्ति चलाने की अनुमति देता है। यहाँ एक उदाहरण है जिसे मैं कभी-कभी एक साधारण क्रॉसप्रोड के लिए अलग-अलग बीएलएएस के लिए उपयोग करता हूं।

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

इसी तरह,

 r -lMatrix -e'example(spMatrix)'

मैट्रिक्स पैकेज को लोड करता है (-पैकेजेस के माध्यम से -l स्विच) और स्पैक्ट्रिक्स फ़ंक्शन के उदाहरण चलाता है। जैसा कि आर हमेशा 'ताजा' शुरू होता है, यह विधि पैकेज के विकास के दौरान भी एक अच्छा परीक्षण है।

अंतिम लेकिन कम से कम r '#! / Usr / bin / r' shebang-header का उपयोग करके स्क्रिप्ट में स्वचालित बैच मोड के लिए बहुत अच्छा काम नहीं करता है। रुस्क्रिप्ट एक ऐसा विकल्प है जहां लिटलर अनुपलब्ध है (जैसे विंडोज पर)।


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 को सूचीबद्ध नहीं करता है, इसलिए यह महान नहीं है
userJT

16
  1. मैं भाग्यशाली हूं और मेरे बड़े डेटा सेट लगभग 100 एमबी (32 बिट बाइनरी) के "हिस्सा" (सबसेट) में साधन द्वारा सहेजे गए हैं। इस प्रकार मैं डेटा सेट को फ़्यूज़ करने से पहले चरण-पूर्व प्रक्रिया (अनइनफॉर्मेटिव पार्ट्स को हटाना, डाउनसम्पलिंग करना) कर सकता हूँ।

  2. gc ()"हाथ से" कॉल करने पर मदद मिल सकती है अगर डेटा का आकार उपलब्ध मेमोरी के करीब हो।

  3. कभी-कभी एक अलग एल्गोरिथ्म को बहुत कम मेमोरी की आवश्यकता होती है।
    कभी-कभी वैश्वीकरण और स्मृति उपयोग के बीच एक व्यापार बंद होता है।
    तुलना करें: splitऔर lapplyबनाम एक 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.matrixया data.tableजो अपनी सामग्री को जगह में बदलने की अनुमति देता है, बहुत ही कुशल स्मृति उपयोग प्राप्त किया जा सकता है।


6
यह अब सच नहीं है: हैडली के उन्नत आर से , "आर 3.1.0 में परिवर्तन ने इस उपयोग को [वातावरण का] काफी हद तक कम महत्वपूर्ण बना दिया है क्योंकि एक सूची को संशोधित करना अब एक गहरी प्रतिलिपि नहीं बनाता है।"
पेट्रेलर्प

8

llमें समारोह gDataपैकेज प्रत्येक वस्तु के स्मृति उपयोग के साथ-साथ दिखा सकते हैं।

gdata::ll(unit='MB')

मेरे सिस्टम पर नहीं: R संस्करण 3.1.1 (2014-07-10), x86_64-pc-linux-gnu (64-bit), gdata_2.13.3, gtools_3.4.1।
krlmlr

आप सही कह रहे हैं कि मैं इसे एक बार परीक्षण कर चुका हूँ, यह संयोग से आदेश दिया गया था!
user1436187

1
कृपया Gb, Mb
userJT

7

यदि आप वास्तव में लीक से बचना चाहते हैं, तो आपको वैश्विक वातावरण में कोई भी बड़ी वस्तु बनाने से बचना चाहिए।

आम तौर पर मैं क्या करता हूं कि एक फ़ंक्शन होता है जो काम करता है और रिटर्न करता है NULL- सभी डेटा को इस फ़ंक्शन या अन्य में पढ़ा और हेरफेर किया जाता है जिसे वह कॉल करता है।


7

केवल 4GB RAM (विंडोज 10 चलाने के साथ, इसलिए कि लगभग 2 या अधिक वास्तविक 1GB) के साथ मुझे आवंटन के साथ वास्तविक सावधान रहना होगा।

मैं लगभग विशेष रूप से data.table का उपयोग करता हूं।

'फ़्रेड' फ़ंक्शन आपको आयात पर फ़ील्ड नामों से जानकारी को कम करने की अनुमति देता है; केवल उन क्षेत्रों को आयात करें जिनके साथ वास्तव में शुरू करने की आवश्यकता होती है। यदि आप बेस आर रीड का उपयोग कर रहे हैं, तो आयात के तुरंत बाद स्पूसियस कॉलम को बंद कर दें।

42- के रूप में पता चलता है, जहां कभी भी संभव है मैं जानकारी आयात करने के तुरंत बाद स्तंभों के भीतर निर्वाह करूंगा।

मैं अक्सर rm () वातावरण से वस्तुओं को जैसे ही वे अब जरूरत नहीं है, जैसे अगली पंक्ति पर उन्हें कुछ और सबसेट करने के लिए उपयोग करने के बाद, और gc () कहते हैं।

data.table से 'fread' और 'fwrite' को आधार R रीड और राइट के साथ तुलना करके बहुत तेज किया जा सकता है ।

जैसा कि kpierce8 सुझाव देता है, मैं लगभग हमेशा पर्यावरण से बाहर सब कुछ फिर से लिखता हूं और इसे वापस लाता हूं, यहां तक ​​कि हजार / सैकड़ों हजारों छोटी फाइलों के माध्यम से भी। यह न केवल पर्यावरण को 'साफ' रखता है और स्मृति आवंटन को कम रखता है, बल्कि संभवतः रैम की गंभीर कमी के कारण, आर मेरे कंप्यूटर पर अक्सर दुर्घटनाग्रस्त होने की प्रवृत्ति है; वास्तव में अक्सर। कोड के विभिन्न चरणों के माध्यम से आगे बढ़ने के साथ ही ड्राइव पर जानकारी का बैकअप होने का मतलब है कि क्रैश होने पर मुझे शुरुआत से ही सही शुरुआत नहीं करनी है।

2017 के अनुसार, मुझे लगता है कि सबसे तेज एसएसडी एम 2 पोर्ट के माध्यम से प्रति सेकंड कुछ जीबी के आसपास चल रहे हैं। मेरे पास वास्तव में बुनियादी 50GB किंग्स्टन V300 (550MB / s) SSD है जिसे मैं अपनी प्राथमिक डिस्क के रूप में उपयोग करता हूं (इस पर विंडोज और आर है)। मैं सभी थोक सूचनाओं को एक सस्ते 500GB WD प्लैटर पर रखता हूँ। जब मैं उन पर काम करना शुरू करता हूं, तो मैं डेटा सेट को एसएसडी में स्थानांतरित कर देता हूं। यह, 'फैडरिंग' और 'राइटराइटिंग' के साथ संयुक्त रूप से सब कुछ बढ़िया काम कर रहा है। मैंने 'ff' का उपयोग करने की कोशिश की है, लेकिन पूर्व को प्राथमिकता दें। 4K पढ़ने / लिखने की गति हालांकि इसके साथ समस्याएं पैदा कर सकती हैं; SSD से प्लैटर तक एक मिलियन 1k फ़ाइलों (250MBs लायक) के एक चौथाई का बैकअप लेने में घंटों लग सकते हैं। जहां तक ​​मुझे जानकारी है, अभी तक कोई आर पैकेज उपलब्ध नहीं है जो स्वचालित रूप से 'chunkification' प्रक्रिया को अनुकूलित कर सके; उदाहरण के लिए देखें कि उपयोगकर्ता के पास कितनी रैम है, रैम की रीड / राइट स्पीड / कनेक्टेड सभी ड्राइव्स का परीक्षण करें और फिर एक इष्टतम 'chunkification' प्रोटोकॉल का सुझाव दें। यह कुछ महत्वपूर्ण वर्कफ़्लो सुधार / संसाधन अनुकूलन का उत्पादन कर सकता है; उदाहरण के लिए इसे विभाजित करें ... MB के लिए RAM -> इसे विभाजित करें ... SSD के लिए MB -> इसे विभाजित करें ... थाली पर MB -> इसे विभाजित करें ... टेप पर MB। यह पहले से काम करने के लिए इसे और अधिक यथार्थवादी गेज स्टिक देने के लिए डेटा सेट का नमूना ले सकता है।

जिन समस्याओं पर मैंने काम किया है उनमें आर और संयोजन और क्रमपरिवर्तन जोड़े, ट्राइएबल्स आदि शामिल हैं, जो केवल सीमित रैम को अधिक सीमित बनाता है क्योंकि वे किसी बिंदु पर कम से कम तेजी से विस्तार करेंगे । इसने मुझे गुणवत्ता पर बहुत अधिक ध्यान केंद्रित किया है, क्योंकि इसके बाद शुरू होने वाली जानकारी की मात्रा के विपरीत , इसे बाद में साफ करने की कोशिश करने के बजाय, और शुरू करने के लिए जानकारी तैयार करने में संचालन के अनुक्रम पर। सरल ऑपरेशन और जटिलता में वृद्धि); जैसे सब्मिट, फिर मर्ज / ज्वाइन, फिर कॉम्बिनेशन / पर्मुटेशन आदि।

कुछ उदाहरणों में पढ़ने और लिखने के आधार आर का उपयोग करने के कुछ लाभ प्रतीत होते हैं। उदाहरण के लिए, 'फ़्रेड' के भीतर त्रुटि का पता लगाना इतना अच्छा है कि इसे साफ करने के लिए आर में वास्तव में गड़बड़ जानकारी प्राप्त करने की कोशिश करना मुश्किल हो सकता है। यदि आप लिनक्स का उपयोग कर रहे हैं तो बेस आर भी काफी आसान लगता है। बेस आर लिनक्स में ठीक काम करने लगता है, विंडोज 10 ~ 20 जीबी डिस्क स्पेस का उपयोग करता है जबकि उबंटू को केवल कुछ जीबी की आवश्यकता होती है, उबंटू के साथ आवश्यक रैम थोड़ा कम है। लेकिन (एल) उबंटू में तीसरे पक्ष के पैकेज स्थापित करते समय मैंने बड़ी मात्रा में चेतावनी और त्रुटियों को देखा है। मैं (L) उबंटू या लिनक्स के साथ अन्य स्टॉक वितरण से बहुत दूर बहने की सलाह नहीं दूंगा क्योंकि आप समग्र रूप से बहुत अधिक अनुकूलता को ढीला कर सकते हैं, यह प्रक्रिया को लगभग व्यर्थ कर देता है (मुझे लगता है कि 'एकता' उबंटू को 2017 के रूप में रद्द कर दिया गया है। )।

उम्मीद है कि इनमें से कुछ दूसरों की मदद कर सकते हैं।


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

5

इस उत्कृष्ट पुराने प्रश्न का यह एक नया उत्तर है। हैडली एडवांस्ड आर से:

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

आप पर काम कर रहे हैं, तो लिनक्स और उपयोग करना चाहते हैं कई प्रक्रियाओं और केवल इतना करना है पढ़ने में एक या अधिक पर कार्रवाई बड़ी वस्तुओं का उपयोग makeForkClusterएक के बजाय makePSOCKcluster। यह आपको बड़ी ऑब्जेक्ट को अन्य प्रक्रियाओं में भेजने का समय भी बचाता है।


2

मैं वास्तव में ऊपर दिए गए कुछ उत्तरों की सराहना करता हूं, @hadley और @Dirk के बाद जो आर को बंद करने sourceऔर कमांड लाइन जारी करने और उपयोग करने का सुझाव देता है, मैं एक समाधान के साथ आता हूं जो मेरे लिए बहुत अच्छा काम करता है। मुझे सैकड़ों मास स्पेक्ट्रा से निपटना पड़ा, प्रत्येक में लगभग 20 एमबी मेमोरी होती है, इसलिए मैंने दो आर स्क्रिप्ट का उपयोग किया, इस प्रकार है:

पहले एक आवरण:

#!/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, और मैं आउटपुट के लिए डेटा उत्तर लिखता हूं। इसके साथ, हर बार रैपर स्क्रिप्ट को कॉल करता है ऐसा लगता है कि आर फिर से खोल दिया गया है और मेमोरी को मुक्त कर दिया गया है।

आशा है ये मदद करेगा।


2

साथ ही साथ ऊपर दिए गए उत्तरों में दी गई अधिक सामान्य मेमोरी प्रबंधन तकनीक, मैं हमेशा अपनी वस्तुओं के आकार को यथासंभव कम करने की कोशिश करता हूं। उदाहरण के लिए, मैं बहुत बड़े लेकिन बहुत विरल मैट्रिस के साथ काम करता हूं, दूसरे शब्दों में मैट्रिसेस जहां अधिकांश मूल्य शून्य हैं। 'मैट्रिक्स' पैकेज (कैपिटलाइज़ेशन महत्वपूर्ण) का उपयोग करके मैं अपने औसत ऑब्जेक्ट साइज़ को ~ 2GB से ~ 200MB तक कम करने में सक्षम था:

my.matrix <- Matrix(my.matrix)

मैट्रिक्स पैकेज में डेटा प्रारूप शामिल होते हैं जो बिल्कुल एक नियमित मैट्रिक्स की तरह उपयोग किए जा सकते हैं (आपके अन्य कोड को बदलने की आवश्यकता नहीं है), लेकिन विरल डेटा को अधिक कुशलता से संग्रहीत करने में सक्षम हैं, चाहे वह मेमोरी में लोड हो या डिस्क पर सहेजा गया हो।

इसके अतिरिक्त, मुझे प्राप्त होने वाली कच्ची फाइलें 'लंबे' प्रारूप में होती हैं, जहां प्रत्येक डेटा बिंदु में चर होते हैं x, y, z, ix * 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)

समय-समय पर आर को अप्रयुक्त मुक्त करने में मदद करता है, लेकिन फिर भी मेमोरी जारी नहीं करता है।


forपाश यहाँ क्या करता है? कॉल iमें कोई नहीं है gc
उमाओमाओमाओ

@qqq यह gc(reset = T)नौ बार कॉपी-पेस्ट से बचने के लिए है
मार्सेलो वेंचुरा

14
लेकिन आप इसे 9 बार क्यों चलाएंगे? (जिज्ञासु, आलोचनात्मक नहीं)
उमाओमाओमाओ

1

आप knitr का उपयोग करके और Rmd चंक्स में अपनी स्क्रिप्ट डालकर कुछ लाभ प्राप्त कर सकते हैं।

मैं आमतौर पर कोड को अलग-अलग विखंडों में विभाजित करता हूं और यह चुनता हूं कि कौन से चेकपॉइंट को कैश या एक आरडीएस फ़ाइल में सहेजेगा, और

वहाँ पर आप "कैश" में सहेजे जाने के लिए एक चंक सेट कर सकते हैं, या आप किसी विशेष चंक को चलाने या नहीं करने का निर्णय ले सकते हैं। इस तरह, पहले भाग में आप केवल "भाग 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)
```

एक साइड इफेक्ट के रूप में, यह भी आपको reproducibility के मामले में कुछ सिरदर्द बचा सकता है :)


1

@ डिर्क और @ टोनी के जवाब के आधार पर मैंने थोड़ा सा अपडेट किया है। परिणाम [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)

मैं कई मध्यवर्ती फाइल की जरूरत है, मैं का उपयोग करें temp1, temp2, temp3

परीक्षण मैं उपयोग के लिए test, test2...

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.