Optimierung: Aufteilen des Datenrahmens in eine Liste von Datenrahmen, um Daten pro Zeile zu transformieren

8

Vorbemerkungen : Diese Frage ist meist von pädagogischem Wert, die eigentliche Aufgabe ist abgeschlossen, auch wenn der Ansatz nicht ganz optimal ist. Meine Frage ist, ob der folgende Code für Geschwindigkeit optimiert und / oder eleganter implementiert werden kann. Vielleicht mit zusätzlichen Paketen, wie zB plyr oder reshape. Auf den tatsächlichen Daten ausgeführt dauert es ungefähr 140 Sekunden, viel höher als die simulierten Daten, da einige der ursprünglichen Zeilen nichts als NA enthalten und zusätzliche Überprüfungen durchgeführt werden müssen. Zum Vergleich werden die simulierten Daten in etwa 30 Sekunden verarbeitet.

Bedingungen : Der Datensatz enthält 360 Variablen, 30 mal den Satz von 12. Benennen wir sie als V1_1, V1_2 ... (erster Satz), V2_1, V2_2 ... (zweiter Satz) und so weiter. Jeder Satz von 12 Variablen enthält dichotome (ja / nein) Antworten, die in der Praxis einem Karrierestatus entsprechen. Zum Beispiel: Arbeit (Ja / Nein), Studium (Ja / Nein) usw., insgesamt 12 Status, 30 Mal wiederholt.

Task : Die Aufgabe besteht darin, jeden Satz von 12 dichotomen Variablen in eine einzige Variable mit 12 Antwortkategorien (z. B. Arbeit, Studium ...) umzuschreiben. Letztendlich sollten wir 30 Variablen mit jeweils 12 Antwortkategorien erhalten.

Daten : Ich kann den eigentlichen Datensatz nicht posten, aber hier ist eine gute simulierte Approximation:

%Vor%

Meine Lösung :

%Vor%

Alles in allem gibt es eine doppelte * Anwendungsfunktion, eine über die Liste, die andere über die Datenrahmenzeilen. Das macht es ein bisschen langsam. Irgendwelche Vorschläge? Danke im Voraus.

    
Maxim.K 10.04.2013, 18:59
quelle

4 Antworten

4

Ich mag @ Aruns Matrixmultiplikationsidee sehr. Interessanterweise könnten Sie, wenn Sie R gegen einige OpenBLAS-Bibliotheken kompilieren, parallel dazu arbeiten.

Allerdings wollte ich Ihnen eine andere, vielleicht langsamer als Matrix-Multiplikation, Lösung anbieten, die Ihr ursprüngliches Muster verwendet, aber viel schneller ist als Ihre Implementierung:

%Vor%

Wenn Sie einen sehr großen Datenrahmen und viele Prozessoren haben, können Sie diese Operation mit:

in Betracht ziehen %Vor%

Nachdem ich @Arun und @mnel gelesen habe, habe ich eine Menge darüber gelernt, wie man diese Funktion verbessern kann, indem man die Nötigung zu einem Array vermeidet, indem man die data.frame by Spalte statt der Zeile verarbeitet. Ich will hier keine Antwort "stehlen"; OP sollte in Erwägung ziehen, das Kontrollkästchen auf @ mnels Antwort zu setzen.

Ich wollte jedoch eine Lösung teilen, die data.table nicht verwendet, und vermeidet for . Es ist jedoch immer noch langsamer als @ Mnels Lösung, wenn auch nur geringfügig.

%Vor%

Ich möchte auch hinzufügen, dass @ Aarons Ansatz, which mit arr.ind=TRUE zu verwenden, auch sehr schnell und elegant wäre, wenn mydata als matrix und nicht als data.frame beginnen würde. Die Koerziation auf matrix ist langsamer als der Rest der Funktion. Wenn die Geschwindigkeit ein Problem wäre, wäre es eine Überlegung wert, die Daten als Matrix zu lesen.

    
nograpes 10.04.2013, 20:11
quelle
5

Hier ist ein Ansatz, der im Prinzip sofort ist. (system.time = 0.1 Sekunden)

se set . Die columnMatch-Komponente hängt von Ihren Daten ab. Wenn sie jedoch alle 12 Spalten umfasst, funktioniert Folgendes.

%Vor%

Dies würde genauso gut funktionieren, indem Spalten mit Bezug auf das Original hinzugefügt werden.

Hinweis set funktioniert auch auf data.frames ....

    
mnel 11.04.2013 00:15
quelle
4

IIUC, Sie haben nur ein 1 pro 12 Spalten. Du hast den Rest mit Nullen oder Nullen. Wenn dies der Fall ist, kann die Operation durch diese Idee viel schneller durchgeführt werden.

Die Idee: Anstatt jede Zeile durchzugehen und nach der Position von 1 zu fragen, könnten Sie eine Matrix mit den Dimensionen 1500 * 12 verwenden, wobei jede Zeile nur 1:12 ist. Das ist:

%Vor%

Nun können Sie diese Matrix mit jeder Ihrer Untermenge data.frame (von gleichen Dimensionen, 1500 * 12 hier) multiplizieren und sie nehmen ihre "rowSums" (die vektorisiert ist) mit na.rm = TRUE . Dies gibt dir direkt die Zeile, in der du 1 hast (weil diese 1 mit dem entsprechenden Wert zwischen 1 und 12 multipliziert wurde).

data.table-Implementierung: Hier werde ich data.table verwenden, um die Idee zu veranschaulichen. Da es Spalte für Referenzen erstellt, würde ich erwarten, dass dieselbe Idee, die für data.frame verwendet wird, ein bisschen langsamer ist, obwohl es Ihren aktuellen Code drastisch beschleunigen sollte.

%Vor%

Nun haben Sie 30 Spalten, die der Position von 1 entsprechen. Auf meinem System dauert dies etwa 0,4 Sekunden.

%Vor%     
Arun 10.04.2013 19:34
quelle
4

Eine andere Möglichkeit, dies mit Base R zu tun, besteht darin, einfach die Werte zu erhalten, die Sie in die neue Matrix einfügen wollen, und sie direkt mit der Matrixindexierung zu füllen.

%Vor%     
Aaron 11.04.2013 01:54
quelle

Tags und Links