Crear nuevo proyecto

Para que mantengas un buen orden en tu aprendizaje, es momento de crear un nuevo proyecto en el que irás anotando todo lo que aprendas en esta sesión. Cabe mencionar que todo lo que anotes deberás publicarlo al final en tu perfil de Rpubs.com

  • Crear un nuevo proyecto en nuevo directorio: “04-ejercicios”
  • Publica el resultado de ejecutar getwd() en la consola una vez creado el proyecto.

Instala el paquete de ejercicios

Puedes instalar la versión más reciente de ejerciciosT2 desde el r-universe de talleresdedatos con:

install.packages("ejerciciosT2", repos = 'https://talleresdedatos.r-universe.dev')

O desde el repositorio en Github con:

remotes::install_github("talleresdedatos/ejerciciosT2")

Ejercicios de repaso

Ejercicio 1

Crea un archivo R Markdown a partir de la plantilla T2-04 Repaso de documento de referencia. Guardala con el nombre “repaso.Rmd”

Ejercicio 2

Completa las secciones faltantes del documento. Puedes crear funciones para lograrlo.

Ejercicio 3

Crea un documento de referencia y úsalo en el encabezado YAML. Modifica todos los estilos de texto para tener espacio antes y después del párrafo.

Opcionalmente, modifica el formato del texto (tamaño, color, tipo de fuente).

Ejercicio 4

Adapta el documento de tal manera que te permita hacer uso de parámetros. Comprueba el funcionamiento de los parámetros haciendo la comparación entre Europa (Europe) y Asia (Asia).

Environments

Créditos

Buena parte de lo que se verá en esta sección es una adaptación breve del capítulo “Environments” del libro Advanved R de Hadley Wickham.

Recomiendo su lectura. Personalmente, fue el libro que me hizo enamorarme de R y entender todo lo que no entendía tan solo con la práctica diaria.

Quiero decir explícitamente que los ejemplos y expresiones usadas para ilustrar esta sesión, no son 100% correctos técnicamente, sin embargo están diseñados para aportar claridad a la explicación.

Objetos básicos de R

Hasta el momento hemos ido conociendo algunos objetos con los que se trabajan típicamente en R. Por mencionar algunos:

  • Operador: Es un símbolo que nos permite realizar operaciones dentro de nuestra sesión. En su forma básica, permite realizar operaciones aritméticas, relacionales y lógicas.
  • Vector: La estructura básica de almacenamiento de datos en R. En su forma básica, pueden contener valores de tipo lógico (logical), numérico (integer y double) y de texto (character).
  • Dataframe: Es la manera en que R almacena datos tabulares. Dentro de ellos, cada fila puede corresponder a una observación y cada columna a una variable. Se forma a partir de vectores.
  • Función: Es la manera en que R almacena la lógica de una operación para obtener un output. Puede contener argumentos, que sirven como input en la operación definida. Es posible utilizar funciones dentro de otras funciones.

Scoping

Cada vez que referenciamos el nombre de un objeto en una operación, debemos tomar en cuenta el contexto en el que se va a ejecutar esa operación. El contexto es lo que conocemos como “Environment”.

En RStudio tienes un panel en el que puedes inspeccionar el contenido de tu Environment. Por defecto, este panel muestra el contenido de los valores que vas creando dentro de tu sesión de R.

Por ejemplo, si creas el siguiente vector:

mi_vector <- 1:100

El panel Environment te mostrará un objeto llamado “mi_vector” y te dará una vista previa de su contenido. Así, cada vez que creas un objeto en tu sesión, se va añadiendo o sobreescribiendo como objeto en tu panel Environment.

Cuando realizas una operación referenciando un objeto, R necesita encontrar el objeto que estás referenciando. Por ejemplo, para calcular la suma de los elementos de mi_vector:

sum(mi_vector)
## [1] 5050

R busca el objeto mi_vector en tu Environment. Si no lo encuentra, te avisará arrojando un error. Por ejemplo, si nos equivocamos al escribir mi_vector:

sum(MI_VECTOR)
## Error in eval(expr, envir, enclos): object 'MI_VECTOR' not found

Nos avisa que no ha encontrado el objeto que le hemos pedido.

En este estado, podemos pensar en R haciendo la siguiente búsqueda. Primero, en tu Environment, y luego en los paquetes “de inicio”. Si no encuentra el objeto en en esta búsqueda arroja un error.

Algo similar ocurre cuando queremos usar un objeto (data o funciones) de un paquete que tenemos instalado. A menos que lo hayamos cargado, R no será capaz de encontrarlo. Por ejemplo, si queremos usar la data gapminder.

gapminder
## Error in eval(expr, envir, enclos): object 'gapminder' not found

Es necesario que antes hayamos cargado el paquete que la contiene.

library(gapminder)
gapminder
## # A tibble: 1,704 x 6
##    country     continent  year lifeExp      pop gdpPercap
##    <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
##  1 Afghanistan Asia       1952    28.8  8425333      779.
##  2 Afghanistan Asia       1957    30.3  9240934      821.
##  3 Afghanistan Asia       1962    32.0 10267083      853.
##  4 Afghanistan Asia       1967    34.0 11537966      836.
##  5 Afghanistan Asia       1972    36.1 13079460      740.
##  6 Afghanistan Asia       1977    38.4 14880372      786.
##  7 Afghanistan Asia       1982    39.9 12881816      978.
##  8 Afghanistan Asia       1987    40.8 13867957      852.
##  9 Afghanistan Asia       1992    41.7 16317921      649.
## 10 Afghanistan Asia       1997    41.8 22227415      635.
## # ... with 1,694 more rows

Una vez que cargaste el paquete gapminder, R realiza una búsqueda de la siguiente manera:

Como habrás notado, el environment que ves en tu panel de Rstudio es siempre el primer lugar en el que R buscará. Si no lo encuentra allí, acude a los paquetes que hayas llamado con library().

Scoping en funciones

Pongamos como ejemplo la función raiz_cuadrada().

raiz_cuadrada <- function(x) {
    x ** (1/2)
}

Vemos que hace uso del argumento x dentro de sus operaciones. ¿Qué pasa si queremos operador con x sin usar raiz_cuadrada()?

x + 1
## Error in eval(expr, envir, enclos): object 'x' not found

R nos avisa que no pudo encontrar a x. ¿Por qué sucede?

Cuando creamos una función, estamos creando un Environment artificial, donde los argumentos usados hacen las veces de objetos almacenados en ese Environment. En el caso anterior, R no puede encontrar x porque no está definido en ningún Environment.

Lo mismo sucede si llamamos a la función sin especificar el valor de x.

raiz_cuadrada()
## Error in raiz_cuadrada(): argument "x" is missing, with no default

Sin embargo, una vez que se especifica ese valor, la función opera sin problemas.

raiz_cuadrada(x = 400)
## [1] 20

La búsqueda que hace R al usar la función raiz_cuadrada() (en esta sesión de R) puede interpretarse de la siguiente manera:

Ejercicios

Ejercicio 1

Trata de predecir el resultado del siguiente bloque de código:

mi_valor <- 10

foo <- function() {
    mi_valor <- 100
    mi_valor
}

mi_valor

Ejercicio 2

Trata de predecir el resultado del siguiente bloque de código:

mi_valor <- 50

foo <- function(mi_valor = 20) {
    mi_valor <- 100
    mi_valor
}

mi_valor

Ejercicio 3

Trata de predecir el resultado del siguiente bloque de código:

mi_valor <- 5

foo <- function(mi_valor = 10) {
    mi_valor <- 20
    mi_valor
}

foo()

Tidy evaluation

Créditos

Esta sección es una adaptación del vignette Programming with dplyr.

Nuevamente, las explicaciones realizadas no son 100% técnicamente precisas, pero están diseñadas para aportar claridad a la explicación.

Variables

En nuestro trabajo con R, es común referirnos a las variables. Entendamos que podríamos estar utilizando este término con dos significados distintos:

  • Estadístico: Son las columnas de nuestro conjunto de datos. Aportan información acerca de nuestras observaciones.
  • Programación: Son los objetos que se crean dentro de un Environment, por ejemplo el de neustra sesión de R. Típicamente, se crean al usar el operador <- para asignarle nombre al resultado de ejecutar cierto código.

Fíjate en el siguiente código. country y year no están definidos en ningún environment, sin embargo el código no falla.

library(gapminder)
library(dplyr)

filter(gapminder, country == "Peru", year > 1990)
## # A tibble: 4 x 6
##   country continent  year lifeExp      pop gdpPercap
##   <fct>   <fct>     <int>   <dbl>    <int>     <dbl>
## 1 Peru    Americas   1992    66.5 22430449     4446.
## 2 Peru    Americas   1997    68.4 24748122     5838.
## 3 Peru    Americas   2002    69.9 26769436     5909.
## 4 Peru    Americas   2007    71.4 28674757     7409.

¿A qué se debe?

Las funciones del tidyverse están diseñadas para trabajar con conjuntos de datos (dataframes).

Cuando usamos funciones del tidyverse, las variables estadísticas, son interpretadas como variables de programación. Estas funciones entienden que las variables a las que se hace referencia son las variables del conjunto de datos.

Es por eso que no es necesario que existan previamente en algún Environment, y no generan error al ser utilizadas. Esto significa también que el primer lugar donde buscará los objetos referenciados será en las variables del conjunto de datos.

Ejercicio 5

Predice el resultado del siguiente bloque de código

library(gapminder)
library(dplyr)

gapminder %>% 
    filter(country == "Peru", year == 2007) %>% 
    select(country, year, lifeExp)

Ejercicio 6

Predice el resultado del siguiente bloque de código

library(gapminder)
library(dplyr)

my_year <- 2002

gapminder %>% 
    filter(country == "Peru", year == my_year) %>% 
    select(country, year, lifeExp)

Ejercicio 7

Predice el resultado del siguiente bloque de código

library(gapminder)
library(dplyr)

year <- 2002

gapminder %>% 
    filter(country == "Peru", year == year) %>% 
    select(country, year, lifeExp)

Funciones con tidy evaluation

Las funciones de dplyr nos permiten usar las variables de un conjunto de datos como variables de programación de tal manera que es más sencillo escribir código interactivamente.

Fíjate en los siguientes bloques de código

gapminder %>% 
    filter(country == "Peru") %>% 
    select(year, country, pop)
## # A tibble: 12 x 3
##     year country      pop
##    <int> <fct>      <int>
##  1  1952 Peru     8025700
##  2  1957 Peru     9146100
##  3  1962 Peru    10516500
##  4  1967 Peru    12132200
##  5  1972 Peru    13954700
##  6  1977 Peru    15990099
##  7  1982 Peru    18125129
##  8  1987 Peru    20195924
##  9  1992 Peru    22430449
## 10  1997 Peru    24748122
## 11  2002 Peru    26769436
## 12  2007 Peru    28674757

gapminder %>% 
    filter(country == "Peru") %>% 
    select(year, country, gdpPercap)
## # A tibble: 12 x 3
##     year country gdpPercap
##    <int> <fct>       <dbl>
##  1  1952 Peru        3759.
##  2  1957 Peru        4245.
##  3  1962 Peru        4957.
##  4  1967 Peru        5788.
##  5  1972 Peru        5938.
##  6  1977 Peru        6281.
##  7  1982 Peru        6435.
##  8  1987 Peru        6361.
##  9  1992 Peru        4446.
## 10  1997 Peru        5838.
## 11  2002 Peru        5909.
## 12  2007 Peru        7409.

gapminder %>% 
    filter(country == "Peru") %>% 
    select(year, country, lifeExp)
## # A tibble: 12 x 3
##     year country lifeExp
##    <int> <fct>     <dbl>
##  1  1952 Peru       43.9
##  2  1957 Peru       46.3
##  3  1962 Peru       49.1
##  4  1967 Peru       51.4
##  5  1972 Peru       55.4
##  6  1977 Peru       58.4
##  7  1982 Peru       61.4
##  8  1987 Peru       64.1
##  9  1992 Peru       66.5
## 10  1997 Peru       68.4
## 11  2002 Peru       69.9
## 12  2007 Peru       71.4

Lo único que cambia es la última variable seleccionada. Así que sabemos que esto podría convertirse en una función.

Estaríamos tentados a definir nuestra función así:

mi_tabla <- function(variable_escogida) {
    gapminder %>% 
    filter(country == "Peru") %>% 
    select(year, country, variable_escogida)
}

¿Qué pasa cuando intentamos usarla?

mi_tabla(variable_escogida = lifeExp)
## Error: object 'lifeExp' not found
mi_tabla(variable_escogida = gdpPercap)
## Error: object 'gdpPercap' not found

Esto se debe a que la ventaja de poder usar con facilidad los nombres de variable cuando escribimos código interactivamente (fuera de la definición de una función) vienen con el costo de tener que tratarlos de manera especial cuando programamos (escribimos funciones).

Cuando queremos usar el nombre de una variable del conjunto de datos como argumento de una función, debemos rodearlo un símbolo especial.

mi_tabla <- function(variable_escogida) {
    gapminder %>% 
        filter(country == "Peru") %>% 
        select(year, country, {{ variable_escogida }})
}

mi_tabla(variable_escogida = lifeExp)
## # A tibble: 12 x 3
##     year country lifeExp
##    <int> <fct>     <dbl>
##  1  1952 Peru       43.9
##  2  1957 Peru       46.3
##  3  1962 Peru       49.1
##  4  1967 Peru       51.4
##  5  1972 Peru       55.4
##  6  1977 Peru       58.4
##  7  1982 Peru       61.4
##  8  1987 Peru       64.1
##  9  1992 Peru       66.5
## 10  1997 Peru       68.4
## 11  2002 Peru       69.9
## 12  2007 Peru       71.4

mi_tabla(variable_escogida = gdpPercap)
## # A tibble: 12 x 3
##     year country gdpPercap
##    <int> <fct>       <dbl>
##  1  1952 Peru        3759.
##  2  1957 Peru        4245.
##  3  1962 Peru        4957.
##  4  1967 Peru        5788.
##  5  1972 Peru        5938.
##  6  1977 Peru        6281.
##  7  1982 Peru        6435.
##  8  1987 Peru        6361.
##  9  1992 Peru        4446.
## 10  1997 Peru        5838.
## 11  2002 Peru        5909.
## 12  2007 Peru        7409.

Ejercicio 8

Convierte el siguiente bloque de código en una función llamada tabla_promedio. Debe permitir elegir otra variable para obtener un promedio.

gapminder %>% 
    filter(year == 2007) %>% 
    group_by(continent) %>% 
    summarise(promedio = mean(lifeExp))
## # A tibble: 5 x 2
##   continent promedio
##   <fct>        <dbl>
## 1 Africa        54.8
## 2 Americas      73.6
## 3 Asia          70.7
## 4 Europe        77.6
## 5 Oceania       80.7

Ejercicio 9

Convierte el siguiente bloque de código en una función llamada tabla_medidas. Debe permitir elegir otra variable para obtener sus medidas.

gapminder %>% 
    filter(year == 1952) %>% 
    group_by(continent) %>% 
    summarise(
        promedio = mean(pop),
        mediana = median(pop)
    )
## # A tibble: 5 x 3
##   continent  promedio  mediana
##   <fct>         <dbl>    <dbl>
## 1 Africa     4570010. 2668124.
## 2 Americas  13806098. 3146381 
## 3 Asia      42283556. 7982342 
## 4 Europe    13937362. 7199786.
## 5 Oceania    5343003  5343003

Ejercicio 10

Convierte el siguiente bloque de código en una función llamada tabla_anualizada. Debe permitir elegir otra variable para obtener su promedio y además permitir escoger otro año.

gapminder %>% 
    filter(year == 1952) %>% 
    group_by(continent) %>% 
    summarise(promedio = mean(pop))
## # A tibble: 5 x 2
##   continent  promedio
##   <fct>         <dbl>
## 1 Africa     4570010.
## 2 Americas  13806098.
## 3 Asia      42283556.
## 4 Europe    13937362.
## 5 Oceania    5343003

Ejercicio 11

Convierte el siguiente bloque de código en una función llamada tabla_comparacion. Debe permitir elegir dos países y una variable de comparación para determinado año.

gapminder %>% 
    filter(year == 1952) %>% 
    filter(country %in% c("Colombia", "Mexico")) %>% 
    select(country, continent, year, lifeExp)
## # A tibble: 2 x 4
##   country  continent  year lifeExp
##   <fct>    <fct>     <int>   <dbl>
## 1 Colombia Americas   1952    50.6
## 2 Mexico   Americas   1952    50.8