R 세션에서 사용 가능한 메모리를 관리하기위한 요령


490

사람들이 대화 형 R 세션의 사용 가능한 메모리를 관리하기 위해 어떤 트릭을 사용합니까? 아래 기능 ([Petr Pikal 및 David Hinds가 2004 년 r-help 목록에 게시 한 내용을 기반으로])을 사용하여 가장 큰 개체를 나열하고 rm()일부 를 간헐적 으로 나열합니다. 그러나 지금까지 가장 효과적인 솔루션은 메모리가 충분한 64 비트 Linux에서 실행하는 것입니다.

다른 좋은 트릭 사람들이 공유하고 싶어? 게시물 당 하나주세요.

# improved list of objects
.ls.objects <- function (pos = 1, pattern, order.by,
                        decreasing=FALSE, head=FALSE, n=5) {
    napply <- function(names, fn) sapply(names, function(x)
                                         fn(get(x, pos = pos)))
    names <- ls(pos = pos, pattern = pattern)
    obj.class <- napply(names, function(x) as.character(class(x))[1])
    obj.mode <- napply(names, mode)
    obj.type <- ifelse(is.na(obj.class), obj.mode, obj.class)
    obj.size <- napply(names, object.size)
    obj.dim <- t(napply(names, function(x)
                        as.numeric(dim(x))[1:2]))
    vec <- is.na(obj.dim)[, 1] & (obj.type != "function")
    obj.dim[vec, 1] <- napply(names, length)[vec]
    out <- data.frame(obj.type, obj.size, obj.dim)
    names(out) <- c("Type", "Size", "Rows", "Columns")
    if (!missing(order.by))
        out <- out[order(out[[order.by]], decreasing=decreasing), ]
    if (head)
        out <- head(out, n)
    out
}
# shorthand
lsos <- function(..., n=10) {
    .ls.objects(..., order.by="Size", decreasing=TRUE, head=TRUE, n=n)
}

의심의 여지가 없지만 그 사용법은 무엇입니까? 나는 R의 메모리 문제에 익숙하지 않지만 최근에 (이 게시물을 검색하는 이유가 있습니다.) –이 모든 것부터 시작합니다. 이것이 나의 일상 업무에 어떻게 도움이됩니까?
Matt Bannert

4
함수 내에서 객체를 보려면 lsos (pos = environment ())를 사용해야합니다. 그렇지 않으면 전역 변수 만 표시됩니다. 표준 오류에 쓰려면 : write.table (lsos (pos = environment ()), stderr (), quote = FALSE, sep = '\ t')
Michael Kuhn

64 비트 Windows가 아닌 64 비트 Linux 인 이유는 무엇입니까? 32GB의 램을 사용할 때 OS를 선택하면 사소한 차이가 있습니까?
Jase

3
@pepsimax : 패키지에 multilevelPSA패키지되었습니다 . 패키지는 다른 용도로 설계되었지만이라고 말하여 패키지를로드하지 않고도 함수를 사용할 수 있습니다 requireNamespace(multilevelPSA); multilevelPSA::lsos(...). 또는 Dmisc패키지 (CRAN이 아님).
krlmlr

1
데이터 세트가 관리 가능한 크기이면 일반적으로 R studio> Environment> Grid View로 이동합니다. 크기에 따라 현재 환경의 모든 항목을보고 정렬 할 수 있습니다.
kRazzy R

답변:


197

재현 가능한 스크립트로 작업을 기록하십시오. 때때로 R을 다시 연 다음 source()스크립트를 다시여 십시오. 더 이상 사용하지 않는 것을 정리하면 추가 혜택으로 코드를 테스트하게됩니다.


58
내 전략은 load.R 및 do.R 라인을 따라 스크립트를 분리하는 것입니다. 여기서 load.R은 파일 또는 데이터베이스에서 데이터를로드하는 데 꽤 시간이 걸리고 최소한의 전처리 / 병합을 수행합니다. 그 데이터. load.R의 마지막 줄은 작업 공간 상태를 저장하는 것입니다. 그런 다음 do.R은 분석 기능을 구축하는 스크래치 패드입니다. do.R을 자주 다시로드합니다 (필요에 따라 load.R에서 작업 공간 상태를 다시로드하거나하지 않고).
Josh Reich

32
좋은 기술입니다. 파일이 같은 특정 순서로 실행하면, 나는 종종 숫자로 접두사 : 1-load.r, 2-explore.r, 3-model.r- 그것은 다른 사람에게 분명 그런 식으로 몇 가지 주문 선물이 있음.
hadley

4
나는이 아이디어를 충분히 뒷받침 할 수 없다. 나는 R에게 소수의 사람들에게 가르쳤으며 이것이 내가 말하는 첫 번째 것 중 하나입니다. 이는 개발에 REPL과 편집중인 파일 (예 : Python)이 통합 된 모든 언어에도 적용됩니다. rm (ls = list ()) 및 source ()도 작동하지만 다시 여는 것이 좋습니다 (패키지도 지워짐).
Vince

53
최고 투표 응답이 R을 다시 시작해야한다는 사실은 가능한 R에 대한 최악의 비판입니다.
sds

7
글로벌 환경에서 생성 된 객체 만 제거하는 @ MartínBel. 패키지 나 S4 객체 또는 다른 많은 것들을 언로드하지 않습니다.
hadley

160

data.table 패키지를 사용합니다 . :=운영자 와 함께 할 수있는 작업 :

  • 참조로 열 추가
  • 참조 및 그룹별로 기존 열의 하위 집합 수정
  • 참조로 열 삭제

이러한 작업 중 어느 것도 (잠재적으로 큰) 전혀 복사 data.table하지 않습니다.

  • data.table작업 메모리가 훨씬 적게 사용 되므로 집계가 특히 빠릅니다 .

관련된 링크들 :


109

트위터 포스트에서 이것을 보았고 Dirk의 멋진 기능이라고 생각하십시오! JD Long의 답변에 따라 사용자 친화적 인 독서를 위해이 작업을 수행합니다.

# improved list of objects
.ls.objects <- function (pos = 1, pattern, order.by,
                        decreasing=FALSE, head=FALSE, n=5) {
    napply <- function(names, fn) sapply(names, function(x)
                                         fn(get(x, pos = pos)))
    names <- ls(pos = pos, pattern = pattern)
    obj.class <- napply(names, function(x) as.character(class(x))[1])
    obj.mode <- napply(names, mode)
    obj.type <- ifelse(is.na(obj.class), obj.mode, obj.class)
    obj.prettysize <- napply(names, function(x) {
                           format(utils::object.size(x), units = "auto") })
    obj.size <- napply(names, object.size)
    obj.dim <- t(napply(names, function(x)
                        as.numeric(dim(x))[1:2]))
    vec <- is.na(obj.dim)[, 1] & (obj.type != "function")
    obj.dim[vec, 1] <- napply(names, length)[vec]
    out <- data.frame(obj.type, obj.size, obj.prettysize, obj.dim)
    names(out) <- c("Type", "Size", "PrettySize", "Length/Rows", "Columns")
    if (!missing(order.by))
        out <- out[order(out[[order.by]], decreasing=decreasing), ]
    if (head)
        out <- head(out, n)
    out
}

# shorthand
lsos <- function(..., n=10) {
    .ls.objects(..., order.by="Size", decreasing=TRUE, head=TRUE, n=n)
}

lsos()

다음과 같은 결과가 발생합니다.

                      Type   Size PrettySize Length/Rows Columns
pca.res                 PCA 790128   771.6 Kb          7      NA
DF               data.frame 271040   264.7 Kb        669      50
factor.AgeGender   factanal  12888    12.6 Kb         12      NA
dates            data.frame   9016     8.8 Kb        669       2
sd.                 numeric   3808     3.7 Kb         51      NA
napply             function   2256     2.2 Kb         NA      NA
lsos               function   1944     1.9 Kb         NA      NA
load               loadings   1768     1.7 Kb         12       2
ind.sup             integer    448  448 bytes        102      NA
x                 character     96   96 bytes          1      NA

참고 : 내가 추가 한 주요 부분은 (JD의 답변에서 다시 한 번)입니다.

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

이 기능은 dplyr 또는 다른 키 패키지에 추가 할 수 있습니다.
userJT

1
(적어도 base-3.3.2에서는) capture.output더 이상 필요하지 않으며 obj.prettysize <- napply(names, function(x) {format(utils::object.size(x), units = "auto") })깨끗한 출력을 생성 한다는 점에 주목할 가치가 있습니다. 실제로, 그것을 제거하지 않으면 출력에서 ​​원하지 않는 따옴표가 생성 [1] "792.5 Mb"됩니다 792.5 Mb.
Nutle

@Nutle 훌륭합니다. 코드를 적절히 업데이트했습니다 :)
Tony Breyal

또한 항상 문자 벡터 (base-3.5.0)를 반환 obj.class <- napply(names, function(x) as.character(class(x))[1])하기 obj.class <- napply(names, function(x) class(x)[1]) 때문에로 변경 했습니다 class.
DeltaIV

49

회귀 함수 subsetdata=인수에 데이터 프레임을 전달할 때 필요한 변수 만 선택 하여 매개 변수를 적극적으로 사용 합니다. 수식과 select=벡터 에 변수를 추가하는 것을 잊어 버린 경우 약간의 오류가 발생 하지만 객체 복사가 줄어들어 메모리 시간이 크게 줄어 여전히 많은 시간을 절약합니다. 110 개의 변수를 가진 4 백만 개의 레코드가 있다고 가정 해 봅시다. 예 :

# library(rms); library(Hmisc) for the cph,and rcs functions
Mayo.PrCr.rbc.mdl <- 
cph(formula = Surv(surv.yr, death) ~ age + Sex + nsmkr + rcs(Mayo, 4) + 
                                     rcs(PrCr.rat, 3) +  rbc.cat * Sex, 
     data = subset(set1HLI,  gdlab2 & HIVfinal == "Negative", 
                           select = c("surv.yr", "death", "PrCr.rat", "Mayo", 
                                      "age", "Sex", "nsmkr", "rbc.cat")
   )            )

맥락과 전략을 설정하는 방법 : gdlab2변수는 여러 실험실 테스트에 대해 모든 정상 또는 거의 정상 값을 가진 데이터 세트의 대상에 대해 구성된 논리 벡터 HIVfinal이며 HIV에 대한 예비 및 확인 테스트를 요약 한 문자 벡터입니다. .


48

Dirk의 .ls.objects () 스크립트를 좋아하지만 크기 열의 문자 수를 squinting했습니다. 그래서 크기에 맞는 서식을 지정하기 위해 추한 해킹을했습니다.

.ls.objects <- function (pos = 1, pattern, order.by,
                        decreasing=FALSE, head=FALSE, n=5) {
    napply <- function(names, fn) sapply(names, function(x)
                                         fn(get(x, pos = pos)))
    names <- ls(pos = pos, pattern = pattern)
    obj.class <- napply(names, function(x) as.character(class(x))[1])
    obj.mode <- napply(names, mode)
    obj.type <- ifelse(is.na(obj.class), obj.mode, obj.class)
    obj.size <- napply(names, object.size)
    obj.prettysize <- sapply(obj.size, function(r) prettyNum(r, big.mark = ",") )
    obj.dim <- t(napply(names, function(x)
                        as.numeric(dim(x))[1:2]))
    vec <- is.na(obj.dim)[, 1] & (obj.type != "function")
    obj.dim[vec, 1] <- napply(names, length)[vec]
    out <- data.frame(obj.type, obj.size,obj.prettysize, obj.dim)
    names(out) <- c("Type", "Size", "PrettySize", "Rows", "Columns")
    if (!missing(order.by))
        out <- out[order(out[[order.by]], decreasing=decreasing), ]
        out <- out[c("Type", "PrettySize", "Rows", "Columns")]
        names(out) <- c("Type", "Size", "Rows", "Columns")
    if (head)
        out <- head(out, n)
    out
}

34

좋은 속임수입니다.

다른 제안은 가능한 한 메모리 효율적인 객체를 사용하는 것입니다. 예를 들어 data.frame 대신 행렬을 사용하십시오.

이것은 실제로 메모리 관리를 다루지는 않지만 널리 알려지지 않은 중요한 함수 중 하나는 memory.limit ()입니다. 이 명령 memory.limit (size = 2500)를 사용하여 기본값을 늘릴 수 있습니다. 여기서 크기는 MB입니다. Dirk가 언급했듯이, 이것을 활용하려면 64 비트를 사용해야합니다.


25
이것은 Windows에만 적용되지 않습니까?
Christopher DuBois

4
> memory.limit () [1] Inf 경고 메시지 : 'memory.limit ()'는 Windows에 따라 다릅니다.
LJT

data.frame 대신 tibble을 사용하면 메모리를 절약하는 데 도움이됩니까?

32

Dirk이 개발 한 개선 된 객체 기능을 매우 좋아합니다. 그러나 대부분의 경우 객체 이름과 크기가 더 기본적인 출력으로 충분합니다. 비슷한 목표를 가진 간단한 함수가 있습니다. 메모리 사용은 알파벳순 또는 크기 순으로 정렬 될 수 있으며, 특정 개수의 객체로 제한 될 수 있으며 오름차순 또는 내림차순으로 정렬 될 수 있습니다. 또한 종종 1GB 이상의 데이터로 작업하므로 함수가 단위를 변경합니다.

showMemoryUse <- function(sort="size", decreasing=FALSE, limit) {

  objectList <- ls(parent.frame())

  oneKB <- 1024
  oneMB <- 1048576
  oneGB <- 1073741824

  memoryUse <- sapply(objectList, function(x) as.numeric(object.size(eval(parse(text=x)))))

  memListing <- sapply(memoryUse, function(size) {
        if (size >= oneGB) return(paste(round(size/oneGB,2), "GB"))
        else if (size >= oneMB) return(paste(round(size/oneMB,2), "MB"))
        else if (size >= oneKB) return(paste(round(size/oneKB,2), "kB"))
        else return(paste(size, "bytes"))
      })

  memListing <- data.frame(objectName=names(memListing),memorySize=memListing,row.names=NULL)

  if (sort=="alphabetical") memListing <- memListing[order(memListing$objectName,decreasing=decreasing),] 
  else memListing <- memListing[order(memoryUse,decreasing=decreasing),] #will run if sort not specified or "size"

  if(!missing(limit)) memListing <- memListing[1:limit,]

  print(memListing, row.names=FALSE)
  return(invisible(memListing))
}

그리고 여기 예제 출력이 있습니다 :

> showMemoryUse(decreasing=TRUE, limit=5)
      objectName memorySize
       coherData  713.75 MB
 spec.pgram_mine  149.63 kB
       stoch.reg  145.88 kB
      describeBy    82.5 kB
      lmBandpass   68.41 kB

30

R 작업 공간을 저장하지 않습니다. 가져 오기 스크립트와 데이터 스크립트를 사용하고 자주 파일로 다시 만들고 싶지 않은 특히 큰 데이터 개체를 출력합니다. 이 방법으로 나는 항상 신선한 작업 공간으로 시작하며 큰 물체를 정리할 필요가 없습니다. 그래도 아주 좋은 기능입니다.


30

불행히도 나는 그것을 광범위하게 테스트 할 시간이 없었지만 여기에 내가 보지 못한 메모리 팁이 있습니다. 나에게 필요한 메모리는 50 % 이상 줄었다. read.csv와 같이 R로 내용을 읽을 때는 특정 양의 메모리가 필요합니다. save("Destinationfile",list=ls()) 다음에 R을 열면 저장할 수 있습니다 . 다음에 R을 열 때 사용할 수 있습니다. load("Destinationfile") 이제 메모리 사용량이 줄어들 수 있습니다. 이것이 다른 데이터 세트로 유사한 결과를 생성하는지 여부를 확인할 수 있다면 좋을 것입니다.


4
예, 같은 경험을했습니다. 필자의 경우 메모리 사용량이 30 %로 떨어졌습니다. 1.5GB 메모리 사용, .RData (~ 30MB)로 저장 .RData를로드 한 후 새 세션은 500MB 미만의 메모리를 사용합니다.
f3lix

을 사용하여 data.table에로드 된 2 개의 데이터 세트 (100MB 및 2.7GB)로 시도한 fread다음 .RData에 저장했습니다. RData 파일은 실제로 약 70 % 작았지만 다시로드 한 후 사용 된 메모리는 정확히 동일했습니다. 이 트릭이 메모리 풋 프린트를 줄 이길 바랐습니다.
초보자 Prog

@ 초보자 Prog 나는 당신이 무언가를 놓치고 있다고 생각하지 않지만, 속임수입니다. 모든 상황에서 작동하지는 않을 것 같습니다. 필자의 경우 다시로드 후 메모리가 실제로 설명대로 줄어 들었습니다.
Dennis Jaheruddin

6
@NoviceProg 몇 가지. 먼저, data.table의 credo를 따르는 fread는 아마도 read.csv보다 파일을로드하는 데 더 메모리 효율적일 것입니다. 둘째, 사람들이 여기서 주목하는 메모리 절약은 주로 R 프로세스의 메모리 크기와 관련이 있습니다 (가비지 수집이 발생하면 객체를 보유하도록 확장되고 축소됩니다). 그러나 가비지 콜렉션은 항상 모든 RAM을 OS로 다시 릴리스하지는 않습니다. R 세션을 중지하고 저장된 위치에서 항목을로드하면 가능한 한 많은 RAM이 해제되지만 오버 헤드가 작 으면 이득이 없습니다.
russellpierce

27

자주 다시 시작하는 일반적인 전략을 자세히 설명 하기 위해 명령 줄에서 간단한 표현식을 직접 실행할 수있는 little 를 사용할 수 있습니다 . 다음은 간단한 크로스 프로드를 위해 때때로 다른 BLAS를 시간 측정하는 데 사용하는 예입니다.

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

마찬가지로,

 r -lMatrix -e'example(spMatrix)'

--packages | -l 스위치를 통해 Matrix 패키지를로드하고 spMatrix 함수의 예제를 실행합니다. r은 항상 'fresh'를 시작하므로이 방법은 패키지 개발 중에도 좋은 테스트입니다.

마지막으로 r은 '#! / usr / bin / r'shebang-header를 사용하는 스크립트의 자동 배치 모드에서도 훌륭하게 작동합니다. Rscript는 더 작게 사용할 수없는 대안입니다 (예 : Windows).


23

속도와 메모리 목적을 위해 복잡한 일련의 단계를 통해 큰 데이터 프레임을 구축 할 때 주기적으로 디스크에 플러시 (진행중인 데이터 세트를 플러시)하여 이전에 있던 것을 추가 한 다음 다시 시작합니다. . 이런 식으로 중간 단계는 작은 데이터 프레임에서만 작동합니다 (예를 들어 rbind 가 큰 객체 에서는 상당히 느려짐). 모든 중간 오브젝트가 제거되면 프로세스 종료시 전체 데이터 세트를 다시 읽을 수 있습니다.

dfinal <- NULL
first <- TRUE
tempfile <- "dfinal_temp.csv"
for( i in bigloop ) {
    if( !i %% 10000 ) { 
        print( i, "; flushing to disk..." )
        write.table( dfinal, file=tempfile, append=!first, col.names=first )
        first <- FALSE
        dfinal <- NULL   # nuke it
    }

    # ... complex operations here that add data to 'dfinal' data frame  
}
print( "Loop done; flushing to disk and re-reading entire data set..." )
write.table( dfinal, file=tempfile, append=TRUE, col.names=FALSE )
dfinal <- read.table( tempfile )

17

그냥 참고로 data.table패키지의이 tables()더크의에 대한 꽤 좋은 교체 될 것으로 보인다 .ls.objects()비록 단지 data.frames / 테이블이 아닌 예를 들어 행렬, 배열,리스트, (이전 답변에 설명) 사용자 정의 함수입니다.


이것은 어떤
data.frames도

16
  1. 운이 좋으며 큰 데이터 세트는 계측기에 의해 약 100MB (32 비트 이진)의 "청크"(서브 세트)로 저장됩니다. 따라서 데이터 세트를 융합하기 전에 사전 처리 단계 (정보가없는 부분 삭제, 다운 샘플링)를 순차적으로 수행 할 수 있습니다.

  2. gc ()데이터 크기가 사용 가능한 메모리에 가까워지면 "손으로"를 호출 하면 도움이됩니다.

  3. 때로는 다른 알고리즘에 훨씬 적은 메모리가 필요합니다.
    때로는 벡터화와 메모리 사용간에 상충 관계가 있습니다.
    비교 : split& lapplyfor루프.

  4. 빠르고 쉬운 데이터 분석을 위해 데이터의 작은 임의의 하위 집합 ( sample ())을 먼저 사용합니다. 데이터 분석 스크립트 / .Rnw가 완료되면 데이터 분석 코드가 완성되고 완전한 데이터가 밤새 / 주말 / ... 계산을 위해 계산 서버로 이동합니다.


11

많은 양의 작업 메모리를 차지하는 오브젝트 콜렉션을 처리하기 위해 목록 대신 환경 사용.

이유 : list구조 의 요소 가 수정 될 때마다 전체 목록이 일시적으로 복제됩니다. 목록의 스토리지 요구 사항이 사용 가능한 작업 메모리의 약 절반 인 경우 데이터가 느린 하드 디스크로 교체되어야하기 때문에 문제가됩니다. 반면에 환경은이 동작의 영향을받지 않으며 목록과 유사하게 처리 될 수 있습니다.

예를 들면 다음과 같습니다.

get.data <- function(x)
{
  # get some data based on x
  return(paste("data from",x))
}

collect.data <- function(i,x,env)
{
  # get some data
  data <- get.data(x[[i]])
  # store data into environment
  element.name <- paste("V",i,sep="")
  env[[element.name]] <- data
  return(NULL)  
}

better.list <- new.env()
filenames <- c("file1","file2","file3")
lapply(seq_along(filenames),collect.data,x=filenames,env=better.list)

# read/write access
print(better.list[["V1"]])
better.list[["V2"]] <- "testdata"
# number of list elements
length(ls(better.list))

컨텐츠를 제자리에서 변경하는 것과 같은 구조 big.matrix또는 구조와 함께 data.table매우 효율적인 메모리 사용이 가능합니다.


6
더 이상 사실이 아닙니다. Hadley의 고급 R 에서 "R 3.1.0으로 변경하면 목록을 수정해도 더 이상 딥 카피를 만들지 않기 때문에 [환경] 사용이 그다지 중요하지 않게되었습니다."
petrelharp

8

패키지 의 ll기능 gData은 각 객체의 메모리 사용량을 보여줄 수 있습니다.

gdata::ll(unit='MB')

내 시스템에 없음 : R 버전 3.1.1 (2014-07-10), x86_64-pc-linux-gnu (64 비트), gdata_2.13.3, gtools_3.4.1.
krlmlr

우연히 주문되면 테스트 해보십시오!
user1436187

1
Gb, Mb
userJT

7

실제로 누출을 피하려면 글로벌 환경에서 큰 객체를 생성하지 않아야합니다.

내가 보통하는 일은 작업을 수행하고 반환하는 함수를 갖는 것입니다 NULL.이 함수 나 다른 함수에서 모든 데이터를 읽고 조작합니다.


7

4GB의 RAM (Windows 10을 실행하므로 약 2GB 이상으로 현실적으로 1GB로 설정)을 사용하면 할당에 실제로주의해야했습니다.

나는 거의 독점적으로 data.table을 사용합니다.

'fread'기능을 사용하면 가져올 때 필드 이름별로 정보를 서브 세트 할 수 있습니다. 실제로 시작하는 데 필요한 필드 만 가져옵니다. 기본 R 읽기를 사용하는 경우 가져 오기 직후 스퓨리어스 열을 null로 처리하십시오.

으로 42 인치가 제안, 나는 즉시 정보를 가져온 후 열 내에서 부분 집합 곳에 이제까지 가능합니다.

더 이상 필요하지 않은 즉시 환경에서 객체를 자주 rm ()합니다 (예 : 객체를 사용하여 다른 것을 서브 셋팅 한 후 다음 줄). gc ()를 호출합니다.

data.table의 'fread'및 'fwrite'는 기본 R 읽기 및 쓰기와 비교하여 매우 빠릅니다.

kpierce8이 제안 했듯이 , 나는 거의 항상 환경에서 모든 것을 쓸어 버리고 수천 / 수십만 개의 작은 파일을 통해 다시 확산시킵니다 . 이것은 환경을 '깨끗한'상태로 유지하고 메모리 할당을 낮게 유지하지만, 가용 한 RAM 부족으로 인해 R은 내 컴퓨터에서 자주 충돌하는 경향이 있습니다. 정말 자주. 코드가 다양한 단계를 거치면서 드라이브 자체에 정보를 백업한다는 것은 충돌이 발생하더라도 처음부터 시작할 필요가 없음을 의미합니다.

2017 년 현재, 가장 빠른 SSD가 M2 포트를 통해 초당 약 몇 GB를 실행하고 있다고 생각합니다. 기본 디스크로 사용하는 기본 50GB Kingston V300 (550MB / s) SSD가 있습니다 (Windows 및 R이 있음). 나는 모든 대량 정보를 저렴한 500GB WD 플래터에 보관합니다. 작업을 시작할 때 데이터 세트를 SSD로 옮깁니다. 이것은 '확산'및 'fwrite'와 결합하여 모든 것이 훌륭하게 해결되었습니다. 나는 'ff'를 사용해 보았지만 전자를 선호합니다. 4K 읽기 / 쓰기 속도는 이로 인해 문제를 일으킬 수 있습니다. SSD에서 플래터에 백만 개의 1k 파일 (250MB)을 백업하는 데 몇 시간이 걸릴 수 있습니다. 내가 아는 한, '청크 화'프로세스를 자동으로 최적화 할 수있는 R 패키지는 아직 없습니다. 예를 들어 사용자의 RAM 용량을 확인하십시오. RAM / 연결된 모든 드라이브의 읽기 / 쓰기 속도를 테스트 한 다음 최적의 '청크'프로토콜을 제안하십시오. 이는 상당한 워크 플로우 개선 / 자원 최적화를 생성 할 수 있습니다. 예를 들어 램의 경우 ... MB로 분할-> SSD의 경우 ... MB로 분할-> 플래터에서 ... MB로 분할-> 테이프의 ... MB로 분할합니다. 데이터 세트를 미리 샘플링하여보다 현실적인 게이지 스틱을 사용할 수 있습니다.

내가 R에 근무 한 문제의 많은 그들은 종종하므로 단지 더 제한 제한된 RAM을 가진하게 트리플 등 조합과 순열 쌍 형성 포함 적어도 기하 급수적으로 어떤 점에서 확장을. 이로 인해 나중에 정보를 정리하려고하지 않고 정보로 시작하는 정보의 양과 달리 정보 의 품질 에 많은 관심을 기울 였습니다. 가장 간단한 조작과 복잡성 증가); 예를 들어 하위 집합, 병합 / 결합, 조합 / 순열 등

경우에 따라 기본 R 읽기 및 쓰기를 사용하면 이점이있는 것 같습니다. 예를 들어, 'fread'내의 오류 감지가 너무 좋으므로 R로 정보를 정리하기 위해 실제로 지저분한 정보를 얻는 것이 어려울 수 있습니다. Linux를 사용하는 경우 Base R도 훨씬 쉬워 보입니다. 기본 R은 Linux에서 잘 작동하는 것으로 보이며 Windows 10은 ~ 20GB의 디스크 공간을 사용하지만 Ubuntu는 몇 GB 만 ​​필요하며 Ubuntu에 필요한 RAM은 약간 낮습니다. 그러나 (L) 우분투에 타사 패키지를 설치할 때 많은 경고와 오류가 나타났습니다. (L) Ubuntu 또는 Linux와의 다른 주식 배포판에서 너무 멀리 떨어져 표류하지 않는 것이 좋습니다. 너무 전반적인 호환성을 잃어 버릴 수 있기 때문에 프로세스가 거의 무의미합니다. ).

그 중 일부는 다른 사람들을 도울 수 있기를 바랍니다.


5

이것은 위의 내용을 추가하지 않지만 내가 좋아하는 단순하고 심하게 주석이 달린 스타일로 작성되었습니다. 크기 순서대로 객체가 있지만 위의 예제에 제공된 세부 정보가없는 테이블을 생성합니다.

#Find the objects       
MemoryObjects = ls()    
#Create an array
MemoryAssessmentTable=array(NA,dim=c(length(MemoryObjects),2))
#Name the columns
colnames(MemoryAssessmentTable)=c("object","bytes")
#Define the first column as the objects
MemoryAssessmentTable[,1]=MemoryObjects
#Define a function to determine size        
MemoryAssessmentFunction=function(x){object.size(get(x))}
#Apply the function to the objects
MemoryAssessmentTable[,2]=t(t(sapply(MemoryAssessmentTable[,1],MemoryAssessmentFunction)))
#Produce a table with the largest objects first
noquote(MemoryAssessmentTable[rev(order(as.numeric(MemoryAssessmentTable[,2]))),])


3

당신이에서 작업하는 경우 리눅스 와 사용하고자하는 여러 프로세스를 만해야 읽기 하나 이상에 대한 작업을 큰 개체 사용 makeForkCluster대신의 makePSOCKcluster. 또한 큰 개체를 다른 프로세스로 보내는 시간도 절약됩니다.


2

R을 닫고 source명령 줄을 실행 하고 사용 하는 것을 제안하는 @hadley와 @Dirk에 따라 위의 답변 중 일부에 감사드립니다 . 수백 개의 질량 스펙트럼을 처리해야했으며 각각 약 20MB의 메모리를 차지하므로 다음과 같이 두 개의 R 스크립트를 사용했습니다.

먼저 래퍼 :

#!/usr/bin/Rscript --vanilla --default-packages=utils

for(l in 1:length(fdir)) {

   for(k in 1:length(fds)) {
     system(paste("Rscript runConsensus.r", l, k))
   }
}

이 스크립트를 사용하여 기본적으로 기본 스크립트가 수행하는 작업을 제어 runConsensus.r하고 출력에 대한 데이터 응답을 작성합니다. 이를 통해 랩퍼가 스크립트를 호출 할 때마다 R이 다시 열리고 메모리가 해제 된 것 같습니다.

도움이 되길 바랍니다.


2

위의 답변에 제공된보다 일반적인 메모리 관리 기술뿐만 아니라 항상 가능한 한 객체 크기를 줄이려고합니다. 예를 들어, 매우 크지 만 매우 희소 행렬, 즉 대부분의 값이 0 인 행렬로 작업합니다. '매트릭스'패키지 (자본 중요)를 사용하여 다음과 같이 평균 객체 크기를 ~ 2GB에서 ~ 200MB로 줄일 수있었습니다.

my.matrix <- Matrix(my.matrix)

Matrix 패키지에는 일반 매트릭스처럼 정확하게 사용할 수있는 데이터 형식이 포함되어 있지만 (다른 코드를 변경할 필요는 없지만) 메모리에로드하든 디스크에 저장하든 스파 스 데이터를 훨씬 더 효율적으로 저장할 수 있습니다.

또한 내가받는 원시 파일은 각 데이터 포인트에 변수가있는 '긴'형식 x, y, z, i입니다. x * y * zvariable 만 사용 하여 데이터를 차원 배열 로 변환하는 것이 훨씬 더 효율적 i입니다.

데이터를 알고 약간의 상식을 사용하십시오.


2

무거운 중간 계산이 필요한 개체를 처리하기위한 팁 : 많은 계산 및 중간 단계를 필요로하는 개체를 사용하여 개체를 만드는 경우에는 개체를 만드는 함수와 함께 코드 청크를 작성한 다음 별도의 청크를 작성하는 것이 유용한 경우가 많습니다. 객체를 생성하여 rmd파일 로 저장 하거나 rmd이미 저장 한 파일 에서 외부로로드 할 수 있는 옵션을 제공합니다 . R Markdown다음 코드 청크 구조 를 사용하면 특히 쉽습니다 .

```{r Create OBJECT}

COMPLICATED.FUNCTION <- function(...) { Do heavy calculations needing lots of memory;
                                        Output OBJECT; }

```
```{r Generate or load OBJECT}

LOAD <- TRUE;
#NOTE: Set LOAD to TRUE if you want to load saved file
#NOTE: Set LOAD to FALSE if you want to generate and save

if(LOAD == TRUE) { OBJECT <- readRDS(file = 'MySavedObject.rds'); } else
                 { OBJECT <- COMPLICATED.FUNCTION(x, y, z);
                             saveRDS(file = 'MySavedObject.rds', object = OBJECT); }

```

이 코드 구조를 LOAD사용하면 객체 생성 및 저장 여부에 따라 변경 하거나 기존 저장된 파일에서 직접로드하기 만하면됩니다. (물론, 나는 그것을 생성하고 처음으로 저장해야하지만,이 후에는로드 할 수있는 옵션이 있습니다.) 설정 LOAD = TRUE은 복잡한 기능의 사용을 무시하고 그 안에 무거운 계산을 모두 피합니다. 이 방법은 여전히 ​​관심 객체를 저장하기에 충분한 메모리가 필요하지만 코드를 실행할 때마다 계산할 필요가 없습니다. 중간 단계를 많이 계산해야하는 개체 (예 : 큰 배열에 대한 루프 관련 계산)는 상당한 시간과 계산을 절약 할 수 있습니다.


1

달리는

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

때때로 R은 사용되지 않지만 여전히 해제되지 않은 메모리를 해제하는 데 도움이됩니다.


뭐라고합니까 for루프는 여기에서? 더 없습니다 igc전화를 겁니다.
Umaomamaomao

@qqq 복사 붙여 넣기를 gc(reset = T)9 번 피하는 것이 좋습니다
Marcelo Ventura

14
하지만 왜 9 번이나 하시겠습니까? (호기심, 중요하지 않음)
Umaomamaomao

1

knitr를 사용하고 Rmd chuncks에 스크립트를 넣는 것도 도움이됩니다.

일반적으로 코드를 다른 청크로 나누고 검사 점을 캐시 또는 RDS 파일에 저장할 코드를 선택하고

거기에서 "캐시"에 저장되도록 청크를 설정하거나 특정 청크의 실행 여부를 결정할 수 있습니다. 이런 식으로, 첫 번째 실행에서는 "파트 1"만 처리하고 다른 실행은 "파트 2"만 선택할 수 있습니다.

예:

part1
```{r corpus, warning=FALSE, cache=TRUE, message=FALSE, eval=TRUE}
corpusTw <- corpus(twitter)  # build the corpus
```
part2
```{r trigrams, warning=FALSE, cache=TRUE, message=FALSE, eval=FALSE}
dfmTw <- dfm(corpusTw, verbose=TRUE, removeTwitter=TRUE, ngrams=3)
```

부작용으로 재현성 측면에서 두통을 줄일 수 있습니다. :)


1

@ Dirk와 @Tony의 답변을 바탕으로 약간의 업데이트를했습니다. 결과는 [1]예쁜 크기 값보다 먼저 출력 되었으므로 capture.output문제를 해결했습니다.

.ls.objects <- function (pos = 1, pattern, order.by,
                     decreasing=FALSE, head=FALSE, n=5) {
napply <- function(names, fn) sapply(names, function(x)
    fn(get(x, pos = pos)))
names <- ls(pos = pos, pattern = pattern)
obj.class <- napply(names, function(x) as.character(class(x))[1])
obj.mode <- napply(names, mode)
obj.type <- ifelse(is.na(obj.class), obj.mode, obj.class)
obj.prettysize <- napply(names, function(x) {
    format(utils::object.size(x),  units = "auto") })
obj.size <- napply(names, utils::object.size)

obj.dim <- t(napply(names, function(x)
    as.numeric(dim(x))[1:2]))
vec <- is.na(obj.dim)[, 1] & (obj.type != "function")
obj.dim[vec, 1] <- napply(names, length)[vec]
out <- data.frame(obj.type, obj.size, obj.prettysize, obj.dim)
names(out) <- c("Type", "Size", "PrettySize", "Rows", "Columns")
if (!missing(order.by))
    out <- out[order(out[[order.by]], decreasing=decreasing), ]
if (head)
    out <- head(out, n)

return(out)
}

# shorthand
lsos <- function(..., n=10) {
    .ls.objects(..., order.by="Size", decreasing=TRUE, head=TRUE, n=n)
}

lsos()

-1

중간 단계가 많은 대형 프로젝트에서 작업 할 때 객체의 양을 작게 유지하려고합니다. 따라서 많은 고유 한 객체를 만드는 대신

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

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

내가 호출하는 임시 개체로 작업합니다 temp.

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

중간 파일이 적고 개요가 더 좋습니다.

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

더 많은 메모리를 절약하기 위해 더 temp이상 필요 없을 때 간단히 제거 할 수 있습니다 .

rm(temp)

나는 몇 가지 중간 파일이 필요하면, 내가 사용 temp1, temp2, temp3.

내가 사용하는 테스트를 위해 test, test2...

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.