Esta es una demostración anotada de subsetting en R utilizando el set de datos iris incluido en R.

data(iris)
#para aquellos no familiarizados con los datos, 
#corramos str() y summary()
str(iris)
## 'data.frame':    150 obs. of  5 variables:
##  $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
##  $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
##  $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
##  $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
##  $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
summary(iris)
##   Sepal.Length   Sepal.Width    Petal.Length   Petal.Width 
##  Min.   :4.30   Min.   :2.00   Min.   :1.00   Min.   :0.1  
##  1st Qu.:5.10   1st Qu.:2.80   1st Qu.:1.60   1st Qu.:0.3  
##  Median :5.80   Median :3.00   Median :4.35   Median :1.3  
##  Mean   :5.84   Mean   :3.06   Mean   :3.76   Mean   :1.2  
##  3rd Qu.:6.40   3rd Qu.:3.30   3rd Qu.:5.10   3rd Qu.:1.8  
##  Max.   :7.90   Max.   :4.40   Max.   :6.90   Max.   :2.5  
##        Species  
##  setosa    :50  
##  versicolor:50  
##  virginica :50  
##                 
##                 
## 

Hagamos un gráfico de todos los datos (de una forma ligeramente indirecta que será más adecuada para demostrar el subsetting)

plot(iris$Petal.Length, iris$Petal.Width, type="n",xlab="Largo Pétalo", ylab="Ancho Pétalo")
points(iris$Petal.Length, iris$Petal.Width, pch=19, col=iris$Species)

plot of chunk unnamed-chunk-3

Ahora podemos hacer un subset utilizando el operador []

plot(iris$Petal.Length, iris$Petal.Width, type="n", xlab="Largo Pétalo", ylab="Ancho Pétalo")
points(iris$Petal.Length[iris$Species=="setosa"], iris$Petal.Width[iris$Species=="setosa"], pch=19, col=iris$Species[iris$Species=="setosa"])

plot of chunk unnamed-chunk-4

Lo que nos dice básicamente la gráfica es la longitud del pétalo (Petal.Length) (de los casos donde la especie (Species) es setosa) versus el ancho del pétalo (Petal.Width) (de los casos donde la especie es setosa).

Hay un error muy común que muchos cometen en este punto. Si ingresan el siguiente código:

plot(iris$Petal.Length, iris$Petal.Width, type="n", xlab="Largo Pétalo", ylab="Ancho Pétalo")
points(iris$Petal.Length[iris$Species=="setosa"], iris$Petal.Width, pch=19, col=iris$Species[iris$Species=="setosa"])
Obtendrán el siguiente mensaje de error:

Error in xy.coords(x, y, xlabel, ylabel, log) :

‘x’ and ‘y’ lengths differ

Esto sucede porque estás intentando comparar algo que posee un subset (Petal.Length) contra algo que no lo tiene (Petal.Width) y R no tiene idea como hacer coincidir el número diferente de entradas.

Las cosas en el interior de [] son el criterio para seleccionar las entradas, para que podamos ver lo que está pasando en una forma un poco menos congestionada podemos establecer los criterios como una variable.

criterios <- iris$Species=="setosa"
plot(iris$Petal.Length, iris$Petal.Width, type="n", xlab="Largo Pétalo", ylab="Ancho Pétalo")
points(iris$Petal.Length[criterios], iris$Petal.Width[criterios], pch=19, col=iris$Species[criterios])

plot of chunk unnamed-chunk-6

El doble signo igual es utilizado para hacer una comparación directa, y dado que estamos trabajando con texto usamos “”. Otros operadores comunes son <,<=,>,>=,!=, y ! (que quiere decir “no es el caso”)

criterios <-  iris$Sepal.Width < 3.1
plot(iris$Petal.Length, iris$Petal.Width, type="n", xlab="Largo Pétalo", ylab="Ancho Pétalo")
points(iris$Petal.Length[criterios], iris$Petal.Width[criterios], pch=19, col=iris$Species[criterios])

plot of chunk unnamed-chunk-7

Si queremos un resultado mas estrecho podemos utilizar el símbolo AND (&) para combinar diferentes criterios.

criterios <- iris$Species=="setosa" & iris$Sepal.Width < 3.1
plot(iris$Petal.Length, iris$Petal.Width, type="n", xlab="Largo Pétalo", ylab="Ancho Pétalo")
points(iris$Petal.Length[criterios], iris$Petal.Width[criterios], pch=19, col=iris$Species[criterios])

plot of chunk unnamed-chunk-8

En este caso combinamos en “criterios” la especie setosa y un ancho de sépalo menor a 3.1.

Si queremos resultados más amplios, se puede utilizar el símbolo OR | para proveer una lista de criterios, pero en este caso es también buena idea usar paréntesis () para dejar claro cuáles son los grupos (como cuando aprendes matemáticas, las cosas dentro del paréntesis se ordenan primero.

criterios <- iris$Species=="setosa" & (iris$Sepal.Width < 3.1 | iris$Sepal.Width > 3.5)
plot(iris$Petal.Length, iris$Petal.Width, type="n",xlab="Largo Pétalo", ylab="Ancho Pétalo")
points(iris$Petal.Length[criterios], iris$Petal.Width[criterios], pch=19, col=iris$Species[criterios])

plot of chunk unnamed-chunk-9

Utilizando la misma lectura que en matemáticas, el primer criterio que procesamos es donde indicamos que queremos incluir las observaciones que tengan un ancho de sépalo menor a 3.1 ó mayor a 3.5, obtenido eso, agregamos aquellas donde la especie es setosa. Fijense que la cantidad de datos que cumple con esos criterios es mayor que en nuestro gráfico anterior.

Si no utilizamos paréntesis obtendríamos un resultado bastante diferente:

criterios <- iris$Species=="setosa" & iris$Sepal.Width < 3.1 | iris$Sepal.Width > 3.5
plot(iris$Petal.Length, iris$Petal.Width, type="n", xlab="Largo Pétalo", ylab="Ancho Pétalo")
points(iris$Petal.Length[criterios], iris$Petal.Width[criterios], pch=19, col=iris$Species[criterios])

plot of chunk unnamed-chunk-10

En este caso la lectura es distinta, lo que hace R es seguir el orden y primero nos entrega aquellos datos de especie setosa Y ancho de sépalo mayor a 3.1, además aquellas observaciones con ancho de sépalo mayor a 3.5 que no están asociados solo a setosa.

El operador %in% puede ser útil para proveer una lista para mirar

criterios <- iris$Species %in% c("setosa","versicolor","dingo")
plot(iris$Petal.Length, iris$Petal.Width, type="n", xlab="Largo Pétalo", ylab="Ancho Pétalo")
points(iris$Petal.Length[criterios], iris$Petal.Width[criterios], pch=19, col=iris$Species[criterios])

plot of chunk unnamed-chunk-11

R buscará los match de la lista entregada, en este caso si existe dentro de especie la palabra “setosa”, “versicolor” y “dingo”, arrojará las observaciones correspondientes. Dado que “dingo” no es una de las especies incluídas en nuestro frame de datos, solo veremos todas las observaciones correspondientes a “setosa” y “versicolor”.

También puedes realizar un subset numérico, eligiendo un rango de números de fila

criterios <- 5:10
plot(iris$Petal.Length, iris$Petal.Width, type="n", xlab="Largo Pétalo", ylab="Ancho Pétalo")
points(iris$Petal.Length[criterios], iris$Petal.Width[criterios], pch=19, col=iris$Species[criterios])

plot of chunk unnamed-chunk-12

O puedes incluir una lista de números de fila con distintos rangos.

criterios <- c(2, 5:10, 12, 18:32)
plot(iris$Petal.Length, iris$Petal.Width, type="n", xlab="Largo Pétalo", ylab="Ancho Pétalo")
points(iris$Petal.Length[criterios], iris$Petal.Width[criterios], pch=19, col=iris$Species[criterios])

plot of chunk unnamed-chunk-13

Hasta ahora hemos hecho subsetting a una variable en particular, pero también podemos hacer subset a un frame de datos completo utilizando la forma dataframe[criteriofila, criteriocolumna]

criteriofila <- iris$Species=="setosa"
criteriocolumna <- 1:2
summary(iris[criteriofila,criteriocolumna])
##   Sepal.Length   Sepal.Width  
##  Min.   :4.30   Min.   :2.30  
##  1st Qu.:4.80   1st Qu.:3.20  
##  Median :5.00   Median :3.40  
##  Mean   :5.01   Mean   :3.43  
##  3rd Qu.:5.20   3rd Qu.:3.67  
##  Max.   :5.80   Max.   :4.40

La coma es el marcador de el criterio de fila y el criterio de columna. En el caso que queramos todas las filas o todas las columnas dejaremos vacio el espacio después o antes de la coma correspondientemente.

criteriofila <- iris$Species=="setosa"
criteriocolumna <- 1:2
summary(iris[,criteriocolumna])
##   Sepal.Length   Sepal.Width  
##  Min.   :4.30   Min.   :2.00  
##  1st Qu.:5.10   1st Qu.:2.80  
##  Median :5.80   Median :3.00  
##  Mean   :5.84   Mean   :3.06  
##  3rd Qu.:6.40   3rd Qu.:3.30  
##  Max.   :7.90   Max.   :4.40

o

criteriofila <- iris$Species=="setosa"
criteriocolumna <- 1:2
summary(iris[criteriofila,])
##   Sepal.Length   Sepal.Width    Petal.Length   Petal.Width   
##  Min.   :4.30   Min.   :2.30   Min.   :1.00   Min.   :0.100  
##  1st Qu.:4.80   1st Qu.:3.20   1st Qu.:1.40   1st Qu.:0.200  
##  Median :5.00   Median :3.40   Median :1.50   Median :0.200  
##  Mean   :5.01   Mean   :3.43   Mean   :1.46   Mean   :0.246  
##  3rd Qu.:5.20   3rd Qu.:3.67   3rd Qu.:1.57   3rd Qu.:0.300  
##  Max.   :5.80   Max.   :4.40   Max.   :1.90   Max.   :0.600  
##        Species  
##  setosa    :50  
##  versicolor: 0  
##  virginica : 0  
##                 
##                 
## 

Hay otro error común que podemos encontrar en este punto. Si estas seleccionando filas, es fácil que se olvide incluir la coma al final.

criteriofila <- iris$Species=="setosa"
criteriocolumna <- 1:2
summary(iris[criteriofila])

Obtendrán el siguiente error: Error in ‘[.data.frame’(iris, rowcriteria) : undefined columns selected

Debido a que estamos lidiando con un bloque de datos, sin la coma R no sabe como aplicar las reglas incluídas.

También se puede utilizar una lista numerada de las columnas que se desean

criteriofila <- iris$Species=="setosa"
criteriocolumna <- c(1:2,4)
summary(iris[criteriofila,criteriocolumna])
##   Sepal.Length   Sepal.Width    Petal.Width   
##  Min.   :4.30   Min.   :2.30   Min.   :0.100  
##  1st Qu.:4.80   1st Qu.:3.20   1st Qu.:0.200  
##  Median :5.00   Median :3.40   Median :0.200  
##  Mean   :5.01   Mean   :3.43   Mean   :0.246  
##  3rd Qu.:5.20   3rd Qu.:3.67   3rd Qu.:0.300  
##  Max.   :5.80   Max.   :4.40   Max.   :0.600

Y una lista de nombres

criteriofila <- iris$Species=="setosa"
criteriocolumna <- c("Petal.Length","Petal.Width")
summary(iris[criteriofila,criteriocolumna])
##   Petal.Length   Petal.Width   
##  Min.   :1.00   Min.   :0.100  
##  1st Qu.:1.40   1st Qu.:0.200  
##  Median :1.50   Median :0.200  
##  Mean   :1.46   Mean   :0.246  
##  3rd Qu.:1.57   3rd Qu.:0.300  
##  Max.   :1.90   Max.   :0.600

Si por ejemplo tienen datos para usar de una forma en particular, por ejemplo en un test estadístico, probablemente quieran almacenarlos en un objeto

criteriofila <- iris$Species=="setosa"
criteriocolumna <- c("Petal.Length","Petal.Width")
misubset <- iris[criteriofila,criteriocolumna]
summary(misubset)
##   Petal.Length   Petal.Width   
##  Min.   :1.00   Min.   :0.100  
##  1st Qu.:1.40   1st Qu.:0.200  
##  Median :1.50   Median :0.200  
##  Mean   :1.46   Mean   :0.246  
##  3rd Qu.:1.57   3rd Qu.:0.300  
##  Max.   :1.90   Max.   :0.600

También puedes hacer un subset removiendo columnas (en vez de especificar las columnas que quieres)

criteriofila <- iris$Species=="setosa"
criteriocolumna <- names(iris) %in% c("Petal.Length","Petal.Width")
misubset <- iris[criteriofila,!(criteriocolumna)]
summary(misubset)
##   Sepal.Length   Sepal.Width         Species  
##  Min.   :4.30   Min.   :2.30   setosa    :50  
##  1st Qu.:4.80   1st Qu.:3.20   versicolor: 0  
##  Median :5.00   Median :3.40   virginica : 0  
##  Mean   :5.01   Mean   :3.43                  
##  3rd Qu.:5.20   3rd Qu.:3.67                  
##  Max.   :5.80   Max.   :4.40

Esto dice básicamente “Encuentra las columnas con ese nombre, las ves, pues esas son las que no quiero”

También pueden realizar subsetting removiendo datos al utilizar números negativos

criteriofila <- iris$Species=="setosa"
criteriocolumna <- c(-1,-3:-5)
misubset <- iris[criteriofila,criteriocolumna]
summary(misubset)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    2.30    3.20    3.40    3.43    3.68    4.40

Pueden remover filas de una forma similar, utilizando números negativos

criteriofila <- c(-1:-25)
criteriocolumna <- c(-1,-3:-5)
mysubset <- iris[criteriofila,criteriocolumna]
summary(mysubset)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    2.00    2.70    3.00    2.97    3.20    4.20

Subsetting no es lo mismo que borrar una variable. Subsetting es esconder aquellas que no queremos, pero siguen estando disponibles para posteridad, borrar es destruirlas. Aunque a veces se puede utilizar de la misma manera haciendo primero una copia de los datos

misubset <- iris
misubset$Species <- NULL
summary(misubset)
##   Sepal.Length   Sepal.Width    Petal.Length   Petal.Width 
##  Min.   :4.30   Min.   :2.00   Min.   :1.00   Min.   :0.1  
##  1st Qu.:5.10   1st Qu.:2.80   1st Qu.:1.60   1st Qu.:0.3  
##  Median :5.80   Median :3.00   Median :4.35   Median :1.3  
##  Mean   :5.84   Mean   :3.06   Mean   :3.76   Mean   :1.2  
##  3rd Qu.:6.40   3rd Qu.:3.30   3rd Qu.:5.10   3rd Qu.:1.8  
##  Max.   :7.90   Max.   :4.40   Max.   :6.90   Max.   :2.5