Capítulo 5 Funciones

5.1 Resumen

En este capítulo:

  • Finalizamos la introducción a algunos de los elementos básicos del trabajo estadístico en R: objetos, bases de datos y funciones.
  • Mostramos cómo aplicar funciones existentes y cómo escribir funciones nuevas que nos ayuden a analizar datos.
  • Ilustramos el potencial de ambas cuestiones con una corta aplicación a la política colombiana.

Principales conceptos: función; datos no disponibles (NA); estadísticas resumen.

Funciones clave: mean(); table(); cor(); is.na(); function().

5.1.1 Librerías

Vamos a utilizar las siguientes librerías:

library(tidyverse)

5.1.2 Datos

Debemos descargar los siguientes archivos de datos y guardarlos en la carpeta /data de nuestro proyecto:

  • Datos de ingreso ficticios: link. Para descargar, hacer click derecho, “Guardar como…”.

5.2 Qué es una función

En general, queremos hacer algo con los objetos en R (o sea, con los datos). Como ya hemos visto, en R hacemos operaciones usando funciones que toman un input y producen un output tras un procedimiento. Podemos aplicale funciones a valores individuales, vectores, bases de datos, variables y otros objetos.

Recapitulando, una función toma un input, le aplica una operación y nos devuelve un output. Por ejemplo, en la función \(f(x) = x + 1\):

  • Input: la información que queremos transformar (\(x\)).
  • Operación: la transformación o relación (\(x + 1\)).
  • Output: el resultado de aplicar la función (si \(x = 1\), entonces \(f(x) = 1 + 1 = 2\)).

En R, esto se vería así:

# definimos la funcion
sumar_uno <- function(a){a + 1}
# definimos unos valores para evaluar la funcion
x <- 1
# aplicamos la funcion a esos valores
sumar_uno(x)
## [1] 2

Si quisiéramos aplicar esta función a más de un valor al mismo tiempo:

# definimos unos valores para evaluar la funcion
var <- 1:10
# aplicamos la funcion a esos valores
sumar_uno(var)
##  [1]  2  3  4  5  6  7  8  9 10 11

En R, las funciones toman argumentos, separados por comas: nombre_funcion(argumento1 = valor, argumento2 = valor, ...). Por ejemplo, para encontrar la mediana de un vector, usamos median(). Esta función toma como primer argumento un vector para encontrar el valor mediano. Adicionalmente, puede tomar un argumento na.rm = con un valor TRUE o FALSE (na.rm = FALSE o na.rm = TRUE) que elimina los valores NA antes de hallar la mediana. Veamos qué pasa si tenemos un valor NA e intentamos calcular la mediana:

mis_numeros <- c(1, 1, 2, 3, 5, 8, 13, 21, 34, NA)
median(mis_numeros)
## [1] NA

Como hay un NA en mis_numeros, R no puede estimar la mediana del vector. Por eso, usamos el argumento na.rm = TRUE:

median(mis_numeros, na.rm = TRUE)
## [1] 5

Podemos consultar los argumentos de una función y sus valores por defecto ejecutando ? en la consola, seguido del nombre de la función. Por ejemplo, intenten ejecutar ?median o ?tibble:

?tibble

Es posible especificar los argumentos de una función de manera explícita o implícita. Cuando hacemos explícito un argumento, usamos el nombre del argumento, como hicimos arriba con na.rm =. Aquí hacemos lo mismo con la función rnorm() y los argumentos mean = y sd =:

set.seed(42) # para asegurar replicabilidad
head(rnorm(n = 10000, mean = 0, sd = 1))
## [1]  1.3709584 -0.5646982  0.3631284  0.6328626  0.4042683 -0.1061245

En contraste, podemos dejar los argumentos implícitos. Cada función tiene un orden predefinido de sus argumentos; podemos consultar este orden para una función con ?. El siguiente bloque de código es equivalente al anterior:

head(rnorm(10000, 0, 1)) # diferencias en el resultado son producto de la aleatoriedad de rnorm()
## [1]  1.1631089 -0.1902346 -0.2894558 -0.3988458  0.7092426 -1.6226473

Muchas funciones tienen valores por defecto para cada argumento. En el caso de rnorm(), mean = 0 y sd = 1 a menos que los definamos de manera diferente. Podemos comprobarlo:

normal_sim <- rnorm(10000)
mean(normal_sim)
## [1] 0.008092089
sd(normal_sim)
## [1] 1.01399

Podemos cambiar el orden en que van los argumentos si usamos sus nombres (o sea, si somos explícitos):

head(rnorm(mean = 0, sd = 1, n = 10000))
## [1]  0.680923388  1.013496371 -0.009105223  0.560053416 -1.478541110
## [6]  0.952096837

Comparen lo anterior con el siguiente código que produce 1 observación distribuida normalmente, con media de 10000 y desviación estándar de 0.

head(rnorm(1, 10000, 0))
## [1] 10000

5.3 Funciones básicas

Hay funciones básicas para crear o modificar objetos en R. Muchas ya vienen instaladas y ya hemos usado varias. Otras funciones están en librerías adicionales que descargamos y cargamos, como las del tidyverse. Aquí hay algunos ejemplos:

  • c() pega, combina o concatena valores y objetos.
  • data.frame() crea un marco de datos; tibble() crea un tibble.
  • read_csv() y read_dta() leen archivos de datos CSV o de Stata, respectivamente.
  • as_tibble para convertir un data.frame u otro objeto existente en un tibble.
  • as.factor() para convertir una variable numérica en una categórica y factor() para crear un factor (una variable categórica).
    • Además, funciones de la librería forcats para trabajar con factores.
  • as.numeric(), as.character(), etc.

A continuación, revisamos algunas funciones centrales para usar R en el contexto de hacer análisis de datos.

5.3.1 Estadisticas resumen

Algunas funciones básicas resumen datos numéricos. Estas incluyen median(), mean() y muchas más. Por ejemplo:

sum(mis_numeros, na.rm = TRUE) # suma todos los elementos del vector
## [1] 88
min(mis_numeros, na.rm = TRUE) # encontrar el valor mínimo
## [1] 1
max(mis_numeros, na.rm = TRUE) # encontrar el valor máximo
## [1] 34
range(mis_numeros, na.rm = TRUE) # rango (mínimo y máximo)
## [1]  1 34

Hablando de resumir, en R usamos la función round() para redondear variables numéricas. pi es una función de R que nos da el valor de la constante \(\pi\). Especificamos el número de dígitos de \(\pi\) después del decimal con el argumento digits =:

round(pi, digits = 2) # redondea al segundo decimal
## [1] 3.14

Finalmente, podemos hacer resúmenes de objetos más grandes –por ejemplo, una base de datos– con summary(). Este resumen incluye información importante sobre cada columna/variable:

summary(mtcars)
##       mpg             cyl             disp             hp       
##  Min.   :10.40   Min.   :4.000   Min.   : 71.1   Min.   : 52.0  
##  1st Qu.:15.43   1st Qu.:4.000   1st Qu.:120.8   1st Qu.: 96.5  
##  Median :19.20   Median :6.000   Median :196.3   Median :123.0  
##  Mean   :20.09   Mean   :6.188   Mean   :230.7   Mean   :146.7  
##  3rd Qu.:22.80   3rd Qu.:8.000   3rd Qu.:326.0   3rd Qu.:180.0  
##  Max.   :33.90   Max.   :8.000   Max.   :472.0   Max.   :335.0  
##       drat             wt             qsec             vs        
##  Min.   :2.760   Min.   :1.513   Min.   :14.50   Min.   :0.0000  
##  1st Qu.:3.080   1st Qu.:2.581   1st Qu.:16.89   1st Qu.:0.0000  
##  Median :3.695   Median :3.325   Median :17.71   Median :0.0000  
##  Mean   :3.597   Mean   :3.217   Mean   :17.85   Mean   :0.4375  
##  3rd Qu.:3.920   3rd Qu.:3.610   3rd Qu.:18.90   3rd Qu.:1.0000  
##  Max.   :4.930   Max.   :5.424   Max.   :22.90   Max.   :1.0000  
##        am              gear            carb      
##  Min.   :0.0000   Min.   :3.000   Min.   :1.000  
##  1st Qu.:0.0000   1st Qu.:3.000   1st Qu.:2.000  
##  Median :0.0000   Median :4.000   Median :2.000  
##  Mean   :0.4062   Mean   :3.688   Mean   :2.812  
##  3rd Qu.:1.0000   3rd Qu.:4.000   3rd Qu.:4.000  
##  Max.   :1.0000   Max.   :5.000   Max.   :8.000

Más adelante, veremos cómo crear tablas con estadísticas resumen.

5.3.2 Datos NA o no disponibles

A veces, no tenemos información para una observación y/o una variable. Decimos entonces que el dato no está disponible (en inglés, “not available” o N/A). R tiene un tipo de datos específicamente para esta situación: NA. Para saber si tenemos NA en un objeto (y dónde están), usamos is.na(), lo cual nos da una respuesta lógica (TRUE o FALSE) a nuestra pregunta:

is.na(mis_numeros)
##  [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE

Si queremos contar cuántos NA tenemos en un vector, podemos aprovechar que los vectores lógicos como el producido por is.na() pueden ser “sumados”. Cada TRUE es igual a 1 y cada FALSE es igual a 0. Y si aplicamos la función sum(), obtenemos el número de NA en el vector:

sum(is.na(mis_numeros)) # contar cuantos NA
## [1] 1

Es importante entender que hay una diferencia importante entre datos verdaderamente no disponibles (que R marca como NA) y celdas vacías o con valores como "N/A", "No disponible" o incluso "NA". También es distinto a códigos de valores no disponibles que a veces se utilizan en bases de datos (como -99). R interpreta estos como valores, no como datos no disponibles:

is.na(c(1, 3, NA, "N/A", "No disponible", "NA", -99))
## [1] FALSE FALSE  TRUE FALSE FALSE FALSE FALSE

Más adelante veremos cómo convertir estos en verdaderos NA.

5.3.3 Dimensiones de un objeto

Podemos ver cuantos elementos tiene un objeto y cuáles son sus dimensiones. Carguemos una base de datos que creamos en un capítulo anterior:

datos_ingreso <- read_csv("data/datos_ingreso.csv")
## 
## -- Column specification --------------------------------------------------------
## cols(
##   nombre = col_character(),
##   edad = col_double(),
##   ciudad = col_character(),
##   ingreso = col_double()
## )
datos_ingreso
## # A tibble: 7 x 4
##   nombre     edad ciudad       ingreso
##   <chr>     <dbl> <chr>          <dbl>
## 1 José         28 Barranquilla 8000000
## 2 Antonio      25 Medellín     4000000
## 3 María        32 Medellín     9500000
## 4 Inés         30 Medellín     7300000
## 5 Pablo        35 Barranquilla 6500000
## 6 Catalina     33 Bogotá       6000000
## 7 Cristóbal    42 Bogotá       9000000

Ahora, miremos sus dimensiones:

length(datos_ingreso$nombre) # cuantos elementos en un vector (filas en una columna)
## [1] 7
nrow(datos_ingreso) # número de filas
## [1] 7
ncol(datos_ingreso) # número de columnas
## [1] 4
dim(datos_ingreso) # dimensiones (filas por columnas)
## [1] 7 4

Vemos que esta base de datos tiene 7 filas y ncol(datos_ingreso) columnas.

5.3.4 Medidas de tendencia central y de dispersión

Las medidas de tendencia central y de dispersión son dos pilares de los cursos de estadística de bachillerato y universidad. Supongamos que tenemos una variable distribuida normalmente, con una media de 5 y una desviación estándar de 2. Creemos un vector con esas características:

x <- rnorm(1000, mean = 5, sd = 2)

Tomemos ese vector y miremos dos medidas de tendencia central:

mean(x) # media aritmética
## [1] 5.058195
median(x) # mediana
## [1] 5.029246

Y ahora, dos de dispersión:

sd(x) # desviación estándar
## [1] 1.933959
var(x) # varianza
## [1] 3.740196

La estadística descriptiva e inferencial depende crucialmente de medidas de dispersión y de tendencia central como estas.

5.3.5 Relaciones entre variables

Con frecuencia, no nos interesa saber algo sobre una variable aislada. Más bien, queremos ver cómo se relaciona con otras. Digamos que queremos calcular el coeficiente de correlación entre x como la definimos arriba y otra variable y definida así:

y <- rnorm(1000, 10, 3) # argumentos implícitos

¿Cuál es la correlación? Usemos la función cor():

cor(x, y)
## [1] -0.000156751

Podemos aprovechar las propiedades de los vectores en R para crear nuevos objetos a partir de los ya existentes, como una vector de valores z que dependen del valor de x:

z <- x + 3

En este caso, la correlación entre x y z es perfecta porque una está definida en términos de la otra, sin distorsión alguna:

cor(x, z)
## [1] 1

Pero podría haber algo de distorsión, que agregamos aquí con e, una variable aleatoria con distribución normal:

e <- rnorm(1000)
z <- x + e
cor(x, z)
## [1] 0.8890784

cor() funciona también con bases de datos. Por ejemplo, veamos que en nuestros datos ficticios de ingreso individual hay una correlación positiva entre edad e ingreso:

cor(datos_ingreso$edad, datos_ingreso$ingreso)
## [1] 0.5456026

5.4 Anidar funciones

No estamos limitados a utilizar una función a la vez. En R, es fácil usar múltiples funciones al mismo tiempo para realizar operaciones más complejas. Para esto, las “anidamos”. El orden de operaciones es sencillo: se leen de adentro hacia afuera. Pero esto a veces puede ser confuso – ¡hay que tener cuidado con los paréntesis!

round(mean(mis_numeros, na.rm = TRUE)) # si no especificamos, redondea al primer decimal
## [1] 10
(mean(x) - mean(y))^2
## [1] 23.94037

Más adelante, vamos a introducir el operador %>% (“pipe”, tubo o tubería) de la librería magrittr (y usado extensivamente en el tidyverse), una aproximación que no exige anidar funciones, simplifica la lectura del código y facilita realizar operaciones complejas. Como abrebocas, podemos reescribir la primera operación del bloque de código anterior de la siguiente manera:

# tomamos nuestro vector
mis_numeros %>%
  # se lo pasamos a una funcion para calcular la media
  # noten que si el objeto pasa a ser el primer argumento de la funciona no tenemos que nombrarlo
  mean(na.rm = TRUE) %>%
  # redondeamos el resultado de ese calculo
  round()
## [1] 10

5.5 Tablas y resúmenes

Hay funciones para contar o hacer resúmenes de variables cualitativas. Por ejemplo, table() crea una tabla sencilla que cuenta cuántas veces aparece cada número en el vector mis_numeros. Todos, excepto el número 1, aparecen una sola vez.

table(mis_numeros)
## mis_numeros
##  1  2  3  5  8 13 21 34 
##  2  1  1  1  1  1  1  1

A veces queremos “cruzar” variables categóricas, esto es, ver cuántas observaciones tienen distintas combinaciones de valores de dos variables. table() también sirve para hacer lo que llamamos una tabla cruzada, tabulación cruzada o tabla de contingencia entre dos variables discretas o categóricas. En este caso, el tipo de transmisión y el número de cilindros de los carros en mtcars:

table(mtcars$am, mtcars$cyl)
##    
##      4  6  8
##   0  3  4 12
##   1  8  3  2

¿Cuántos carros de 8 cilindros en esta muestra tienen transmisión automática?

5.6 Escribir funciones

A veces no existe la función para lo que queremos hacer. Podemos crear nuestras propias funciones para hacer otras operaciones o incluso construir indicadores – ¿o cómo creían que se calculaba el coeficiente de Gini o la volatilidad electoral? Con frecuencia, esta parte del trabajo es considerada “programación”, pero en realidad cualquier serie de operaciones es un “programa”. Ya hemos escrito funciones propias en un par de ocasiones (¿sí saben dónde?).

Las funciones también son útiles cuando queremos hacer algo muchas veces o cuando queremos simplificar nuestro código. Algunos sugieren que si hacemos la misma operación mas de 2 veces, deberíamos escribir una función.6

El proceso para crear una función en R tiene tres pasos:

  1. Darle un nombre descriptivo a la función (calc_indicador en vez de mi_funcion).
  2. Listar los argumentos que toma.
  3. Escribir el código que especifica las operaciones que realiza.

Este proceso lo hacemos con la función function().

Como ejercicio, escribamos una función. Digamos que queremos tomar unos datos numéricos y ponerlos en una escala que vaya de 0 a 1, donde 1 sea el valor más alto. Formalmente, lo que queremos hacer se puede representar de la siguiente manera:

\[ f(x) = (x - min) / (max - min) \]

Donde \(x\) es un vector numérico, \(min\) es el valor mínimo del vector y \(max\) el valor máximo. Así, cada valor de \(x\) va a tener un nuevo valor entre 0 y 1.

Para crear la función en R, seguimos los tres pasos especificados arriba. Primero, le damos nombre a la función: digamos reescalar01. Segundo, definimos qué argumentos toma la función: en este caso, uno solo, que vamos a llamar x. Tercero, escribimos el código de la operación que realiza nuestra función:

# nombre y argumentos de la función
reescalar01 <- function(x){ 
  # operaciones
  minimo <- min(x, na.rm = TRUE) # encontrar el mínimo y guardarlo
  maximo <- max(x, na.rm = TRUE) # encontrar el máximo y guardarlo
  reescalados <- (x - minimo) / (maximo - minimo) # calcular
  # resultado
  return(reescalados)
}

Aplicamos nuestra función a un vector de números cualquiera:

vector_num <- c(0, 25, 60, 80)
reescalar01(vector_num)
## [1] 0.0000 0.3125 0.7500 1.0000

5.6.1 Media aritmética

Ahora supongamos que queremos hallar la media de un conjunto de datos numérico. Y ahora supongamos que esa función no existe ya en R (sí existe, pero supongamos…). ¡Podemos escribir una función! Formalmente, la media \(m\) de un conjunto \(x\) se define como:

\[ m = \frac{\sum(x_i)}{n} \]

Donde \(x_i\) son todos los valores de \(x\) y \(n\) es el número de observaciones. Entonces, creamos un objeto llamado media que es la función. Esa función recibe un solo argumento, que aquí llamamos z. La función toma z, suma todos sus elementos y los divide por el numero de elementos, antes de “devolvernos” el resultado:

# nombre y argumentos de la función
media <- function(z){
  # operaciones
  med <- sum(z)/length(z)
  # resultado
  return(med)
}

Apliquemos la función para ver si sirve:

media(vector_num)
## [1] 41.25

Afortunadamente, ya sabemos que R cuenta con una función que calcula la media. Comparemos ambas. El operador lógico == evalúa si dos objetos son idénticos (estrictamente iguales), así que podemos utilizarlo para evaluar si nuestra función está funcionando como queremos:

media(vector_num) == mean(vector_num)
## [1] TRUE

¡Muy bien!

5.6.2 Número efectivo de partidos

Queremos saber cuántos partidos efectivos hay en una legislatura o congreso. Escribimos una función siguiendo la formula clásica de M. Laakso y R. Taagepera.7 Formalmente:

\[ NEP = \frac{1}{\sum_{i=1}^{n}{p_i^2}} \] Donde \(NEP\) es el indicador del número efectivo de partidos, \(n\) el número de partidos \(i\) que ganaron votos o curules y \(p_i\) es la proporción de votos o de curules obtenidas por cada partido.

Para implementar esta función en R, empezamos por asignarle un nombre: nep. Siguiendo la fórmula, esta tiene un solo argumento: votos =, el número de votos o curules por partido. Vamos a suponer que no tenemos proporciones aún, solo votos o curules. Entonces, hallamos la proporción del total de votos que obtuvo cada partido: dividimos los votos de cada partido por el total de votos con sum(). Elevamos al cuadrado esa proporción usando el operador ^. Finalmente, sumamos los cuadrados de las proporciones con sum() y hallamos el inverso (dividimos sobre 1):

# nombre y argumentos de la función
nep <- function(votos){
  # operaciones
  proporcion_votos <- votos/sum(votos) # hallar prop.
  proporcion_votos2 <- proporcion_votos^2 # elevar prop. al cuadrado
  sum_proporcion_votos2 <- sum(proporcion_votos2) # sumar props.
  nep <- 1/sum_proporcion_votos2
  # resultado
  return(nep)
}

Ahora, solo necesitamos unos resultados electorales para probar nuestra función, específicamente cuántos votos o curules sacaron todos los partidos. Como primera prueba, creamos un vector con números de votos de una elección ficticia dominada por el partido B:

eleccion1 = tibble(
  partido = LETTERS[1:6],
  num_votos = c(10000, 500000, 35000, 66000, 3000, 1700)
)

Veamos estos datos:

eleccion1
## # A tibble: 6 x 2
##   partido num_votos
##   <chr>       <dbl>
## 1 A           10000
## 2 B          500000
## 3 C           35000
## 4 D           66000
## 5 E            3000
## 6 F            1700

Aplicamos la función a los datos y obtenemos el resultado, un NEP bastante bajo:

nep(eleccion1$num_votos)
## [1] 1.482585

Intentemos aplicar la función a un conjunto de datos distinto en el que los votos están distribuidos más y con más partidos:

eleccion2 <- tibble(
  partido = LETTERS[1:8],
  num_votos = c(10000, 30000, 20000, 25000, 13000, 18000, 3000, 4000)
)
eleccion2
## # A tibble: 8 x 2
##   partido num_votos
##   <chr>       <dbl>
## 1 A           10000
## 2 B           30000
## 3 C           20000
## 4 D           25000
## 5 E           13000
## 6 F           18000
## 7 G            3000
## 8 H            4000

El resultado es bastante diferente y refleja la distribución de votos en este contexto:

nep(eleccion2$num_votos)
## [1] 5.949273

5.7 Ejercicio: partidos en el Congreso colombiano, 2018-2022

Las elecciones ficticias de la sección anterior están muy bien, ¿pero sí podemos usar nuestra función en un conjunto de datos reales? ¿Cuántos partidos efectivos hay en la Cámara de Representantes de Colombia en la legislatura 2018-2022? Intentemos responder esta pregunta aplicando la función que acabamos de escribir. Para eso, necesitamos datos.

Como pueden ver (list.files("data/")), no contamos con una base de datos con información sobre los partidos colombianos y sus votos o curules… Pero, podemos crearla con información fácilmente disponible: Wikipedia. Recuperar información de una página web que no tiene un archivo de datos se conoce como web scraping y es precisamente lo que vamos a hacer.

Para este ejercicio, nos vamos a apoyar en varias funciones de la librería rvest (también del tidyverse). Son varios pasos:

  • Especificamos la URL de la página de Wikipedia que tiene los resultados de las elecciones a Congreso de 2018 (read_html()).
  • Usando trucos de magia,8 le señalamos a R qué elemento en la página web tiene la información que queremos usar (html_node()) y le decimos que se trata de una tabla (html_table()).
  • Limpiamos un poco las variables dentro de la función mutate():
    • La librería janitor nos permite limpiar un poco los nombres de las variables con clean_names()
    • Convertimos la variable escanos de texto a número con as.numeric().
    • Codificamos los nombres de candidatos más votados no disponibles (partidos con lista cerrada) como NA.
    • Eliminamos los puntos en la variable votos y la convertimos de texto a número.
  • Desechamos las dos últimas filas de la tabla con slice(), pues se trata de los totales y una nota al pie que venía en la tabla original de Wikipedia.

En todo el proceso, nos apoyamos en el operador %>% para simplificar el código -menos funciones anidadas- y leerlo de manera lineal:

# cargar librerias adicionales
library(rvest)
library(janitor)

# definir la URL donde esta la informacion
url <- "https://es.wikipedia.org/wiki/Elecciones_legislativas_de_Colombia_de_2018"

# crear la base de datos
camara2018 <- url %>%
  # leer la url como html
  read_html() %>%
  # señalar el elemento que contiene la tabla
  html_node(xpath = '//*[@id="mw-content-text"]/div[1]/table[3]') %>%
  # extraer la tabla
  html_table() %>%
  # convertir a tibble
  as_tibble() %>%
  # homogeneizar nombres de variables
  clean_names() %>%
  # eliminar ultimas filas de la tabla
  slice(1:(n()-2)) %>%
  # modificar variables
  mutate(
    escanos = as.numeric(escanos),
    candidato_a_mas_votado_a = na_if(candidato_a_mas_votado_a, "—"),
    votos = str_remove_all(votos, "\\.") %>% as.numeric()
  )

Después de todo esto, tenemos esta pequeña base de datos:

camara2018
## # A tibble: 13 x 5
##    partido_o_movimiento            votos porcentaje candidato_a_mas_vot~ escanos
##    <chr>                           <dbl> <chr>      <chr>                  <dbl>
##  1 Partido Liberal Colombiano     2.47e6 16,57%     Nubia López Morales       35
##  2 Centro Democrático             2.39e6 16,19%     Edward David Rodríg~      32
##  3 Partido Cambio Radical         2.14e6 14,23%     Hernando José Padau~      30
##  4 Partido Social de Unidad Naci~ 1.84e6 12,13%     Wilmer Ramiro Carri~      25
##  5 Partido Conservador Colombiano 1.82e6 12,14%     Yamil Hernando Aran~      21
##  6 Alianza Verde                  8.84e5 6,04%      Inti Raúl Asprilla ~       9
##  7 Polo Democrático Alternativo   4.45e5 3,00%      Germán Navas Talero        2
##  8 Opción Ciudadana               3.11e5 2,04%      Franklin Lozano de ~       2
##  9 Partido MIRA                   5.52e5 3,98%      Irma Luz Herrera Ro~       1
## 10 Lista de la Decencia           2.55e5 1,84%      Maria José Pizarro         2
## 11 Colombia Justa Libres          1.10e5 0,79%      <NA>                       1
## 12 Alternativa Santandereana (Po~ 7.12e4 0,51%      <NA>                       1
## 13 Colombiano Dignidades por Col~ 4.40e4 0,30%      César Augusto Pachó~       1

Si la queremos guardar para después, podemos crear un archivo tipo CSV:

write_csv(camara2018, "data/camara2018.csv")

Esto también significa que los datos están disponibles para descargar directamente en este link para cargar en una sesión de R. Así, pueden completar el ejercicio sin hacer el web scraping.

Ahora, por fin, estamos listos para calcular el número efectivo de partidos en la Cámara. En este caso, como la fórmula del NEP está diseñada tanto para votos (NEP electoral), como para curules (NEP parlamentario), podemos hacer el cálculo con el número de escaños o curules.

Entonces: ¿cuántos partidos hay en la Cámara de Representantes colombiana en el periodo 2019-2022?


  1. Wickham, Hadley, y Garrett Grolemund. R for Data Science: Import, Tidy, Transform, Visualize, and Model Data. O’Reilly Media, 2016.↩︎

  2. Si estamos en RStudio Cloud, debemos empezar por subirlos y ubicarlos en una carpeta dentro del proyecto. Vamos al panel inferior derecho, pestaña Files, click en Upload y seguimos las indicaciones.↩︎

  3. Hagan clic derecho en la página de Wikipedia y escojan la opción “Inspeccionar”.↩︎