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

사람들이 대화 형 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을 다시 연 다음 source()스크립트를 다시여 십시오. 더 이상 사용하지 않는 것을 정리하면 추가 혜택으로 코드를 테스트하게됩니다.


답변

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

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

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

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

관련된 링크들 :


답변

트위터 포스트에서 이것을 보았고 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") })


답변

회귀 함수 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에 대한 예비 및 확인 테스트를 요약 한 문자 벡터입니다. .


답변

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
}


답변

좋은 속임수입니다.

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

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


답변

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