548 Stimmen

Tricks zur Verwaltung des verfügbaren Speichers in einer R-Sitzung

Welche Tricks verwenden die Leute, um den verfügbaren Speicher einer interaktiven R-Sitzung zu verwalten? Ich verwende die folgenden Funktionen [basierend auf Postings von Petr Pikal und David Hinds in der r-help-Liste im Jahr 2004], um die größten Objekte aufzulisten (und/oder zu sortieren) und um gelegentlich rm() einige von ihnen. Aber die bei weitem effektivste Lösung war ... unter 64-Bit-Linux mit reichlich Speicher zu laufen.

Gibt es noch andere nette Tricks, die Sie uns mitteilen möchten? Einen pro Beitrag, bitte.

# 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 Stimmen

Wohlgemerkt, ich zweifle NICHT daran, aber was nützt das schon? Ich bin ziemlich neu bei Speicherproblemen in R, aber ich erlebe einige in letzter Zeit (das ist, warum ich für diesen Beitrag gesucht:) - so bin ich gerade erst anfangen mit all dies. Wie hilft mir das bei meiner täglichen Arbeit?

5 Stimmen

Wenn Sie die Objekte innerhalb einer Funktion sehen wollen, müssen Sie lsos(pos = environment()) verwenden, sonst werden nur globale Variablen angezeigt. Um in den Standardfehler zu schreiben: write.table(lsos(pos=environment()), stderr(), quote=FALSE, sep=' \t ')

0 Stimmen

Warum 64-Bit-Linux und nicht 64-Bit-Windows? Macht die Wahl des Betriebssystems einen nicht-trivialen Unterschied, wenn ich 32 GB Arbeitsspeicher zur Verfügung habe?

7voto

Alexander Radev Punkte 642

Wenn Sie die Lecks wirklich vermeiden wollen, sollten Sie keine großen Objekte in der globalen Umgebung erstellen.

Normalerweise habe ich eine Funktion, die die Aufgabe erledigt und Folgendes zurückgibt NULL - alle Daten werden in dieser Funktion oder in anderen, die sie aufruft, gelesen und manipuliert.

7voto

bg49ag Punkte 143

Mit nur 4 GB RAM (unter Windows 10, also etwa 2 oder realistischerweise 1 GB) musste ich bei der Zuweisung sehr vorsichtig sein.

Ich verwende fast ausschließlich data.table.

Mit der Funktion "fread" können Sie die Informationen beim Import nach Feldnamen untergliedern; importieren Sie nur die Felder, die tatsächlich benötigt werden, und beginnen Sie damit. Wenn Sie base R read verwenden, löschen Sie die unerwünschten Spalten sofort nach dem Import.

Como 42- schlägt vor, dass ich, wo immer es möglich ist, unmittelbar nach dem Import der Informationen in den Spalten eine Unterteilung vornehme.

Ich lösche häufig Objekte aus der Umgebung, sobald sie nicht mehr benötigt werden, z. B. in der nächsten Zeile, nachdem ich sie für eine andere Untermenge verwendet habe, und rufe gc() auf.

'fread' und 'fwrite' aus data.table können sein sehr schnell im Vergleich zu Base R Lese- und Schreibvorgängen.

Como kpierce8 Ich schlage vor, dass ich fast immer alles aus der Umgebung herausschreibe und wieder einlese, selbst bei Tausenden oder Hunderttausenden winziger Dateien, die ich durchgehen muss. Dies hält nicht nur die Umgebung "sauber" und hält die Speicherzuweisung niedrig, aber, möglicherweise aufgrund der schweren Mangel an RAM zur Verfügung, R hat eine Neigung für häufig Abstürze auf meinem Computer; wirklich häufig. Da die Informationen auf dem Laufwerk selbst gesichert werden, während der Code die verschiedenen Phasen durchläuft, muss ich bei einem Absturz nicht wieder von vorne anfangen.

Ich glaube, dass die schnellsten SSDs im Jahr 2017 einige GB pro Sekunde über den M2-Anschluss laufen. Ich habe eine wirklich einfache 50 GB Kingston V300 (550 MB/s) SSD, die ich als meine primäre Festplatte (mit Windows und R darauf) verwende. Alle wichtigen Daten bewahre ich auf einer billigen 500-GB-Platte von WD auf. Ich verschiebe die Datensätze auf die SSD, wenn ich anfange, an ihnen zu arbeiten. Dies, kombiniert mit 'fread'ing und 'fwrite'ing, hat hervorragend funktioniert. Ich habe versucht, 'ff' zu verwenden, bevorzuge aber Ersteres. Die 4K-Lese-/Schreibgeschwindigkeiten können dabei allerdings zu Problemen führen; das Sichern einer Viertelmillion 1k-Dateien (250 MB) von der SSD auf die Platte kann Stunden dauern. Soweit mir bekannt ist, gibt es noch kein R-Paket, das den "Chunkification"-Prozess automatisch optimieren kann; z. B. kann es sich ansehen, wie viel RAM ein Benutzer hat, die Lese-/Schreibgeschwindigkeiten des RAM / aller angeschlossenen Laufwerke testen und dann ein optimales "Chunkification"-Protokoll vorschlagen. Dies könnte zu erheblichen Verbesserungen des Arbeitsablaufs bzw. zur Optimierung der Ressourcen führen, z. B. Aufteilung auf ... MB für den Arbeitsspeicher -> aufteilen auf ... MB für die SSD -> aufteilen in ... MB auf der Platte -> aufteilen auf ... MB auf dem Band. Es könnte vorher eine Stichprobe von Datensätzen machen, um eine realistischere Messlatte für die Arbeit zu haben.

Viele der Probleme, an denen ich in R gearbeitet habe, beinhalten die Bildung von Kombinations- und Permutationspaaren, Tripeln usw., was den begrenzten Arbeitsspeicher nur noch mehr einschränkt, da sie oft mindestens irgendwann exponentiell wachsen. Dies hat mich dazu veranlasst, mich intensiv mit der Qualität im Gegensatz zu Menge der Informationen, die zu Beginn in sie eingehen, anstatt zu versuchen, sie im Nachhinein zu bereinigen, und auf die Reihenfolge der Operationen bei der Aufbereitung der Informationen (beginnend mit der einfachsten Operation und mit zunehmender Komplexität); z. B. Untermenge, dann Zusammenführen/Verbinden, dann Kombinationen/Permutationen bilden usw.

Die Verwendung von Base R zum Lesen und Schreiben scheint in manchen Fällen einige Vorteile zu bieten. Zum Beispiel ist die Fehlererkennung in "fread" so gut, dass es schwierig sein kann, wirklich unordentliche Informationen in R zu bekommen, um sie zu bereinigen. Base R scheint auch viel einfacher zu sein, wenn man Linux benutzt. Base R scheint unter Linux gut zu funktionieren, Windows 10 benötigt ~20 GB Festplattenspeicher, während Ubuntu nur ein paar GB benötigt, der benötigte RAM ist bei Ubuntu etwas geringer. Aber ich habe eine große Anzahl von Warnungen und Fehlern bei der Installation von Paketen von Drittanbietern in (L)Ubuntu festgestellt. Ich würde nicht empfehlen, sich mit Linux zu weit von (L)Ubuntu oder anderen Standarddistributionen zu entfernen, da man so viel Kompatibilität verlieren kann, dass der Prozess fast sinnlos wird (ich glaube, "Unity" soll in Ubuntu ab 2017 abgeschafft werden). Mir ist klar, dass dies bei einigen Linux-Nutzern nicht gut ankommen wird, aber einige der benutzerdefinierten Distributionen sind grenzwertig sinnlos über die Neuheit hinaus (ich habe Jahre damit verbracht, Linux allein zu verwenden).

Ich hoffe, dass einige dieser Informationen anderen helfen können.

6voto

Chris Beeley Punkte 541

Dies ist eine neuere Antwort auf diese sehr alte Frage. Aus 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 )

5voto

JamesF Punkte 81

Dies fügt dem oben Gesagten nichts hinzu, ist aber in dem einfachen und stark kommentierten Stil geschrieben, den ich mag. Es ergibt eine Tabelle mit den nach Größe geordneten Objekten, aber ohne einige der in den obigen Beispielen angegebenen Details:

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

3voto

D Greenwood Punkte 364

Neben den allgemeineren Speicherverwaltungstechniken, die in den obigen Antworten genannt werden, versuche ich immer, die Größe meiner Objekte so weit wie möglich zu reduzieren. Ich arbeite zum Beispiel mit sehr großen, aber sehr spärlichen Matrizen, d. h. Matrizen, bei denen die meisten Werte Null sind. Mit dem 'Matrix'-Paket (Großschreibung wichtig) konnte ich meine durchschnittlichen Objektgrößen von ~2GB auf ~200MB reduzieren, so einfach ist das:

my.matrix <- Matrix(my.matrix)

Das Matrix-Paket enthält Datenformate, die genau wie eine reguläre Matrix verwendet werden können (ohne dass Sie Ihren anderen Code ändern müssen), die aber in der Lage sind, spärliche Daten viel effizienter zu speichern, egal ob sie in den Speicher geladen oder auf der Festplatte gespeichert werden.

Außerdem sind die Rohdateien, die ich erhalte, im "langen" Format, in dem jeder Datenpunkt Variablen enthält x, y, z, i . Viel effizienter ist die Umwandlung der Daten in eine x * y * z Dimension Array mit nur Variable i .

Kennen Sie Ihre Daten und benutzen Sie einen gesunden Menschenverstand.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X