¿De qué sirve?

Estoy tratando de entender which función es ubicua. Hasta que comencé a leer preguntas / respuestas sobre SO, nunca encontré la necesidad de hacerlo. Y todavía no lo hago

Tal como lo entiendo, which toma un vector booleano y devuelve un vector débilmente más corto que contiene los índices de los elementos que eran verdaderos:

 > seq(10) [1] 1 2 3 4 5 6 7 8 9 10 > x  tf  tf [1] FALSE FALSE FALSE FALSE FALSE TRUE FALSE TRUE FALSE FALSE > w  w [1] 6 8 

Entonces, ¿por qué iba a usarlo en vez de simplemente usar el vector Boolean directamente? Quizás podría ver algunos problemas de memoria con vectores enormes, ya que length(w) << length(tf) , pero eso no es convincente. Y hay algunas opciones en el archivo de ayuda que no añaden mucho a mi comprensión de los posibles usos de esta función. Los ejemplos en el archivo de ayuda tampoco son de mucha ayuda.

Editar para mayor claridad : entiendo que el which devuelve los índices. Mi pregunta es sobre dos cosas: 1) ¿por qué necesitarías usar los índices en lugar de simplemente usar el vector selector booleano? y 2) ¿qué comportamientos interesantes podrían hacer que prefiriera simplemente usar una comparación booleana vectorizada?

De acuerdo, aquí hay algo en lo que resultó útil anoche:

En un vector de valores dado, ¿cuál es el índice del tercer valor distinto de NA?

 > x <- c(1,NA,2,NA,3) > which(!is.na(x))[3] [1] 5 

Un poco diferente del uso de DWin, ¡aunque diría que también es convincente!

El título de la página del hombre ?which proporciona una motivación. El título es:

¿Qué índices son TRUE ?

Lo cual interpreto como la función que uno podría usar si quiere saber qué elementos de un vector lógico son TRUE . Esto es inherentemente diferente a solo usar el vector lógico en sí mismo. Eso seleccionaría los elementos que son TRUE , no le diría cuál de ellos era TRUE .

Los casos de uso común consistían en obtener la posición de los valores máximos o mínimos en un vector:

 > set.seed(2) > x <- runif(10) > which(x == max(x)) [1] 5 > which(x == min(x)) [1] 7 

Esos fueron usados ​​tan comúnmente que which.max() y which.min() fueron creados:

 > which.max(x) [1] 5 > which.min(x) [1] 7 

Sin embargo, tenga en cuenta que los formularios específicos no son reemplazos exactos para la forma genérica. Ver ?which.min para más detalles. Un ejemplo es a continuación:

 > x <- c(4,1,1) > which.min(x) [1] 2 > which(x==min(x)) [1] 2 3 

Dos razones muy convincentes para no olvidar which :

1) Cuando use “[” para extraer de un dataframe, cualquier cálculo en la posición de la fila que resulte en NA obtendrá una fila basura devuelta. Usando lo which elimina las NA. Puede usar subset o %in% , que no crean el mismo problema.

 > dfrm <- data.frame( a=sample(c(1:3, NA), 20, replace=TRUE), b=1:20) > dfrm[dfrm$a >0, ] ab 1 1 1 2 3 2 NA NA NA NA.1 NA NA NA.2 NA NA 6 1 6 NA.3 NA NA 8 3 8 # Snipped remaining rows 

2) Cuando necesita los indicadores de la matriz.

which podría ser útil (mediante el ahorro de recursos informáticos y humanos), por ejemplo, si tiene que filtrar los elementos de un dataframe / matriz por una variable / columna determinada y actualizar otras variables / columnas en función de eso. Ejemplo:

 df <- mtcars 

En lugar de:

 df$gear[df$hp > 150] <- mean(df$gear[df$hp > 150]) 

Podrías hacerlo:

 p <- which(df$hp > 150) df$gear[p] <- mean(df$gear[p]) 

Caso extra sería si tiene que filtrar elementos filtrados, lo que no podría hacerse con un simple o | , por ejemplo, cuando tiene que actualizar algunas partes de un dataframe basado en otras tablas de datos. De esta forma, se requiere almacenar (al menos temporalmente) los índices del elemento filtrado.

Otro problema es lo que me viene a la mente si tienes que crear un bucle pensado como parte de un dataframe / matriz o tienes que hacer otro tipo de transformaciones que requieren conocer los índices de varios casos. Ejemplo:

 urban <- which(USArrests$UrbanPop > 80) > USArrests[urban, ] - USArrests[urban-1, ] Murder Assault UrbanPop Rape California 0.2 86 41 21.1 Hawaii -12.1 -165 23 -5.6 Illinois 7.8 129 29 9.8 Massachusetts -6.9 -151 18 -11.5 Nevada 7.9 150 19 29.5 New Jersey 5.3 102 33 9.3 New York -0.3 -31 16 -6.0 Rhode Island -2.9 68 15 -6.6 

Perdón por los ejemplos falsos, sé que no tiene mucho sentido comparar los estados más urbanizados de EE. UU. Por los estados antes de los que están en el alfabeto, pero espero que esto tenga sentido 🙂

Revisar which.min y which.max da alguna pista también, ya que no tiene que escribir mucho, por ejemplo:

 > row.names(mtcars)[which.max(mtcars$hp)] [1] "Maserati Bora" 

Bueno, encontré una posible razón. Al principio pensé que podría ser la opción ,useNames , pero resulta que la selección booleana simple también lo hace.

Sin embargo, si su objeto de interés es una matriz, puede usar la opción ,arr.ind para devolver el resultado como pares ordenados (fila, columna):

 > x <- matrix(seq(10),ncol=2) > x [,1] [,2] [1,] 1 6 [2,] 2 7 [3,] 3 8 [4,] 4 9 [5,] 5 10 > which((x == 6 | x == 8),arr.ind=TRUE) row col [1,] 1 2 [2,] 3 2 > which((x == 6 | x == 8)) [1] 6 8 

Es un truco útil para saber, pero apenas parece justificar su uso constante.

Sorprendido, nadie ha respondido esto: ¿qué hay de la eficiencia de la memoria?

Si tiene un vector largo de TRUE muy escaso, entonces hacer un seguimiento de solo los índices de los valores TRUE será probablemente mucho más compacto.

Lo uso silencioso a menudo en la exploración de datos. Por ejemplo, si tengo un conjunto de datos de niños y veo, a partir del resumen, que la edad máxima es 23 (y debería ser 18), podría ir:

 sum(dat$age>18) 

Si eso fuera 67, y quisiera mirar más de cerca, podría usar:

 dat[which(dat$age>18)[1:10], ] 

También es útil si está haciendo una presentación y desea extraer un fragmento de datos para demostrar cierta rareza o no.