2012-06-05 9 views
5

Tengo un vector que me dice, para cada fila en un marco de fecha, el índice de columna para el cual se debe actualizar el valor en esta fila.Elija una celda por fila en el marco de datos

> 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 

Esto significa que para las filas 1 y 4, se debe actualizar c3; para las filas 2, 3 y 5, se debe actualizar c2 (entre otros). ¿Cuál es la forma más limpia de lograr esto en R usando operaciones vectorizadas, es decir, sin apply y amigos? EDITAR: Y, si es posible, ¿sin bucles R?

He pensado en transformar d en una matriz y luego abordar los elementos de la matriz utilizando un vector unidimensional. Pero luego no encontré una forma clara de calcular la dirección unidimensional a partir de los índices de fila y columna.

Respuesta

3

Si usted está dispuesto a convertir su primera hoja.de.datos a una matriz, se puede indexar los elementos-a- ser reemplazado usando una matriz de dos columnas. (A partir del , esto será posible con data.frames directamente). La matriz de indexación debe tener índices de filas en sus primeros índices de columnas y columnas en su segunda columna.

He aquí un ejemplo:

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

Comenzando con , usted será capaz de utilizar la misma sintaxis para tramas de datos (es decir, sin tener que convertir primero en tramas de datos de matrices).

Desde el archivo R-develNEWS:

Matriz de indexación de tramas de datos de índices numéricos dos columnas ahora es compatible para su sustitución, así como la extracción.

Usando la corriente R-devel instantánea, esto es lo que parece:

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

¿Ha sido portado a la rama 2.15.1? R-devel generalmente significa la próxima versión menor, es decir, 2.16.x. –

+0

@GavinSimpson - Buena captura. Gracias. Mirando nuevamente, ahora veo la nota destacada que la "instantánea de desarrollo R59537 de R [...] eventualmente se convertirá en R-2.16.0". Editaré mi publicación en consecuencia. –

+0

¿Habrá compatibilidad análoga para matrices/matrices también? – krlmlr

3

Aquí hay una manera:

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

Gracias. Esto requiere un ciclo sobre las columnas, lo cual no es tan malo. Aún así, ¿hay una solución completamente vectorizada? – krlmlr

4

Con los datos del ejemplo, y utilizando sólo las primeras filas (D y I a continuación) que puede hacer fácilmente lo que desee a través de una matriz como supones.

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) 

En primer lugar, convertir D en una matriz:

dmat <- data.matrix(D) 

Siguiente calcular los índices de la representación vectorial de la matriz correspondiente a las filas y columnas indicadas por I. Para esto, es fácil generar los índices de fila así como el índice de columna (dado por I) usando seq_along(I) que en este ejemplo simple es el vector 1:6. Para calcular los índices vectoriales podemos utilizar:

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

donde la primera parte ((I - 1) * nrow(D)) nos da el múltiplo correcto del número de filas (6 aquí) para indexar el inicio de la columna de I XX. A continuación, agregamos el índice de la fila para obtener el índice del elemento n-ésimo en la columna I.

Usando esto simplemente indexamos en dmat usando "[", tratándolo como un vector. La versión de reemplazo de "[" ("[<-") nos permite hacer el reemplazo en una sola línea. Aquí puedo reemplazar los elementos indicados con NA para que sea más fácil de ver que se identificaron los elementos correctos:

> 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

Gracias. Pero, ¿esta construcción '(I - 1) * nrow (D) + seq_along (I)' encapsulada en alguna función que sea públicamente accesible? (Más general, estoy buscando algo como 'matrix.index (m, r, c)' donde 'r' es el vector de fila y' c' es el vector de columna. Sé cómo construirlo, pero esto debe ser estar en el núcleo R en algún lado, ¿no?) ¿Cómo funciona el direccionamiento matricial internamente? – krlmlr

+0

No, no lo es. 'I' es la columna (' c' en su notación), 'seq_along (I)' es la fila (o 'r'). Usé las cosas que hice debido a su ejemplo, aunque 'i' es un vector siempre que el número de filas de acuerdo con su ejemplo por lo que mi código aún funciona incluso para' i' grande. Para el último bit, estudie el código C o la documentación de R Internals; todo se hace en C, pero tenga en cuenta que, en lo que respecta a R, una matriz es solo un vector con elementos apilados en forma de columna, es decir, las columnas se rellenan primero, por lo que al tratar una matriz como vector, todas las filas , luego las filas de la columna 2, etc. –

+0

@ user946850 Dicho esto, no hay nada que te impida escribir 'matrixIndex()' usando el ejemplo que se muestra arriba. Puede colocarlo en su propio paquete privado y cargarlo (o disponer que se cargue automágicamente) al inicio de cada sesión R. –

Cuestiones relacionadas