[ ]
which()
Las estructuras de datos son objetos que contienen datos y organizados de diferentes maneras. Las estructuras tienen diferentes características, siendo las más importantes su número de dimensiones y si son homogeneas o hereterogeneas.
La siguiente tabla muestra las principales estructuras de datos que maneja R.
Dimensiones | Homogeneas | Heterogeneas |
---|---|---|
1 | Vector | Lista |
2 | Matriz | Data frame |
n | Array |
Sintaxis de R
Un vector es una secuencia ordenada de datos del mismo tipo (siendo éstos númericos, cadenas, fechas, etc). Es la estructura de datos más sencilla. Un simple valor (el número 3) constituye un vector númerico:
3
is.vector(3) # Verificamos que el 3 es un vector con la función is.vector().
length(3) # La función length() para conocer su largo.
Lo mismo ocurre con otros tipos de datos, por ejemplo, con cadenas de texto y datos lógicos.
is.vector("tres")
is.vector(TRUE)
La forma más sencilla de crear un vector es usando la función
c()
(combinar o contatenar) que debe incluir los datos que
deseamos integrar en ese vector, separados por comas (y en caso de datos
de tipo charater
flanqueados por comillas).
<- c(1,5,6,2,5,7,8,3,5,2,1,0) # Creación de un vector numérico con la función c (concatenar)
x
x
assign("edad", c(22,28,37,34,13,24,39,5,33,32)) # Equivalente a crear un vector con el asignador <-
edad
<- c("Jose","Catalina","Juan","Pablo") # Idem vector alfanumérico (cada elemento siempre entre comillas)
nombres
nombresmode(nombres) # Tipo de vector
print(nombres)
print(class(nombres)) # Obtención de la clase del vector.
Cada uno de los elementos de un vector de caracteres debe escribirse entre comillas. En caso contrario, la máquina devuelve un mensaje de error.
<- c(Jose,Catalina,Juan,Pablo) nombres
c(TRUE, TRUE, FALSE, FALSE, TRUE)
Otra posibilidad de creación de vectores es la función
scan()
. Esta función es muy flexible ya que permite varias
opciones:
<- scan() # Al terminar Intro 2 veces
x_scan x_scan
<- scan("http://aprender.uib.es/Rdir/notas.txt",
notas sep="\t", # Separador
what="character") # Tipo de datos
notas
<- scan("notas.txt")
notas2 notas2
Existen otras opciones para la creación de vectores. Por ejemplo, podemos crear un vector pidiendo a R que genere secuencias de números
<- 1:15 # Serie del 1 hasta el 15
vector1
vector1
<- 2.3:12.5 # Serie del 2,3 hasta el 12,5
vector2 34:-5 # Idem entre 34 y -5
-3:5 # Cuidado con los paréntesis
-(3:5)
<- 1:10 # Vector x compuesto por una serie de 10 números
x x
Si nuestro número de inicio contiene decimales, estas serán respetadas al hacer los incrementos o decrecimientos de uno en uno. En contraste, si es nuestro número de final el que tiene cifras decimales, este será redondeado.
-2.48:2
56.007:50
166:170.05
968:960.928
Una de las capacidades más importantes de R es la posibilidad de
creación de vectores a partir de secuencias de números
aleatorios. Cabe señalar que, en realidad, R no genera números
puramente aleatorios, sino pseudoaletarios. Esto significa que el
algorítmo que genera los numeros necesita una semilla (función
set.seed()
) para inicializarse. Si conoces la semilla,
podemos reproducir exactamente la secuencia de números en diferentes
ordenadores, cosa que es imposible sin la semilla (proporcionará
diferentes resultados).
set.seed(123)
Fundamentalmente, se utilizan dos funciones para la generación de estos números:
runif()
: genera números racionales (con
decimales).help(runif)
runif(10, # Cantidad de número racionales
3, # Valor mínimo
6) # Valor máximo
sample()
genera números
enteros (sin decimales)help(sample)
sample(1:30, # Intervalo de valores (entre 1 y 30 inclusive)
size = 10, # Cantidad de números en el intervalo anterior
replace = FALSE) # TRUE permite que se repitan los números
La función sample()
también se puede utilizar con
cadenas de caracteres o con
fechas.
sample(c("María", "Pedro","Jaime"), # Caracteres a reproducir
size = 10, # Número de caracteres
replace = TRUE, # Se pueden repetir
prob=c(0.5,0.3,0.2)) # Probabilidades de aparición
La función rnorm()
crea una población teórica
con distribución normal (con una media y una desviación
estándar concretas) .
rnorm(10, # Número de valores
100, # Media
20) # Desviación típica
También podemos crear vectores a partir de progresiones aritméticas.
help(seq)
# Secuencia ascendente empezando en 2, acabando en 50 y separados por 1,5
seq(2,
50,
by=1.5)
# Secuencia descendente empezando por 80, acabando por 4 y separados por 3,5
seq(80,
4,
by=-3.5)
# Error: falta el signo (negativo) de la progresión
seq(80,
4,
by=3.5)
# Progresión aritmética de 2 a 10 con 10 miembros
seq(2, 10,
length.out=10)
# Progresión aritmética desde 2, con 10 miembros cada 0.5
seq(2,
by=0.5,
length.out=10)
De nuevo, es posible crear estas progresiones con cadenas de caracteres.
<- letters[1:11] # Progresión de las 11 primeras letras del alfabeto
alfabeto alfabeto
La función rep()
crea vectores a partir de
repeticiones
rep(1,6) # El número 1 repetido 6 veces
rep("Santander",5) # Igual, pero los caracteres siempre entre comillas
sample(rep(c("lectura", "musica", "deportes"),25)) # Igual, pero los caracteres siempre entre comillas
rep(c(1,2,3),times=5) # Secuencia 1 2 3 repetida 5 veces
rep(c(1,2,3),each=5) # Secuencia 1 2 3 pero cada valor se repite 5 veces
rep(c(1,2,3,4),
times=c(2,3,4,5)) # Repite cada elemento un diferente número de veces
Una vez creados los vectores, pueden ser modificados posteriormente. Por ejemplo, si deseamos agregar un elemento a un vector ya existente, lo añadimos asignándolo a nuestro vector original.
<- c(TRUE, FALSE, TRUE)
mi_vector
<- c(mi_vector, FALSE)
mi_vector mi_vector
También es posible combinar 2 vectores previos
<- c(1, 3, 5)
mi_vector_1 <- c(2, 4, 6)
mi_vector_2
<- c(mi_vector_1, mi_vector_2)
mi_vector_3 mi_vector_3
Si intentamos combinar datos de diferentes tipos en un mismo vector, R realizará una coerción automáticamente. El vector resultante será del tipo más flexible, siguiendo las reglas de coerción antes señaladas.
<- c(1, 2, 3)
mi_vector class(mi_vector)
<- c(mi_vector, "a")
mi_vector_nuevo class(mi_vector_nuevo)
Como las cadenas de texto son el tipo de dato más flexible, siempre que creamos un vector que incluye un dato de este tipo, el resultado será un vector de cadena de texto.
<- c(FALSE, 2, "tercero", 4.00)
mi_vector_mezcla class(mi_vector_mezcla)
La modificación de los elementos de un vector se puede hacer elemento a elemento.
<- 1:10
x
x3] <- 15 # En la posición 3 escribimos 15
x[11] <- 25 # Añadimos en la posición 11 un 25
x[ x
También se puede llevar a cabo para todo un subvector de golpe.
c(2, 3, 4)]=x[c(2, 3, 4)]+10 # Sumamos 10 a las entradas en las posiciones 2, 3 y 4
x[ x
rm(list=ls())
Desafío
Crea los siguientes vectores:
<- 1:100 ID
<- sample(c("Centro", "Arganzuela", "Retiro", "Salamanca", "Chamartin", "Tetuán", "Chamberí"),
barrio size = 100, # Número de caracteres
replace = TRUE) # Se pueden repetir
<- sample(3:10, # Intervalo de valores (entre 1 y 30 inclusive)
parques size = 100, # Cantidad de números en el intervalo anterior
replace = TRUE)
<- runif(100, # Cantidad de número racionales
superficie 3, # Valor mínimo
12)
obras
formado por 100 valores (0,1,NA).<- sample(c(0:1, NA), #Caracteres a reproducir
obras size = 100, # Número de caracteres
replace = TRUE, # Se pueden repetir
prob=c(0.75,0.15,0.10)) # Probabilidades de aparición
fecha_inauguración
formado por 100 fechas
entre el 1 de enero de 1930 y el 1 de enero de 2017<- sample(seq(as.Date('1930-01-01'),
fecha_inauguracion as.Date('2017-01-01'),
by = "day"),
100)
[ ]
La notación []
hace siempre referencia a la posición de
un elemento en un vector Es obligatorio su uso para acceder con algún
elemento de un vector.
<- 1:8
n <- 2*3^n-5*n^3*2^n
x x
3] # El tercer elemento del vector, siempre entre corchetes
x[x(3) # ¿El tercer elemento de un vector?
-3] # x sin el tercer elemento
x[c(1,3,5)] # Varios elementos al mismo tiempo
x[3:7] # Los elementos tercero a séptimo de x
x[7:3] # Los elementos séptimo a tercero de x
x[
length(x)] # El último elemento del vector
x[length(x)-5] # El sexto elemento del vector, pero empezando empezando por el final (es decir, quita los 5 últimos)
x[
seq(1,
x[length(x),
by=2)] # Secuencia empezando por uno, cada dos números hasta el final (elementos en posición impar)
seq(2,
x[length(x),
by=2)] # Idem par
-seq(1,
x[length(x),
by=2)] # Borramos los elementos en posición impar, equivalente a la anterior orden
length(x)-5):length(x)] # Los últimos 6 elementos de x
x[(length(x)-5:length(x)] # OJO con los paréntesis x[
La selección de la posición de los elementos de un vector formado por caracteres es similar
<- c("k", "j", "h", "a", "c", "m")
z 3]
z[c(1, 3, 5)]
z[2:6] z[
which()
Con la función which()
podemos conocer qué elemento de un
vector satisface una determinada condición. Aplicada a un vector de
valores lógicos devuelve sus posiciones.
<- sample(1:10, # Intervalo de valores (entre 1 y 30 inclusive)
x size = 20, # Cantidad de números en el intervalo anterior
replace = TRUE)
which(x>3) # Posiciones de los elementos mayores que 3
which(x>2 & x<=5) # Posiciones de los elementos 2 y <= 5
which(x!=2 & x!=5) # Posiciones de los elementos diferentes de 2 y 5
which(x>5 | x<=2) # Posiciones de los elementos > 5 ó <= 2
La función which.min()
proporciona la primera posición
en la que el vector toma su valor mínimo; which.max()
hace
lo mismo, pero para el máximo.
which.min(x)
which(x==min(x))
¡ATENCIÓN! También es posible seleccionar
<- c(1,5,6,2,5,7,8,3,5,2,1,0)
x >3] # Elementos mayores que 3
x[x>3
x
>2 & x<=5] # Elementos mayores que 2 y menores o iguales que 5
x[x!=2 & x!=5] # Elementos diferentes de 2 y de 5
x[x>5 | x<=2] # Elementos mayores que 5 o menores o iguales que 2
x[x>=4] # Elementos mayores o iguales que 4
x[x!x<4] # Condición equivalente a la anterior
x[%%4==0] # Múltiplos de 4 x[x
Si un vector no contiene ningún término que satisfaga la condición que imponemos, obtenemos un vector vacío. R lo indica con numeric(0) si es numérico, character(0) si es alfanumérico, o integer(0
<- 2^(0:10)
x
x20<x & x<30] # Elementos de x estrictamente entre 20 y 30
x[length(x[20<x & x<30]) # ¿Cuántas entradas hay entre 20 y 30?
which(x>1500) # ¿Qué índices de elementos mayores que 1500
<- c() # Vector vacío
x # R no sabe de qué tipo son los datos que faltan en un vector vacío
x <- NULL # Idem
z # Idem
z <- c(x, 2, z) # Sólo muestra el único elemento del vector con valor real
y y
Los operadores lógicos también se pueden usar para pedir si una condición sobre unos números concretos se satisface o no
exp(pi)>pi^(exp(1)) # ¿Es mayor e^pi que pi^e?
1234567%%9==0 # ¿Es 1234567 múltiplo de 9?
<- c(1,5,6,2,5,7,8,3,5,2,1,0)
x <- c(2,-3,0,1,2,-1,4,-1,-2,3,5,1)
y >0] # Entradas de x correspondientes a entradas positivas de y x[y
Existen algunas operaciones, por ejemplo las operaciones aritméticas y relacionales, que se aplican a cada uno de los elementos de un vector. Por ejemplo, creamos un vector numérico.
<- c(2, 3, 6, 7, 8, 10, 11) mi_vector
+ 2 # Operaciones aritméticas
mi_vector * 2
mi_vector %% 2 mi_vector
> 7
mi_vector < 7
mi_vector == 7 mi_vector
Esta manera de aplicar una operación es muy eficiente. Comparada con otros procedimientos, requiere de menos tiempo de cómputo, lo cual a veces es considerable, en particular cuando trabajamos con un número grande de datos. Aunque el nombre de este proceso es vectorización, también funciona, en ciertas circunstancias, para otras estructuras de datos.
<-c(1,2,3,4,5)
x <-c(2,4,6,8,10)
y+y # Suma de vectores
x*y # Producto de vectores término a término
x^2 # Cuadrado de todos los términos de un vector
xsum(x) # Suma de todos los valores de un vector
mean(x) # Media de todos los valores de un vector
sum(x*y) # Producto escalar de dos vectores
plot(x,y) # Gráfico de nube de puntos
1:5+1:5 # Suma entrada a entrada
1:5)*(1:5) # Producto entrada a entrada
(1:5)^(1:5) # Potencia entrada a entrada
(
<- 1:20 # Secuencia 1,...,20
n <- 3*2^n-20 # Aplicamos la fórmula a la secuencia desde n=1,...,20
x
x<- 0:20
n <- n/(n^2+1)
y
y0:20)/((0:20)^2+1)
(
<- c(1,5,6,2,5,7,8,3,5,2,1,0)
x length(x)
max(x)
min(x)
sum(x)
prod(x)
mean(x)
cumsum(x)
diff(x)
diff(cumsum(x))
sort(x)
sort(x,
dec=TRUE)
rev(x)
<- 0:200
n sum(1/(n^2+1))
<- 0:20
i <- 2^(-i)
x <- cumsum(x)
y y
Los datos ausentes aparecen codificados en R como NA. Hay que tener en cuenta que, en cualquier cálculo, la presencia de NA da como resultado NA. Por ello, es conveniente decidir si se eliman del análisis o se sustituyen por otros datos.
<- c(1,4,3,NA,7,6,9,4,0,8)
x
xsum(x) # Al incluir NA, no realiza ningún cálculo
is.na(x) # Preguntamos si hay algún caso perdido
which(is.na(x)) # Los casos perdidos a los elementos situados en las posiciones 12,13,15 y 16
Cómo trabajar los datos ausentes en R. Varias posibilidades:
!is.na(x)] x[
sum(x, na.rm=TRUE) # argumento na.rm = TRUE; la función sólo tiene en cuenta los valores no ausentes
<- x # Creamos una copia de x y la llamamos y
y is.na(y)] <- mean(y, na.rm=TRUE) # Reemplazamos los valores NA del vector y por la media del resto de elementos válidos del vector
y[ y
Se eliminan todos los objetos del área de trabajo y se limpia la consola.
rm(i, mi_vector, n, x, y, z)
cat("\014")
Desafío
ID
?.c(25,45,60)] ID[
barrio
?seq(60,
barrio[length(barrio),
by=2)]
parques
mayores que 5 y menores o iguales que 8 (utiliza la
función which
)?.which(parques > 9 & parques <= 10)
superficie
superan el valor
de 5?.>5] superficie[superficie
fecha_inauguración
?.length(x)-5):length(x)] x[(
/ parques * 10000 superficie
is.na(obras) # Preguntamos si hay algún caso perdido
which(is.na(obras))
Los data frames son estructuras de datos de dos dimensiones que pueden contener datos de diferentes tipos. Es la estructura de datos de mayor uso en Ciencias Sociales. Mientras que en una matriz todas las celdas deben contener datos del mismo tipo, cada columna de un dataframe pueden contener un tipo diferente de datos. En un dataframe:
Cada columna se identifica con un nombre, diferente al del resto de columnas.
Cada columna debe contener el mismo número de datos.
En términos generales, las filas de un data frame representan casos, individuos u observaciones, mientras que las columnas representan atributos o variables. Por ejemplo, el famoso conjunto de datos Iris:
Los primeros cinco renglones corresponden a cinco casos, en este caso flores.
Las columnas son variables con los rasgos de cada flor: largo y ancho de sépalo, largo y ancho de pétalo, y especie.
Dataset Iris
A la hora de crear un dataframe hay que tener en cuenta que, en realidad, está compuesto por vectores (columnas) con la misma longitud.
La creación de un dataframe puede realizarse siguiendo varios procedimientos:
data.frame()
, y
utilizando como argumentos cada uno de los vectores que conformarán el
dataframe. A cada vector se le asignará un nombre, que se convertirá en
el nombre de la variable (columna). Como todos los nombres, es
recomendable que sea claro.<- data.frame("entero" = 1:4,
df1 "factor" = c("a", "b", "c", "d"),
"numero" = c(1.2, 3.4, 4.5, 5.6),
"cadena" = as.character(c("a", "b", "c", "d")))
df1
Si los vectores no son de la misma longitud, R nos devuelve un error. El ejemplo que viene a continuación lo muestra
data.frame("entero" = 1:3,
"factor" = c("a", "b", "c", "d"),
"numero" = c(1.2, 3.4, 4.5, 5.6),
"cadena" = as.character(c("a", "b", "c", "d")))
<- c(1, 2, 3, 4, 5, 6, 7)
ID <- c(0,1,1,0,1,0,0)
sexo <- c(25, 34, 28, 43, 70, 65, 52)
edad <- c(83.5,63.8,102.6,88.5,80.1,55.8,64.7)
peso <- c("10/24/08","10/28/08","10/1/08","10/12/08","5/1/09","01/16/09","01/28/09")
ingreso <- c("Tipo1", "Tipo2", "Tipo2", "Tipo1", "Tipo1", "Tipo1", "Tipo2")
diabetes <- c("Pobre", "Excelente", "Mejorando", "Mejorando", "Mejorando", "Excelente","Pobre")
estatus <- c(1,2,0,1,3,2,3)
estudios
<- data.frame(ID, sexo, edad, peso, ingreso, diabetes, estatus, estudios)
df2 df2
Para no llenar el Global Environment
de objetos que no
se utilizarán más, se eliminan todos los vectores creados previamente
(¡pero no el dataframe!).
rm(ID, sexo, edad, peso, ingreso, diabetes, estatus, estudios) # Eliminamos los vectores originales
También podemos convertir una matriz en data frame (coercionar) y viceversa.
<- matrix(1:12, ncol = 4) # Creamos una matriz.
matriz
matriz
<- as.data.frame(matriz) # Usamos as.data.frame() para coercionar .
df3 class(df3) # Verificamos el resultado
# Resultado
df3 rm(matriz)
Desafío
Crea un dataframe denominado zonas_verdes que
contenga los vectores ID
, barrio
,
parques
, superficie
, obras
y
fecha_inauguracion
en este mismo orden.
<- data.frame(ID, barrio, parques, superficie, obras, fecha_inauguracion)
zonas_verdes zonas_verdes
Elimina posteriormente los vectores originales.
rm(ID, barrio, parques, superficie, obras, fecha_inauguracion)
Podemos solicitar información muy diversa acerca de cualquier dataframe.
# Vista general del dataframe
df2
dim(df2) # Dimensiones (filas y columnas)
length(df2) # La longitud de un data frame es igual a su número de columnas
class(df2) # Tipo de estructura del objeto
str(df2) # Información sobre la estructura del dataframe
head(df2, 3) # Primeras 3 líneas
tail(df2, 5) # Últimas 5 líneas
names(df2) # Etiquetas de las variables
rownames(df2) # Identificadores de los casos (filas).
dimnames(df2) # Lista los identificadores de las filas y los nombres de las columnas.
Una utilidad de R bastante interesante es una ventana de datos cuya estructura recuerda a Excel.
View(df2)
Sólo a una variable (columna). Hay dos opciones
OPCIÓN 1: utilizando la sintaxis
nombre del dataframe$variable
. Es la más habitual.
$edad df2
attach()
se cargan en
memoria las variables del dataframe, de tal manera que no es necesario
indicarle a R que esa variable pertenece a un dataframe concreto. Esta
circunstancia se desactiva con la función detach()
.¡ATENCIÓN! cualquier modificación del dataframe original (pe. el
añadido de una nueva variable o la recodificación de otra) desactiva la
función attach()
.
attach(df2)
edad
detach(df2)
[]
, para acceder a los elementos de un dataframe, que tiene
una estructura formada por filas y columnas se utilizan los corchetes,
pero incluyendo una ,
que separa las filas de las columnas
[fila
, columna
]1:2, ] # Muestra los dos primeros CASOS (FILAS)
df2[
1:2] # Muestra las 2 primeras VARIABLES (COLUMNAS)
df2[, 1:2] # Por defecto muestra las dos primeras VARIABLES
df2[c("diabetes","estatus")] # Especifica las VARIABLES según su nombre
df2[
$edad[2:5] # CASOS 2 a 5 de la VARIABLE edad
df22:5] # Idem
df2[1:5,1:3] # 5 primeras filas y las 3 primeras columnas
df2[
$sexo=="Hombre" & df2$edad > 20, ] # Selección de casos basada en criterios
df2[df2=="Hombre" & edad > 20, ] # Mensaje de error: ¿por qué?
df2[sexo$sexo=="Hombre" & df2$edad > 20, ][1:3, ] # Encadenamiento de varias opciones: las 3 primeras filas de la anterior df2[df2
Desafío
zonas verdes
?length(df2) # La longitud de un data frame es igual a su número de columnas
zonas verdes
.head(zonas_verdes, 10)
zonas_verdes
str(zonas_verdes) # Información sobre la estructura del dataframe
fecha_inauguración
.$fecha_inauguracion[17:45] zonas_verdes
$fecha_inauguracion >= "2012-07-01", ] zonas_verdes[zonas_verdes
$obras == 1 & zonas_verdes$superficie > 10, ] zonas_verdes[zonas_verdes
Es muy habitual disponer tanto de variables en forma de cadenas de texto como de variables cuantitativas discretas que, en realidad, representan variables cualitativas, como el sexo (habitualmente codficada como 0 = hombre y 1 = mujer). Para trabajar con ellas se pueden transformar en factores (variable cualitativa nominal), lo que permitirá operar con ella de una manera más eficiente
class(df2$sexo) # Verifica si la variable estatus es un factor.
is.factor(df2$sexo) # Conversión de una variable numérica en factor.
$sexo <- factor(df2$sexo, # Convierte la variables categórica sexo en factor.
df2levels=c(0,1), # Categorías (o niveles)
labels=c("Hombre","Mujer")) # Etiquetas
$sexo
df2is.factor(df2$sexo)
En el caso de variables cualitativas ordinales también es posible transformar una variable original en un factor ordenado. Existen dos posibilidades.
$estudios <- ordered(df2$estudios, # Convierte la variables categórica estudios en factor ordenado
df2levels=c(0,1,2,3), # Categorías (o niveles)
labels=c("Sin estudios","Estudios Primarios","Estudios Secundarios","Estudios Superiores"))
$estudios df2
$diabetes <- as.factor(df2$diabetes)
df2$diabetes
df2$estatus <- as.factor(df2$estatus)
df2$estatus df2
Desafío
Discute qué variables del dataframe zonas_verdes
pueden
ser transformadas en factores. Transfórmalas en factores.
$barrio <- as.factor(zonas_verdes$barrio)
zonas_verdes
$barrio <- factor(zonas_verdes$barrio,
zonas_verdeslevels=c(0,1),
labels=c("Sin obras","Con obras"))
¡ATENCIÓN! A veces es conveniente duplicar la variable original creando una nueva variable como factor.
La creación de otros dataframes a partir de la selección de casos y/o variables es una prolongación del apartado anterior, dado que simplemente creamos un nuevo objeto (como dataframe) accediendo a los elementos del dataframe original.
<- df2[c(5:7), ] # Opción 1
nuevasfilas1
nuevasfilas1
<- df2[1:3, ] # Opción 2
nuevasfilas2
nuevasfilas2
rm(nuevasfilas1, nuevasfilas2)
Una o varias variables (columnas).
OPCIÓN 1. Identificando las nuevas variables como un vector y utilizando este vector para extraer las columnas a continuación.
<- c("sexo", "estudios")
variables.seleccionadas <- df2[ , variables.seleccionadas]
nuevascolumnas
nuevascolumnas
rm(variables.seleccionadas, nuevascolumnas)
subset()
extrae un subconjunto que
cumple con una o varias condiciones.<- subset(df2, # Dataframe
hombres == "Hombre") # Condición: selección de los "Hombres" en la variable "sexo".
sexo
hombres<- subset(df2, # Dataframe
mayores == "Mujer" & edad>30) # Condicion(es)
sexo
mayores<- subset(df2, # Dataframe
grupo_riesgo == "Hombre" & edad > 50 & estatus == "pobre") # Condicion(es)
sexo
<- subset(df2, # Dataframe
nuevosdatos >= 45 | edad < 24, # Condiciones
edad select=c("estatus","diabetes")) # Variables seleccionadas (estatus y grupo)
<- subset(df2, # Dataframe
nuevosdatos =="Hombre" & edad > 30, # Condiciones
sexoselect = ingreso:estatus) # Variables seleccionadas: desde estudios a grupo
nuevosdatos
rm(hombres, mayores, grupo_riesgo, nuevosdatos)
Para mostrar cómo eliminar variables de un dataframe, respetando el
dataframe original, es pertinente crear un nuevo dataframe, denominado
borrame
(que luego será borrado), similar al original, sin
alguna de las variables.
Una alternativa puede ser la función subset()
que
requiere como argumentos:
El dataframe con el que se está trabajando.
Las variables a eliminar. Son posibles diferentes alternativas:
<- subset(df2,
borrame select =-edad) # Elimina del dataframe la variable "edad".
<- subset(df2,
borrame select =-c(edad,sexo)) # Elimina del dataframe las variables "edad" y "sexo".
<- subset(df2,
borrame select =-c(ingreso:estatus)) # Elimina todas las variables situadas entre "ingreso" y "estatus".
rm(borrame)
Desafío
Selecciona los siguientes casos como un nuevo dataframe que llamarás borrame1
El caso 37.
Los casos 57 a 83
Los casos 33, 44 y 55
Elimina borrame1.
Crea un nuevo dataframe denominado barrio_salamanca
formado por los casos correspondientes al barrio de Salamanca.
Crea un nuevo dataframe denominado subconjunto
formado por las variables ID
, barrio
y
superficie
.
Crea un nuevo dataframe denominado subconjunto_2
que
comprenda aquellos casos correspondientes a las variables
barrio
y fecha_inauguración
en los que el
número de parques sea igual o mayor que 4 y estén actualmente en
obras.
Elimina del dataframe barrio_salamanca
las variables
parques
y `fecha_inauguración”.
Es posible dividir un dataframe con la función split()
.
Esta función divide los datos originales en diferentes grupos, basándose
en los valores de una variable.El siguiente bloque resume los argumentos
de la función y su descripción.
° split(x, # Vector o data frame ° f, # Grupos de clase factor, vector o lista ° drop = FALSE, # Si eliminar los grupos no usados (TRUE) o no (FALSE) ° sep = “.”, # Cadena de caracteres para separar los grupos cuando f es una lista ° lex.order = FALSE, # Si la concatenación de factores debe ser ordenada léxicamente (TRUE) o no (FALSE) ° …) # Argumentos adicionales :::
Es posible juntarlos con la función unsplit()
.
<- split(df2, df2$sexo)
fichero.dividido.sexo
fichero.dividido.sexo<- split(df2, list(df2$sexo, df2$diabetes))
fichero.dividido.sexo.diabetes
unsplit(fichero.dividido.sexo, df2$sexo)
rm(fichero.dividido.sexo, fichero.dividido.sexo.diabetes)
Consiste en la creación de una variable nueva a partir de una
preexistente. Ejemplo: vamos a recodificar la variable edad
en 3 categorías (jóvenes, adultos, ancianos) creando una nueva variable
denominada grupo
en el dataframe df2
.
$grupo[df2$edad > 64] <- "ancianos"
df2$grupo[df2$edad >= 30 & df2$edad <= 64] <- "adultos"
df2$grupo[df2$edad < 30] <- "jovenes"
df2 df2
Como alternativa, las funciones with()
y
within()
ejecuta una o varias instrucciones sobre las
variables de un dataframe accediendo a ellas solamente por su nombre,
sin necesidad de utilizar attach()
.
<- within(df2,{
df2 <- NA # Crea la variable grupo, pero vacía
grupo > 64] <- "ancianos" # Los restantes comandos rellenan esa variable de manera ordenada
grupo[edad >= 30 & edad <= 64] <- "adultos"
grupo[edad < 30] <- "jovenes" }) grupo[edad
fix(df2)
names(df2) # Lista los nombres de las variables
names(df2)[4] <- "hospitalizacion" # Cambia el nombre de la 4ª variable
dfnames(df2)[5:8] <- c("item1", "item2", "item3", "item4") # Renombra las columnas 5 a 8 con los nombres del vector
rename.vars()
del paquete
gdata.if(!require("gdata")) install.packages("gdata")
library(gdata)
<- rename.vars(df2,
df2 c("hospitalizacion","item1", "item2","item3","item4"),
c("edad","diabetes","estatus","estudios","grupo"))
df2
order(df2$edad), ]
df2[order(df2$sexo,df2$edad), ] # Ordeno el nuevo dataframe según género y edad
df2[order(df2$sexo, -df2$edad), ] # Según género (ascendente) y edad (descendente) df2[
Desafío
Divide el dataframe en varios grupos utilizando como factor la
variable obras
.
Crea una nueva variable denominada tamaño_parque
recodificando la variable superficie en tres categorías:
Microparques: hasta 1 ha
Parques medianos: entre 1 y 5 ha
Grandes parques: > 5 ha.
Cambia el nombre de esta última variable y reemplazalo por
tamaño
.
Ordena el dataframe zonas_verdes
utilizando como
criterio el número de parques
en orden descendente. Extrae
a continuación los 6 primeros casos.
Para ello, en primer lugar vamos a crear un dataframe con las variables e df2, pero vacío (reflejando por inclusión, tras el tipo de variable, del número 0 entre paréntesis).
<- data.frame(ID=numeric(0), # c(8, 9, 10, 11, 12, 13, 14)
nuevos.df sexo=numeric(0), # c(0,1,0,0,0,1,1)
edad =numeric(0), # c(35, 44, 38, 53, 80, 75, 62)
ingreso=character(0), # c("11/24/08","11/28/08","11/1/08","11/12/08","2/1/09","03/16/09","03/28/09")
diabetes=character(0), # c("Tipo2", "Tipo1", "Tipo1", "Tipo2", "Tipo2","Tipo2", "Tipo1")
estatus=character(0), # c("Mejorando", "Mejorando","Excelente","Pobre","Pobre", "Excelente", "Mejorando")
estudios=numeric(0)) # c(1,3,2,3,1,2,0)
A continuación se abrirá el editor de texto (función
edit()
) y se rellenará manualmente los datos.
<- edit(nuevos.df) nuevos.df
#El dataframe se crea uniendo los uniendo los vectores
#nuevos.df <- data.frame(ID, sexo, edad, ingreso, diabetes, estatus, estudios)
Con la función rbind()
(r de row) los nuevos casos se
añaden a continuación.
<- rbind(df2,nuevos.df) # Añadimos nuevas.filas debajo
df.actual
df.actual str(df.actual)
Crea un nuevo dataframe, compuesto por 25 casos, con las mismas
variables que el dataframe zonas_verdes
, salvo que ahora
añadiremos los parques de nuevos barrios.
Se creará una variable identificativa ID
compuesta
de 25 números consecutivos entre 101 y 125.
El vector barrio
debe estar formado por 25 elementos
con los siguientes elementos (Fuencarral, Latina, Usera)
repetidos.
El vector parques
estará formado por secuencia
aleatoria de 25 números enteros entre los valores 3 y 10 con
reemplazo.
El vector superficie
debe ser una secuencia de 25
números racionales entre 5 y 10.
El vector obras
estará formado por 25 valores, pero
sin valores NA
.
El vector fecha_inauguración
contendrá 25 fechas
entre el 13 de junio de 1978 y el 31 de agosto de 2022
Estos vectores se unen para formar un dataframe denominado
zonas_verdes_añadido
, que una vez añadido al dataframe
zonas_verdes
, eliminándose posteriormente.
A continuación, se eliminan tanto los vectores como el dataframe
zonas_verdes_añadido
.
Atención: en caso de existir casos repetidos en los dos dataframes se
utiliza la función merge()
:
con el argumento all=FALSE
(valor por defecto) solo
aquellos que son comunes a ambos.
con el argumento all=TRUE
se consigue que se
muestren todos los datos de ambos dataframes
Se pueden añadir diferentes vectores para crear un único dataframe
con la función cbind
(c de column). ¡ATENCIÓN! todos ellos
deben tener la misma longitud.
length(df.actual)
<- c(1,0,0,1,2,3,2,1,3,2,1,0,3,0)
hijos
<- cbind(df.actual, hijos) df.actual
En caso de existir alguna variable repetida, puede utilizarse como
guía; en este caso, la variable repetida será ID. Tenemos que crear el
dataframe pulsaciones
con el ID de cada fila y el número de
pulsaciones, para luego mezclarlos.
<- data.frame(ID=numeric(0),
nuevos.datos pulsaciones=numeric(0))
<- edit(nuevos.datos)
nuevos.datos
<- merge(df.actual, nuevos.datos, by="ID") total
A continuación, se añadirá una nueva variable, denominada
canchas
, que informa sobre el número de canchas deportivas
en cada parque.
Primero, se creará una variable identificativa ID
compuesta por 125 números consecutivos entre 1 y 125.
En segundo lugar, la variable canchas
estará formado
por una secuencia aleatoria de 125 números enteros entre los valores 0 y
3, con reemplazo.
Posteriormente, se creará un nuevo dataframe denominado
canchas
, que se unirá al dataframe
zonas_verdes
. Para ello utiliza la función
merge()
y el argumento by
.
# Creamos un dataframe provisional
<- c("a", "b", NA, NA,"a","b","b","b","c","d")
x1 <- c(2,8,7,5,1,9,4,3,7,NA)
y1 <- data.frame(x1,y1)
borrame head(borrame, n=10)
rm(x1, y1)
Existen multitud de procedimientos para aplicar cuando tenemos valores perdidos. Básicamente existen dos aproximaciones posibles:
Eliminar los casos y las variables que tienen datos faltantes.
Imputar los valores perdidos, es decir, sustituirlos por estimaciones.
¿Cómo verificamos si existen datos ausentes?
sapply(borrame,
function(x) sum(is.na(x))) # Cuenta el número de nulos por variable
<- borrame # Creamos un nuevo objeto copiado del original
borrame2 <- borrame2[!is.na(borrame2$x1), ] # Cada variable por separado; habría que repetir para y1
borrame2 # ó
<- na.omit(borrame) # Elimina todas las filas que contengan algun valor nulo
borrame3
borrame3<- borrame[complete.cases(borrame), ] # Similar al anterior
borrame4 borrame4
is.na(borrame$y1), "y1"] <- mean(borrame$y1, na.rm=T)
borrame[ borrame
rm(x1, y1,borrame, borrame2, borrame3, borrame4)
El formato largo es el más conveniente para filtrar y realizar algunos tipos de agregaciones, mientras que el formato ancho es típico de datos realizados en el tiempo.
Formato ancho: una columna para cada variable.
Formato largo: cada fila es una combinación única de variable de identificación.
install.package("reshape2")
library(reshape2)
# La función de fusión ("melt»): permite pasar de un formato ancho a uno largo.
# Necesitamos indicar qué variables se miden y cuáles son de identificación.
# Argumentos:
# data: Conjunto de datos para fundir
# id.vars: Variables de identificación (Id). Si está en blanco, usará todas las variables que no sean measure.vars. Puede ser un valor entero (posición variable) o cadena (nombre de la variable)
# measure.vars: Variables medidas Si está en blanco, usará todas las variables que no sean id.vars. Puede ser un valor entero (posición variable) o cadena (nombre de la variable)
# variable_name: Nombre de la variable que almacenará los nombres de las variables originales
# na.rm: ¿Deben eliminarse los valores de NA del conjunto de datos?
# ¡ATENCIÓN! la función asume que cualquier variable de tipo factor o carácter es una variable "id" si no se especifica explícitamente.
<- c("Ana", "Pepe")
sujeto <- c(1,1)
tiempo <- c(33, NA)
edad <- c(NA, 90)
peso <- c(1.87,1.73)
altura <- as.data.frame(sujeto, tiempo, edad, peso, altura)
pareja
<- melt(pareja)
largo
largo<- melt(pareja,
largoid=c("sujeto","tiempo")) # Si queremos que la variable «tiempo» se incluya como variable de identificación, junto al sujeto
largomelt(pareja,
id=c("sujeto","tiempo"), na.rm=T) # No incluye los valores ausentes (NA).
La función de moldear (“cast») nos permite pasar de un formato largo a uno ancho. Los argumentos son:
data
: el conjunto de datos para utilizar.
formula
: si fuera necesario, con la fórmula de
conversión describimos la forma del formato de salida (si omite este
argumento, devolverá el marco de datos en la forma clásica con las
variables medidas en las columnas y todas las demás variables de
identificación en las filas).
fun.aggregate
(opcional): función de agregación para
usar, si es necesario
margins
(opcional): ¿qué valores marginales se deben
calcular?. Vector de nombres de variables (puede incluir «grand _col» y
«grand _row») a calcular los márgenes, o TRUE para calcular todos los
márgenes.
cast(largo)
library(MASS)
print(ships)
<- melt(ships,
molten.ships id = c("type","year"))
print(molten.ships)
<- cast(molten.ships,
recasted.ship +year~variable,
type
sum)print(recasted.ship)
<- as.Date("2009-01-01")
fechainicio <- as.Date("2009-10-31")
fechafin <- df[which(df$fecha >= fechainicio &
nuevosdatos $fecha <= fechafin), ]
df== -9999, "edad"] <- NA # Recode 99 to missing for the variable age
df[edad df
save()
.save(df2, file="fichero_exportado_R.rdata") # Exportamos un único objeto, el dataframe df2
Pero también podríamos salvar varios objetos simultáneamente, por ejemplo
save(df1, df2, file = "primera_sesion.RData")
Como se ha señalado en líneas precedentes, en caso de disponer de muchos objetos, es más conveniente grabar todo el espacio de trabajo con la función ’save.image()`; con esto, además, se salva el script de R con las órdenes.
save.image(file = "mi_espacio_trabajo.RData")
Podemos exportar un data frame a un fichero de texto usando la
función write.table()
. Como en el caso de su importación,
el separador entre las columnas puede también modificarse.
write.table(NH3, # Dataframe a exportar
"borrame.txt", # Nombre del fichero
sep=";") # Separador entre columanas, en este caso punto y coma.
En el caso de que queramos exportar el fichero como *.csv podemos recurrir a dos opciones, que dependen del formato:
write.csv(df, file="fichero_exportado_csv.csv") # Formato anglosajón: campos separados por comas, símbolo decimal es un punto
write.csv2(df,file="fichero_exportado_csv2.csv") # Formato español: campos separados punto y coma, símbolo decimal es la coma
Por último, para ficheros excel puede recurrirse a varios paquetes. Uno de ellos es el paquete xlsx.
if(!require("xlsx")) install.packages("xlsx")
library(xlsx)
write.xlsx(df, # Dataframe
"fichero_exportado_excel.xlsx", # Nombre del fichero de salida en formato excel
sheetName = "Hoja1", # Nombre del libro (hoja)
append = TRUE) # Si TRUE este fichero se añade como otro libro al fichero excel -preexistente-
Cuando se trabaja con grandes ficheros, es habitual importarlos de una fuente externa. A través de diferentes paquetes, R es capaz de leer la mayoría de los formatos de datos existentes en la actualidad, tanto desde nuestro disco duro como desde fuentes externas. Tenemos diferentes opciones
RStudio ofrece una serie de herramientas para importar ficheros. A través de algunas ventanas, por ejemplo File, podemos importar diferentes tipos de ficheros.
Importar datos desde Environment: elección del formato
También es posible importar ficheros acudiendo a la ventana Environment.
Tanto en
un caso como en otro, una vez elegido el formato de entrada, aparece una
nueva ventana en la que podemos elegir una serie de opciones.
Importar datos desde Environment: elección del fichero y sus características
También es posible importar ficheros a través de códigos. La sintaxis depende del tipo de fichero:
Ficheros .rdata.
<- load("mi_espacio_trabajo.rdata",
fichero_importado_rdata verbose=TRUE) # Opción verbose=TRUE muestra el nombre de los objetos del archivo
Ficheros de texto. Para importar este tipo de ficheros, es necesario instalar el paquete readr.
if(!require("readr")) install.packages("readr")
library(readr)
La función read.table
importa los ficheros de texto, pero
deben tomarse algunas precauciones previas. Este es el caso de los
separadores entre columnas. Para informar a R de qué separador es el
correcto, se debe utilizar el argumento sep
con las
siguientes posibilidades: - sep=","
las separaciones entre
columnas son comas - sep=";"
idem signos de punto y coma -
sep="\t"
idem son tabuladores. - dec=
separador decimal (ATENCIÓN, en España el decimal es una coma, en US/UK
un punto)
Fichero de texto con columnas está separadas por espacios en blanco.
<- read.table("http://aprender.uib.es/Rdir/NotaHermanos.txt",
NH1 header=TRUE) # Importante si el fichero contiene los nombres de las variables
head(NH1)
str(NH1)
Fichero de texto con Formato csv: las columnas están separadas por comas.
<- read.table("http://aprender.uib.es/Rdir/NotaHermanosc.txt",
NH3 header=TRUE,
sep=",", # Separador de columas
stringsAsFactors=TRUE) # Impide que transforme (por defecto) en factores todas la columnas con caracteres.
str(NH3)
Podemos descargar datos procedentes de páginas web con las mismas funciones. La única diferencia consiste en que, en lugar de proporcionar la ruta al fichero, tendremos que proporcionar la ruta de internet. Por ejemplo:
<- read_csv("https://raw.githubusercontent.com/datasciencelabs/data/master/bio260-heights.csv")
datos str(datos)
rm(datos)
Si los datos originales carecen de encabezado R las nombra con V1,
V2, …, V6 etc. Sin embargo, podemos asignar nombre a cada variable con
la función colnames()
o se pueden asignar directamente
cuando se importan usando el argumento col.names
de la
función read.table()
.
<- c("ID", "edad", "hijos", "coches", "yates", "motos")
nombres <- "http://people.cst.cmich.edu/lee1c/spss/V16_materials/DataSets_v16/Diseaseoutbreak.txt"
web <- read.table(web,
misdatos_web col.names = nombres)
head(misdatos_web) # un vistazo para ver qué resulta
Ficheros excel.
library(readxl)
<- read_excel("fichero_exportado_R.xlsx", # Libro que queremos abrir
fichero_importado_excel sheet = "Hoja1", # Hoja que queremos importar, bien especificando su nombre o su posición
skip = 1) # Empezamos a importar a partir de la cuarta fila.
str(fichero_importado_excel) # Verificar la estructura de los datos que hemos leído mediante
head(fichero_importado_excel) # Comprobar las primeras lineas de datos
Existe la posibilidad de importar otros tipos de ficheros (SPSS, Stata), pero no son de utilidad en este curso.
Las matrices y arrays pueden ser descritas como vectores multidimensionales. Al igual que un vector, únicamente pueden contener datos de un sólo tipo, pero además tienen más dimensiones.
En un sentido estricto, las matrices son una caso especial de un array, que se distingue por tener específicamente dos dimensiones, un “largo”” y un “alto”. Las matrices son, por lo tanto, una estructura con forma rectangular, con renglones y columnas. Como las matrices son usadas de manera regular en matemáticas y estadística, es una estructura de datos de uso común en R común y en la que nos enfocaremos en este libro.
Los arrays, por su parte, pueden tener un número arbitrario de dimensiones. Pueden ser cubos, hipercubos y otras formas. Su uso no es muy común en R, aunque a veces es deseable contar con objetos n-dimensionales para manipular datos. Como los arrays tienen la restricción de que todos sus datos deben ser del mismo tipo, no importando en cuántas dimensiones se encuentren, esto limita sus usos prácticos.
En general, es preferible usar listas en lugar de arrays, una estructura de datos que además tienen ciertas ventajas que veremos más adelante.
Creamos matrices en R con la función matrix(). La función matrix() acepta dos argumentos, nrow y ncol. Con ellos especificamos el número de renglones y columnas que tendrá nuestra matriz.
1:12 # Un vector numérico del uno al doce
matrix(1:12) # matrix() sin especificar renglones ni columnas
matrix(1:12, nrow = 3, ncol = 4) # Tres renglones y cuatro columnas
matrix(1:12, nrow = 4, ncol = 3) # Cuatro columnas y tres columnas
matrix(1:12, nrow = 4, ncol = 3) # Dos renglones y seis columnas
Los datos que intentemos agrupar en una matriz serán acomodados en orden, de arriba a abajo, y de izquierda a derecha, hasta formar un rectángulo. Si multiplicamos el número de renglones por el número de columnas, obtendremos el número de celdas de la matriz. En los ejemplo anteriores, el número de celdas es igual al número de elementos que queremos acomodar, así que la operación ocurre sin problemas.
Cuando intentamos acomodar un número diferente de elementos y celdas, ocurren dos cosas diferentes.
Si el número de elementos es mayor al número de celdas, se acomodarán todos los datos que sean posibles y los demás se omitirán.
matrix(1:12, nrow = 3, ncol = 3)
Si, por el contrario, el número de celdas es mayor que el número de elementos, estos se reciclaran. En cuanto los elementos sean insuficientes para acomodarse en las celdas, R nos devolverá una advertencia y se empezaran a usar los elementos a partir del primero de ellos.
matrix(1:12, nrow = 5, ncol = 4)
Otro procedimiento para crear matrices es la unión vectores con las siguientes funciones:
cbind()
para unir vectores, usando cada uno como una
columna.rbind()
para unir vectores, usando cada uno como un
renglón.De este modo podemos crear cuatro vectores y unirlos para formar una matriz. Cada vector será un renglón en esta matriz. Creamos cuatro vectores, cada uno de largo igual a cuatro.
<- 1:4
vector_1 <- 5:8
vector_2 <- 9:12
vector_3 <- 13:16 vector_4
Usamos rbind() para crear un matriz, en la que cada vector será un renglón.
<- rbind(vector_1, vector_2, vector_3, vector_4)
matriz
# Resultado matriz
Si utilizamos cbind(), entonces cada vector será una columna.
<- cbind(vector_1, vector_2, vector_3, vector_4)
matriz
# Resultado matriz
Al igual que con matrix(), los elementos de los vectores son reciclados para formar una estructura rectangular y se nos muestra un mensaje de advertencia.
# Elementos de largo diferente
<- 1:2
vector_1 <- 1:3
vector_2 <- 1:5
vector_3
<- cbind(vector_1, vector_2, vector_3)
matriz
# Resultado matriz
Finalmente, las matrices pueden contener NAs. Creamos dos vectores con un NA en ellos.
<- c(NA, 1, 2)
vector_1 <- c(3, 4, NA) vector_2
Creamos una matriz con rbind().
<- rbind(vector_1, vector_2)
matriz
# Resultados matriz
Como NA
representa datos perdidos, puede estar presente
en compañía de todo tipo de de datos.
No obstante que las matrices y arrays son estructuras que sólo pueden
contener un tipo de datos, no son atómicas. Su clase es igual a matriz
(matrix) o array segun corresponda. Verificamos esto usando la función
class()
.
<- matrix(1:10)
mi_matriz
class(mi_matriz)
Las matrices y arrays pueden tener más de una dimensión. Obtenemos el
número de dimensiones de una matriz o array con la función
dim()
. Esta función nos devolverá varios números, cada uno
de ellos indica la cantidad de elementos que tiene una dimensión.
<- matrix(1:12,
mi_matriz nrow = 4,
ncol = 3)
dim(mi_matriz)
Cabe señalar que si usamos dim()
con un vector,
obtenemos NULL
. Esto ocurre con todos los objetos
unidimensionales
<- 1:12
mi_vector
dim(mi_vector)
Finalmente, las operaciones aritméticas también son vectorizadas al aplicarlas a una matriz. La operación es aplicada a cada uno de los elementos de la matriz. Creamos una matriz.
<- matrix(1:9, nrow = 3, ncol = 3)
mi_matriz
# Resultado mi_matriz
Intentemos sumar, multiplicar y elevar a la tercera potencia.
+ 1 # Suma
mi_matriz
* 2 # Multiplicación
mi_matriz
^ 3 # Potenciación mi_matriz
Si intentamos vectorizar una operación utilizando una matriz con
NAs
, esta se aplicará para los elementos válidos,
devolviendo NA
cuando corresponda. Creamos una matriz con
NAs
.
<- c(NA, 2, 3)
vector_1 <- c(4, 5, NA)
vector_2
<- rbind(vector_1, vector_2)
matriz
# Resultado matriz
Intentamos dividir sus elementos entre dos.
/ 2 matriz
Finalmente, podemos usar la función t()
para transponer
una matriz, es decir, rotarla 90°. Creamos una matriz con tres renglones
y dos columnas.
<- matrix(1:6, nrow = 3)
matriz
# Resultado matriz
Usamos t()
para transponer y obtenemos una matriz con
dos renglones y dos columnas.
<- t(matriz)
matriz_t
# Resultado matriz_t
Una matriz de orden n x m es una tabla rectangular de números (o, en algunas situaciones específicas, algún otro tipo de datos: valores lógicos, etiquetas…) formada por n filas y m columnas. Una matriz es cuadrada cuando tiene el mismo número de filas que de columnas, es decir, cuando n = m.
Desde el punto de vista de R, una matriz es una colección de valores con dos dimensiones (como un dataframe) pero todos del mismo tipo (a diferencia del dataframe). Las matrices son una estructura de datos con gran importancia en Geografía, ya que es una estructura de datos usada frecuentemente para almacenar información (formato raster).
Una matriz se crea con la función matrix, que acepta los siguientes argumentos:
- `data` Un vector con los valores que componen la matriz
- `nrow` Número de filas
- `ncol` Número de columnas
- `byrow` Indica si la matriz será rellena columna a columna (FALSE, por defecto) o fila a fila (TRUE)
Ejemplos:
matrix(1:6, nrow = 2) # Matriz del 1 al 6 organizada en dos filas
matrix(1:6, ncol = 2) # Matriz del 1 al 6 organizada en dos columnas
matrix(1:12, nrow = 3) # Matriz del 1 al 12 organizada en 3 filas
matrix(1:12, nrow = 3, byrow = TRUE) # Matriz el 1 al 12
<- matrix(1:20,
m nrow=5,
ncol=4)
mclass(m)
= c(
altitud NA, NA, NA, NA, NA, NA, NA, 3, 5, 7,
NA, NA, NA, 61, 106, 47, 31, 39, 32, 49,
NA, NA, NA, 9, 132, 254, 233, 253, 199, 179,
NA, NA, NA, 4, 11, 146, 340, 383, 357, 307,
NA, 4, 6, 9, 6, 6, 163, 448, 414, 403,
3, 6, 9, 10, 6, 6, 13, 152, 360, 370,
3, 4, 7, 16, 27, 12, 64, 39, 48, 55)
<- matrix(altitud,
dem nrow = 10,
ncol = 7)
dem
En una matriz como la llamada dem
- las filas se identifican como [i, ], donde i es el índice de la fila: dem[5, ] significa la 5ª fila.
- Las columnas con [,j], donde j es el índice de la columna.
Las dimensiones de una matriz, es decir, sus números de filas y de columnas, se obtienen con las funciones nrow y ncol. Si queremos un vector formado por las dos dimensiones, podemos emplear la función dim.
nrow(dem)
ncol(dem)
dim(dem)
También podemos realizar numerosos cálculos con estas matrices.
sum(dem, na.rm = T)
mean(dem, na.rm = T)
A diferencia de las matrices, confinadas a dos dimensiones, los
arrays pueden tener cualquier número de dimensiones. La función
array()
tiene un atributo dim
que crea el
número requerido de dimensiones.
<- array(c('green','yellow'),
a dim = c(3,3,2))
print(a)
<- c("A1", "A2")
dim1 <- c("B1", "B2", "B3")
dim2 <- c("C1", "C2", "C3", "C4")
dim3 <- array(1:24,
z c(2,3,4),
dimnames=list(dim1, dim2, dim3))
Las listas, al igual que los vectores, son estructuras de datos unidimensionales, sólo tienen largo, pero a diferencia de los vectores cada uno de sus elementos puede ser de diferente tipo o incluso de diferente clase, por lo que son estructuras heterogéneas.
Podemos tener listas que contengan datos atómicos, vectores, matrices, arrays, data frames u otras listas. Esta última característica es la razón por la que una lista puede ser considerada un vector recursivo, pues es un objeto que puede contener objetos de su misma clase.
Para crear una lista usamos la función list(), que nos pedirá los elementos que deseamos incluir en nuestra lista. Para esta estructura, no importan las dimensiones o largo de los elementos que queramos incluir en ella.
Al igual que con un data frame, tenemos la opción de poner nombre a cada elemento de una lista.
Por último, no es posible vectorizar operaciones aritméticas usando una lista, se nos devuelve un error como resultado.
<- 1:10
mi_vector <- matrix(1:4, nrow = 2)
mi_matriz <- data.frame("num" = 1:3, "let" = c("a", "b", "c"))
mi_df
<- list("un_vector" = mi_vector, "una_matriz" = mi_matriz, "un_df" = mi_df)
mi_lista
mi_lista
Creamos una lista que contiene otras listas.
<- list("lista1" = mi_lista, "lista2" = mi_lista)
lista_recursiva
# Resultado
lista_recursiva
Una lista es unidimensional, sólo tiene largo. El largo de una lista es igual al número de elementos que contiene, sin importar de qué tipo o clase sean. Usamos la lista recursiva que creamos en la sección anterior para ilustrar esto.
length(lista_recursiva)
Dado que una lista siempre tiene una sola dimensión, la función dim() nos devuelve NULL.
dim(lista_recursiva)
Las listas tienen clase list, sin importar qué elementos contienen.
class(lista_recursiva)
Finalmente, no es posible vectorizar operaciones aritméticas usando listas. Al intentarlo nos es devuelto un error.
/ 2 mi_lista
Si deseamos aplicar una función a cada elemento de una lista, usamos lapply()
Al igual que con los datos, cuando intentamos hacer operaciones con una estructura de datos, R intenta coercionarla al tipo apropiado para poder llevarlas a cabo con éxito.
También podemos usar alguna de las funciones de la familia as() coercionar de un tipo de estructura de datos. A continuación se presentan las más comunes.
Función | Coerciona a | Coerciona a |
---|---|---|
as.vector() | Vector | Matrices |
as.matrix() | Matrices | Vectores, Data frames |
as.data.frame() | Data frame | Vectores, Matrices |
as.list() | Lista | Vectores, Matrices, Data frames |
Las estructuras de datos más sencillas, (unidimensionales, homogeneas) pueden ser coercionadas a otras más complejas (multidimensionales, heterogeneas), pero la operación inversa casi nunca es posible.
Veamos algunos ejemplos. Creamos un vector, una matriz, un data frame y una lista.
<- c("a", "b", "c")
mi_vector <- matrix(1:4, nrow = 2)
mi_matriz <- data.frame("a" = 1:2, "b" = c("a", "b"))
mi_df <- list("a" = mi_vector, "b" = mi_matriz, "c" = mi_df) mi_lista
Intentemos coercionar a vector con as.vector()
.
as.vector(mi_matriz)
as.vector(mi_df)
as.vector(mi_lista)
La coerción que intentamos sólo tuvo éxito para una matriz. Para data frame y lista, nos devolvió los mismos objetos. Nota que as.vector() no devolvió un error o una advertencia a pesar de que no tuvo éxito al coercionar, en este caso un data frame o una lista. Esto es importante, pues no puedes confiar que as.vector() tuvo éxito porque corrió sin errores, es necesaria una verificación adicional. Como R intenta coercionar automáticamente, esto puede producir resultados inesperados si no tenemos cuidado. Intentemos coercionar a matriz con as.matrix().
as.matrix(mi_vector)
as.matrix(mi_df)
as.matrix(mi_lista)
El vector fue coercionado a una matriz con una sola columna.
Por su parte, al correr la función con un data frame, coercionamos también todos los datos que contiene, siguiendo las reglas de coerción de tipos de dato que vimos en el capítulo 4.
Al coercionar una lista a una matriz, efectivamente obtenemos un objeto de este tipo, sin embargo perdemos toda la información que contiene, por lo tanto, no podemos considerar que esta es una coerción exitosa. Del mismo modo que con as.vector(), no nos es mostrado ningún error ni advertencia.
Intentemos coercionar a matriz con as.data.frame().
as.data.frame(mi_vector)
as.data.frame(mi_matriz)
as.data.frame(mi_lista)
El vector, al igual que cuando fue coercionado a matriz, devolvió como resultado un objeto con una sola columna, mientras que la matriz conservó sus renglones y columnas.
En este caso, al intentar la coerción de lista a data frame, obtenemos un error. Esta es la única situación en la que esto ocurre utilizando las funciones revisadas en esta sección.
Por último, intentemos coercionar a matriz con as.list().
as.list(mi_vector)
as.list(mi_matriz)
as.list(mi_df)
ACTIVIDAD DE EVALUACIÓN CONTINUA
Una vez concluida la explicación teórica, el alumnado deberá realizar las siguientes actividades de evaluación continua, correspondientes a este apartado
Actividad evaluación continua 1