548 votes

Astuces pour gérer la mémoire disponible dans une session R

Quelles astuces utilise-t-on pour gérer la mémoire disponible d'une session R interactive ? J'utilise les fonctions ci-dessous [basées sur les messages de Petr Pikal et David Hinds sur la liste r-help en 2004] pour lister (et/ou trier) les plus gros objets et pour occasionnellement rm() certains d'entre eux. Mais la solution de loin la plus efficace était ... de fonctionner sous Linux 64 bits avec beaucoup de mémoire.

D'autres trucs sympas que vous voulez partager ? Un par poste, s'il vous plaît.

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

1 votes

Remarque, je n'en doute PAS, mais à quoi bon ? Je suis assez novice en ce qui concerne les problèmes de mémoire dans R, mais j'en rencontre quelques-uns ces derniers temps (c'est pourquoi je cherchais ce post :) - donc je ne fais que commencer avec tout ça. En quoi cela aide-t-il mon travail quotidien ?

5 votes

Si vous voulez voir les objets à l'intérieur d'une fonction, vous devez utiliser : lsos(pos = environment()), sinon il ne montrera que les variables globales. Pour écrire dans l'erreur standard : write.table(lsos(pos=environnement()), stderr(), quote=FALSE, sep=' \t ')

0 votes

Pourquoi linux 64 bits et pas Windows 64 bits ? Le choix du système d'exploitation fait-il une différence non négligeable lorsque j'ai 32 Go de RAM à utiliser ?

213voto

hadley Points 33766

Assurez-vous d'enregistrer votre travail dans un script reproductible. De temps en temps, rouvrez R, puis source() votre script. Vous nettoierez tout ce que vous n'utilisez plus, et comme avantage supplémentaire, vous aurez testé votre code.

62 votes

Ma stratégie consiste à diviser mes scripts en deux parties : load.R et do.R, où load.R peut prendre un certain temps pour charger des données à partir de fichiers ou d'une base de données, et effectue le minimum de prétraitement/fusion de ces données. La dernière ligne de load.R sert à sauvegarder l'état de l'espace de travail. Ensuite, do.R est mon bloc-notes dans lequel je construis mes fonctions d'analyse. Je recharge fréquemment do.R (avec ou sans rechargement de l'état de l'espace de travail depuis load.R si nécessaire).

34 votes

C'est une bonne technique. Lorsque les fichiers sont exécutés dans un certain ordre comme ça, je les fais souvent précéder d'un numéro : 1-load.r , 2-explore.r , 3-model.r - de cette façon, il est évident pour les autres qu'il y a un certain ordre.

0 votes

@josh : c'est un bon conseil, mettez-le dans une réponse à part entière et gagnez des votes !

175voto

Matt Dowle Points 20936

J'utilise le table.de.données paquet. Avec son := opérateur vous pouvez :

  • Ajouter des colonnes par référence
  • Modifier des sous-ensembles de colonnes existantes par référence, et par groupe par référence
  • Supprimer les colonnes par référence

Aucune de ces opérations ne copie le fichier (potentiellement important) data.table pas du tout, pas même une fois.

  • L'agrégation est également particulièrement rapide car data.table utilise beaucoup moins de mémoire de travail.

Liens connexes :

126voto

Tony Breyal Points 2707

J'ai vu ça sur un post twitter et je pense que c'est une fonction géniale de Dirk ! Dans le prolongement de La réponse de JD Long Je le ferais pour une lecture conviviale :

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

Ce qui donne quelque chose comme ce qui suit :

                      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

NOTE : La partie principale que j'ai ajoutée est (encore une fois, adaptée de la réponse de JD) :

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

1 votes

Cette fonction peut-elle être ajoutée à dplyr ou à un autre paquet clé ?

1 votes

Il est intéressant de noter que (au moins avec la base-3.3.2) capture.output n'est plus nécessaire, et obj.prettysize <- napply(names, function(x) {format(utils::object.size(x), units = "auto") }) produit une sortie propre. En fait, ne pas l'enlever produit des guillemets non désirés dans la sortie, c'est-à-dire [1] "792.5 Mb" au lieu de 792.5 Mb .

0 votes

@Nutle Excellent, j'ai mis à jour le code en conséquence :)

52voto

BondedDust Points 105234

Je fais un usage agressif de la subset avec la sélection des seules variables requises lors de la transmission des cadres de données à l'outil de gestion des données. data= argument des fonctions de régression. Il en résulte quelques erreurs si j'oublie d'ajouter des variables à la fois à la formule et à l'argument de régression. select= mais il permet néanmoins de gagner beaucoup de temps en raison de la diminution de la copie d'objets et de réduire considérablement l'empreinte mémoire. Disons que j'ai 4 millions d'enregistrements avec 110 variables (et c'est le cas.) Exemple :

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

A titre de mise en contexte et de stratégie : le gdlab2 est un vecteur logique qui a été construit pour les sujets d'un ensemble de données présentant toutes les valeurs normales ou presque normales pour un ensemble de tests de laboratoire et d'analyses. HIVfinal était un vecteur de caractères qui résumait les tests préliminaires et de confirmation du VIH.

49voto

JD Long Points 20477

J'adore le script .ls.objects() de Dirk script mais je n'arrêtais pas de loucher pour compter les caractères dans la colonne de taille. J'ai donc fait des hacks moches pour que ça soit présent avec un joli formatage pour la taille :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X