El objetivo de sesión es familiarizarnos con los conceptos básicos de R. ¿Qué es un objeto en R? ¿Con qué clases/tipos de objetos se trabaja en R? A lo largo de este tutorial aprenderemos a definir vectores y operar con ellos; a crear dataframes y listas; a seleccionar elementos, añadir filas y columnas, etc. Como lo que se pretende es que se entienda la filosofía y la práctica del trabajo con R, todos los conceptos que se introducen se ilustran con ejemplos muy sencillos.
IMPORTANTE: Los materiales de esta sesión (v.1.0) fueron compilados el día 2021-05-19 y pueden ser susceptibles de modificación (corrección de errores, ampliación de contenidos, etc.)
Una vez hemos entrado en la aplicación RStudio
, deberíamos establecer el directorio de trabajo para indicar a R y RStudio donde se encuentran nuestros datos, scripts, etc. Sin embargo, la mejor opción es crear un proyecto. Al crear un proyecto todos los ficheros (datos, scripts, etc.) y carpetas quedan vinculados directamente al proyecto. Es decir, todo el trabajo que realicemos en un proyecto estará auto-contenido en el directorio del proyecto. De esta forma, podemos compartir fácilmente nuestro proyecto con alguien más o podemos copiar y pegar nuestro proyecto en otro ordenador, etc.
Para crear un proyecto en RStudio, seleccionamos File > New project… Se abrirá una ventana similar a la que se muestra en la siguiente Figura.
Para crear un proyecto en un nuevo directorio, hacemos clic en el botón New Directory. Seguidamente, seleccionamos el tipo de proyecto, en nuestro caso New Project. Ahora, asignamos un nombre al directorio (carpeta) que se va a crear y que al mismo tiempo será el nombre del proyecto de R. Para terminar, hacemos clic en el botón Create Project. Al seguir este proceso se habrá creado una carpeta en Documentos y dentro encontraremos el archivo: “nombre_carpeta.Rproj”.
Para crear un proyecto en una carpeta que ya existe, hacemos clic en el botón Existing Directory y después seleccionamos el directorio o carpeta ayudándonos del botón Browse…. Una vez elegida la carpeta, clicamos en el botón Create Project.
Para abrir un proyecto, hacemos doble clic sobre el archivo con extensión .Rproj
. También podemos abrir el proyecto desde el menú de RStudio: File > Open Project…
Ventaja de los proyectos: cualquier fichero que guardemos trabajando en un proyecto se guardará en la carpeta del proyecto.
Aquí os dejo la dirección de dos lecturas cortas sobre los proyectos, la segunda incluye información sobre cómo crear proyectos.
Resulta muy muy interesante la versión cloud de Rstudio.
Una vez nos hemos familiarizado con el entorno de trabajo, vamos a ver algunos conceptos básicos de Rbase. En esta sesión vamos a estudiar los diferentes tipos de datos y objetos con los que trabja R.
Podéis descargaros una cheat cheet de R-base AQUÍ.
Vamos a comenzar utilizando R como una “super” calculadora, aunque evidentemente no es para esto para lo que vamos utilizarlo!!!
3 + 4
## [1] 7
log(10)
## [1] 2.302585
exp(-0.5)
## [1] 0.6065307
x <- 3 + 4
x # x es un vector cuya primera componente es 7. Enseguida vamos con los vectores!
## [1] 7
y = 2 + 6
y
## [1] 8
z <- c(x,y) # la función c() se utiliza para crear vectores
z
## [1] 7 8
mean(z)
## [1] 7.5
a <- mean(z)
a
## [1] 7.5
b <- max(z)
b
## [1] 8
(c <- rnorm(100))
## [1] 0.82561464 0.87935716 -0.10115100 -0.21769659 -0.37152977 0.93470495
## [7] -0.38675856 -1.08454986 -0.45833126 0.62327892 -0.37737486 -0.26364165
## [13] -0.80734314 -1.79016353 -1.29721262 0.20012131 -0.27812200 1.82114081
## [19] -0.23593601 0.06119301 -0.46323579 -0.90864057 -0.61548029 1.04805721
## [25] -0.09440932 -0.67771830 -0.89786033 -1.29170300 -0.85457883 -1.50478371
## [31] 1.76024442 0.53845744 0.96196305 0.94325062 -0.62639268 0.24894934
## [37] -0.53288829 -0.76823650 -0.38740431 0.06683049 0.79076209 1.63389095
## [43] -0.29012643 0.74710643 0.32599245 1.32378722 0.95161986 1.70262157
## [49] -1.15698705 -0.27039370 1.51299235 0.15031265 1.04402408 -0.07213720
## [55] -0.16110914 -0.73119190 -2.63217774 -0.34620634 1.19405457 0.33755491
## [61] 0.05474002 0.73561924 0.36454505 0.59317083 0.93578725 0.72123947
## [67] 0.19317392 -0.06989232 -0.13630997 -1.07553195 -0.27633964 0.63447023
## [73] -2.52175574 0.06424918 -0.49951363 0.59281248 -1.82164169 0.39732387
## [79] 0.76649343 -1.72673696 1.89346219 -0.23654118 0.62336827 -0.01191655
## [85] -0.83164752 0.04587481 0.37983674 -0.10273752 1.01999318 -1.90016803
## [91] 0.72968805 0.96182940 -0.25872846 0.54023267 0.03864592 0.83862656
## [97] -0.92851314 1.14586337 -2.14993378 1.00488180
round(c, 2)
## [1] 0.83 0.88 -0.10 -0.22 -0.37 0.93 -0.39 -1.08 -0.46 0.62 -0.38 -0.26
## [13] -0.81 -1.79 -1.30 0.20 -0.28 1.82 -0.24 0.06 -0.46 -0.91 -0.62 1.05
## [25] -0.09 -0.68 -0.90 -1.29 -0.85 -1.50 1.76 0.54 0.96 0.94 -0.63 0.25
## [37] -0.53 -0.77 -0.39 0.07 0.79 1.63 -0.29 0.75 0.33 1.32 0.95 1.70
## [49] -1.16 -0.27 1.51 0.15 1.04 -0.07 -0.16 -0.73 -2.63 -0.35 1.19 0.34
## [61] 0.05 0.74 0.36 0.59 0.94 0.72 0.19 -0.07 -0.14 -1.08 -0.28 0.63
## [73] -2.52 0.06 -0.50 0.59 -1.82 0.40 0.77 -1.73 1.89 -0.24 0.62 -0.01
## [85] -0.83 0.05 0.38 -0.10 1.02 -1.90 0.73 0.96 -0.26 0.54 0.04 0.84
## [97] -0.93 1.15 -2.15 1.00
set.seed(10)
d <- round(rnorm(100),2)
R utiliza funciones para realizar operaciones. En el ejemplo anterior son funciones: log()
, exp()
, c()
, mean()
, rnorm()
, set.seed()
, etc. Para utilizar una función deben especificarse unos determinados argumentos que los escribimos dentro de los paréntesis separados por comas. En el caso de la función round() hemos especificado dos argumentos: el vector que queremos redondear (c
) y el número de decimales del redondeo (digits
); en el caso de rnorm() sólo hemos especificado el número de datos que queríamos, el resto de argumentos son fijados a los valores por defecto.
El símbolo <- es el operador para asignar. También se puede utilizar = (o menos frecuente ->), aunque es preferible utilizar el <-.
El símbolo # se utiliza para introducir un comentario. Todo lo que quede a la derecha de # no se ejecutará.
Cuando se realiza una asignación se obtiene un objeto. Podemos ver el resultado o contenido de un objeto de varias formas. Por ejemplo, para ver qué es el objeto x podemos escribir en la consola:
También lo podemos ver en el panel de entorno del escritorio de RStudio.
R está compuesto por un sistema base, pero para extender su funcionalidad es necesario instalar paquetes adicionales.
Podemos instalar paquetes de varias formas:
A través del menú: Tools > Install packages…
En el escritorio de RStudio: Packages/Install. Vemos los paquetes que tenemos actualmente instalados y aquellos que se encuentran cargados.
install.packages("rio") # rio es un paquete que se utiliza para importar/exportar datos.
En ocasiones, para nuestra sesión de trabajo necesitamos instalar varios paquetes.
install.packages(c("dplyr","ggplot2","rio"))
También es muy habitual instalar paquetes que se encuentran en GitHub (generalmente, versiones de desarrollo). Para hacer esto, primero tenemos que tener instalado el paquete devtools
y luego …
# install.packages("devtools")
devtools::install_github("perezp44/personal.pjp")
Una vez instalado el paquete, hay que cargarlo para poderlo utilizar. Esto se hace con la función library().
library(rio) # el nombre del paquete se puede poner entre comillas o se pueden omitir.
Aprovechando que hemos instalado y cargado el paquete rio
, vamos a ver cómo cargar datos (en distintos formatos) en R. En una sesión posterior veremos con más detenimiento la tarea de importar/exportar datos.
En este sesión vamos a utilizar el paquete rio
porque cargar y guardar datos este paquete es muy fácil. Para cargar datos se utiliza la función import()
y para guardar la función export()
.
Aquí tenemos un ejemplo:
df <- import("https://www.uv.es/vcoll/curso_R_sfp/precio_casas.xlsx")
df
está formado por 546 observaciones de 12 variables. Para ver la estrucutra de un conjunto de datos (dataframe
) puede utilizarse la función str()
str(df)
## 'data.frame': 546 obs. of 12 variables:
## $ price : num 42000 38500 49500 60500 61000 66000 66000 69000 83800 88500 ...
## $ lotsize : num 5850 4000 3060 6650 6360 4160 3880 4160 4800 5500 ...
## $ bedrooms : num 3 2 3 3 2 3 3 3 3 3 ...
## $ bathrooms : num 1 1 1 1 1 1 2 1 1 2 ...
## $ stories : num 2 1 1 2 1 1 2 3 1 4 ...
## $ driveway : chr "yes" "yes" "yes" "yes" ...
## $ recreation: chr "no" "no" "no" "yes" ...
## $ fullbase : chr "yes" "no" "no" "no" ...
## $ gasheat : chr "no" "no" "no" "no" ...
## $ aircon : chr "no" "no" "no" "no" ...
## $ garage : num 1 0 0 0 0 0 2 0 0 1 ...
## $ prefer : chr "no" "no" "no" "no" ...
¿Qué tipos de datos tenemos en R?
Veamos algunos ejemplos…
x <- c(1,2,3,4) # con la función c() creamos el vector x
class(x) # la función class() devuelve el tipo de objeto
## [1] "numeric"
y <- c("a","b")
class(y)
## [1] "character"
z <- c(1L,2L,3L) # escribimos L detrás del número para obligar a que sea entero
class(z)
## [1] "integer"
w <- c(TRUE, F) # en general, puede escribirse TRUE/FALSE o T/F
class(w)
## [1] "logical"
t <- c(1+2i, 1+3i)
class(t)
## [1] "complex"
k <- factor(x) # convierte el vector x en un factor
k
## [1] 1 2 3 4
## Levels: 1 2 3 4
class(k)
## [1] "factor"
En los ejemplos anteriores hemos definido un vector en el que todos sus elementos eran del mismo tipo. Pero….¿qué pasa si tenemos los siguientes vectores?
x <- c(1,2,"a")
y <- c(FALSE, 1)
z <- c("a",T)
¿De qué tipo son ahora los vectores x, y, z?
class(x)
## [1] "character"
class(y)
## [1] "numeric"
class(z)
## [1] "character"
R ha forzado a que todos los elementos del vector sean del mismo tipo. A esto se le llama implicit coercion. Fijémonos cúal es el resultado de los vectores que hemos definido antes.
x
## [1] "1" "2" "a"
y
## [1] 0 1
z
## [1] "a" "TRUE"
En ocasiones somos nosotros los que estamos interesados en forzar que todos los elementos del vector sean del mismo tipo (esto es la explicit coercion). Para ello utilizamos las funciones as.numeric() , as.character(), as.logical() … Si el resultado no tiene sentido R producirá un mensaje de error o warning. Un ejemplo:
x <- c(1,2,"a")
x
## [1] "1" "2" "a"
as.numeric(x)
## Warning: NAs introducidos por coerción
## [1] 1 2 NA
as.character(x)
## [1] "1" "2" "a"
Por último, podemos evaluar el tipo/clase de objeto con las funciones is.numeric(), is.character(), etc.
x <- c(1,2,"a")
x
## [1] "1" "2" "a"
x <- as.numeric(x)
## Warning: NAs introducidos por coerción
is.na(x)
## [1] FALSE FALSE TRUE
Básicamente R trabaja con los siguientes tipos de objetos:
Lo acabamos de ver, para crear un vector se utiliza la función c() (c de concatenate). Por ejemplo:
x <- c(1,2,3,4)
x # x es un vector que tiene cuatro componentes
## [1] 1 2 3 4
y <- c(5,6,7,8)
y
## [1] 5 6 7 8
z <- c() # crea un vector vacío
z
## NULL
Nota: Observemos que los objetos x, y, z que habíamos definido anteriormente has sido reemplazados por los nuevos objetos.
La mayoría de las operaciones (+, -, *, /) y funciones en R están definidas con carácter vectorial. ¿Qué significa esto?
R opera componente a componente.
z <- x + y
¿Qué resultado espero obtener para z?
Exacto!!! Como la operación se realiza vectorialmente (componente a componente, muy importante!) el resultado es:
## [1] 6 8 10 12
Vamos a ver si lo entendemos de verdad. Supongamos que x e y son los siguientes vectores:
x <- c(1,2,3,4)
y <- c(1,2,3)
¿Qué longitud tienen los vectores x e y? Aquí la respuesta está clara, pero en aplicaciones reales utilizaríamos la función length().
length(x) # esta función es muy útil, conviene recordarla.
## [1] 4
length(y)
## [1] 3
Los vectores no tienen la misma longitud, entonces… ¿cuál será el resultado de z <- x + y?
z <- x + y
## Warning in x + y: longitud de objeto mayor no es múltiplo de la longitud de uno
## menor
z
## [1] 2 4 6 5
R nos da un mensaje de aviso (warning), no es lo mismo que un error. Nos avisa que hay algo que no cuadra pero…realiza la operación que nosotros queremos.
Una cuestión muy importante que siempre tenemos que tener en cuenta cuando trabajamos con vectores es que en un vector sólo podemos concatenar elementos del mismo tipo.
Para seleccionar elementos de un objeto se suelen emplear: [], $, [[]]. Si el objeto es un vector, se utiliza []
Vamos a crear el objeto x que será un vector de cuatro componentes formado por los cuatro primeros números pares. Así:
x <- c(2,4,6,8)
Si queremos acceder/seleccionar/extraer al/el segundo componente de x
x[2]
## [1] 4
Consideremos este ejemplo:
x <- c(2,4,6,8)
y <- c(1,2,3)
z <- x + y
## Warning in x + y: longitud de objeto mayor no es múltiplo de la longitud de uno
## menor
# ¿Qué resultados darán los siguientes ejemplos?
z[6]
# si primero hacemos: z[6] <- 12
z
z[-2]
length(z)
# si primero hacemos: length(z) <- 3
z
Más tarde veremos con más profundidad cómo seleccionar elementos de un objeto. ¡Esto es esencial!
Los dataframe se usan para almacenar datos en forma de tablas (filas / columnas). Este es el formato en el que estamos acostumbrados a trabajar en Excel, Spss, etc.
Los dataframe pueden almacenar objetos/datos de distinto tipo: numéricos, carácter, …
Normalmente los dataframe se crean al cargar/leer una base de datos. Por ejemplo, nosotros tenemos en el environment el objeto df
, que recordemos hace referencia al precio de casas (fichero: precio_casas.xlsx). También podemos crear nosotros un dataframe utilizando la función data.frame()
(lo veremos cuando escribamos cuestiones para las pruebas).
class(df)
## [1] "data.frame"
¿Cuál es la dimensión del objeto df?
nrow(df) # número de filas
## [1] 546
ncol(df) # número de columnas
## [1] 12
dim(df) # número de filas y columnas
## [1] 546 12
Si echamos un vistazo al entorno global también podemos ver que df está formado por 546 observaciones de 12 variables. Si hacemos clic sobre df podemos ver el dataframe. También si escribimos:
View(df)
Una buena práctica una vez hemos cargado unos datos es ver su estructura. Esto puede hacerse haciendo clic sobre el icono azul con la flecha situado justo al lado del nombre del objeto en el entorno global o
str(df)
## 'data.frame': 546 obs. of 12 variables:
## $ price : num 42000 38500 49500 60500 61000 66000 66000 69000 83800 88500 ...
## $ lotsize : num 5850 4000 3060 6650 6360 4160 3880 4160 4800 5500 ...
## $ bedrooms : num 3 2 3 3 2 3 3 3 3 3 ...
## $ bathrooms : num 1 1 1 1 1 1 2 1 1 2 ...
## $ stories : num 2 1 1 2 1 1 2 3 1 4 ...
## $ driveway : chr "yes" "yes" "yes" "yes" ...
## $ recreation: chr "no" "no" "no" "yes" ...
## $ fullbase : chr "yes" "no" "no" "no" ...
## $ gasheat : chr "no" "no" "no" "no" ...
## $ aircon : chr "no" "no" "no" "no" ...
## $ garage : num 1 0 0 0 0 0 2 0 0 1 ...
## $ prefer : chr "no" "no" "no" "no" ...
Normalmente los dataframes con los que trabajamos tienen muchas filas (individuos) y muchas columnas (variables). Si directamente escribimos el nombre del objeto (dataframe) para ver su contenido lo que ocurrirá es que veremos poca cosa, apenas si observaremos como R nos lista todo el contenido de forma continua.
df
Para echar un vistazo al contenido de un dataframe suelen utilizarse las funciones head() y tail(). Por defecto, la primera permite ver las 6 primeras observaciones y la segunda las 6 últimas. También podemos indicar el número de observaciones que queremos visualizar
head(df)
## price lotsize bedrooms bathrooms stories driveway recreation fullbase gasheat
## 1 42000 5850 3 1 2 yes no yes no
## 2 38500 4000 2 1 1 yes no no no
## 3 49500 3060 3 1 1 yes no no no
## 4 60500 6650 3 1 2 yes yes no no
## 5 61000 6360 2 1 1 yes no no no
## 6 66000 4160 3 1 1 yes yes yes no
## aircon garage prefer
## 1 no 1 no
## 2 no 0 no
## 3 no 0 no
## 4 no 0 no
## 5 no 0 no
## 6 yes 0 no
tail(df)
## price lotsize bedrooms bathrooms stories driveway recreation fullbase
## 541 85000 6525 3 2 4 yes no no
## 542 91500 4800 3 2 4 yes yes no
## 543 94000 6000 3 2 4 yes no no
## 544 103000 6000 3 2 4 yes yes no
## 545 105000 6000 3 2 2 yes yes no
## 546 105000 6000 3 1 2 yes no no
## gasheat aircon garage prefer
## 541 no no 1 no
## 542 no yes 0 no
## 543 no yes 0 no
## 544 no yes 1 no
## 545 no yes 1 no
## 546 no yes 1 no
head(df,10)
tail(df,10)
Para seleccionar elementos de un dataframe utilizamos los símbolos $ o []. La forma de proceder es similar a la que se ha visto con vectores o matrices.
Si queremos seleccionar la variable bedrooms del objeto df:
df$bedrooms # observad que al comenzar la escritura RStudio facilita una ayuda
# También lo podemos hacer así:
df[3]
y para seleccionar sus cinco primeros elementos:
df$bedrooms[1:5] # los : es una forma de obtener una secuencia, más adelante veremos otras formas
## [1] 3 2 3 3 2
df[1:5,1]
## [1] 42000 38500 49500 60500 61000
Podemos incluir directamente una nueva variable a nuestro dataframe. Por ejemplo, vamos a añadir la variable id (de identificador) al objeto df. Esto lo podemos hacer directamente utilizando el símbolo $.
df$id <- 1:nrow(df) # los : se utilizan para generar una secuencia
# en el apartado 3 volveremos a referirnos a las secuencias
df
o podemos crear la nueva variable, por ejemplo la variable obs (de observación) y después combinarla con nuestro dataframe df.
obs <- 1:nrow(df)
df <- cbind(obs,df) # la función cbind se utiliza para juntar. También puede
# utilizarse la función rbind
df
Ahora vamos a practicar la selección de datos (observaciones y/o variables) en un dataframe (funciona igual si trabajamos con matrices).
En primer lugar, seleccionamos las variables: price, lotsize, bedrooms y bathrooms.
df2 <- df[,1:4]
Ahora, seleccionamos del objeto df datos las variables: **price, lotsize* y aircon.
df3 <- df[,c(1,2,10)] # también df3<- df[c(1,2,10)]
Sin en lugar de seleccionar variables (columnas) estamos interesados en seleccionar individuos/observaciones (filas):
df4 <- df[1:6,]
# mirar la ayuda de la función seq() y seleccionar las observaciones 4,8,12,...,28,32.
df5 <- df[seq(0,nrow(df),4),]
Para seleccionar tanto observaciones como variables no tenemos más que combinar las estrategias anteriores:
df6 <- df[seq(0,nrow(df),4), c(2,3,7)]
En ocasiones estamos interesados en seleccionar los casos para los que cierta variable toma determinado valor. Vamos a ver primero un resumen de los datos que tenemos:
summary(df)
## price lotsize bedrooms bathrooms
## Min. : 25000 Min. : 1650 Min. :1.000 Min. :1.000
## 1st Qu.: 49125 1st Qu.: 3600 1st Qu.:2.000 1st Qu.:1.000
## Median : 62000 Median : 4600 Median :3.000 Median :1.000
## Mean : 68122 Mean : 5150 Mean :2.965 Mean :1.286
## 3rd Qu.: 82000 3rd Qu.: 6360 3rd Qu.:3.000 3rd Qu.:2.000
## Max. :190000 Max. :16200 Max. :6.000 Max. :4.000
## stories driveway recreation fullbase
## Min. :1.000 Length:546 Length:546 Length:546
## 1st Qu.:1.000 Class :character Class :character Class :character
## Median :2.000 Mode :character Mode :character Mode :character
## Mean :1.808
## 3rd Qu.:2.000
## Max. :4.000
## gasheat aircon garage prefer
## Length:546 Length:546 Min. :0.0000 Length:546
## Class :character Class :character 1st Qu.:0.0000 Class :character
## Mode :character Mode :character Median :0.0000 Mode :character
## Mean :0.6923
## 3rd Qu.:1.0000
## Max. :3.0000
Ahora, seleccionamos price y bedrooms para todas las observaciones en las que la variable bathrooms satisfaga un valor:
unique(df$bathrooms) # valores que toma la variable bathrooms
## [1] 1 2 3 4
sort(unique(df$bathrooms)) # observad la diferencia con order()
## [1] 1 2 3 4
df7 <- df[df$bathrooms==2, c(1,3)] # observad como al establecer la igualdad se utiliza ==
df8 <- df[df$bathrooms>=2 & df$bathrooms<48, c(1,3)]
Para seleccionar subconjuntos de datos en un dataframe también podemos utilizar la función subset().
df9 <- subset(df, bathrooms==2 & lotsize <= mean(lotsize), select=c(price,bedrooms))
df10 <- subset(df, bathrooms !=2 & lotsize <= mean(lotsize)) # el símbolo ! equivale a "lo contrario"
En los dataframe las columnas representarían variables y las filas representarían individuos (observaciones).
Si las columnas de un data frame no tienen nombres , podemos incluirlos utilizando la función names(). Para incluir nombres a las filas se utiliza la función row.names()
names(df)
## [1] "price" "lotsize" "bedrooms" "bathrooms" "stories"
## [6] "driveway" "recreation" "fullbase" "gasheat" "aircon"
## [11] "garage" "prefer"
# ¿Qué hace esto?
df$id <- row.names(df)
row.names(df) <- 1:nrow(df) # observad los cambios
Observemos esta lista que tiene 5 componentes (pueden ser matrices, vectores, dataframes,..).
x <- list(c(1,2,3,4), "Curso", F, 1+2i, 3L)
x
## [[1]]
## [1] 1 2 3 4
##
## [[2]]
## [1] "Curso"
##
## [[3]]
## [1] FALSE
##
## [[4]]
## [1] 1+2i
##
## [[5]]
## [1] 3
Utilizamos el doble corchete [[]] para acceder al contenido concreto de una lista.
x[[3]] # accedemos al tercer componente de la lista
## [1] FALSE
x[[1]][2] # accedemos al segundo elemento del primer componente de la lista
## [1] 2
Vamos a crear otra lista para practicar.
y <- list( Titulacion = c("Economía", "Sociología", "Derecho"), Edad =c(25,26,27))
y
## $Titulacion
## [1] "Economía" "Sociología" "Derecho"
##
## $Edad
## [1] 25 26 27
Fijémonos en la diferencia de presentación de las listas x e y. Como en la lista y hemos nombrado los componentes, estos aparecen al ejecutar el objeto precedidos del símbolo $. Ahora también podemos acceder a un componente de la lista por su nombre.
y$Titulacion
## [1] "Economía" "Sociología" "Derecho"
y[[1]]
## [1] "Economía" "Sociología" "Derecho"
y[1]
## $Titulacion
## [1] "Economía" "Sociología" "Derecho"
y[[1]][1]
## [1] "Economía"
y$Titulacion[1]
## [1] "Economía"
Evidentemente, también podemos realizar operaciones con listas.
y[[2]]*3
## [1] 75 78 81
Podemos crear una lista vacía con una determinada longitud:
z <- vector("list", length= 3)
Los factores, que pueden ser ordenados o no ordenados, se utilizan para representar variables de naturaleza categórica. Generalmente es preferible trabajar con carácteres y suele dejarse los factores cuando se necesitan en un análisis estadístico, por ejemplo en el análisis de regresión.
factor_nominal <- factor(rep(c("Ford","Seat","Renault"),10))
levels(factor_nominal) # ordena los factores por orden alfabético
## [1] "Ford" "Renault" "Seat"
nuevo_factor_nominal <- factor(factor_nominal, levels=c("Seat","Renault","Ford")) # reordenación de factores
levels(nuevo_factor_nominal)
## [1] "Seat" "Renault" "Ford"
Vamos a cargar la base de datos iris, que se encuentra en el paquete datasets(). Iris contiene información sobre longitud y anchura de pétalos y sépalos y especie de un total de 150 lirios.
data("iris")
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 ...
Como podemos ver, el tipo de especie (Species) es una variable categórica (o factor) que tiene tres niveles (levels): setosa, versicolor, virginica. Vamos a ver la distribución del tipo de especie con una tabla
levels(iris$Species)
## [1] "setosa" "versicolor" "virginica"
table(iris$Species)
##
## setosa versicolor virginica
## 50 50 50
En ocasiones, cuando cargamos variables que son carácter se crean como factores.
Si vamos a realizar un análisis de regresión es conveniente guardar las variables categóricas como factores (R codificará internamente los distintos niveles del factor como enteros). Además, puede que sea de nuestro interés cambiar el orden de los niveles. Para aprender más sobre factores aquí.
Para crear secuencias y repeticiones se utilizan los :
y las funciones seq()
, rep()
. Veamos estas funciones a través de varios ejemplos de aplicación.
seq(from = -3, to = 3, by = 0.1)
## [1] -3.0 -2.9 -2.8 -2.7 -2.6 -2.5 -2.4 -2.3 -2.2 -2.1 -2.0 -1.9 -1.8 -1.7 -1.6
## [16] -1.5 -1.4 -1.3 -1.2 -1.1 -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1
## [31] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4
## [46] 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9
## [61] 3.0
seq(-3, 3, 0.1)
## [1] -3.0 -2.9 -2.8 -2.7 -2.6 -2.5 -2.4 -2.3 -2.2 -2.1 -2.0 -1.9 -1.8 -1.7 -1.6
## [16] -1.5 -1.4 -1.3 -1.2 -1.1 -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1
## [31] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4
## [46] 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9
## [61] 3.0
seq(-3, 3, length = 50)
## [1] -3.00000000 -2.87755102 -2.75510204 -2.63265306 -2.51020408 -2.38775510
## [7] -2.26530612 -2.14285714 -2.02040816 -1.89795918 -1.77551020 -1.65306122
## [13] -1.53061224 -1.40816327 -1.28571429 -1.16326531 -1.04081633 -0.91836735
## [19] -0.79591837 -0.67346939 -0.55102041 -0.42857143 -0.30612245 -0.18367347
## [25] -0.06122449 0.06122449 0.18367347 0.30612245 0.42857143 0.55102041
## [31] 0.67346939 0.79591837 0.91836735 1.04081633 1.16326531 1.28571429
## [37] 1.40816327 1.53061224 1.65306122 1.77551020 1.89795918 2.02040816
## [43] 2.14285714 2.26530612 2.38775510 2.51020408 2.63265306 2.75510204
## [49] 2.87755102 3.00000000
rep(1, times = 5)
## [1] 1 1 1 1 1
rep(1, 5)
## [1] 1 1 1 1 1
rep(c(1,2), 5)
## [1] 1 2 1 2 1 2 1 2 1 2
1:10
## [1] 1 2 3 4 5 6 7 8 9 10
rep(1:10,5)
## [1] 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5
## [26] 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10
apply()
Las funciones de la familia apply son bastante utilizadas por su sencillez y “potencia”. En general, utilizan una matriz, lista o dataframe como input sobre la que se aplica una función. En muchas situaciones permite evitar crear loops cuando se escriben funciones. La familia apply está compuesta por varias funciones (apply, lapply, sapply, tapply, mapply, vapply, rapply), pero las más comunes es la función apply
.
Para ver los argumentos de la función apply() vamos a leer la ayuda de R.
help(apply)
Como vemos, apply() se utiliza para pasar una función (por ejemplo, si queremos calcular la media la función mean()) sobre una matriza, array, lista o dataframe (argumento X) bien por filas (MARGIN=1) o columnas (MARGIN=2).
Esquemáticamente:
Por ejemplo, vamos a calcular la media de las 5 primeras columnas de df
.
apply(df[,1:5], 2, mean)
y ahora un resumen:
apply(df[,1:5], 2, summary)
El objetivo que se persigue con el desarrollo de este caso es practicar lo visto hasta el momento e introducir el uso de funciones básicas de estadística para ver en contexto cómo utilizarlas.
Descargad dentro de la carpeta datos
el fichero de Excel que se encuentra en: https://www.uv.es/vcoll/curso_R_sfp/precio_casas.xlsx
Como podéis ver, son los datos de los precios de las casas que trabajamos anteriormente.
Cargad los datos y asignarlos al objeto datos.
library(tidyverse) # cargo esta librería porque más adelante comparamos algunas instrucciones de RBase con tidyverse.
library(rio) # si no se ha cargado en la sesión de trabajo
# Cargamos los datos. obervar los símbolos de asignación.
datos <- import("datos/precio_casas.xlsx") # el más habitual
datos2 = import("datos/precio_casas.xlsx")
import("datos/precio_casas.xlsx") -> datos3
rm(datos3) # elimino el objeto datos3
# ver los datos
View(datos)
# ver estructura de los datos
str(datos)
glimpse(datos) #tidyverse
# resumen de los datos
summary(datos)
# cambiar 1 variable character a factor
datos$prefer <- as.factor(datos$prefer)
summary(datos)
# cambiar todas las variables caracter a factor
datos[sapply(datos, is.character)] <- lapply(datos[sapply(datos, is.character)],
as.factor)
rm(datos)
datos <- datos2 %>% mutate_if(is.character,as.factor) # MÁS FÁCIL CON DPLYR!!!
# En la próxima sesión se explicará con más detenimiento.
summary(datos)
# tablas de frecuencias
freq_bed <- table(datos$bedrooms) # es una table
freq_bed2 <- datos %>% group_by(bedrooms) %>% count() # tb con tally
freq_cum_bed <- cumsum(freq_bed)
freq_cum_bed2 <- datos %>%
count(bedrooms) %>%
mutate(freq_cum = cumsum(n))
freq_rel_bed <- prop.table(freq_bed)
freq_cum_rel_bed <- cumsum(freq_rel_bed)
freq_rel_bed2 <- freq_cum_bed2 %>% mutate(freq_rel_bed2 = n / sum(n),
freq_cum_rel_bed2 = freq_cum / sum(n))
# tablas de valores agrupados
precio <- datos$price
precio2 <- cut(precio, seq(from = min(precio),
to = max(precio),
by = (max(precio) - min(precio))/20),
include.lowest=TRUE)
table(precio2) %>% as.data.frame()
# tabla cruzada
table(datos$bedrooms, datos$bathrooms)
library(descr) # En esta introducción, solo por curiosidad: crea tablas parecidas a las de SPSS
crosstab(datos$bedrooms, datos$bathrooms, prop.c = TRUE, plot = FALSE)
# MEDIDAS DE POSICION
mean(datos$bedrooms, na.rm = TRUE)
weighted.mean(freq_bed2$bedrooms,freq_bed2$n)
median(datos$bedrooms, na.rm = TRUE)
median(datos$bedrooms, na.rm = TRUE, type=5)
# type= 5 es más parecido a lo que suele encontrar en manuales
quantile(datos$bedrooms, c(.25,.5,.75), na.rm = TRUE, type = 5)
#install.packages("reldist")
library(reldist)
wtd.quantile(freq_bed2$bedrooms, 0.5, weight=freq_bed2$n, na.rm = TRUE)
wtd.quantile(freq_bed2$bedrooms, c(.25,.5,.75), weight=freq_bed2$n, na.rm = TRUE)
# cálculo de la moda: creo una función que detecta modas y omite los NAs
moda <- function(x) {
distintos_valores <- na.omit(unique(x)) # valores distintos
veces_x <- tabulate(match(x, distintos_valores)) # veces que se repite cada valor
distintos_valores[veces_x == max(veces_x)] # identifica los valores que mas se repiten
}
moda(datos$bedrooms)
# esto también permite identificar varias modas
moda2 <- table(datos$bedrooms)
names(moda2)[which(moda2==max(moda2))]
# instalar algún paquete que tenga la función built-in. Por ejemplo:
# los paquetes modeest -función mfv()- y DescTools -función Mode()-
#if (!require("remotes")) install.packages("remotes")
#remotes::install_github("AndriSignorell/DescTools")
# y si los datos se presentan en una tabla de frecuencias, ¿cómo calcular la moda?
datos2 <- data.frame("x" = c(1,2,3,1,2),
"n" = c(3,2,1,5,4))
datos2 %>% group_by(x) %>%
summarize(freq = sum(n)) %>%
arrange(desc(freq)) %>%
filter(freq == max(freq))
# MEDIDAS DE DISPERSION
datos %>% summarize(bed = n(),
varianza_muestral = var(datos$bedrooms),
desv_tip_muestral = sd(datos$bedrooms),
varianza_poblacional = ((bed-1)/bed)*varianza_muestral,
rango = max(bedrooms) - min(bedrooms),
IQR = IQR(bedrooms),
coef_var = desv_tip_muestral/mean(datos$bedrooms))
# medidas de forma
#install.packages("moments")
library(moments)
moments::skewness(datos$bedrooms)
moments::kurtosis(datos$bedrooms)
#install.packages("e1071")
library(e1071)
e1071::skewness(datos$bedrooms)
e1071::kurtosis(datos$bedrooms)
# covarianza (muestral) y correlación
cov(datos$bedrooms,datos$price)
cor(datos$bedrooms,datos$price)
# covarianza (poblacional)
((nrow(datos)-1) / nrow(datos)) * cov(datos$bedrooms,datos$price)
# matrices de var-covar (muestral) y correlación
var(datos[c(1,3,4)], na.rm = TRUE) # también: var(datos[,c(1,3,4)])
cov(datos[c(1,3,4)])
cor(datos[c(1,3,4)])
# matrices de var-cov (poblacional)
((nrow(datos)-1) / nrow(datos)) * var(datos[c(1,3,4)], na.rm = TRUE)
((nrow(datos)-1) / nrow(datos)) * cov(datos[c(1,3,4)])
# regresión lineal
modelo <- lm(price ~ bedrooms, data= datos)
summary(modelo)
modelo$coefficients
modelo$fitted.values # fitted.values(modelo)
modelo$residuals # residuals(modelo)
str(summary(modelo))
summary(modelo)$r.squared
Albert, J. y Rizzo, M. (2012). R by Example. Concepts to Code. Springer. (Este manual está disponible en línea para usuarios de la Universitat de València).
FUNDAMENTAL!!! R for Data Science de Garrett Grolemund y Hadley Wickham
La guía definitiva de Rmarkdwon de Yihui Xie
Para facilitarnos la vida con latex: