2012-06-05 14 views
5

Ich habe einen Vektor, der mir für jede Zeile in einem Datumsrahmen den Spaltenindex angibt, für den der Wert in dieser Zeile aktualisiert werden soll.Wählen Sie eine Zelle pro Zeile im Datenrahmen

> set.seed(12008); n <- 10000; d <- data.frame(c1=1:n, c2=2*(1:n), c3=3*(1:n)) 
> i <- sample.int(3, n, replace=TRUE) 
> head(d); head(i) 
    c1 c2 c3 
1 1 2 3 
2 2 4 6 
3 3 6 9 
4 4 8 12 
5 5 10 15 
6 6 12 18 
[1] 3 2 2 3 2 1 

Dies bedeutet, dass für die Zeilen 1 und 4, C 3 aktualisiert werden soll; Für die Zeilen 2, 3 und 5 sollte c2 (unter anderem) aktualisiert werden. Was ist der sauberste Weg, dies in R mit vektorisierten Operationen zu erreichen, d. H. Ohne apply und Freunde? EDIT: Und, wenn überhaupt möglich, ohne R-Schleifen?

Ich habe darüber nachgedacht, d in eine Matrix umzuwandeln und dann die Matrixelemente adressieren einen eindimensionalen Vektor verwendet wird. Aber dann habe ich keine saubere Methode gefunden, die eindimensionale Adresse aus den Zeilen- und Spaltenindizes zu berechnen.

Antwort

3

Wenn Sie bereit sind, zuerst Ihre data.frame in eine Matrix zu konvertieren, können Sie Indexelemente-to- ersetzt werden mit einer zweispaltigen Matrix. (Ab ist dies direkt mit data.frames möglich.) Die Indexierungsmatrix sollte Zeilenindizes in der ersten Spalte und Spaltenindizes in der zweiten Spalte enthalten.

Hier ist ein Beispiel:

## Create a subset of the your data 
set.seed(12008); n <- 6 
D <- data.frame(c1=1:n, c2=2*(1:n), c3=3*(1:n)) 
i <- seq_len(nrow(D))   # vector of row indices 
j <- sample(3, n, replace=TRUE) # vector of column indices 
ij <- cbind(i, j)    # a 2-column matrix to index a 2-D array 
           # (This extends smoothly to higher-D arrays.) 

## Convert it to a matrix  
Dmat <- as.matrix(D) 

## Replace the elements indexed by 'ij' 
Dmat[ij] <- NA 
Dmat 
#  c1 c2 c3 
# [1,] 1 2 NA 
# [2,] 2 NA 6 
# [3,] 3 NA 9 
# [4,] 4 8 NA 
# [5,] 5 NA 15 
# [6,] NA 12 18 

mit Anfang, können Sie die gleiche Syntax für Datenrahmen verwenden (das heißt, ohne zuerst Datenrahmen zu Matrizen konvertieren).

Von der R-develNEWS Datei:

Matrix Indizierung von Datenrahmen durch zwei Spalte numerische Indizes wird nun für den Ersatz sowie Extraktion unterstützt.

den aktuellen R-devel Snapshot, hier ist, wie das aussieht:

D[ij] <- NA 
D 
# c1 c2 c3 
# 1 1 2 NA 
# 2 2 NA 6 
# 3 3 NA 9 
# 4 4 8 NA 
# 5 5 NA 15 
# 6 NA 12 18 
+0

Wurde das in den Zweig 2.15.1 portiert? R-devel würde normalerweise die nächste Nebenversion bedeuten, d.h. 2.16.x. –

+0

@GavinSimpson - Netter Fang. Vielen Dank. Wenn ich es noch einmal anschaue, sehe ich jetzt den Hinweis, dass der "r59537 Entwicklungs-Schnappschuss von R [...] irgendwann R-2.16.0 werden wird". Wird meinen Beitrag entsprechend bearbeiten. –

+0

Wird es auch analoge Unterstützung für Matrizen/Arrays geben? – krlmlr

3

Hier ist eine Art und Weise:

d[which(i == 1), "c1"] <- "one" 
d[which(i == 2), "c2"] <- "two" 
d[which(i == 3), "c3"] <- "three" 

    c1 c2 c3 
1 1 2 three 
2 2 two  6 
3 3 two  9 
4 4 8 three 
5 5 two 15 
6 one 12 18 
+0

Danke. Dies erfordert eine Schleife über die Spalten, die nicht zu schlecht ist. Gibt es eine vollständig vektorisierte Lösung? – krlmlr

4

Mit Ihrem Beispiel Daten, und nur die ersten paar Zeilen mit (D und I unten) Sie können ganz einfach tun, was Sie über eine Matrix wollen, wie Sie vermuten.

set.seed(12008) 
n <- 10000 
d <- data.frame(c1=1:n, c2=2*(1:n), c3=3*(1:n)) 
i <- sample.int(3, n, replace=TRUE) 
## just work with small subset 
D <- head(d) 
I <- head(i) 

Zuerst konvertiert D in eine Matrix:

dmat <- data.matrix(D) 

Next die Indizes der Vektordarstellung der Matrix durch I angegeben entsprechend Zeilen und Spalten berechnen. Dazu ist es einfach, die Zeilenindizes sowie den Spaltenindex (gegeben durch I) unter Verwendung von seq_along(I) zu erzeugen, was in diesem einfachen Beispiel der Vektor 1:6 ist. Zur Berechnung der Vektor Indizes können wir verwenden:

(I - 1) * nrow(D) + seq_along(I) 

, wo der erste Teil ((I - 1) * nrow(D)) gibt uns die richtige Vielfaches der Anzahl der Reihen (6 hier) zu indizieren den Beginn der I ten Spalte. Wir fügen dann den Zeilenindex hinzu, um den Index für das n-te Element in der Spalte I zu erhalten.

Mit diesem indexieren wir einfach in dmat mit "[", behandelt es wie ein Vektor. Die Ersatzversion von "[" ("[<-") ermöglicht es uns, den Austausch in einer einzigen Zeile durchzuführen. Hier ersetze ich die angegebenen Elemente mit NA, um es einfacher zu sehen, dass die richtigen Elemente identifiziert:

> dmat 
    c1 c2 c3 
1 1 2 3 
2 2 4 6 
3 3 6 9 
4 4 8 12 
5 5 10 15 
6 6 12 18 
> dmat[(I - 1) * nrow(D) + seq_along(I)] <- NA 
> dmat 
    c1 c2 c3 
1 1 2 NA 
2 2 NA 6 
3 3 NA 9 
4 4 8 NA 
5 5 NA 15 
6 NA 12 18 
+0

Vielen Dank. Aber ist dieses Konstrukt "(I - 1) * nrow (D) + seq_along (I)" in einer öffentlich zugänglichen Funktion eingekapselt? (Allgemeiner suche ich nach etwas wie "matrix.index (m, r, c)", wobei "r" der Zeilenvektor und "c" der Spaltenvektor ist. Ich weiß, wie man es erstellt, aber das muss irgendwo im R-Kern sein, nein?) Wie funktioniert Matrixadressierung intern? – krlmlr

+0

Nein, ist es nicht. "I" ist die Spalte ('c' in Ihrer Notation),' seq_along (I) 'ist die Zeile (oder' r'). Ich habe die Dinge, die ich gemacht habe, wegen Ihres Beispiels verwendet, obwohl 'i' ein Vektor ist, solange die Anzahl der Zeilen Ihrem Beispiel entspricht, so funktioniert mein Code auch für große' i'. Für das letzte Bit, studieren Sie den C-Code oder die R Internals Dokumentationen; Es ist alles in C gemacht, aber beachten Sie, dass, was R betrifft, eine Matrix nur ein Vektor mit Elementen ist, die spaltenweise gestapelt sind, dh Spalten werden zuerst gefüllt, also wenn eine Matrix als ein Vektor behandelt wird, kommen alle Zeilen von Spalte 1 zuerst , dann die Zeilen von Spalte 2 usw. –

+0

@ user946850 Nichtsdestotrotz gibt es nichts, was Sie daran hindert, ein 'matrixIndex()' zu schreiben, indem Sie das oben gezeigte Beispiel verwenden. Sie können dies in Ihr eigenes privates Paket einfügen und es laden (oder veranlassen, dass es automatisch geladen wird) zu Beginn jeder R-Sitzung. –

Verwandte Themen