[1] TRUE
Algunos datos sobre mí:
Un lenguaje de programación es un conjunto de intrucciones y reglas que permite a los humanos comunicar órdenes a una computadora.
R fue originalmente desarrollado para realizar análisis estadístico.
Sin embargo, actualmente también se ha consolidado como una potente herramienta para la manipulación de datos en general en diferentes áreas como las ciencias sociales, la ecología, la medicina, las finanzas, el marketing, etc.
Para instalar R (Agosto de 2024):
Para mayor detalle sobre la instalación, incluyendo cómo instalar R en macOS, revisar el capítulo de Pre-requisitos del libro r4pubh.
Un “código” se refiere al conjunto de instrucciones escritas en un lenguaje de programación, como R, que una computadora puede interpretar y ejecutar.
El código es la base de todos los programas y aplicaciones que utilizamos en nuestra vida diaria, desde simples calculadoras hasta complejos sistemas operativos y aplicaciones web.
Así como para escribir documentos usamos Word, también existen programas que nos permiten escribir código de manera eficiente.
A estos programas se les llama Integrated Development Environments (IDE).
RStudio es un IDE que fue desarrollado particularmente para escribir código en R.
Existen otros IDE donde podemos escribir código en R, pero ninguno es tan eficiente para este lenguaje como RStudio (hasta ahora).
Para instalar RStudio Desktop (Agosto de 2024):
Un proyecto en RStudio es una funcionalidad que proporciona un entorno de trabajo organizado y gestionado para trabajar con R.
Es recomendable crear un proyecto de RStudio asociado a cada proyecto de análisis de datos con R que realicemos.
Al crear un proyecto en RStudio, estamos creando una carpeta dedicada a nuestro proyecto de análisis de datos con R.
Para crear un proyecto en RStudio:
File > New Project
.Un script de R es un archivo de texto que contiene el código en R que usaremos para darle comandos a la computadora.
Los scripts de R tienen extensión .R
. Por ejemplo, para crear un script con el nombre hola.R
ingresamos en la consola:
Veremos que en la pestaña Files
en RStudio aparecerá el script de R que hemos creado. Esta pestaña sirve como un explorador de archivos.
En la parte superior podemos ver la ruta de la carpeta donde nos encontramos trabajando, la cual será la carpeta donde creamos el proyecto de RStudio.
En Files
podemos darle click al archivo hola.R
y se abrirá un panel de edición, el cual se le conoce como el editor de RStudio.
En este editor podemos escribir las líneas de código que queramos dentro del script y también ejecutar el código línea por línea, por partes, o en su totalidad.
En el editor, escribamos:
Y luego, con el cursor en la misma línea de código, demos click en Run
o presionemos Ctrl + Enter
para ejecutarlo.
En la consola veremos:
La consola es el lugar donde el código se ejectua.
Con “ejecutar” nos referimos a que los comandos que hemos escrito en R se traducen al lenguaje máquina para que la computadora nos pueda entender y devolver el resultado deseado.
¡Felicidades 🎉! Has creado tu primer programa con R.
Para crear nuestro primer programa con R, hemos utilizado una función llamada print()
.
Una función es un módulo de código diseñado para realizar una tarea específica.
En R, se denota a una función por su nombre, seguido de paréntesis ()
. Por ejemplo: print()
.
Las funciones reciben un conjunto de entradas o argumentos, que sirven para modificar su comportamiento, y devuelven una o varias salidas.
En nuestro programa, el argumento de print()
fue "¡Hola, mundo"
. Los argumentos se ingresan en una función separados por una coma.
La tarea específica de esta función es imprimir en la consola el argumento. La salida es el mismo argumento, solo que en este caso se devuelve de manera silenciosa.
Todas las funciones tienen una página de ayuda, donde se tiene documentado cómo usar la función y los argumentos que recibe.
La página de ayuda se mostrará en la pestaña de Help
.
También es posible usar esta pestaña para buscar la página de ayuda de una función.
¿Qué pasa si en vez de print
escribimos prin
?
Los mensajes de error de R nos precisan en qué parte del código hay un error.
Esto nos ayuda a la depuración o debugging de nuestro código.
¿Cómo haríamos si quisieramos saludar a un usuario en particular?
En R, podemos preguntarle su nombre al usuario utilizando la función readline()
.
readline()
devuelve lo que hayamos ingresado en la consola:
¿Cómo armamos el saludo?
Podemos usar el botón de Source
para ejectuar todo el código en este script.
¿Qué pasa si ingreso otro nombre?
Un objeto en R sirve para almacenar información.
Podemos darle un nombre a un objeto, y asignarle la información que queramos.
Así, cada vez que queramos usar la información almacenada, solo debemos llamar al nombre del objeto.
Almacenemos la salida de la función readline()
en un objeto llamado nombre
:
El símbolo <-
sirve para asignar o almacenar la salida de readline()
al objeto de nombre nombre
.
Vemos que en la pestaña de Environment
se ha creado un objeto con el valor de “Diego”.
Ahora veamos el saludo completo:
¿Por qué no sale mi nombre?
Hasta ahora, hemos usado texto representado como una cadena de caracteres para escribir los saludos.
Las cadenas de caracteres, o simplemente caracteres, se escriben en R dentro de comillas dobles (""
).
Al incluir nombre
dentro de las comillas en el texto del saludo, esta cadena se toma literalmente.
¿Cómo podríamos incluir los caracteres almacenados en el objeto nombre
?
Una opción es usar la función paste()
. Esta función convierte sus argumentos a cadenas de caracteres (si es que no lo son) y los concatena:
¿Por qué hay un espacio de más entre “Hola,” y “Diego”?
Si revisamos la página de ayuda de paste()
vemos que uno de sus argumentos es sep
, el cual sirve como separador entre las cadenas que se quieren concatenar.
Por defecto, sep
tiene el valor de " "
.
Si cambiamos el valor de sep
a ""
, vemos que ya no hay un espacio de más en el saludo:
Sin embargo, alguien creó una función cuyo argumento sep
ya tiene el valor por defecto ""
:
Podríamos haber escrito el mismo código en una sola línea:
A esto se le llama composición de funciones.
Obtenemos el mismo resultado. Pero, ¿es esta la mejor forma de escribirlo?
Podemos escribir notas en nuestro código para nosotros mismos o para otras personas usando comentarios. Para insertar un comentario, se escribe un numeral (#
) al inicio de la línea:
¡Trabajemos ahora con datos! Escribamos un programa que nos permita ingresar el conteo de casos confirmado de tres enfermedades:
R permite realizar operaciones aritméticas básicas usando los siguientes operadores:
+
para sumar,-
para restar,*
para multiplicar (multiplicación escalar),/
para dividir.¿Por qué nos sale error? Vemos que Environment
los valores que hemos ingresado se han guardado como cadenas de caracteres.
¿Se pueden sumar cadenas de caracteres (texto)?
R tiene diferentes modos para guardar información:
character
para caracteres o cadenas de caracteres,double
para números decimales,integer
para números enteros,También se les conoce como tipo de dato.
R permite transformar el modo de almacenamiento de un objeto coercitivamente usando funciones:
as.character()
para cambiar a modo character
,as.double()
para cambiar a modo double
,as.integer()
para cambiar a modo integer
,Estas funciones botarán un mensaje de error si es no es posible hacer la transformación.
Por ejemplo, no es posible convertir "Diego"
a un número, pero sí podemos convertir "32"
a un número.
Apliquemos el concepto de coerción:
dengue <- readline("Ingresa el número de casos de Dengue: ")
malaria <- readline("Ingresa el número de casos de Malaria: ")
lepto <- readline("Ingresa el número de casos de Leptospirosis: ")
as.integer(dengue)
as.integer(malaria)
as.integer(lepto)
total <- dengue + malaria + lepto
print(paste0("El número total de casos es: ", total))
Los cambios de modo de almacenamiento no se hacen automáticamente. Es necesario guardar o actualizar los valores con el nuevo modo de almacenamiento:
dengue <- readline("Ingresa el número de casos de Dengue: ")
malaria <- readline("Ingresa el número de casos de Malaria: ")
lepto <- readline("Ingresa el número de casos de Leptospirosis: ")
dengue <- as.integer(dengue)
malaria <- as.integer(malaria)
lepto <- as.integer(lepto)
total <- dengue + malaria + lepto
print(paste0("El número total de casos es: ", total))
Poder acortar el código usando composición de funciones:
dengue <- as.integer(readline("Ingresa el número de casos de Dengue: "))
malaria <- as.integer(readline("Ingresa el número de casos de Malaria: "))
lepto <- as.integer(readline("Ingresa el número de casos de Leptospirosis: "))
total <- dengue + malaria + lepto
print(paste0("El número total de casos es: ", total))
¿Qué pasaría si tuviéramos que sumar muchos valores? Definitivamente, tipear +
muchas veces no es eficiente.
Afortunadamente, R tiene una función llamada sum()
que permite calcular la suma de sus argumentos:
dengue <- as.integer(readline("Ingresa el número de casos de Dengue: "))
malaria <- as.integer(readline("Ingresa el número de casos de Malaria: "))
lepto <- as.integer(readline("Ingresa el número de casos de Leptospirosis: "))
total <- sum(dengue, malaria, lepto)
print(paste0("El número total de casos es: ", total))
Una tabla es un arreglo de información en filas y columnas:
Podemos usar esta tabla para calcular el número de casos total de dengue:
O el número total de casos confirmados:
A estas operaciones se les llama tabulaciones.
Una forma popular de almacenar tablas es usando archivos de valores separados por coma o CSV (Comma Separated Values). Por ejemplo, nuestra tabla en formato CSV se veería así:
enfermedad, confirmados, probables
Dengue, 37, 63
Malaria, 43, 107,
Leptospirosis, 25, 44
Creemos el archivo CSV de nuestra tabla usando las opciones New File > Text File
en RStudio. Dentro del archivo en blanco, ingresmos los valores separados por coma y luego guardemos el archivo con el nombre casos.csv
Es importante asegurarse que el nombre del archivo tenga la extensión .csv
.
Creemos un nuevo script de R para realizar las tabulaciones:
R tiene una función para leer un archivo con formato de tabla llamada read.table()
. El primer argumento de esta función es la ruta donde se ubica el archivo:
Podemos ver la tabla usando la función View()
:
R tiene una función para leer un archivo con formato de tabla llamada read.table()
. El primer argumento de esta función es la ruta donde se ubica el archivo:
Podemos ver la tabla usando la función View()
:
¡Esto no se ve bien!
Veamos la página de ayuda de read.table()
. Vemos que esta función posee un argumento llamado sep
para indicar qué separador de columnas tiene el archivo que queremos leer. En nuestro caso, el separador es la coma (","
):
¡Vamos bien!
Además, read.table()
tiene otro argumento llamado header
el cual puede tomar los valores lógicos TRUE
o FALSE
dependiendo de si nuestro archivo tiene los nombres de las columna en la primera línea o no, respectivamente. En nuestro caso, los nombres de las columnas sí están en la primera fila:
¡Ahora sí tenemos nuestra tabla!
Para mejorar la legibilidad del código, podemos escribir los argumentos en líneas separadas:
Los programadores son flojos. Uno de ellos creó una función llamada read.csv()
que hace lo mismo que read.table()
pero con los argumentos sep = ","
y header = TRUE
por defecto:
La salida que nos devuelve la función read.csv()
es un data frame. Un data frame en R es un modo de almacenamiento bidimensional (filas y columnas) que sirve para almacenar datos tabulares.
Podemos realizar diversas operaciones sobre un data frame, como acceder a los datos de las filas o columnas usando la notación de corchetes:
Por ejemplo, para acceder al número de casos confirmados de Dengue (el primer valor de la segunda columna):
Si quisiéramos acceder a todos los valores de una columna, demos el blanco el lugar de la fila. Por ejemplo, para acceder a la columna de casos confirmados:
En R:
¿Qué pasaría si cambio el orden de las columnas? Tendría que estar actualizando el número de la columna a la cual quiero acceder. Es más fácil acceder a los datos de una columna por su nombre.
En R, para acceder a una columna por su nombre escribimos el nombre del data frame, seguido del símbolo $
y el nombre de la columna. Por ejemplo, para acceder a la columna de los casos confirmados:
En R:
Cuando accedemos a una columna usando el símbolo $
, R nos devuelve un vector. Un vector es una lista de elementos del mismo tipo. Es decir, la salida no es más un data frame, sino un vector de datos.
Un vector es un arreglo unidimensional de datos, y por tanto también acepta la notación de corchetes. Por ejemplo, para acceder al primer elemento del vector de casos confirmados:
En un vector, ya no es necesario ingresar el número de fila y de columna, ya que solo tiene una dimensión.
¿Cómo podríamos calcular el número total de casos confirmados? Una opción es la siguiente:
Sin embargo, ¿qué pasaría si tenemos más de tres enfermedades? ¿Es esto eficiente?
Intentemos lo siguiente:
¿Por qué funciona?
Las funciones en R están vectorizadas. Es decir, operan sobre todos los elementos de un vector sin tener que operar uno por uno. Por esta razón, podemos usar la función sum()
para realizar la suma de todos los elementos del vector:
La cadena de caracteres que usamos para el salud es un vector (de un solo elemento):
Incluso un data frame es una colección de vectores (columnas).
¿Cómo podría calcular el número total de casos para cada enfermedad?
Una opción en R:
¿Qué tal si tengo muchas enfermedades? ¿Habrá una formas más eficiente de hacerlo?
Como todo en R es un vector, es posible aplicar la aritmética vectorial para calcular la suma de los elementos de cada vector según su posición:
El resultado de realizar una operación aritmetica entre vectors siempre será también un vector.
En R:
También podríamos usar la notación de corchetes:
Sin embargo, hay que tener cuidado con la siguiente notación:
Esta notación devuelve un data frame y no un vector. Si bien los totales son correctos, es más conveniente tener los resultados en un vector que en un data frame, ya que el primeor es más sencillo de manipular.
Podemos asignar los totales calculados a una nueva columna en la tabla usando el símbolo $
seguido del nombre de la nueva columna:
Esto se puede hacer siempre y cuando la nueva columna tenga el mismo número de filas de la tabla.
Podemos escribir un nuevo archivo CSV con nuestra nueva tabla usando la función write.csv()
. Si vemos la documentación, el primer argumento es el data frame y el segundo la ruta donde se va a escribir el archivo:
Si abrimos el archivo, vemos que tiene la siguiente estructura:
"","enfermedad","confirmados","probables","totales"
"1","Dengue",37,63,100
"2","Malaria",43,107,150
"3","Leptospirosis",25,44,69
Vemos que además de las columnas que tenía el data frame, se añadió una columna que indica la posición de las filas. Esta columna sirve para nombrar las filas.
Podemos decirle a write.csv()
si queremos (TRUE
) o no queremos (FALSE
) nombres de fila usando el argumento row.names
:
Creemos un nuevo script con el nombre dengue.R
y usémoslo para importar desde una página web un archivo CSV con los casos notificados de Dengue en la provincia de Maynas en los años 2018 y 2019:
Guardémoslo para poder usarlo luego:
¿Cuál es el número de filas de este data frame?
¿Cuál es el número de columnas de este data frame?
¿Qué enfermedades se notificaron en esta tabla?
Para ver los valores únicos de una variable, podemos usar la función unique()
:
Veamos la variable de código de localidad:
¿Qué son estos valores NA
?
NA
en R significa Not Available o “no disponible”. Es un valor especial que indica que debería existir un dato en esa posición, pero por alguna razón no se encuentra disponible o está perdido.
R tiene otros valores especiales:
NaN
de Not a Number, sirve para indicar un valor que es imposible de calcular o no es determinado (división entre cero).Inf
y -Inf
sirven para indicar valores infinitos positivos y negativos, respectivamente.NULL
representa a un objeto nulo. Es la representación de “la nada”. Es posible tener un vector de NA
s pero no de NULL
s. Un vector que conciente un NULL
es considerado NULL
.R tiene otros valores especiales:
NaN
de Not a Number, sirve para indicar un valor que es imposible de calcular o no es determinado (división entre cero).Inf
y -Inf
sirven para indicar valores infinitos positivos y negativos, respectivamente.NULL
representa a un objeto nulo. Es la representación de “la nada”. Es posible tener un vector de NA
s pero no de NULL
s. Un vector que conciente un NULL
es considerado NULL
.Veamos la variable sexo
:
Veamos los valores únicos de la variable sexo
:
Vemos que esta variable toma dos valores: F
de femenino y M
de masculino.
Un tipo de dato en R bastante útil para manejar estos tipos de variables son los factores.
Un factor es un modo de almacenamiento utilizado para representar variables categóricas. Es decir, variables que tienen un número limitado y fijo de valores posibles, llamados niveles.
Podemos definir un factor usando la función factor()
. Por ejemplo, usando la variable sex
:
Vemos que ahora R reconoce que la variable sex
tiene dos niveles o categorías: F
y M
.
Podemos darle etiquetas a los niveles usando el argumento labels
. Este argumento recibe un vector de la misma dimensión de los niveles de la variable con las etiquetas que queramos según el orden de los niveles.
Es decir, el primer elemento del vector de etiquetas es la etiqueta del primer nivel, el segundo elemento del vector es la etiqueta del segundo nivel, y así sucesivamente.
Para crear un vector en R podemos usar la función c()
. Por ejemplo, para crear un vector con las etiquetas Femenino
y Masculino
:
Ahora pasamos el vector al argumento labels
de la función factor()
:
Si quisiéramos cambiar el orden de los niveles, podemos usar el argumento levels
de la función factor()
. Este argumento recibe un vector con los niveles en el orden que queramoss:
¡Cuidado! Hay que cambiar el orden de las etiquetas también.
Digamos que tenemos el siguiente vector:
Definimos el factor solo con los niveles F
y M
:
Vemos que J
fue reemplazado con un NA
. Los factores son útiles para asegurar la integridad de la variable categórica.
Creemos un script de R llamado iquitos.R
y leamos los datos diarios de temperatura mínima en C° en Iquitos durante el año 2022:
Veamos el vector de temperaturas mínimas:
Podemos usar la función sort()
para ordenar el vector temperaturas mínimas de manera ascendente:
Podemos usar el argumento decreasing
para indicarle a sort()
que queremos ordenar el vector manera descendente:
Vemos que los menores valores de la temperatura parecen ser valores atípicos. Digamos que queremos eliminar los primeros 5 valores atípicos. ¿Cómo los eliminamos?
Recordemos que podemos acceder a cada elemento del vecto usando la notación de corchetes:
Sin embargo, lo que queremos es extraer todos estos valores en un solo vector.
Hasta ahora hemos visto que podemos acceder a los elementos de un vector uno por uno:
También podemos usar un vector para acceder a más de una elemento del vector:
En R:
También podemos usar el operador :
para generar una secuencia regular:
Sin embargo, todavía no hemos removido estos valores atípico. Para eliminar elementos de un vector, debemos pasar índices negativos:
¿Qué tal si tuviéramos datos de temperatura de otro distrito? ¿Simpre los valores atípicos van a ser los 5 valores menores?
Lo mejor sería establecer un umbral. Valores menores a este umbral serían considerados valores atípicos.
Para saber si un valor es menor al umbral, necesitamos comparar sus magnitudes. En R, esto se puede hacer mediante operadores de comparación:
==
se lee “es igual a”,!=
se lee “es diferente a”,>
se lee “es mayor a”,>=
se lee “es mayor o igual a”,<
se lee “es menor a”,<=
se lee “es menor o igual a”.Por ejemplo, al evaluar el enunciado a < b
, dos resultados son posibles:
a
es de hecho menor a b
, por lo cual el enunciado es verdadero, oa
no es menor a b
, por lo cual el enunciado es falso.En el primer caso, R devuelve un valor lógico de TRUE
, mientras que en el segundo devuelve un valor lógico de FALSE
.
Debido a que el resulado de una comparación puede tomar solo dos valores lógicos, a los enunciados de comparación se les conoce como expresiones lógicas.
Por ejemplo, si definimos que las temperaturas menores a 19 C° son valores atípicos, necesitamos comparar cada elemento de temps
con este umbral:
Recordemos que las funciones en R está vectorizadas. Los operadores también actuan como funciones, por tanto también tienen la propiedad de vectorización:
En este caso, R devuelve un vector lógico, el cual indica el resultado de la comparación de cada elemento de temps
con el valor 19.
Volviendo al problema de indexación, en R podemos utilizar la función which()
para saber cuáles son los índices del vector temps
que son menores a 19 automáticamente:
De esta manera, podemos indicarle a R que elimine los valores atípicos usando los negativos de los índices:
¿Qué tal si quisiéramos incluir a las temperatures mayores a 24.6 C° como valores atípicos? Para esto, necesitamos hacer uso de operadores lógicos, es decir, operadores que trabajen sobre valores lógicos:
&
representa al operador lógico “Y”,|
representa al operador lógico “O”,!
representa al operador lógico de negación o “NO”.&
y |
funcionan con vectores lógicos. Para comparar valores individuales debemos usar &&
y ||
.
Con los operadores lógicos, podemos construir las tablas lógicas:
Para el caso de la negación:
En R:
Ahora con which()
:
Si quisiéramos eliminar los valores atípicos:
De hecho, usar which()
es innecesario. Podemos acceder o filtrar a los elementos que queramos usando el vector lógico:
De hecho, usar which()
es innecesario. Podemos acceder o filtrar a los elementos que queramos usando el vector lógico:
En R:
Si quisiéramos quedarnos con los elementos que no son valores atípicos podemos usar el operador de negación !
:
Definimos nuestros vectores
Creemos un script de R llamado dengue_casos.R
y carguemos a nuestro conjunto de datos de Dengue:
Sabemos que hay casos en los que no se registró la localidad. Es decir, donde la localidad es un NA
.
Para identificar los NA
s, podemos usar la función lógica is.na()
, la cual devuelve TRUE
si el valor que se le pase es un NA
y FALSE
en el caso contrario.
Si quisiéramos filtrar los casos (filas) en donde no se registró la localidad, podemos hacer uso de la función lógica is.na()
y la notación de corchetes:
Si, por el contrario, quisiéramos filtrar los casos en los que sí se registró la localidad, entonces negamos a la función lógica:
Existen otras funciones lógicas:
is.nan()
para valores no definidos,is.infinite()
para valores infinitos,is.null()
para valores nulos,En R existe una función para hacer filtrar filas sin usar la notación por corchetes llamada subset()
:
No es necesario poner dengue$localidad
ya que subset()
reconoce el nombre de las columnas en el data frame.
Guardemos los datos que contienen todas las localidades en un nuevo objeto:
Digamos que queramos calcular el número de casos notificados por cada tipo de Dengue durante los años 2018 y 2019:
¿Cómo filtramos por tipo de enfermedad?
Por ejemplo, para los casos de dengue con señales de alarma:
Utilizamos subset()
:
Guardamos el resultado en nuevo objeto:
¿Cómo podemos saber cuánto casos notificados de dengue con señales de alarma hubieron? Podemos calcular el número de filas de dengue_alarma
:
Creemos ahora un programa que le permita al usuario decidir de qué tipo de dengue calcular el número de casos registrados. Empecemos por crear un vector con los valores únicos de dengue$enfermedad
:
Y ahora, creemos un menú que liste los tipos de enfermedad usando la función cat()
:
A diferencia de print()
, la función cat()
concatena sus argumentos imprime los resultados en la consola como texto, no como un vector.
Los caracteres de escape sirven para insertar caracteres especiales en una cadena de caracteres. Por ejemplo:
\n
inserta un salto de línea.\t
inserta una tabulación (TAB
en el teclado).Mejoremos nuestro menú:
¿Qué pasaría si tengo muchas opciones? Podemos vectorizar el menú:
Esto no es lo que esperábamos.
Si vemos la página de ayuda de cat()
, hay un argumento llamado sep
que inserta un caracter en cada elemento del vector que ingresemos. Podemos probar pasando el caracter de escape \n
a este argumento:
Faltaría agregar los número para que el usuario no tenga que escribir todo el texto de la enfermedad. Podemos aprovechar la propiedad de vectorización de paste()
para crear un vector con las opciones:
¿Qué pasaría si tengo más de 3 opciones? Podemos hacer que la secuencia de adapte al número de opciones usango la función length()
que calcula el número de elementos de un vector:
Ahora sí podemos mostrar correctamente el menú:
Ahora, pedimos al usuario que ingrese la opción que desee:
Estas opciones corresponden a los índices del vector enfermedad
. Por lo tanto, podemos filtrar la enfermedad que el usuario desea:
¿Qué salió mal?
El problema fue que no convertimos la opción a un valor numérico:
Ahora, filtramos con subset()
:
Y calculamos el número de casos:
Por último, mostramos el mensaje con el resultado al usuario: