6 Contenedores de datos
Hasta ahora hemos creado objetos simples que contienen solo un valor. Sin embargo, pudimos ver que un objeto tenía atributos diferentes, como su valor, pero también el tipo de datos contenidos (e.g., numeric
, character
). Ahora vamos a ver que hay diferentes tipos de contenedores para almacenar datos múltiples.
6.1 El contenedor vector
En R, un vector
es una combinación de datos con la particularidad de que todos los datos contenidos en un vector
son del mismo tipo. Podemos almacenar por ejemplo múltiples elementos del tipo character
o numeric
en un vector
, pero no ambos. El contenedor vector
es importante porque es el elemento básico de R.
6.1.1 Crear un vector
Para crear un vector
utilizaremos la función c()
que permite combinar elementos en un vector
. Los elementos para combinar deben estar separados por comas.
<- c(1, 2, 3, 4) # un vector de 4 elementos de tipo numeric ; double
miVec01 print(miVec01)
## [1] 1 2 3 4
typeof(miVec01)
## [1] "double"
is.vector(miVec01)
## [1] TRUE
La funcion is.vector()
permite verificar el tipo de contenedor.
<- c("a", "b", "c")
miVec02 print(miVec02)
## [1] "a" "b" "c"
typeof(miVec02)
## [1] "character"
is.vector(miVec02)
## [1] TRUE
<- c(TRUE, FALSE, FALSE, TRUE)
miVec03 print(miVec03)
## [1] TRUE FALSE FALSE TRUE
typeof(miVec03)
## [1] "logical"
is.vector(miVec03)
## [1] TRUE
<- c(1, NA, 3, NA, 5)
miVecNA print(miVecNA)
## [1] 1 NA 3 NA 5
typeof(miVecNA)
## [1] "double"
is.vector(miVecNA)
## [1] TRUE
<- c(1, "a")
miVec04 print(miVec04)
## [1] "1" "a"
typeof(miVec04)
## [1] "character"
is.vector(miVec04)
## [1] TRUE
Si combinamos diferentes tipos de datos, R intentará transformar los elementos en un tipo de forma predeterminada. Si como aquí en el objeto miVec03
tenemos los tipos character
y numeric
, R convertirá todos los elementos en character
.
<- c(factor("abc"), "def")
miVec05 print(miVec05)
## [1] "1" "def"
typeof(miVec05)
## [1] "character"
<- c(TRUE, "def")
miVec06 print(miVec06)
## [1] "TRUE" "def"
typeof(miVec06)
## [1] "character"
<- c(factor("abc"), 55)
miVec07 print(miVec07)
## [1] 1 55
typeof(miVec07)
## [1] "double"
<- c(TRUE, 55)
miVec08 print(miVec08)
## [1] 1 55
typeof(miVec08)
## [1] "double"
También podemos combinar objetos existentes dentro de un vector
.
<- c(miVec02, "d", "e", "f")
miVec09 print(miVec09)
## [1] "a" "b" "c" "d" "e" "f"
<- c("aaa", "aa", miVec09, "d", "e", "f")
miVec10 print(miVec10)
## [1] "aaa" "aa" "a" "b" "c" "d" "e" "f" "d" "e" "f"
<- c(789, miVec01 , 564)
miVec11 print(miVec11)
## [1] 789 1 2 3 4 564
6.1.2 Hacer operaciones con un vector
También podemos realizar operaciones en un vector
.
print(miVec01)
## [1] 1 2 3 4
+ 1 miVec01
## [1] 2 3 4 5
- 1 miVec01
## [1] 0 1 2 3
* 2 miVec01
## [1] 2 4 6 8
/10 miVec01
## [1] 0.1 0.2 0.3 0.4
Las operaciones de un vector
a otro también son posibles, pero se debe tener cuidado para asegurar que el número de elementos en un vector
sea el mismo que el otro, de lo contrario R realizará el cálculo comenzando desde el inicio del vector
mas pequeño. Aquí hay un ejemplo para ilustrar lo que R hace:
<- c(1, 1, 1, 1, 1, 1, 1, 1, 1)
miVec12 print(miVec12)
## [1] 1 1 1 1 1 1 1 1 1
<- c(10, 20, 30)
miVec13 print(miVec13)
## [1] 10 20 30
+ miVec13 # vectores de diferentes tamaños: atención al resultado miVec12
## [1] 11 21 31 11 21 31 11 21 31
<- c(10, 20, 30, 40, 50, 60, 70, 80, 90)
miVec14 print(miVec14)
## [1] 10 20 30 40 50 60 70 80 90
+ miVec14 # los vectores tienen el mismo tamaño miVec12
## [1] 11 21 31 41 51 61 71 81 91
<- c(1, 1, 1, 1)
miVec15 print(miVec15)
## [1] 1 1 1 1
+ miVec13 # vectores de diferentes tamaños y no múltiples miVec15
## Warning in miVec15 + miVec13: la taille d'un objet plus long n'est pas multiple
## de la taille d'un objet plus court
## [1] 11 21 31 11
6.1.3 Acceder a los valores de un vector
Suele pasar que sea necesario poder acceder a los valores de un vector
, es decir, recuperar un valor o un grupo de valores dentro de un vector
. Para acceder a un elemento de un vector
usamos los corchetes []
. Entre los corchetes, podemos usar un número correspondiente al número del elemento en el vector
.
<- c(10, 20, 30, 40, 50, 60, 70, 80, 90)
miVec20 <- c("a", "b", "c", "d", "e", "f", "g", "h", "i")
miVec21 print(miVec20)
## [1] 10 20 30 40 50 60 70 80 90
print(miVec21)
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i"
print(miVec20[1])
## [1] 10
print(miVec21[3])
## [1] "c"
También podemos usar la combinación de diferentes elementos (otro vector
).
print(miVec20[c(1, 5, 9)])
## [1] 10 50 90
print(miVec21[c(4, 3, 1)])
## [1] "d" "c" "a"
print(miVec21[c(4, 4, 3, 4, 3, 2, 5)])
## [1] "d" "d" "c" "d" "c" "b" "e"
También podemos seleccionar elementos usando un operador de comparación o un operador lógico.
print(miVec20[miVec20 >= 50])
## [1] 50 60 70 80 90
print(miVec20[(miVec20 >= 50) & ((miVec20 < 80))])
## [1] 50 60 70
print(miVec20[miVec20 != 50])
## [1] 10 20 30 40 60 70 80 90
print(miVec20[miVec20 == 30])
## [1] 30
print(miVec20[(miVec20 == 30) | (miVec20 == 50)])
## [1] 30 50
print(miVec21[miVec21 == "a"])
## [1] "a"
Otra característica interesante es la posibilidad de condicionar los elementos a seleccionar en base a otro vector
.
print(miVec21[miVec20 >= 50])
## [1] "e" "f" "g" "h" "i"
print(miVec21[(miVec20 >= 50) & ((miVec20 < 80))])
## [1] "e" "f" "g"
print(miVec21[miVec20 != 50])
## [1] "a" "b" "c" "d" "f" "g" "h" "i"
print(miVec21[miVec20 == 30])
## [1] "c"
print(miVec21[(miVec20 == 30) | (miVec20 == 50)])
## [1] "c" "e"
print(miVec21[(miVec20 == 30) | (miVec21 == "h")])
## [1] "c" "h"
También es posible excluir ciertos elementos en lugar de seleccionarlos.
print(miVec20[-1])
## [1] 20 30 40 50 60 70 80 90
print(miVec21[-5])
## [1] "a" "b" "c" "d" "f" "g" "h" "i"
print(miVec20[-c(1, 2, 5)])
## [1] 30 40 60 70 80 90
print(miVec21[-c(1, 2, 5)])
## [1] "c" "d" "f" "g" "h" "i"
Los elementos de un vector
también se pueden seleccionar sobre la base de un vector
tipo logical
. En este caso, solo se seleccionarán elementos con un valor TRUE
.
<- c(TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE)
miVec22 print(miVec21[miVec22])
## [1] "a" "b" "d" "f" "h" "i"
6.1.4 Dar nombres a los elementos de un vector
Los elementos de un vector
se pueden nombrar para referenciarlos y luego selectionarlos. La función names()
recupera los nombres de los elementos de un vector.
<- c(aaa = 10, bbb = 20, ccc = 30, ddd = 40, eee = 50)
miVec23 print(miVec23)
## aaa bbb ccc ddd eee
## 10 20 30 40 50
print(miVec23["bbb"])
## bbb
## 20
print(miVec23[c("bbb", "ccc", "bbb")])
## bbb ccc bbb
## 20 30 20
names(miVec23)
## [1] "aaa" "bbb" "ccc" "ddd" "eee"
6.1.5 Editar los elementos de un vector
Para modificar un vector
, operamos de la misma manera que para modificar un objeto simple, con el signo <-
y el elemento o los elementos a modificar entre corchetes.
print(miVec21)
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i"
3] <- "zzz"
miVec21[print(miVec21)
## [1] "a" "b" "zzz" "d" "e" "f" "g" "h" "i"
>= 50) & ((miVec20 < 80))] <- "qwerty"
miVec21[(miVec20 print(miVec21)
## [1] "a" "b" "zzz" "d" "qwerty" "qwerty" "qwerty" "h"
## [9] "i"
print(miVec23)
## aaa bbb ccc ddd eee
## 10 20 30 40 50
"ccc"] <- miVec23["ccc"] + 100
miVec23[print(miVec23)
## aaa bbb ccc ddd eee
## 10 20 130 40 50
También podemos cambiar los nombres asociados con los elementos de un vector
.
print(miVec23)
## aaa bbb ccc ddd eee
## 10 20 130 40 50
names(miVec23)[2] <- "bb_bb"
print(miVec23)
## aaa bb_bb ccc ddd eee
## 10 20 130 40 50
Podemos hacer mucho más con un vector
y volveremos a su manejo y operaciones posibles en el capítulo sobre funciones.
6.2 El contenedor list
El segundo tipo de contenedor que vamos a presentar es el contenedor list
, que es también el segundo contenedor después del tipovector
debido a su importancia en la programación con R. El contenedor de tipo list
le permite almacenar listas de elementos. Contrariamente a lo que vimos antes con el tipo vector
, los elementos del tipo list
pueden ser diferentes (por ejemplo, un vector
de tipo numeric
, luego un vector
de tipo character
). Los elementos del tipo list
también pueden ser contenedores diferentes (por ejemplo, un vector
, luego una list
). El tipo de contenedor list
tendrá mas sentido cuando hayamos estudiado los bucles y funciones de la familia apply
.
6.2.1 Crear una list
Para crear una list
usaremos la función list()
, que toma elementos (objetos) como argumentos.
<- list()
miList01 print(miList01)
## list()
<- list(5, "qwerty", c(4, 5, 6), c("a", "b", "c"))
miList02 print(miList02)
## [[1]]
## [1] 5
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "a" "b" "c"
<- list(5, "qwerty", list(c(4, 5, 6), c("a", "b", "c")))
miList03 print(miList03)
## [[1]]
## [1] 5
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [[3]][[1]]
## [1] 4 5 6
##
## [[3]][[2]]
## [1] "a" "b" "c"
La función is.list()
se usa para probar si hemos creado un objeto de tipo list
.
is.list(miList02)
## [1] TRUE
typeof(miList02)
## [1] "list"
6.2.2 Acceder a los valores de una list
Los elementos del contenedor list
son identificables por los corchetes dobles [[ ]]
.
print(miList02)
## [[1]]
## [1] 5
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "a" "b" "c"
En el objeto de tipo list
miList02
, hay cuatro elementos identificables con [[1]]
, [[2]]
, [[3]]
y [[4]]
. Cada uno de los elementos es de tipo vector
. El primer elemento tiene un tamaño de 1 con elementos del tipo double
, el segundo elemento tiene un tamaño de 1 con elementos del tipo character
, el tercero elemento tiene un tamaño de 3 con elementos del tipo double
, y el cuarto elemento tiene un tamaño de 3 con elementos del tipo character
.
typeof(miList02)
## [1] "list"
print(miList02[[1]])
## [1] 5
typeof(miList02[[1]])
## [1] "double"
print(miList02[[2]])
## [1] "qwerty"
typeof(miList02[[2]])
## [1] "character"
print(miList02[[3]])
## [1] 4 5 6
typeof(miList02[[3]])
## [1] "double"
print(miList02[[4]])
## [1] "a" "b" "c"
typeof(miList02[[4]])
## [1] "character"
El acceso al segundo elemento del vector
ubicado en la cuarta posición de la list
se hace con miList02[[4]][2]
. Usamos doble corchetes para el cuarto elemento de la list
, luego corchetes simples para el segundo elemento del vector
.
print(miList02[[4]][2])
## [1] "b"
Como una list
puede contener una o más list
, podemos acceder a la información buscada combinando corchetes dobles. El objeto miList04
es una list
de dos elementos: la list
miList02
y la list
miList03
. El objeto miList03
en sí contiene una list
como tercer elemento. Para acceder al primer elemento del vector
en la primera posición del elemento en la tercera posición del segundo elemento del list
miList04
, podemos usar miList04[[2]][[3]][[1]][1]
. No hay límite en cuanto a la profundidad de list
pero en la práctica raramente hay necesidad de hacer list
de list
de list
.
<- list(miList02, miList03)
miList04 print(miList04)
## [[1]]
## [[1]][[1]]
## [1] 5
##
## [[1]][[2]]
## [1] "qwerty"
##
## [[1]][[3]]
## [1] 4 5 6
##
## [[1]][[4]]
## [1] "a" "b" "c"
##
##
## [[2]]
## [[2]][[1]]
## [1] 5
##
## [[2]][[2]]
## [1] "qwerty"
##
## [[2]][[3]]
## [[2]][[3]][[1]]
## [1] 4 5 6
##
## [[2]][[3]][[2]]
## [1] "a" "b" "c"
print(miList04[[2]][[3]][[1]][1])
## [1] 4
Para concretar el ejemplo anterior, podemos imaginar especies de barrenadores del maíz (Sesamia nonagrioides y Ostrinia nubilalis), muestreados en diferentes sitios, con diferentes abundancias en cuatro fechas. Aquí daremos nombres a los elementos de las list
.
<- list(Snonagrioides = list(site01 = c(12, 5, 8, 7), site02 = c(5, 23, 4, 41), site03 = c(12, 0, 0, 0)), Onubilalis = list(site01 = c(12, 1, 2, 3), site02 = c(0, 0, 0, 1), site03 = c(1, 1, 2, 3)))
bddInsect print(bddInsect)
## $Snonagrioides
## $Snonagrioides$site01
## [1] 12 5 8 7
##
## $Snonagrioides$site02
## [1] 5 23 4 41
##
## $Snonagrioides$site03
## [1] 12 0 0 0
##
##
## $Onubilalis
## $Onubilalis$site01
## [1] 12 1 2 3
##
## $Onubilalis$site02
## [1] 0 0 0 1
##
## $Onubilalis$site03
## [1] 1 1 2 3
Leer una larga línea de código como la línea para crear el objeto bddInsect
resulta difícil porque la profundidad de los elementos solo se puede deducir de los paréntesis. Es por eso que vamos a reorganizar el código para que sea más legible mediante el margen adicional. El margen adicional implica poner información en diferentes niveles para que podamos identificar rápidamente los diferentes niveles de un código. Para aplicar el margen adicional se presiona la tecla de tabulación. Volveremos al margen adicional con más detalles en el capítulo sobre bucles. Recordemos por el momento que si una línea de código es demasiado larga, podemos saltar de línea y usar el margen adicional. R leerá todo como una sola línea de código.
<- list(
bddInsect Snonagrioides = list(
site01 = c(12, 5, 8, 7),
site02 = c(5, 23, 4, 41),
site03 = c(12, 0, 0, 0)
), Onubilalis = list(
site01 = c(12, 1, 2, 3),
site02 = c(0, 0, 0, 1),
site03 = c(1, 1, 2, 3)
) )
Podemos seleccionar los datos de abundancia del segundo sitio de la primera especie como previamente bddInsect[[1]][[2]]
, o alternativamente usando los nombres de los elementos bddInsect$Snonagrioides$site02
. Para hacer esto usamos el signo $
, o como alternativa el nombre de los elementos con comillas simples o dobles bddInsect[['Snonagrioides']][['sitio02']]
.
print(bddInsect[[1]][[2]])
## [1] 5 23 4 41
print(bddInsect$Snonagrioides$site02)
## [1] 5 23 4 41
print(bddInsect[['Snonagrioides']][['site02']])
## [1] 5 23 4 41
En cuanto a los vectores, podemos recuperar los nombres de los elementos con la función names()
.
names(bddInsect)
## [1] "Snonagrioides" "Onubilalis"
names(bddInsect[[1]])
## [1] "site01" "site02" "site03"
Cuando usamos los corchetes dobles [[]]
o el signo $
, R devuelve el contenido del elemento seleccionado. En nuestro ejemplo, los datos de abundancia están contenidos como un vector
, por lo que R devuelve un elemento del tipo vector
. Si queremos seleccionar un elemento de una list
pero manteniendo el formato list
, entonces podemos usar corchetes simples []
.
print(bddInsect[[1]][[2]])
## [1] 5 23 4 41
typeof(bddInsect[[1]][[2]])
## [1] "double"
is.list(bddInsect[[1]][[2]])
## [1] FALSE
print(bddInsect[[1]][2])
## $site02
## [1] 5 23 4 41
typeof(bddInsect[[1]][2])
## [1] "list"
is.list(bddInsect[[1]][2])
## [1] TRUE
El uso de corchetes simples []
es útil cuando queremos recuperar varios elementos de una list
. Por ejemplo, para seleccionar las abundancias de insectos de los primeros dos sitios de la primera especie, usaremos bddInsect [[1]][c(1, 2)]
o alternativamente bddInsect[[1]][c("site01", "sitio02")]
.
print(bddInsect[[1]][c(1, 2)])
## $site01
## [1] 12 5 8 7
##
## $site02
## [1] 5 23 4 41
print(bddInsect[[1]][c("site01", "site02")])
## $site01
## [1] 12 5 8 7
##
## $site02
## [1] 5 23 4 41
6.2.3 Editar una list
Una list
se puede modificar de la misma manera que para el contenedor vector
, es decir, haciendo referencia con corchetes al elemento que queremos modificar.
print(miList02)
## [[1]]
## [1] 5
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "a" "b" "c"
1]] <- 12
miList02[[print(miList02)
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "a" "b" "c"
4]] <- c("d", "e", "f")
miList02[[print(miList02)
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "d" "e" "f"
4]] <- c("a", "b", "c", miList02[[4]], "g", "h", "i")
miList02[[print(miList02)
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i"
4]][5] <- "eee"
miList02[[print(miList02)
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "a" "b" "c" "d" "eee" "f" "g" "h" "i"
3]] <- miList02[[3]] * 10 - 1
miList02[[print(miList02)
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 39 49 59
##
## [[4]]
## [1] "a" "b" "c" "d" "eee" "f" "g" "h" "i"
3]][2] <- miList02[[1]] * 100
miList02[[print(miList02)
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 39 1200 59
##
## [[4]]
## [1] "a" "b" "c" "d" "eee" "f" "g" "h" "i"
print(bddInsect)
## $Snonagrioides
## $Snonagrioides$site01
## [1] 12 5 8 7
##
## $Snonagrioides$site02
## [1] 5 23 4 41
##
## $Snonagrioides$site03
## [1] 12 0 0 0
##
##
## $Onubilalis
## $Onubilalis$site01
## [1] 12 1 2 3
##
## $Onubilalis$site02
## [1] 0 0 0 1
##
## $Onubilalis$site03
## [1] 1 1 2 3
'Snonagrioides']][['site02']] <- c(2, 4, 6, 8)
bddInsect[[print(bddInsect)
## $Snonagrioides
## $Snonagrioides$site01
## [1] 12 5 8 7
##
## $Snonagrioides$site02
## [1] 2 4 6 8
##
## $Snonagrioides$site03
## [1] 12 0 0 0
##
##
## $Onubilalis
## $Onubilalis$site01
## [1] 12 1 2 3
##
## $Onubilalis$site02
## [1] 0 0 0 1
##
## $Onubilalis$site03
## [1] 1 1 2 3
Para combinar dos list
, simplemente usamos la función c()
que hemos usado para crear un vector
.
<- c(miList02, miList03)
miList0203 print(miList0203)
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 39 1200 59
##
## [[4]]
## [1] "a" "b" "c" "d" "eee" "f" "g" "h" "i"
##
## [[5]]
## [1] 5
##
## [[6]]
## [1] "qwerty"
##
## [[7]]
## [[7]][[1]]
## [1] 4 5 6
##
## [[7]][[2]]
## [1] "a" "b" "c"
Un objeto de tipo list
se puede transformar en vector
con la función unlist()
si el formato de los elementos de la lista lo permite (un vector
solo puede contener elementos del mismo tipo).
<- list("a", c("b", "c"), "d")
miList05 print(miList05)
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "b" "c"
##
## [[3]]
## [1] "d"
<- unlist(miList05)
miVec24 print(miVec24)
## [1] "a" "b" "c" "d"
<- list(c(1, 2, 3), c(4, 5, 6, 7), 8, 9, c(10, 11))
miList06 print(miList06)
## [[1]]
## [1] 1 2 3
##
## [[2]]
## [1] 4 5 6 7
##
## [[3]]
## [1] 8
##
## [[4]]
## [1] 9
##
## [[5]]
## [1] 10 11
<- unlist(miList06)
miVec25 print(miVec25)
## [1] 1 2 3 4 5 6 7 8 9 10 11
Para agregar un elemento a una list
, podemos usar la función c()
o los corchetes dobles [[ ]]
.
print(miList05)
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "b" "c"
##
## [[3]]
## [1] "d"
<- c(miList05, "e")
miList05 print(miList05)
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "b" "c"
##
## [[3]]
## [1] "d"
##
## [[4]]
## [1] "e"
5]] <- c("fgh", "ijk")
miList05[[print(miList05)
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "b" "c"
##
## [[3]]
## [1] "d"
##
## [[4]]
## [1] "e"
##
## [[5]]
## [1] "fgh" "ijk"
Para eliminar un elemento de una list
, la técnica más rápida es establecer NULL
en el elemento que deseamos eliminar.
print(miList05)
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "b" "c"
##
## [[3]]
## [1] "d"
##
## [[4]]
## [1] "e"
##
## [[5]]
## [1] "fgh" "ijk"
2]] <- NULL
miList05[[print(miList05)
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "d"
##
## [[3]]
## [1] "e"
##
## [[4]]
## [1] "fgh" "ijk"
6.3 El contenedor data.frame
El contenedor data.frame
se puede comparar a una tabla. Este es en realidad un caso especial de list
donde todos los elementos de la list
tienen el mismo tamaño.
6.3.1 Crear un data.frame
Para crear un data.frame
usamos la función data.frame()
que toma como argumentos los elementos de la tabla que queremos crear. Los elementos son del tipo vector
y son todos del mismo tamaño. Podemos dar un nombre a cada columna (vector
) de nuestra tabla (data.frame
).
# crear un data.frame
<- data.frame(
miDf01 numbers = c(1, 2, 3, 4),
logicals = c(TRUE, TRUE, FALSE, TRUE),
characters = c("a", "b", "c", "d")
)print(miDf01)
## numbers logicals characters
## 1 1 TRUE a
## 2 2 TRUE b
## 3 3 FALSE c
## 4 4 TRUE d
# crear vectores, y el data.frame
<- c(1, 2, 3, 4)
numbers <- c(TRUE, TRUE, FALSE, TRUE)
logicals <- c("a", "b", "c", "d")
characters <- data.frame(numbers, logicals, characters)
miDf01 print(miDf01)
## numbers logicals characters
## 1 1 TRUE a
## 2 2 TRUE b
## 3 3 FALSE c
## 4 4 TRUE d
6.3.2 Acceder a los elementos de un data.frame
El acceso a los diferentes valores de un data.frame
se puede hacer de la misma manera que para un contenedor de tipo list
.
print(miDf01$numbers) # vector
## [1] 1 2 3 4
print(miDf01[[1]]) # vector
## [1] 1 2 3 4
print(miDf01[1]) # list
## numbers
## 1 1
## 2 2
## 3 3
## 4 4
print(miDf01["numbers"]) # list
## numbers
## 1 1
## 2 2
## 3 3
## 4 4
print(miDf01[["numbers"]]) # vector
## [1] 1 2 3 4
También podemos usar otra forma que consiste en especificar la línea o las líneas seguidas de una coma (con un espacio después de la coma), y luego la columna o columnas entre corchetes. Si se omite la información de línea o columna, R mostrará todas las líneas o columnas. Nuevamente podemos usar el número correspondiente a un elemento o el nombre del elemento que queremos seleccionar.
<- 2
myRow <- 1
myCol print(miDf01[myRow, myCol])
## [1] 2
print(miDf01[myRow, ])
## numbers logicals characters
## 2 2 TRUE b
print(miDf01[, myCol])
## [1] 1 2 3 4
<- "numbers"
myCol print(miDf01[, myCol])
## [1] 1 2 3 4
Es posible seleccionar múltiples líneas o columnas.
print(miDf01[, c(1, 2)])
## numbers logicals
## 1 1 TRUE
## 2 2 TRUE
## 3 3 FALSE
## 4 4 TRUE
print(miDf01[c(2, 1), ])
## numbers logicals characters
## 2 2 TRUE b
## 1 1 TRUE a
Como cada columna está en formato vector
, también podemos hacer una selección que depende del contenido con operadores de comparación y operadores lógicos.
<- miDf01[miDf01$numbers > 2, ]
miDfSub01 print(miDfSub01)
## numbers logicals characters
## 3 3 FALSE c
## 4 4 TRUE d
<- miDf01[(miDf01$logicals == TRUE) & (miDf01$numbers < 2), ]
miDfSub02 print(miDfSub02)
## numbers logicals characters
## 1 1 TRUE a
<- miDf01[(miDf01$numbers %% 2) == 0, ]
miDfSub03 print(miDfSub03)
## numbers logicals characters
## 2 2 TRUE b
## 4 4 TRUE d
<- miDf01[((miDf01$numbers %% 2) == 0) | (miDf01$logicals == TRUE), ]
miDfSub04 print(miDfSub04)
## numbers logicals characters
## 1 1 TRUE a
## 2 2 TRUE b
## 4 4 TRUE d
6.3.3 Modificar un data.frame
Para agregar un elemento a un data.frame
, procedemos como para un contenedor de tipo list
. Es necesario asegurarse de que el nuevo elemento sea del mismo tamaño que los otros elementos de nuestro data.frame
. Por defecto, un nuevo elemento en data.frame
toma el nombre de la letra V seguido del número de la columna. Podemos cambiar los nombres de las columnas con la función colnames()
. Podemos nombrar las líneas con la función rownames()
.
<- c(4, 5, 6, 7)
newVec 4]] <- newVec
miDf01[[print(miDf01)
## numbers logicals characters V4
## 1 1 TRUE a 4
## 2 2 TRUE b 5
## 3 3 FALSE c 6
## 4 4 TRUE d 7
print(colnames(miDf01))
## [1] "numbers" "logicals" "characters" "V4"
colnames(miDf01)[4] <- "newVec"
print(miDf01)
## numbers logicals characters newVec
## 1 1 TRUE a 4
## 2 2 TRUE b 5
## 3 3 FALSE c 6
## 4 4 TRUE d 7
print(rownames(miDf01))
## [1] "1" "2" "3" "4"
rownames(miDf01) <- c("row1", "row2", "row3", "row4")
print(miDf01)
## numbers logicals characters newVec
## row1 1 TRUE a 4
## row2 2 TRUE b 5
## row3 3 FALSE c 6
## row4 4 TRUE d 7
<- c(40, 50, 60, 70)
newVec2 $newVec2 <- newVec2
miDf01print(miDf01)
## numbers logicals characters newVec newVec2
## row1 1 TRUE a 4 40
## row2 2 TRUE b 5 50
## row3 3 FALSE c 6 60
## row4 4 TRUE d 7 70
Como el contenedor de tipo data.frame
es un caso especial de list
, la selección y modificación se realiza como un contenedor de tipo list
. Dado que los elementos de un data.frame
son del tipo vector
, la selección y la modificación de los elementos de un data.frame
se hace como para un contenedor vector
.
$newVec2 <- miDf01$newVec2 * 2
miDf01print(miDf01)
## numbers logicals characters newVec newVec2
## row1 1 TRUE a 4 80
## row2 2 TRUE b 5 100
## row3 3 FALSE c 6 120
## row4 4 TRUE d 7 140
$newVec2 + miDf01$newVec miDf01
## [1] 84 105 126 147
$newVec2[2] <- 0
miDf01print(miDf01)
## numbers logicals characters newVec newVec2
## row1 1 TRUE a 4 80
## row2 2 TRUE b 5 0
## row3 3 FALSE c 6 120
## row4 4 TRUE d 7 140
Un vector
se puede transformar en data.frame
con la función as.data.frame()
.
print(newVec2)
## [1] 40 50 60 70
print(as.data.frame(newVec2))
## newVec2
## 1 40
## 2 50
## 3 60
## 4 70
is.data.frame(newVec2)
## [1] FALSE
is.data.frame(as.data.frame(newVec2))
## [1] TRUE
6.4 El contenedor matrix
El contenedor matrix
se puede ver como un vector
de dos dimensiones: líneas y columnas. Corresponde a una matriz en matemáticas, y puede contener solo un tipo de datos (logical
, numeric
, character
, …).
6.4.1 Crear una matrix
Para crear una matrix
primero creamos un vector
, luego especificamos el número deseado de líneas y columnas en la función matrix()
.
<- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
vecForMatrix <- matrix(vecForMatrix, nrow = 3, ncol = 4)
miMat print(miMat)
## [,1] [,2] [,3] [,4]
## [1,] 1 4 7 10
## [2,] 2 5 8 11
## [3,] 3 6 9 12
No tenemos que especificar el número de líneas nrow
y el número de columnas ncol
. Si usamos uno u otro de estos argumentos, R calculará automáticamente el número correspondiente.
<- matrix(vecForMatrix, nrow = 3)
miMat print(miMat)
## [,1] [,2] [,3] [,4]
## [1,] 1 4 7 10
## [2,] 2 5 8 11
## [3,] 3 6 9 12
<- matrix(vecForMatrix, ncol = 4)
miMat print(miMat)
## [,1] [,2] [,3] [,4]
## [1,] 1 4 7 10
## [2,] 2 5 8 11
## [3,] 3 6 9 12
Observamos que los diferentes elementos del vector
inicial aparecen por columna. Si queremos llenar la matrix
empezando por línea, entonces tenemos que dar como valor TRUE
al argumento byrow
.
<- matrix(vecForMatrix, nrow = 3, byrow = TRUE)
miMat print(miMat)
## [,1] [,2] [,3] [,4]
## [1,] 1 2 3 4
## [2,] 5 6 7 8
## [3,] 9 10 11 12
También podemos dar un nombre a las líneas y columnas de nuestra matrix
cuando se crea con el argumento dimnames
que toma como valor una list
de dos elementos: el nombre de las líneas y luego el nombre de las columnas. También podemos cambiar el nombre de las líneas y columnas a posteriori con las funciones rownames()
y colnames()
.
<- matrix(
miMat
vecForMatrix, nrow = 3,
byrow = TRUE,
dimnames = list(c("r1", "r2", "r3"), c("c1", "c2", "c3", "c4"))
)print(miMat)
## c1 c2 c3 c4
## r1 1 2 3 4
## r2 5 6 7 8
## r3 9 10 11 12
colnames(miMat) <- c("col1", "col2", "col3", "col4")
rownames(miMat) <- c("row1", "row2", "row3")
print(miMat)
## col1 col2 col3 col4
## row1 1 2 3 4
## row2 5 6 7 8
## row3 9 10 11 12
Es posible crear una matrix
desde un data.frame
con la función as.matrix()
. Tenemos que verificar que nuestra data.frame
contenga solo elementos del mismo tipo (por ejemplo, elementos de tipo numeric
).
<- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
vecForMat01 <- vecForMat01 * 10
vecForMat02 <- vecForMat01 / 10
vecForMat03 <- data.frame(vecForMat01, vecForMat02, vecForMat03)
dfForMat print(dfForMat)
## vecForMat01 vecForMat02 vecForMat03
## 1 1 10 0.1
## 2 2 20 0.2
## 3 3 30 0.3
## 4 4 40 0.4
## 5 5 50 0.5
## 6 6 60 0.6
## 7 7 70 0.7
## 8 8 80 0.8
## 9 9 90 0.9
## 10 10 100 1.0
## 11 11 110 1.1
## 12 12 120 1.2
is.matrix(dfForMat)
## [1] FALSE
as.matrix(dfForMat)
## vecForMat01 vecForMat02 vecForMat03
## [1,] 1 10 0.1
## [2,] 2 20 0.2
## [3,] 3 30 0.3
## [4,] 4 40 0.4
## [5,] 5 50 0.5
## [6,] 6 60 0.6
## [7,] 7 70 0.7
## [8,] 8 80 0.8
## [9,] 9 90 0.9
## [10,] 10 100 1.0
## [11,] 11 110 1.1
## [12,] 12 120 1.2
is.matrix(as.matrix(dfForMat))
## [1] TRUE
También podemos crear una matrix
desde un vector
con la función as.matrix()
(matriz de una sola columna).
as.matrix(vecForMat01)
## [,1]
## [1,] 1
## [2,] 2
## [3,] 3
## [4,] 4
## [5,] 5
## [6,] 6
## [7,] 7
## [8,] 8
## [9,] 9
## [10,] 10
## [11,] 11
## [12,] 12
6.4.2 Manipular y hacer operaciones en una matrix
Todas las operaciones término a término son posibles con una matrix
.
# operaciones término a término
<- matrix(vecForMat01, ncol = 3)
miMat01 <- c(1, 10, 100, 1000)
miVecOp * miVecOp miMat01
## [,1] [,2] [,3]
## [1,] 1 5 9
## [2,] 20 60 100
## [3,] 300 700 1100
## [4,] 4000 8000 12000
+ miVecOp miMat01
## [,1] [,2] [,3]
## [1,] 2 6 10
## [2,] 12 16 20
## [3,] 103 107 111
## [4,] 1004 1008 1012
/ miMat01 miMat01
## [,1] [,2] [,3]
## [1,] 1 1 1
## [2,] 1 1 1
## [3,] 1 1 1
## [4,] 1 1 1
- 10 miMat01
## [,1] [,2] [,3]
## [1,] -9 -5 -1
## [2,] -8 -4 0
## [3,] -7 -3 1
## [4,] -6 -2 2
Para realizar operaciones algebraicas, podemos usar la función %*%
.
# operaciones algebraicas
<- c(1, 10, 100)
miVecConf %*% miVecConf miMat01
## [,1]
## [1,] 951
## [2,] 1062
## [3,] 1173
## [4,] 1284
<- matrix(c(1, 2, 3, 4, 5, 6, 7, 8, 9), ncol = 3)
miMat02 print(miMat02)
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
%*% miMat02 miMat02
## [,1] [,2] [,3]
## [1,] 30 66 102
## [2,] 36 81 126
## [3,] 42 96 150
La diagonal de una matrix
se puede obtener con la función diag()
y el determinante de una matrix
con la función det()
.
print(miMat02)
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
diag(miMat02)
## [1] 1 5 9
det(miMat02)
## [1] 0
Suele ser útil poder hacer una transposición de matrix
(columnas en líneas o líneas en columnas). Para eso, están las funciones aperm()
o t()
. la función t()
es más genérica y también funciona con data.frame
.
aperm(miMat01)
## [,1] [,2] [,3] [,4]
## [1,] 1 2 3 4
## [2,] 5 6 7 8
## [3,] 9 10 11 12
t(miMat01)
## [,1] [,2] [,3] [,4]
## [1,] 1 2 3 4
## [2,] 5 6 7 8
## [3,] 9 10 11 12
6.4.3 Acceder a los elementos de una matrix
Tal como hemos hecho con los data.frame
, podemos acceder a los elementos de una matrix
especificando un número de línea y un número de columna entre corchetes simples [ ]
, y separados por una coma. Si i
es el número de línea y j
es el número de columna, entonces miMat01[i, j]
devuelve el elemento en la línea i
y en la columnaj
. miMat01[i,]
devuelve todos los elementos de la línea i
, y miMat01[, j]
todos los elementos de la columna j
. Múltiples selecciones son posibles. También podemos acceder a un elemento de acuerdo con su posición en la matrix
entre corchetes simples [ ]
contando por columna y luego por línea. En nuestro ejemplo, el valor del décimo elemento es 10.
<- 2
i <- 1
j print(miMat01[i, j])
## [1] 2
print(miMat01[i, ])
## [1] 2 6 10
print(miMat01[, j])
## [1] 1 2 3 4
print(miMat01[c(1, 2), c(2, 3)])
## [,1] [,2]
## [1,] 5 9
## [2,] 6 10
print(miMat01[10])
## [1] 10
6.5 El contenedor array
El contenedor array
es una generalización del contenedor de tipo matrix
. Donde el tipo matrix
tiene dos dimensiones (líneas y columnas), el tipo array
tiene un número indefinido de dimensiones. Podemos saber el número de dimensiones de un array
(y por lo tanto una matrix
) con la función dim()
.
dim(miMat01)
## [1] 4 3
6.5.1 Crear un array
La creación de una array
es similar a la de una matrix
con una dimensión extra.
<- c(1, 2, 3, 4, 5, 6, 7, 8, 9)
miVecArr <- array(miVecArr, dim = c(3, 3, 2))
miArray print(miArray)
## , , 1
##
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
##
## , , 2
##
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
dim(miArray)
## [1] 3 3 2
is.array(miArray)
## [1] TRUE
<- 10 * miVecArr
miVecArr02 <- array(c(miVecArr, miVecArr02), dim = c(3, 3, 2))
miArray02 print(miArray02)
## , , 1
##
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
##
## , , 2
##
## [,1] [,2] [,3]
## [1,] 10 40 70
## [2,] 20 50 80
## [3,] 30 60 90
dim(miArray02)
## [1] 3 3 2
is.array(miArray02)
## [1] TRUE
Podemos dar nombres a líneas y columnas, pero también a elementos.
<- array(
miArray02 c(miVecArr, miVecArr02),
dim = c(3, 3, 2),
dimnames = list(
c("r1", "r2", "r3"),
c("c1", "c2", "c3"),
c("matrix1", "matrix2")
)
)print(miArray02)
## , , matrix1
##
## c1 c2 c3
## r1 1 4 7
## r2 2 5 8
## r3 3 6 9
##
## , , matrix2
##
## c1 c2 c3
## r1 10 40 70
## r2 20 50 80
## r3 30 60 90
6.5.2 Manipular un array
La manipulación de un array
se hace de la misma manera que para una matrix
. Para acceder a los diferentes elementos de un array
, simplemente hay que especificar la línea i
, la columna j
, y la matrix
k
.
<- 2
i <- 1
j <- 1
k print(miArray02[i, j, k])
## [1] 2
print(miArray02[, j, k])
## r1 r2 r3
## 1 2 3
print(miArray02[i, , k])
## c1 c2 c3
## 2 5 8
print(miArray02[i, j, ])
## matrix1 matrix2
## 2 20
6.6 Conclusión
Felicitaciones! Ahora conocemos los principales tipos de objetos que usaremos con R. Un objeto se caracteriza por sus atributos:
- el tipo de contenedor (
vector
,data.frame
,matrix
,array
) - el tipo de contenido de cada elemento (
numeric
,logical
,character
, …) - el valor de cada uno de los elementos (5, “qwerty”, TRUE, …)
Todos estos objetos se almacenan temporalmente en el entorno global de R (en la memoria RAM de nuestra computadora). El siguiente capítulo tratará las funciones y resaltará uno de los aspectos que hace que R sea tan poderoso para analizar y administrar nuestros datos.