Introducción a Programación en R
Este material es una actualización y traducción de los materiales elaborados por los estudiantes del Departamento de Genética de ESALQ/USP - Brasil. Acceda al contenido en portugués impartido en otros eventos en este sitio.
Sugerimos que, antes de comenzar la práctica descrita aquí, siga este tutorial para la instalación de R y RStudio.
Familiarización con la interfaz de RStudio
Al abrir RStudio verás:
La interfaz está dividida en cuatro ventanas con funciones principales:
- Edición de código
- Entorno de trabajo e historial
- Consola
- Archivos, gráficos, paquetes y ayuda
Explora cada una de las ventanas. Hay numerosas funcionalidades para cada una de ellas, veremos algunas durante el curso.
Un primer script
La ventana de edición de código (probablemente ubicada en la esquina
superior izquierda) se utilizará para escribir tu código. Abre un nuevo
script haciendo clic en el +
en la esquina superior
izquierda y seleccionando R script
.
Vamos a comenzar con el tradicional Hello World
. Escribe
en tu script:
## Hello world
Ahora, selecciona la línea y presiona el botón Run
o
utiliza Ctrl + enter
.
Al hacer esto, tu código será procesado en la ventana
Console
, donde aparecerá en azul (si tienes los colores
predeterminados de R) el código escrito y, a continuación, el resultado
deseado. La línea no será procesada en la consola si tiene el símbolo
#
delante. Ahora, prueba a poner #
delante del
código escrito. Nuevamente, selecciona la línea y presiona
Run
.
El símbolo #
se utiliza para
comentarios en el código. Esta es una excelente
práctica de organización y ayuda a recordar, posteriormente, lo que
estabas pensando cuando escribiste el código. También es esencial para
que otras personas puedan entenderlo. Como en el ejemplo:
## Hello world
Importante: siempre que quieras realizar alguna modificación, edita tu script y no directamente en la consola, ¡porque todo lo que se escribe en ella no se podrá guardar!
Para guardar tu script, puedes utilizar la pestaña Files
ubicada (por defecto) en la esquina inferior derecha. Puedes buscar una
ubicación de tu preferencia, crear una nueva carpeta con el nombre
CursoR
.
Consejo:
- Evita poner espacios y puntuación en el nombre de las carpetas y
archivos, esto puede dificultar el acceso a través de la línea de
comandos en R. Por ejemplo, en lugar de
Curso R
, optamos porCursoR
.
Después, simplemente haz clic en el disquete ubicado en el encabezado
de RStudio o usa Ctrl + s
y selecciona el directorio
CursoR
creado. Los scripts en R se guardan con la extensión
.R
.
Estableciendo el directorio de trabajo
Otra buena práctica en R es mantener el script en el mismo directorio donde están tus datos brutos (archivos de entrada en el script) y los datos procesados (gráficos, tablas, etc.). Para esto, vamos a hacer que R identifique el mismo directorio donde guardaste el script como directorio de trabajo. Así, entenderá que es de allí de donde se obtendrán los datos y es allí donde también irán los resultados.
Puedes hacer esto utilizando las facilidades de RStudio, simplemente
localiza el directorio CursoR
en la pestaña
Files
, haz clic en More
y luego en “Set as
Working Directory”. Observa que aparecerá en la consola algo como:
Es decir, puedes utilizar este mismo comando para realizar esta acción. El resultado será nuestra carpeta de trabajo. Cuando estés perdido/a o para asegurarte de que el directorio de trabajo fue cambiado, utiliza:
Facilitando la vida con Tab
Ahora, imagina que tienes un directorio como
~/Documentos/maestria/semestre1/asignatura_tal/clase_tal/datos_28174/analisis_276182/resultados_161/
.
No es fácil recordar todo este camino para escribir en un comando
setwd()
.
Además de la facilidad de la ventana de RStudio, también puedes
utilizar la tecla Tab
para completar el camino por ti.
Prueba buscando alguna carpeta en tu computadora. ¡Solo tienes que
empezar a escribir el camino y presionar Tab
, y completará
el nombre por ti! Si tienes más de un archivo con ese inicio de nombre,
presiona Tab
dos veces y te mostrará todas las
opciones.
El Tab
funciona no solo para indicar rutas, sino también
para comandos y nombres de objetos. Es muy común cometer errores de
escritura en el código. Utilizar el Tab
reducirá
significativamente estos errores.
El Tab
puede ser aún más poderoso si tienes acceso a la
herramienta GitHub
Copilot. Con ella, puedes utilizar el Tab
para
completar el código que estás escribiendo. Es una herramienta basada en
inteligencia artificial que sugiere el código que estás escribiendo. Es
una herramienta de pago, pero puedes utilizarla gratuitamente durante 60
días.
Operaciones básicas
¡Vamos entonces al lenguaje!
R puede funcionar como una simple calculadora, que utiliza la misma sintaxis que otros programas (como Excel):
1+1.3 #Decimal definido con "."
2*3
2^3
4/2
sqrt(4) #raíz cuadrada
log(100, base = 10) #Logaritmo en base 10
log(100) #Logaritmo en base neperiana
Ahora, utiliza las operaciones básicas para resolver la expresión
siguiente. Recuerda utilizar paréntesis ()
para establecer
prioridades en las operaciones.
\((\frac{13+2+1.5}{3})+ log_{4}96\)
Resultado esperado:
## [1] 8.792481
Ten en cuenta que, si colocas los paréntesis de forma incorrecta, el código no resultará en ningún mensaje de error, pues este es un error que llamamos error lógico o error silencioso, es decir, el código se ejecuta pero no hace lo que quieres que haga. Este es el tipo de error más peligroso y difícil de corregir. Ve un ejemplo:
## [1] 18.79248
Los errores que producen un mensaje, ya sea una advertencia (warning) o un error (error) se llaman errores de sintaxis. En estos casos, R devolverá un mensaje para ayudarte a corregirlos. Los warnings no comprometen el funcionamiento del código, pero llaman la atención sobre algún punto; los errors, por otro lado, necesitan ser corregidos necesariamente para que el código funcione.
Ejemplo de error:
También puedes olvidar cerrar algún paréntesis, comillas, corchetes o
llaves, en estos casos, R esperará el comando para cerrar el bloque de
código señalizando con un +
:
Si esto sucede, ve a la consola y presiona ESC, y el bloque se finalizará para que puedas corregirlo.
Los comandos log
y sqrt
son dos de muchas
otras funciones básicas que R posee. Las funciones son conjuntos de
instrucciones organizadas para realizar una tarea. Para todas ellas, R
tiene una descripción para ayudar en su uso. Para acceder a esta ayuda
usa:
Y se abrirá la descripción de la función en la ventana
Help
de RStudio.
Si la descripción del propio R no es suficiente para que entiendas cómo funciona la función, busca en Google (preferiblemente en inglés). Existen diversos sitios y foros con información didáctica sobre las funciones de R.
Operaciones con vectores
Los vectores son las estructuras más simples trabajadas en R. Construimos un vector con una secuencia numérica usando:
## [1] 1 3 2 5 2
MUCHA ATENCIÓN: La c es la función de R (Combine Values into a Vector or List) con la cual construimos un vector!
Utilizamos el símbolo :
para crear secuencias de números
enteros, como:
## [1] 1 2 3 4 5 6 7 8 9 10
Podemos utilizar otras funciones para generar secuencias, como:
## [1] 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90
## [20] 95 100
## [1] 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90
## [20] 95 100
- Crea una secuencia utilizando la función
seq
que varíe de 4 a 30, con intervalos de 3 en 3.
## [1] 4 7 10 13 16 19 22 25 28
La función rep
genera secuencias con números
repetidos:
## [1] 3 4 5 3 4 5
Podemos realizar operaciones utilizando estos vectores:
Observa que ya está resultando cansado escribir los mismos números repetidamente, vamos a resolver esto creando objetos para almacenar nuestros vectores y mucho más.
Creando objetos
El almacenamiento de información en objetos y su posible manipulación hace de R un lenguaje orientado a objetos. Para crear un objeto basta con asignar valores a las variables, como sigue:
x = c(30.1,30.4,40,30.2,30.6,40.1)
# o
x <- c(30.1,30.4,40,30.2,30.6,40.1)
y = c(0.26,0.3,0.36,0.24,0.27,0.35)
Los usuarios más antiguos suelen usar el signo <-
,
pero tiene la misma función que =
. Hay quienes prefieren
usar <-
para asignación en objetos y =
solo
para definir los argumentos dentro de funciones. Organízate de la forma
que prefieras.
Para acceder a los valores dentro del objeto simplemente:
## [1] 30.1 30.4 40.0 30.2 30.6 40.1
El lenguaje es sensible a mayúsculas y minúsculas. Por lo tanto,
x
es diferente de X
:
El objeto X
no fue creado.
El nombre de los objetos es una elección personal, la sugerencia es tratar de mantener un patrón para mejor organización. Aquí hay algunos consejos:
- Usar nombres descriptivos
- Evitar empezar con números
- No usar espacios (usar _ o camelCase)
- No usar caracteres especiales
- Mantener consistencia en el patrón elegido
- Evitar nombres muy largos
- No usar acentos o caracteres no ASCII
Algunos nombres no pueden usarse por establecer roles fijos en R, son:
- TRUE - Verdadero, valor lógico
- FALSE - Falso, valor lógico
- if, else, for, while, break, next - Palabras reservadas para estructuras condicionales y de repetición
- for, while, repeat - Palabras reservadas para estructuras de repetición
- function - Palabra reservada para definición de funciones
- in, NA, NaN, NULL - Palabras reservadas para valores especiales
- NA_integer_, NA_real, NA_character_, NA_complex_ - Valores especiales para representar datos ausentes
Podemos entonces realizar operaciones con el objeto creado:
## [1] 32.1 32.4 42.0 32.2 32.6 42.1
## [1] 60.2 60.8 80.0 60.4 61.2 80.2
Para realizar la operación, R alinea los dos vectores y realiza la operación elemento a elemento. Observa:
## [1] 30.36 30.70 40.36 30.44 30.87 40.45
## [1] 7.826 9.120 14.400 7.248 8.262 14.035
Si los vectores tienen tamaños diferentes, repetirá el menor para realizar la operación elemento a elemento con todos los del mayor.
Si el vector menor no es múltiplo del mayor, obtendremos una advertencia:
## Warning in x * c(1, 2, 3, 4): longer object length is not a multiple of shorter
## object length
## [1] 30.1 60.8 120.0 120.8 30.6 80.2
Nota que el warning no compromete el funcionamiento del código, solo da una pista de que algo puede no estar como quisieras.
También podemos almacenar la operación en otro objeto:
También podemos aplicar algunas funciones, por ejemplo:
## [1] 101.59
## [1] 16.93167
## [1] 6.427507
Indexación
Accedemos solo al 3er valor del vector creado con
[]
:
También podemos acceder a los números de la posición 2 a 4 con:
## [1] 15.35 20.18 15.22
Para obtener información del vector creado utiliza:
## num [1:6] 15.2 15.3 20.2 15.2 15.4 ...
La función str
nos dice sobre la estructura del vector,
que se trata de un vector numérico con 6 elementos.
Los vectores también pueden recibir otras categorías como caracteres:
Otra clase son los factores, estos pueden ser un poco complejos de manejar.
En general, los factores son valores categorizados por
levels
, como ejemplo, si transformamos nuestro vector de
caracteres clone
en factor, se asignarán niveles para cada
una de las palabras:
## Factor w/ 4 levels "GRA01","GRA02",..: 2 3 4 2 1 3
## [1] "GRA01" "GRA02" "URO01" "URO03"
De esta forma, tendremos solo 4 niveles para un vector con 6 elementos, ya que las palabras “GRA02” y “URO01” se repiten. Podemos obtener el número de elementos del vector o su longitud con:
## [1] 6
También hay vectores lógicos, que reciben valores de verdadero o falso:
## [1] FALSE FALSE FALSE FALSE FALSE TRUE
Con él podemos, por ejemplo, identificar cuáles son las posiciones de los elementos mayores que 40:
## [1] 6
## [1] 40.1
## [1] 40.1
También podemos localizar elementos específicos con:
## [1] TRUE FALSE TRUE TRUE FALSE FALSE
También pueden ser útiles las funciones any
y
all
. Investiga sobre ellas.
Encuentra más sobre otros operadores lógicos, como el
>
utilizado, en este enlace.
[Continúa con la siguiente parte del texto para los Warnings y consejos…]
Advertencia 1
Haz una secuencia numérica, conteniendo 10 valores enteros, y guárdala en un objeto llamado “a”.
## [1] 1 2 3 4 5 6 7 8 9 10
Crea otra secuencia, utilizando números decimales y cualquier operación matemática, de tal forma que sus valores sean idénticos al objeto “a”.
## [1] 1 2 3 4 5 6 7 8 9 10
Los dos vectores parecen iguales, ¿no?
Entonces, utilizando un operador lógico, vamos a verificar si el objeto “b” es igual al objeto “a”.
## [1] TRUE TRUE FALSE TRUE TRUE TRUE FALSE TRUE TRUE TRUE
Algunos valores no son iguales. ¿Cómo es esto posible?
## [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
Advertencia 2
No es posible mezclar diferentes clases dentro de un mismo vector. Al intentar hacer esto, observa que R intentará igualar a una única clase:
## [1] "TRUE" "vish" "1"
En este caso, todos los elementos fueron transformados en caracteres.
Algunos Consejos:
- Ten cuidado con la prioridad de las operaciones, en caso de duda, siempre añade paréntesis según tu interés de prioridad.
- Recuerda que, si olvidas cerrar algún
(
o[
o"
, la consola de R esperará que lo cierres indicando un+
. Nada será procesado hasta que escribas directamente en la consola un)
o presiones ESC. - Ten cuidado de no sobreponer objetos ya creados creando otros con el mismo nombre. Usa, por ejemplo: altura1, altura2.
- Mantén en tu script .R solo los comandos que funcionaron y, preferentemente, añade comentarios. Puedes, por ejemplo, comentar dificultades encontradas, para que no cometas los mismos errores más tarde.
Si estás adelantado/a respecto a tus compañeros, ya puedes hacer los ejercicios de la Sesión 1, si no, hazlos en otro momento y envíanos dudas.
Matrices
Las matrices son otra clase de objetos muy utilizados en R, con ellas podemos realizar operaciones de mayor escala de forma automatizada.
Por ser usadas en operaciones, normalmente almacenamos en ellas elementos numéricos. Para crear una matriz, determinamos una secuencia de números e indicamos el número de filas y columnas de la matriz:
## [,1] [,2]
## [1,] 1 7
## [2,] 2 8
## [3,] 3 9
## [4,] 4 10
## [5,] 5 11
## [6,] 6 12
También podemos utilizar secuencias ya almacenadas en vectores para generar una matriz, siempre que sean numéricos:
## [,1] [,2]
## [1,] 30.1 0.26
## [2,] 30.4 0.30
## [3,] 40.0 0.36
## [4,] 30.2 0.24
## [5,] 30.6 0.27
## [6,] 40.1 0.35
Con ellas podemos realizar operaciones matriciales:
## [,1] [,2]
## [1,] 2 14
## [2,] 4 16
## [3,] 6 18
## [4,] 8 20
## [5,] 10 22
## [6,] 12 24
## [,1] [,2]
## [1,] 1 49
## [2,] 4 64
## [3,] 9 81
## [4,] 16 100
## [5,] 25 121
## [6,] 36 144
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 50 58 66 74 82 90
## [2,] 58 68 78 88 98 108
## [3,] 66 78 90 102 114 126
## [4,] 74 88 102 116 130 144
## [5,] 82 98 114 130 146 162
## [6,] 90 108 126 144 162 180
Utilizar estas operaciones exige conocimiento de álgebra de matrices, si quieres profundizar al respecto, el libro Linear Models in Statistics, Rencher (2008) tiene una buena revisión al respecto. También puedes explorar la sintaxis de R para estas operaciones en este enlace.
Accedemos a los números internos de la matriz dando las coordenadas [fila,columna], como en el ejemplo:
## [1] 0.24
A veces puede ser informativo dar nombres a las columnas y a las filas de la matriz, lo hacemos con:
## altura diametro
## GRA02 30.1 0.26
## URO01 30.4 0.30
## URO03 40.0 0.36
## GRA02 30.2 0.24
## GRA01 30.6 0.27
## URO01 40.1 0.35
Estas funciones colnames
y rownames
también
funcionan en los data.frames.
Data.frames
A diferencia de las matrices, no realizamos operaciones con los data.frames, pero permiten la unión de vectores con clases diferentes. Los data frames son similares a tablas generadas en otros programas, como Excel.
Los data frames son combinaciones de vectores de la misma longitud. Todos los que creamos hasta ahora tienen tamaño 6, verifica.
Podemos así combinarlos en columnas de un único data.frame:
campo1 <- data.frame("clone" = clone, # Antes del signo "="
"altura" = x, # establecemos los nombres
"diametro" = y, # de las columnas
"edad" = rep(3:5, 2),
"corte"= logico)
campo1
## clone altura diametro edad corte
## 1 GRA02 30.1 0.26 3 FALSE
## 2 URO01 30.4 0.30 4 FALSE
## 3 URO03 40.0 0.36 5 FALSE
## 4 GRA02 30.2 0.24 3 FALSE
## 5 GRA01 30.6 0.27 4 FALSE
## 6 URO01 40.1 0.35 5 TRUE
Podemos acceder a cada una de las columnas con:
## [1] 3 4 5 3 4 5
O también con:
## [1] 3 4 5 3 4 5
Aquí, el número dentro de los corchetes se refiere a la columna, por ser el segundo elemento (separado por coma). El primer elemento se refiere a la fila. Como dejamos el primer elemento vacío, nos estaremos refiriendo a todas las filas para esa columna.
De esta forma, si queremos obtener un contenido específico podemos dar las coordenadas con [fila,columna]:
## [1] 30.1
- Obtén el diámetro del clon “URO03”.
## [1] 0.36
Aunque se trate de un data frame, podemos realizar operaciones con los vectores numéricos que lo componen.
- Con el diámetro y la altura de los árboles, calcula el volumen
conforme a la fórmula siguiente y almacénalo en un objeto
volumen
:
\(3.14*(diametro/2)^2*altura\)
## [1] 1.597287 2.147760 4.069440 1.365523 1.751131 3.856116
Ahora, vamos a añadir el vector calculado con el volumen a nuestro
data frame. Para esto usa la función cbind
.
## clone altura diametro edad corte volumen
## 1 GRA02 30.1 0.26 3 FALSE 1.597287
## 2 URO01 30.4 0.30 4 FALSE 2.147760
## 3 URO03 40.0 0.36 5 FALSE 4.069440
## 4 GRA02 30.2 0.24 3 FALSE 1.365523
## 5 GRA01 30.6 0.27 4 FALSE 1.751131
## 6 URO01 40.1 0.35 5 TRUE 3.856116
## 'data.frame': 6 obs. of 6 variables:
## $ clone : chr "GRA02" "URO01" "URO03" "GRA02" ...
## $ altura : num 30.1 30.4 40 30.2 30.6 40.1
## $ diametro: num 0.26 0.3 0.36 0.24 0.27 0.35
## $ edad : int 3 4 5 3 4 5
## $ corte : logi FALSE FALSE FALSE FALSE FALSE TRUE
## $ volumen : num 1.6 2.15 4.07 1.37 1.75 ...
Algunos consejos:
Recuerda que, para construir matrices y data frames, las columnas deben presentar el mismo número de elementos.
En caso de que no sepas el operador o la función que debe ser utilizada, busca en Google o pregunta al chatgpt o cualquier otra herramienta. Por ejemplo, si tienes dudas sobre cómo calcular la desviación estándar, busca por “desviación estándar R” o, mejor aún, “standard deviation R”. La comunidad de R es bastante activa y gran parte de tus preguntas sobre él ya fueron respondidas en algún lugar de la web.
No olvides que todo lo que hagas en R necesita ser explícitamente indicado, como una multiplicación 4ac con
4*a*c
. Para generar un vector 1,3,2,6 es necesario:c(1,3,2,6)
.
Listas
Las listas consisten en una colección de objetos, no necesariamente
de la misma clase. En ellas podemos almacenar todos los otros objetos ya
vistos y recuperarlos mediante la indexación con [[
. Como
ejemplo, vamos a utilizar algunos objetos que ya fueron generados.
mi_lista <- list(campo1 = campo1, media_alt = tapply(campo1$altura, campo1$edad, mean), matrix_ex = W)
str(mi_lista)
## List of 3
## $ campo1 :'data.frame': 6 obs. of 6 variables:
## ..$ clone : chr [1:6] "GRA02" "URO01" "URO03" "GRA02" ...
## ..$ altura : num [1:6] 30.1 30.4 40 30.2 30.6 40.1
## ..$ diametro: num [1:6] 0.26 0.3 0.36 0.24 0.27 0.35
## ..$ edad : int [1:6] 3 4 5 3 4 5
## ..$ corte : logi [1:6] FALSE FALSE FALSE FALSE FALSE TRUE
## ..$ volumen : num [1:6] 1.6 2.15 4.07 1.37 1.75 ...
## $ media_alt: num [1:3(1d)] 30.1 30.5 40
## ..- attr(*, "dimnames")=List of 1
## .. ..$ : chr [1:3] "3" "4" "5"
## $ matrix_ex: num [1:6, 1:2] 30.1 30.4 40 30.2 30.6 40.1 0.26 0.3 0.36 0.24 ...
## ..- attr(*, "dimnames")=List of 2
## .. ..$ : chr [1:6] "GRA02" "URO01" "URO03" "GRA02" ...
## .. ..$ : chr [1:2] "altura" "diametro"
Quiero acceder al data.frame campo1
## clone altura diametro edad corte volumen
## 1 GRA02 30.1 0.26 3 FALSE 1.597287
## 2 URO01 30.4 0.30 4 FALSE 2.147760
## 3 URO03 40.0 0.36 5 FALSE 4.069440
## 4 GRA02 30.2 0.24 3 FALSE 1.365523
## 5 GRA01 30.6 0.27 4 FALSE 1.751131
## 6 URO01 40.1 0.35 5 TRUE 3.856116
## clone altura diametro edad corte volumen
## 1 GRA02 30.1 0.26 3 FALSE 1.597287
## 2 URO01 30.4 0.30 4 FALSE 2.147760
## 3 URO03 40.0 0.36 5 FALSE 4.069440
## 4 GRA02 30.2 0.24 3 FALSE 1.365523
## 5 GRA01 30.6 0.27 4 FALSE 1.751131
## 6 URO01 40.1 0.35 5 TRUE 3.856116
Para acceder a una columna específica en el data.frame
campo1
, que está dentro de mi_lista:
## [1] 0.26 0.30 0.36 0.24 0.27 0.35
## [1] 0.26 0.30 0.36 0.24 0.27 0.35
## [1] 0.26 0.30 0.36 0.24 0.27 0.35
Las listas son muy útiles, por ejemplo, cuando vamos a utilizar/generar diversos objetos dentro de un bucle.
Arrays
Este es un tipo de objeto que probablemente no utilizarás ahora al principio, pero es bueno saber de su existencia. Se utilizan para almacenar datos con más de dos dimensiones. Por ejemplo, si creamos un array:
## , , 1
##
## [,1] [,2] [,3]
## [1,] 1 3 5
## [2,] 2 4 6
##
## , , 2
##
## [,1] [,2] [,3]
## [1,] 7 9 11
## [2,] 8 10 12
##
## , , 3
##
## [,1] [,2] [,3]
## [1,] 13 15 17
## [2,] 14 16 18
##
## , , 4
##
## [,1] [,2] [,3]
## [1,] 19 21 23
## [2,] 20 22 24
Tendremos cuatro matrices con dos filas y tres columnas y los números del 1 al 24 estarán distribuidos en ellas por columnas.
Si estás adelantado/a respecto a tus compañeros, ya puedes hacer los ejercicios de la Sesión 2, si no, hazlos en otro momento y envíanos dudas por el foro.
Importando y exportando datos
Descarga los objetos creados hasta ahora haciendo clic aquí
Los archivos RData son exclusivos de R. Al hacer doble clic sobre el archivo o utilizando el siguiente comando:
Recuperarás todos los objetos generados hasta este punto del tutorial.
Si tienes acceso a internet, también puedes usar el enlace web directamente:
Para generar este archivo RData, ejecuté todos los códigos desde el inicio hasta aquí y utilicé el siguiente comando:
Este comando guarda todo lo que tienes en tu Ambiente Global (todos los objetos que aparecen en la esquina superior derecha). También puedes guardar únicamente un objeto específico utilizando:
Si eliminamos este objeto de nuestro Ambiente Global con el siguiente comando:
Podremos recuperarlo fácilmente más tarde con:
El formato RData es exclusivo de R. Es útil para hacer lo que estamos
haciendo: pausar el análisis un día y continuar otro día sin necesidad
de ejecutar todo nuevamente. Sin embargo, muchas veces necesitamos
exportar nuestros datos a otros programas que requieren otros formatos,
como .txt
o .csv
. Para esto podemos usar los
siguientes comandos:
write.table(campo1, file = "campo1.txt", sep = ";", dec = ".", row.names = FALSE)
write.csv(campo1, file = "campo1.csv", row.names = TRUE)
Nota: Puedes utilizar paquetes para importar y exportar datos en
otros formatos. Por ejemplo, el paquete openxlsx
permite
trabajar con archivos en formato Excel, y el paquete vroom
puede ser utilizado para manejar tablas grandes y comprimidas. Para
instalar paquetes, utiliza la función
install.packages("nombre_del_paquete")
y para cargar un
paquete utiliza library(nombre_del_paquete)
. Veremos más
sobre paquetes en la sesión “Aplicación de Paquetes” de este curso.
Al exportar, hay diversas opciones para la formato del archivo, es importante considerarlas si el archivo será utilizado en otro programa posteriormente.
Abre los archivos generados en tu bloc de notas para visualizar su
formato. Observa que el archivo .txt
fue guardado con el
separador ;
y el separador decimal .
. Por otro
lado, el archivo .csv
fue guardado con el separador de coma
,
y el separador decimal .
.
Estos archivos pueden ser leídos nuevamente por R utilizando las funciones y sus especificaciones:
campo1_txt <- read.table(file = "campo1.txt", sep=";", dec=".", header = TRUE)
campo1_csv <- read.csv(file = "campo1.csv")
campo1_xlsx <- read.xlsx("campo1.xlsx", sheet = 1)
head(campo1_txt)
head(campo1_csv)
head(campo1_xlsx)
Ahora que hemos aprendido a importar datos, vamos a trabajar con el conjunto generado a partir del formulario enviado a ustedes y a estudiantes de otras ediciones de este curso.
La hoja de datos está disponible en el enlace a continuación, añádela a tu directorio de trabajo o especifica la ruta de la carpeta al importarla en R, como se muestra a continuación.
También podemos importar los datos directamente desde Github especificando la dirección web.
Aquí utilizaremos también el argumento na.strings
, que
indicará cómo fueron representados los datos faltantes en el
archivo.
Si el decimal de su tabla es una coma en lugar de un punto
(predeterminado de la función), especifíquelo usando
dec=","
.
Vamos a explorar la estructura de los datos recopilados:
## 'data.frame': 124 obs. of 8 variables:
## $ Timestamp : chr "07/04/2025 14:00:00" "07/04/2025 14:00:00" "07/04/2025 14:00:00" "07/04/2025 14:00:00" ...
## $ Affiliation : chr "Rcourse2021" "Rcourse2021" "Rcourse2021" "Rcourse2021" ...
## $ Using.Google.Maps..please.provide.the.longitude.of.the.city.country.of.your.birth. : chr "-54.5724" "-47.6476" "-48.0547" "-106.6563" ...
## $ Using.Google.Maps..please.provide.the.latitude.of.the.city.country.of.your.birth. : chr "-25.5263" "-22.725" "-15.911" "52.1418" ...
## $ Background.Field..e.g..Molecular.Biology..Animal.Breeding..Genetics..etc.. : chr "Agronomia" "Agronomia" "Biotecnologia" "Licenciatura em Ciências Biológicas" ...
## $ Current.professional.affiliation : chr "PhD" "PhD" "Masters degree" "Other" ...
## $ If.you.chose.other.in.the..current.professional.affiliation..question.above..please.specify.: chr "" "" "" "" ...
## $ Level.of.R.knowledge : chr "Intermediate" "Intermediate" "Beginner (some knowledge)" "Intermediate" ...
## [1] 124 8
Observa que los nombres de las columnas aún corresponden a las preguntas completas del formulario. Vamos a cambiarlos por nombres más fáciles de trabajar:
## [1] "Timestamp"
## [2] "Affiliation"
## [3] "Using.Google.Maps..please.provide.the.longitude.of.the.city.country.of.your.birth."
## [4] "Using.Google.Maps..please.provide.the.latitude.of.the.city.country.of.your.birth."
## [5] "Background.Field..e.g..Molecular.Biology..Animal.Breeding..Genetics..etc.."
## [6] "Current.professional.affiliation"
## [7] "If.you.chose.other.in.the..current.professional.affiliation..question.above..please.specify."
## [8] "Level.of.R.knowledge"
colnames(dados) = c("Fecha", "Afiliacion", "Longitud", "Latitud", "Antecedentes", "Ocupacion_Actual", "Explicacion", "Conocimiento_R")
colnames(dados)
## [1] "Fecha" "Afiliacion" "Longitud" "Latitud"
## [5] "Antecedentes" "Ocupacion_Actual" "Explicacion" "Conocimiento_R"
## 'data.frame': 124 obs. of 8 variables:
## $ Fecha : chr "07/04/2025 14:00:00" "07/04/2025 14:00:00" "07/04/2025 14:00:00" "07/04/2025 14:00:00" ...
## $ Afiliacion : chr "Rcourse2021" "Rcourse2021" "Rcourse2021" "Rcourse2021" ...
## $ Longitud : chr "-54.5724" "-47.6476" "-48.0547" "-106.6563" ...
## $ Latitud : chr "-25.5263" "-22.725" "-15.911" "52.1418" ...
## $ Antecedentes : chr "Agronomia" "Agronomia" "Biotecnologia" "Licenciatura em Ciências Biológicas" ...
## $ Ocupacion_Actual: chr "PhD" "PhD" "Masters degree" "Other" ...
## $ Explicacion : chr "" "" "" "" ...
## $ Conocimiento_R : chr "Intermediate" "Intermediate" "Beginner (some knowledge)" "Intermediate" ...
Ahora usaremos los datos que tenemos para aprender diferentes comandos y funciones en el entorno de R.
Primero, vamos verificar cuántos estudiantes respondieron al
formulario del curso contando el número de filas. Para esto, utilizamos
la función nrow
.
## [1] 124
A continuación, verificaremos si en nuestro grupo hay personas que comparten la misma formación académica y ocupación.
Esto se puede hacer fácilmente con la función table
, que
indica la frecuencia de cada observación:
Estructuras condicionales
if y else
Para nuestra próxima actividad con los datos, primero vamos a
entender cómo funcionan las estructuras if
y
else
.
En las funciones condicionales if
y else
,
establecemos una condición para if
. Si la condición es
verdadera, se realizará la actividad, y en caso contrario
(else
) se ejecutará otra tarea. Veamos un ejemplo:
## dos no es mayor que tres
- Actividad: Descubre el Nivel de Conocimientos en R
de la segunda persona que respondió (línea 2). Envía un mensaje de
“Nivel Intermedio” si es intermedio, o un mensaje de “Nivel Básico o
Avanzado” en caso contrario. (pista: el signo
==
significa “exactamente igual a”).
## Fecha Afiliacion Longitud Latitud
## 1 07/04/2025 14:00:00 Rcourse2021 -54.5724 -25.5263
## 2 07/04/2025 14:00:00 Rcourse2021 -47.6476 -22.725
## 3 07/04/2025 14:00:00 Rcourse2021 -48.0547 -15.911
## 4 07/04/2025 14:00:00 Rcourse2021 -106.6563 52.1418
## 5 07/04/2025 14:00:00 Rcourse2021 -47.6604 -22.7641
## 6 07/04/2025 14:00:00 Rcourse2021 -47.6434 -22.7118
## Antecedentes Ocupacion_Actual Explicacion
## 1 Agronomia PhD
## 2 Agronomia PhD
## 3 Biotecnologia Masters degree
## 4 Licenciatura em Ciências Biológicas Other
## 5 Agronomia Profissional
## 6 Agronomia PhD
## Conocimiento_R
## 1 Intermediate
## 2 Intermediate
## 3 Beginner (some knowledge)
## 4 Intermediate
## 5 Beginner (some knowledge)
## 6 Intermediate
if(dados$Conocimiento_R[2] == "Intermediate"){
cat("Nivel Intermedio")
} else {
cat("Nivel Básico o Avanzado")
}
## Nivel Intermedio
Podemos especificar más de una condición repitiendo la estructura
if
y else
.
Ahora analizaremos la ocupación de las personas que respondieron al
cuestionario.
if(dados$Ocupacion_Actual[2] == "Other"){
print(dados$Explicacion[2])
} else if (dados$Ocupacion_Actual[2] == "PhD"){
print(paste("¿Tu doctorado es en:", dados$Antecedentes[2], "?"))
} else {
print(paste("¿Aún trabajas con:", dados$Antecedentes[2], "?"))
}
## [1] "¿Tu doctorado es en: Agronomia ?"
Sin embargo, observa que solo es posible utilizar estas estructuras para un elemento individual de un vector o para todo el vector. Si queremos recorrer los elementos individualmente, necesitaremos utilizar otro recurso.
Estructuras de repetición
For
Este recurso puede ser la función for
, una función muy
utilizada y poderosa. Constituye una estructura de bucle, ya que
aplicará la misma actividad repetidamente hasta alcanzar una determinada
condición. Observa los ejemplos:
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
## [1] 5 6 7 8 9 10 11 12 13 14
En los casos anteriores, i
funciona como un índice que
varía de 1 a 10 en la operación determinada entre llaves.
Con esta estructura, podemos repetir la operación realizada con las
estructuras if
y else
para todo el vector:
for(i in 1:nrow(dados)){
if(dados$Ocupacion_Actual[i] == "Other"){
print(dados$Explicacion[i])
} else if (dados$Ocupacion_Actual[i] == "PhD"){
print(paste("¿Tu doctorado es en:", dados$Antecedentes[i], "?"))
} else {
print(paste("¿Aún trabajas con:", dados$Antecedentes[i], "?"))
}
}
Observa que algunas personas no respondieron cuando preguntadas sobre
lo que querían decir con “Otros”. Para evitar que R devuelva un error en
este caso, podemos usar la función is.na
para verificar si
la respuesta es NA (no disponible).
for(i in 1:nrow(dados)){
if(dados$Ocupacion_Actual[i] == "Other"){
if(is.na(dados$Explicacion[i])) {
print("Esta persona no explicó qué quiso decir con 'Otros'")
} else {
print(dados$Explicacion[i])
}
} else if (dados$Ocupacion_Actual[i] == "PhD"){
print(paste("¿Tu doctorado es en:", dados$Antecedentes[i], "?"))
} else {
print(paste("¿Aún trabajas con:", dados$Antecedentes[i], "?"))
}
}
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Biotecnologia ?"
## [1] ""
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Zootecnia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Engenharia Florestal ?"
## [1] "¿Tu doctorado es en: Bacharel em Agronomia ?"
## [1] ""
## [1] "¿Tu doctorado es en: Engenharia Agrícola ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Engenharia Agronômica ?"
## [1] "¿Aún trabajas con: Ciências Biológicas ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Engenheiro Florestal ?"
## [1] "¿Aún trabajas con: Genética e Melhoramento de Plantas ?"
## [1] ""
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Aún trabajas con: Engenharia Agronômica ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Ciências Biológicas ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Aún trabajas con: Ciências Biológicas ?"
## [1] "¿Tu doctorado es en: Engenharia Agronômica ?"
## [1] "¿Aún trabajas con: Ciências Biológicas ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Biotecnologia ?"
## [1] "¿Tu doctorado es en: Biologia ?"
## [1] ""
## [1] "¿Aún trabajas con: Biologia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Biologia ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Aún trabajas con: Melhoramento genético ?"
## [1] ""
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Ciências Biológicas ?"
## [1] "¿Aún trabajas con: Ciências Biológicas ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Aún trabajas con: Biologia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] ""
## [1] "¿Tu doctorado es en: Zootecnia ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Tu doctorado es en: Biotecnologia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Tu doctorado es en: Genética e Melhoramento ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] ""
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Biologia ?"
## [1] "¿Tu doctorado es en: Genética e Melhoramento de Plantas ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] ""
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Engeheria em Biotecnologia Vegetal (Chile) ?"
## [1] "¿Aún trabajas con: AGRONOMIA ?"
## [1] "¿Aún trabajas con: Engenharia Agronômica ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Biología ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Ciências Biológicas ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Ciências Biológicas ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Tu doctorado es en: Engenharia Biotecnológica ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Tu doctorado es en: Engenharia Florestal ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Biologia ?"
## [1] "¿Tu doctorado es en: Biologia ?"
## [1] "¿Tu doctorado es en: Ciências Biológicas ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] ""
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Engenheiro Agrônomo ?"
## [1] "¿Tu doctorado es en: Genética e Melhoramento ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] ""
## [1] "¿Tu doctorado es en: Agronomia ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] ""
## [1] "¿Aún trabajas con: Engenharia Agronômica / Licenciatura em Ciências Agrárias ?"
## [1] "¿Aún trabajas con: Ciencias Biologicas ?"
## [1] "¿Aún trabajas con: Agronomia ?"
## [1] "¿Tu doctorado es en: Eng. Florestal ?"
## [1] "Postdoc"
## [1] "¿Aún trabajas con: Professional ?"
## [1] "¿Aún trabajas con: Plant Genetics ?"
## [1] "¿Aún trabajas con: Professional ?"
## [1] "Finished my Masters "
## [1] "¿Aún trabajas con: Soil Sciencies ?"
## [1] "Masters degree"
## [1] "PhD"
Consejo: Identación
Observa la diferencia:
# Sin identación
for(i in 1:nrow(dados)){
if(dados$Ocupacion_Actual[i] == "Other"){
if(is.na(dados$Explicacion[i])) {
print("Esta persona no explicó qué quiso decir con 'Otros'")
} else {
print(dados$Explicacion[i])
}
} else if (dados$Ocupacion_Actual[i] == "PhD"){
print(paste("¿Tu doctorado es en:", dados$Antecedentes[i], "?"))
} else {
print(paste("¿Aún trabajas con:", dados$Antecedentes[i], "?"))
}
}
El editor de código de RStudio tiene una función que facilita la
identación de códigos en R. Selecciona el área que deseas identar y
presiona Ctrl+i
.
Ahora trabajaremos con la columna 5, que contiene información sobre
el background de los participantes. Observa que la función
table
devuelve diferentes categorías que pueden resumirse
en una sola, como “Ingeniería Agronómica” y “Agronomía”. Vamos usar un
loop para identificar quiénes seleccionaron áreas relacionadas con
“Agro”, luego verificar cuáles respuestas no fueron “Agronomía” y
pedirle al participante que modifique su respuesta escribiendo solo
“Agronomía”.
Consejo: Para identificar el patrón “Agro”, podemos usar la función
grepl
.
## [1] "Agronomia"
## [2] "Agronomia"
## [3] "Biotecnologia"
## [4] "Licenciatura em Ciências Biológicas"
## [5] "Agronomia"
## [6] "Agronomia"
## [7] "Zootecnia"
## [8] "Agronomia"
## [9] "Agronomia"
## [10] "Engenharia Florestal"
## [11] "Bacharel em Agronomia"
## [12] "Engenharia Agronômica"
## [13] "Engenharia Agrícola"
## [14] "Agronomia"
## [15] "Engenharia Agronômica"
## [16] "Ciências Biológicas"
## [17] "Agronomia"
## [18] "Engenheiro Florestal"
## [19] "Genética e Melhoramento de Plantas"
## [20] "Agronomia"
## [21] "Agronomia"
## [22] "Engenharia Agronômica"
## [23] "Agronomia"
## [24] "Agronomia"
## [25] "Ciências Biológicas"
## [26] "Agronomia"
## [27] "Ciências Biológicas"
## [28] "Engenharia Agronômica"
## [29] "Ciências Biológicas"
## [30] "Agronomia"
## [31] "Biotecnologia"
## [32] "Biologia"
## [33] "Agronomia"
## [34] "Biologia"
## [35] "Agronomia"
## [36] "Biologia"
## [37] "Agronomia"
## [38] "Melhoramento genético"
## [39] "FAEM - UFPEL"
## [40] "Agronomia"
## [41] "Ciências Biológicas"
## [42] "Ciências Biológicas"
## [43] "Agronomia"
## [44] "Biologia"
## [45] "Agronomia"
## [46] "Agronomia"
## [47] "Eng. Agronômica"
## [48] "Zootecnia"
## [49] "Agronomia"
## [50] "Biotecnologia"
## [51] "Agronomia"
## [52] "Agronomia"
## [53] "Agronomia"
## [54] "Agronomia"
## [55] "Agronomia"
## [56] "Agronomia"
## [57] "Agronomia"
## [58] "Genética e Melhoramento"
## [59] "Agronomia"
## [60] "Agronomia"
## [61] "Agronomia"
## [62] "Ciências bilógicas"
## [63] "Agronomia"
## [64] "Biologia"
## [65] "Genética e Melhoramento de Plantas"
## [66] "Agronomia"
## [67] "Agronomia"
## [68] "Agronomia"
## [69] "Agronomia"
## [70] "Agronomia"
## [71] "Agronomia"
## [72] "Agronomia"
## [73] "Agronomia"
## [74] "Engeheria em Biotecnologia Vegetal (Chile)"
## [75] "AGRONOMIA"
## [76] "Engenharia Agronômica"
## [77] "Agronomia"
## [78] "Agronomia"
## [79] "Biología"
## [80] "Agronomia"
## [81] "Ciências Biológicas"
## [82] "Agronomia"
## [83] "Agronomia"
## [84] "Agronomia"
## [85] "Agronomia"
## [86] "Agronomia"
## [87] "Ciências Biológicas"
## [88] "Agronomia"
## [89] "Agronomia"
## [90] "Agronomia"
## [91] "Agronomia"
## [92] "Agronomia"
## [93] "Engenharia Biotecnológica"
## [94] "Agronomia"
## [95] "Agronomia"
## [96] "Engenharia Florestal"
## [97] "Agronomia"
## [98] "Agronomia"
## [99] "Biologia"
## [100] "Biologia"
## [101] "Ciências Biológicas"
## [102] "Agronomia"
## [103] "Agronomia"
## [104] "Agronomia"
## [105] "Engenheiro Agrônomo"
## [106] "Genética e Melhoramento"
## [107] "Agronomia"
## [108] "Agronomia"
## [109] "Biotecnologia"
## [110] "Agronomia"
## [111] "Agronomia"
## [112] "Biotecnologia"
## [113] "Engenharia Agronômica / Licenciatura em Ciências Agrárias"
## [114] "Ciencias Biologicas"
## [115] "Agronomia"
## [116] "Eng. Florestal"
## [117] "Genetics"
## [118] "Professional"
## [119] "Plant Genetics"
## [120] "Professional"
## [121] "Climate Change"
## [122] "Soil Sciencies "
## [123] "Animal Science"
## [124] "Animal Breeding and Genetics"
## [1] TRUE TRUE FALSE FALSE TRUE TRUE FALSE TRUE TRUE FALSE TRUE TRUE
## [13] FALSE TRUE TRUE FALSE TRUE FALSE FALSE TRUE TRUE TRUE TRUE TRUE
## [25] FALSE TRUE FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE TRUE FALSE
## [37] TRUE FALSE FALSE TRUE FALSE FALSE TRUE FALSE TRUE TRUE TRUE FALSE
## [49] TRUE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE
## [61] TRUE FALSE TRUE FALSE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [73] TRUE FALSE FALSE TRUE TRUE TRUE FALSE TRUE FALSE TRUE TRUE TRUE
## [85] TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE FALSE
## [97] TRUE TRUE FALSE FALSE FALSE TRUE TRUE TRUE FALSE FALSE TRUE TRUE
## [109] FALSE TRUE TRUE FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
## [121] FALSE FALSE FALSE FALSE
## [1] "Agronomia"
## [2] "Agronomia"
## [3] "Agronomia"
## [4] "Agronomia"
## [5] "Agronomia"
## [6] "Agronomia"
## [7] "Bacharel em Agronomia"
## [8] "Engenharia Agronômica"
## [9] "Agronomia"
## [10] "Engenharia Agronômica"
## [11] "Agronomia"
## [12] "Agronomia"
## [13] "Agronomia"
## [14] "Engenharia Agronômica"
## [15] "Agronomia"
## [16] "Agronomia"
## [17] "Agronomia"
## [18] "Engenharia Agronômica"
## [19] "Agronomia"
## [20] "Agronomia"
## [21] "Agronomia"
## [22] "Agronomia"
## [23] "Agronomia"
## [24] "Agronomia"
## [25] "Agronomia"
## [26] "Agronomia"
## [27] "Eng. Agronômica"
## [28] "Agronomia"
## [29] "Agronomia"
## [30] "Agronomia"
## [31] "Agronomia"
## [32] "Agronomia"
## [33] "Agronomia"
## [34] "Agronomia"
## [35] "Agronomia"
## [36] "Agronomia"
## [37] "Agronomia"
## [38] "Agronomia"
## [39] "Agronomia"
## [40] "Agronomia"
## [41] "Agronomia"
## [42] "Agronomia"
## [43] "Agronomia"
## [44] "Agronomia"
## [45] "Agronomia"
## [46] "Agronomia"
## [47] "Agronomia"
## [48] "Engenharia Agronômica"
## [49] "Agronomia"
## [50] "Agronomia"
## [51] "Agronomia"
## [52] "Agronomia"
## [53] "Agronomia"
## [54] "Agronomia"
## [55] "Agronomia"
## [56] "Agronomia"
## [57] "Agronomia"
## [58] "Agronomia"
## [59] "Agronomia"
## [60] "Agronomia"
## [61] "Agronomia"
## [62] "Agronomia"
## [63] "Agronomia"
## [64] "Agronomia"
## [65] "Agronomia"
## [66] "Agronomia"
## [67] "Agronomia"
## [68] "Agronomia"
## [69] "Agronomia"
## [70] "Agronomia"
## [71] "Agronomia"
## [72] "Agronomia"
## [73] "Engenharia Agronômica / Licenciatura em Ciências Agrárias"
## [74] "Agronomia"
for(i in 1:nrow(dados)){
if(grepl("Agro", dados[i,5])){
if(dados[i,5] != "Agronomia"){
print("Por favor, sustituye tu respuesta por Agronomía.")
}
}
}
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
Observa que el código anterior no retorna las filas incorrectas, solo imprime el mensaje. Para solucionar esto, debemos almacenar estas filas en un vector y luego acceder a ellas.
homog <- vector()
for(i in 1:nrow(dados)){
if(grepl("Agro", dados[i,5])){
if(dados[i,5] != "Agronomia"){
print("Por favor, sustituye tu respuesta por Agronomía.")
homog <- c(homog, i)
}
}
}
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] "Por favor, sustituye tu respuesta por Agronomía."
## [1] 11 12 15 22 28 47 76 113
¿Cómo corregirías estos elementos incorrectos? ¡Inténtalo!
‘dados[homog, 5] <- “Agronomía”’
While
En este tipo de estructura de repetición, la tarea se realizará hasta que se alcance determinada condición.
## 2345
Es muy importante que en esta estructura se alcance la condición, en caso contrario el bucle funcionará infinitamente y tendrás que interrumpirlo por medios externos. Un ejemplo de estos “medios externos” en RStudio es hacer clic en el símbolo en rojo en la esquina superior derecha de la ventana de la consola. También puedes presionar Ctrl+C en la consola.
No es muy difícil que esto suceda, basta un pequeño error como:
Aquí podemos utilizar los comandos break
y
next
para atender otras condiciones, como:
## 23
## 235
Repeat
Esta estructura también exige una condición de parada, pero esta
condición se coloca necesariamente dentro del bloque de código con el
uso de break
. Entonces repite el bloque de código hasta que
la condición lo interrumpa.
## 234
Bucles dentro de bucles
También es posible utilizar estructuras de repetición dentro de estructuras de repetición. Por ejemplo, si queremos trabajar tanto en las columnas como en las filas de una matriz.
# Creando una matriz vacía
ex_mat <- matrix(nrow=10, ncol=10)
# cada número dentro de la matriz será el producto del índice de la columna por el índice de la fila
for(i in 1:dim(ex_mat)[1]) {
for(j in 1:dim(ex_mat)[2]) {
ex_mat[i,j] = i*j
}
}
Otro ejemplo de uso:
var1 <- c("fertilizante1", "fertilizante2")
var2 <- c("ESS", "URO", "GRA")
w <- 1
for(i in var1){
for(j in var2){
nombre_archivo <- paste0(i,"_planta_",j,".txt")
archivo <- data.frame("bloque" = "fake_data", "tratamiento" ="fake_data")
write.table(archivo, file = nombre_archivo)
w <- w + 1
}
}
# Verifica tu directorio de trabajo, los archivos deben haber sido generados
Si estás adelantado/a respecto a tus compañeros, ya puedes hacer los ejercicios de la Sesión 3, si no, hazlos en otro momento y envíanos dudas por el foro.
Algunos consejos:
- Ten cuidado al ejecutar el mismo comando más de una vez, algunas variables pueden no ser como eran antes. Para que el comando funcione de la misma forma es necesario que los objetos de entrada estén de la forma que esperas.
- Recuerda que
=
es para definir objetos y==
es el signo de igualdad. - En las estructuras condicionales y de repetición, recuerda que es necesario mantener la sintaxis esperada: If(){} y for(i in 1:10){}. En el for, podemos cambiar la letra que será el índice, pero siempre es necesario proporcionar una secuencia de enteros o caracteres.
- Usar indentación ayuda a visualizar el principio y fin de cada estructura de código y facilita el abrir y cerrar llaves. Indentación son esos espacios que usamos antes de la línea, como:
# Creando una matriz vacía
ex_mat <- matrix(nrow=10, ncol=10)
# cada número dentro de la matriz será el producto del índice de la columna por el índice de la fila
for(i in 1:dim(ex_mat)[1]) { # Primer nivel, no tiene espacio
for(j in 1:dim(ex_mat)[2]) { # Segundo nivel tiene un espacio (tab)
ex_mat[i,j] = i*j # Tercer nivel tiene dos espacios
} # Cerré el segundo nivel
} # Cerré el primer nivel
Vectorización
Aunque los bucles son intuitivos y más fáciles de entender, son más lentos y menos eficientes que la vectorización. La vectorización es una técnica que permite aplicar operaciones en todos los elementos de un vector o matriz de una sola vez, sin la necesidad de iterar sobre cada elemento individualmente.
Aquí está un simple ejemplo de un código no vectorizado (utilizando bucle) y su versión vectorizada:
# No vectorizado (usando bucle)
numeros <- 1:5
resultado_bucle <- numeric(length(numeros))
for(i in 1:length(numeros)) {
resultado_bucle[i] <- numeros[i] * 2
}
# Enfoque vectorizado
numeros <- 1:5
resultado_vectorizado <- numeros * 2
resultado_bucle == resultado_vectorizado
## [1] TRUE TRUE TRUE TRUE TRUE
Esta transformación de código puede volverse más compleja dependiendo del escenario. Por ejemplo, piensa cómo sería una versión vectorizada del bucle anterior:
# No vectorizado (usando bucle)
ex_mat <- matrix(nrow=10, ncol=10)
for(i in 1:dim(ex_mat)[1]) {
for(j in 1:dim(ex_mat)[2]) {
ex_mat[i,j] = i*j
}
}
# ¿Vectorizado?
Aquí es un buen momento para que practiques el uso de una herramienta de IA para ayudarte a transformar el código en una versión vectorizada. Puedes utilizar chatgpt o copilot, por ejemplo. Compara el resultado del código proporcionado con el que generaste con el bucle para verificar si la herramienta está realmente haciendo lo que deseas. Esta transformación vale la pena si el código en bucle está muy lento o si tienes que ejecutar el mismo código muchas veces.
’ex_mat <- outer(1:10, 1:10, “*“)’
Creando funciones
Si ya te sientes cómodo usando bucles, podrías preguntarte: “¿Y si
quiero hacer esto varias veces?” o
“¿Y si quiero aplicar esta lógica a diferentes conjuntos de datos?”.
Aquí es donde entran las funciones.
Podemos crear funciones personalizadas para realizar tareas específicas. La sintaxis básica para crear una función en R es la siguiente:
mi_funcion <- function(arg1, arg2) {
# Código de la función
resultado <- arg1 + arg2
return(resultado)
}
La función mi_funcion
recibe dos argumentos
(arg1
y arg2
) y devuelve su suma. Puedes
llamar a esta función pasando los valores deseados:
## [1] 8
Ejemplo de función personalizada con vectorización:
suma_vectorizada <- function(vector) {
# Verifica si el vector es numérico
if (!is.numeric(vector)) {
stop("El vector debe ser numérico.")
}
# Realiza la suma de los elementos del vector
suma <- sum(vector)
# Estandarización z-score
z_score <- (vector - mean(vector)) / sd(vector)
resultado <- list(suma = suma, z_score = z_score)
return(resultado)
}
# Llamando la función
resultado_vectorizado <- suma_vectorizada(c(1, 2, 3, 4, 5))
resultado_vectorizado
## $suma
## [1] 15
##
## $z_score
## [1] -1.2649111 -0.6324555 0.0000000 0.6324555 1.2649111
Ejemplo de función utilizando un data.frame como entrada. Observa que el uso repetitivo de la función requerirá que el dato de entrada tenga el mismo formato o al menos las columnas utilizadas. Una buena práctica es verificar si las columnas necesarias están presentes antes de realizar cálculos.
calc_volumen <- function(data_frame) {
if (!all(c("diametro", "altura") %in% colnames(data_frame))) {
stop("Las columnas 'diametro' y 'altura' deben estar presentes en el data frame.")
}
volumen <- 3.14 * ((data_frame$diametro / 2)^2) * data_frame$altura
return(volumen)
}
Es recomendable documentar siempre las funciones. Existe un paquete
llamado roxygen2
que genera páginas de manual
automáticamente para la documentación de las funciones en un paquete.
Requiere una sintaxis adecuada, como se indica a continuación:
#' Calculate the volume of cylinders based on diameter and height
#'
#' @param data_frame A data frame containing the columns "diametro" (diameter) and "altura" (height).
#'
#' @return A numeric vector with the calculated volumes for each cylinder.
#'
#' @details
#' Calculates the volume using the formula:
#' \deqn{Volumen = \pi \times \left(\frac{diametro}{2}\right)^2 \times altura}
#' If the required columns are missing, the function will stop with an error.
#'
#' @examples
#' df <- data.frame(diametro = c(4, 6), altura = c(10, 15))
#' calc_volumen(df)
#' # [1] 125.6 424.2
#'
#' @note
#' The function uses 3.14 as an approximation for pi. For higher precision, consider replacing 3.14 with the built-in `pi` constant.
calc_volumen <- function(data_frame) {
if (!all(c("diametro", "altura") %in% colnames(data_frame))) {
stop("Las columnas 'diametro' y 'altura' deben estar presentes en el data frame.")
}
volumen <- 3.14 * ((data_frame$diametro / 2)^2) * data_frame$altura
return(volumen)
}
Si esta función formara parte de un paquete, solo necesitaríamos usar
el comando roxygen2::roxygenise()
para crear la página de
ayuda. Vea un ejemplo de la estructura de un paquete de R en https://github.com/Breeding-Insight/BIGr
Familia de funciones apply
La familia de funciones apply
también puede funcionar
como estructura de repetición. Su sintaxis es más concisa comparada con
for
o while
y puede facilitar la elaboración
del código.
apply
La función apply
es la base de todas las demás de su
familia, por lo que entenderla es esencial. Su sintaxis es: apply(X,
MARGIN, FUN, …), donde X es un array (incluyendo matrices), MARGIN es 1
si se aplica a filas, 2 a columnas y c(1,2) a ambas; FUN es la función a
aplicar.
Ejemplo simple con una matriz:
Suma de columnas:
## [1] 3 15 27 39
Suma de filas:
## [1] 36 48
Equivalente con for
:
## [1] 3
## [1] 15
## [1] 27
## [1] 39
## [1] 36
## [1] 48
Ejemplo con función personalizada:
lapply
A diferencia de apply
, lapply
puede recibir
vectores y listas (se usa principalmente con listas) y devuelve una
lista.
ex_list <- list(A=matrix(seq(0,21,3), nrow = 2),
B=matrix(seq(0,14,2), nrow = 2),
C=matrix(seq(0,39,5), nrow = 2))
str(ex_list)
## List of 3
## $ A: num [1:2, 1:4] 0 3 6 9 12 15 18 21
## $ B: num [1:2, 1:4] 0 2 4 6 8 10 12 14
## $ C: num [1:2, 1:4] 0 5 10 15 20 25 30 35
Seleccionar segunda columna de todas las matrices:
## $A
## [1] 3
##
## $B
## [1] 2
##
## $C
## [1] 5
Usando una función personalizada:
## $A
## [,1] [,2]
## [1,] -1.1618950 -1.1618950
## [2,] -0.3872983 -0.3872983
## [3,] 0.3872983 0.3872983
## [4,] 1.1618950 1.1618950
##
## $B
## [,1] [,2]
## [1,] -1.1618950 -1.1618950
## [2,] -0.3872983 -0.3872983
## [3,] 0.3872983 0.3872983
## [4,] 1.1618950 1.1618950
##
## $C
## [,1] [,2]
## [1,] -1.1618950 -1.1618950
## [2,] -0.3872983 -0.3872983
## [3,] 0.3872983 0.3872983
## [4,] 1.1618950 1.1618950
sapply
sapply
es una variación de lapply
que
intenta simplificar el resultado devolviendo un vector, matriz o
array.
## A B C
## 3 2 5
## A B C
## [1,] -1.1618950 -1.1618950 -1.1618950
## [2,] -0.3872983 -0.3872983 -0.3872983
## [3,] 0.3872983 0.3872983 0.3872983
## [4,] 1.1618950 1.1618950 1.1618950
## [5,] -1.1618950 -1.1618950 -1.1618950
## [6,] -0.3872983 -0.3872983 -0.3872983
## [7,] 0.3872983 0.3872983 0.3872983
## [8,] 1.1618950 1.1618950 1.1618950
tapply
tapply
aplica funciones basadas en niveles de una
variable categórica (factor), comúnmente en data.frames.
## 'data.frame': 124 obs. of 8 variables:
## $ Fecha : chr "07/04/2025 14:00:00" "07/04/2025 14:00:00" "07/04/2025 14:00:00" "07/04/2025 14:00:00" ...
## $ Afiliacion : chr "Rcourse2021" "Rcourse2021" "Rcourse2021" "Rcourse2021" ...
## $ Longitud : chr "-54.5724" "-47.6476" "-48.0547" "-106.6563" ...
## $ Latitud : chr "-25.5263" "-22.725" "-15.911" "52.1418" ...
## $ Antecedentes : chr "Agronomia" "Agronomia" "Biotecnologia" "Licenciatura em Ciências Biológicas" ...
## $ Ocupacion_Actual: chr "PhD" "PhD" "Masters degree" "Other" ...
## $ Explicacion : chr "" "" "" "" ...
## $ Conocimiento_R : chr "Intermediate" "Intermediate" "Beginner (some knowledge)" "Intermediate" ...
dados$Afiliacion <- as.factor(dados$Afiliacion)
dados$Conocimiento_R_num <- NA
dados$Conocimiento_R_num[dados$Conocimiento_R == "Advanced"] <- 3
dados$Conocimiento_R_num[dados$Conocimiento_R == "Intermediate"] <- 2
dados$Conocimiento_R_num[dados$Conocimiento_R == "Beginner (some knowledge)"] <- 1
dados$Conocimiento_R_num[dados$Conocimiento_R == "No R knowledge"] <- 0
dados$Conocimiento_R_num[dados$Conocimiento_R == ""] <- NA
tapply(dados$Conocimiento_R_num, dados$Afiliacion, mean)
## Agronomic Engineer
## NA
## Breeding Insight
## NA
## CIA Central Pecuario
## 0.00000
## INTA
## 1.00000
## National Institute of Innovation and Transfer in Agricultural Technology
## 2.00000
## Rcourse2021
## 1.87069
## Agronomic Engineer
## NaN
## Breeding Insight
## 2.00000
## CIA Central Pecuario
## 0.00000
## INTA
## 1.00000
## National Institute of Innovation and Transfer in Agricultural Technology
## 2.00000
## Rcourse2021
## 1.87069
mapply
mapply
es una versión multivariada de
sapply
, permite aplicar funciones a múltiples vectores.
suma <- function(x, y) {
return(x + y)
}
vetor1 <- c(1, 2, 3)
vetor2 <- c(4, 5, 6)
resultado_mapply <- mapply(suma, vetor1, vetor2)
print(resultado_mapply)
## [1] 5 7 9
multiplicacion <- function(x, y, z) {
return(x * y * z)
}
vetor3 <- c(7, 8, 9)
resultado_mapply <- mapply(multiplicacion, vetor1, vetor2, vetor3)
print(resultado_mapply)
## [1] 28 80 162
resultado_mapply <- mapply(function(x, y) {
return(c(suma = x + y, producto = x * y))
}, vetor1, vetor2)
print(resultado_mapply)
## [,1] [,2] [,3]
## suma 5 7 9
## producto 4 10 18
suma_producto <- function(x, y) {
return(c(suma = x + y, producto = x * y))
}
resultado_mapply <- mapply(suma_producto, vetor1, vetor2)
print(resultado_mapply)
## [,1] [,2] [,3]
## suma 5 7 9
## producto 4 10 18
suma_producto <- function(x, y, z) {
return(c(suma = x + y + z, producto = x * y * z))
}
resultado_mapply <- mapply(suma_producto, vetor1, vetor2, vetor3)
print(resultado_mapply)
## [,1] [,2] [,3]
## suma 12 15 18
## producto 28 80 162
Si estás adelantado respecto a tus compañeros, ya puedes hacer los ejercicios de la Sesión extra. Si no, hazlos desde casa con calma y envíanos tus dudas por el foro.
Formatos Largo y Ancho
En el análisis y visualización de datos con R, especialmente usando
el tidyverse
, la estructura de los datos es muy importante.
tidyverse
es una colección de paquetes de R diseñados para
la ciencia de datos, y enfatiza el uso de principios de datos ordenados
(tidy data). Los datos ordenados son una forma estandarizada de
organizar los datos que facilita su uso. Aquí hay una lista de todos los
paquetes del tidyverse
:
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.2 ✔ tibble 3.2.1
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.0.4
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
## [1] "broom" "conflicted" "cli" "dbplyr"
## [5] "dplyr" "dtplyr" "forcats" "ggplot2"
## [9] "googledrive" "googlesheets4" "haven" "hms"
## [13] "httr" "jsonlite" "lubridate" "magrittr"
## [17] "modelr" "pillar" "purrr" "ragg"
## [21] "readr" "readxl" "reprex" "rlang"
## [25] "rstudioapi" "rvest" "stringr" "tibble"
## [29] "tidyr" "xml2" "tidyverse"
Existen dos formatos principales para organizar los datos:
- Formato ancho (wide): una fila por sujeto con múltiples columnas para medidas repetidas.
- Formato largo (long): una fila por observación,
haciendo que los datos sean ordenados y compatibles con herramientas
como
ggplot2
.
Veamos un conjunto de datos que muestra la población (en millones) de 10 países a lo largo de tres años:
# Datos en formato ancho (estimaciones realistas de población en millones)
data_wide <- tibble(
country = c(
"EEUU", "Canadá", "México", "Brasil", "Costa Rica",
"Uruguay", "China", "Japón", "India", "Groenlandia"
),
`2000` = c(282, 31, 98, 174, 4, 3.3, 1267, 127, 1050, 0.056),
`2010` = c(309, 34, 112, 196, 4.5, 3.4, 1340, 128, 1230, 0.057),
`2020` = c(331, 38, 126, 213, 5, 3.5, 1402, 126, 1380, 0.056)
)
data_wide
## # A tibble: 10 × 4
## country `2000` `2010` `2020`
## <chr> <dbl> <dbl> <dbl>
## 1 EEUU 282 309 331
## 2 Canadá 31 34 38
## 3 México 98 112 126
## 4 Brasil 174 196 213
## 5 Costa Rica 4 4.5 5
## 6 Uruguay 3.3 3.4 3.5
## 7 China 1267 1340 1402
## 8 Japón 127 128 126
## 9 India 1050 1230 1380
## 10 Groenlandia 0.056 0.057 0.056
Usa pivot_longer()
para convertir de formato ancho a
formato largo:
data_long <- pivot_longer(data_wide,
cols = -country,
names_to = "year",
values_to = "population"
)
data_long
## # A tibble: 30 × 3
## country year population
## <chr> <chr> <dbl>
## 1 EEUU 2000 282
## 2 EEUU 2010 309
## 3 EEUU 2020 331
## 4 Canadá 2000 31
## 5 Canadá 2010 34
## 6 Canadá 2020 38
## 7 México 2000 98
## 8 México 2010 112
## 9 México 2020 126
## 10 Brasil 2000 174
## # ℹ 20 more rows
Nota que nuestro data.frame
fue convertido al formato
tibble
. Los tibbles
son una versión moderna de
los data.frames
, diseñados para ser más fáciles de usar y
más eficientes. Son parte del tidyverse
y se utilizan
frecuentemente en análisis de datos. Aquí una comparación práctica:
Característica | data.frame | tibble (del paquete tibble) |
---|---|---|
Base o Tidyverse | Base R | Parte del tidyverse |
Impresión | Muestra todo | Muestra previa (10 filas) |
Tipos de columna | Conversión automática posible | No convierte automáticamente |
Indexación | df[,1] da un vector |
tibble[,1] da un tibble |
Nombres de fila | Siempre tiene | No utiliza nombres de fila |
La mayoría de las funciones de tidyverse
, especialmente
ggplot2
, funcionan mejor con datos en formato largo.
El formato ancho es generalmente más fácil de exportar a CSV o Excel.
Puedes volver al formato ancho con pivot_wider()
:
data_wide_back <- pivot_wider(data_long,
names_from = year,
values_from = population
)
data_wide_back
## # A tibble: 10 × 4
## country `2000` `2010` `2020`
## <chr> <dbl> <dbl> <dbl>
## 1 EEUU 282 309 331
## 2 Canadá 31 34 38
## 3 México 98 112 126
## 4 Brasil 174 196 213
## 5 Costa Rica 4 4.5 5
## 6 Uruguay 3.3 3.4 3.5
## 7 China 1267 1340 1402
## 8 Japón 127 128 126
## 9 India 1050 1230 1380
## 10 Groenlandia 0.056 0.057 0.056
Introducción al uso del pipe
El operador pipe (%>%) es una herramienta poderosa en R, especialmente cuando se utiliza el paquete tidyverse. Permite encadenar múltiples funciones de una manera clara y legible. En lugar de anidar funciones unas dentro de otras, puedes usar el pipe para pasar la salida de una función directamente como entrada a la siguiente. Aquí tienes un ejemplo:
El uso del operador pipe tiene sentido cuando se tiene una secuencia de operaciones que realizar sobre un conjunto de datos. Vamos a explorar algunas otras funciones del tidyverse que pueden utilizarse con el operador pipe.
data_wide_back <- data_long %>%
pivot_wider(
names_from = year,
values_from = population
) %>%
mutate(total_population = `2000` + `2010` + `2020`) %>%
arrange(desc(total_population))
La función mutate
se utiliza para crear nuevas variables
o modificar variables existentes, mientras que la función
arrange
se usa para ordenar el marco de datos según una o
más variables.
Otras funciones útiles incluyen filter
(para filtrar
filas según condiciones) y select
(para seleccionar
columnas específicas).
data_wide_back <- data_long %>%
pivot_wider(
names_from = year,
values_from = population
) %>%
mutate(total_population = `2000` + `2010` + `2020`) %>%
arrange(desc(total_population)) %>%
filter(total_population > 1000) %>%
select(country, total_population)
Usando el formato largo, también podemos resumir los datos utilizando
la función summarise
. Esto es útil para calcular
estadísticas resumidas como la media, la mediana o la población total
por año.
data_summary <- data_long %>%
group_by(year) %>%
summarise(
total_population = sum(population, na.rm = TRUE),
avg_population = mean(population, na.rm = TRUE),
max_population = max(population, na.rm = TRUE)
)
data_summary
## # A tibble: 3 × 4
## year total_population avg_population max_population
## <chr> <dbl> <dbl> <dbl>
## 1 2000 3036. 304. 1267
## 2 2010 3357. 336. 1340
## 3 2020 3625. 362. 1402
El operador pipe se popularizó con el paquete dplyr
y,
en versiones más recientes de R, también está disponible en la versión
base de R. En R base, el operador pipe es |>
,
pero funciona de manera similar al operador %>%
del
paquete dplyr
.
La principal diferencia es que el operador pipe de R base
(|>
) no requiere el paquete magrittr
, el
cual sí es necesario para usar %>%
.
Otra diferencia es que el operador %>%
permite usar el
marcador de posición .
para indicar dónde debe colocarse la
entrada en la siguiente función.
Esto es especialmente útil cuando la entrada no corresponde al primer
argumento de la función:
##
## Call:
## lm(formula = `2020` ~ `2000`, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -105.426 -4.807 -1.463 3.357 130.481
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.5810 23.1470 0.068 0.947
## `2000` 1.1885 0.0434 27.384 3.41e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 60.18 on 8 degrees of freedom
## Multiple R-squared: 0.9894, Adjusted R-squared: 0.9881
## F-statistic: 749.9 on 1 and 8 DF, p-value: 3.409e-09
La función lm
se utiliza para ajustar un modelo lineal,
y la función summary
proporciona un resumen del modelo
ajustado.
Cabe destacar que el marcador de posición .
indica que los
datos de entrada del paso anterior deben utilizarse como argumento
data
en la función lm
.
El operador pipe de R base no admite el uso del marcador
.
. En su lugar, puedes usar funciones anónimas entre
paréntesis para especificar dónde debe ir la entrada:
##
## Call:
## lm(formula = `2020` ~ `2000`, data = df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -105.426 -4.807 -1.463 3.357 130.481
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.5810 23.1470 0.068 0.947
## `2000` 1.1885 0.0434 27.384 3.41e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 60.18 on 8 degrees of freedom
## Multiple R-squared: 0.9894, Adjusted R-squared: 0.9881
## F-statistic: 749.9 on 1 and 8 DF, p-value: 3.409e-09
Introducción a ggplot2
ggplot2
es un paquete poderoso y flexible para crear
visualizaciones en R. Forma parte de la colección de paquetes del
tidyverse
y es ampliamente utilizado en la visualización de
datos.
La idea principal detrás de ggplot2
es crear gráficos
basados en la Gramática de los Gráficos (Grammar of
Graphics), un marco teórico para la visualización de datos que
descompone un gráfico en un conjunto de componentes independientes y
estructurados.
En ggplot2
, encontrarás los siguientes componentes
principales:
- Datos (Data): El conjunto de datos que estás utilizando.
- Estéticas (
aes
): Propiedades visuales (como posición, color, tamaño) que se asignan a los datos. - Geometrías (
geom
): Tipos de elementos visuales en un gráfico, como puntos, líneas, barras, etc. - Estadísticas (
stat
): Transformaciones estadísticas aplicadas a los datos, como suavizado o agrupamiento. - Escalas (
scale
): Ajustes para mapear los datos a las estéticas (por ejemplo, escalas de color). - Coordenadas (
coord
): El sistema de coordenadas, como cartesiano o polar. - Facetas (
facet
): División del conjunto de datos en subconjuntos para crear múltiples paneles (como pequeños múltiplos).
A continuación se presenta un desglose de los elementos clave de la Gramática de los Gráficos:
Aquí tienes la traducción al español manteniendo el formato R
Markdown (.Rmd
):
Datos
Los datos son la base de cualquier gráfico. Contienen las variables
que deseas visualizar. En ggplot2
, se especifican los datos
usando el argumento data
:
Estéticas (aes)
Las estéticas definen cómo se asignan los datos a las propiedades visuales del gráfico, como:
- posición en x e y (x, y)
- color (color)
- tamaño (size)
- forma (shape)
- relleno (fill)
Por ejemplo:
Aquí:
- x = year (eje horizontal)
- y = population (eje vertical)
Geometrías (geom)
Las geometrías son los elementos visuales del gráfico. Diferentes tipos de geometrías permiten crear diferentes tipos de gráficos:
geom_point()
para gráficos de dispersión
geom_line()
para gráficos de líneas
geom_bar()
para gráficos de barras
geom_histogram()
para histogramas
geom_boxplot()
para diagramas de caja
Por ejemplo:
ggplot(data = data_long, aes(x = year, y = population, group = country)) +
geom_line() + geom_point()
# agregar color por país
ggplot(data = data_long, aes(x = year, y = population, group = country, color = country)) +
geom_line()
Esto crea un gráfico de dispersión donde los puntos representan los datos.
Estadísticas (stat)
Algunos gráficos requieren transformaciones estadísticas, como
suavizado o agrupamiento. Puedes aplicar estas transformaciones usando
las funciones stat_*
.
Podemos aplicar resúmenes estadísticos. Por ejemplo, agregar una tendencia suavizada:
ggplot(data_long, aes(x = year, y = population)) +
stat_summary(fun = mean, geom = "line", group = 1) +
labs(title = "Tendencia Promedio de la Población")
Escalas (scale)
Modifica cómo los datos se asignan a las estéticas visuales (por ejemplo, color):
ggplot(data_long, aes(x = year, y = population, group = country, color = country)) +
geom_line(size = 1.2) +
scale_color_manual(values = c("China" = "red", "India" = "orange", "USA" = "blue")) +
labs(title = "Población por País (Colores Seleccionados)")
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
Aquí, scale_color_manual()
personaliza la asignación de
colores para cada país. También puedes usar paletas listas del paquete
viridis
, que es amigable para personas con daltonismo:
## Loading required package: viridisLite
ggplot(data_long, aes(x = year, y = population, group = country, color = country)) +
geom_line(size = 1.2) +
scale_color_viridis_d() +
labs(title = "Población por País (Colores Viridis)")
Esto utiliza la paleta de colores viridis, que está diseñada para ser perceptualmente uniforme y accesible.
Coordenadas (coord)
El sistema de coordenadas define la disposición del gráfico. El sistema más común es el cartesiano (ejes x e y), pero también puedes usar coordenadas polares o transformar los ejes.
Por ejemplo:
ggplot(data_long %>% filter(year == "2020"), aes(x = country, y = population)) +
geom_col() +
coord_flip() +
labs(title = "Población por País en 2020 (Ejes Invertidos)")
Esto invierte los ejes, de modo que el eje x se convierte en el eje y y viceversa.
Facetas (facet)
Las facetas permiten dividir un gráfico en múltiples paneles, lo cual es útil para comparar subconjuntos de los datos. Las facetas pueden hacerse por filas o columnas:
ggplot(data_long, aes(x = year, y = population)) +
geom_line(group = 1) +
facet_wrap(~ country) +
labs(title = "Tendencia de Población por País (Faceteado)")
Etiquetas y Temas
Puedes personalizar el gráfico con etiquetas y temas. Las etiquetas incluyen títulos, etiquetas de ejes y leyendas. Los temas controlan la apariencia general del gráfico.
ggplot(data_long, aes(x = year, y = population, group = country, color = country)) +
geom_line(size = 1.2) +
labs(
title = "Población a lo Largo del Tiempo por País",
subtitle = "Basado en datos simulados (millones)",
x = "Año",
y = "Población (Millones)",
caption = "Fuente de datos: Simulado"
) +
theme_minimal()
Puedes personalizar las fuentes y el estilo:
ggplot(data_long, aes(x = year, y = population, color = country, group = country)) +
geom_line(size = 1.2) +
labs(
title = "Población a lo Largo del Tiempo por País",
subtitle = "Basado en datos simulados (millones)",
x = "Año",
y = "Población (Millones)",
caption = "Fuente de datos: Simulado"
) +
theme_minimal() + theme(
plot.title = element_text(size = 18, face = "bold"),
axis.title = element_text(size = 14),
legend.title = element_text(size = 12)
)
Creación de gráficos de mapas con ggplot2
# Load necessary datasets
dados <- read.csv("https://breeding-insight.github.io/learn-hub/r-intro/data/dados_2025.csv")
colnames(dados) <- c("Date", "Affiliation", "Longitude", "Latitude", "Background", "Present_Occupation", "Explain", "KnowledgeR")
# Create quantitative measure
dados$KnowledgeR_num <- NA
dados$KnowledgeR_num[dados$KnowledgeR == "Advanced"] <- 3
dados$KnowledgeR_num[dados$KnowledgeR == "Intermediate"] <- 2
dados$KnowledgeR_num[dados$KnowledgeR == "Beginner (some knowledge)"] <- 1
dados$KnowledgeR_num[dados$KnowledgeR == "No R knowledge"] <- 0
dados$KnowledgeR_num[dados$KnowledgeR == ""] <- NA
# Cargar los datos del mapa del mundo
world_map <- map_data("world")
dados$Latitude <- as.numeric(dados$Latitude)
## Warning: NAs introduced by coercion
## Warning: NAs introduced by coercion
# Crear el gráfico
ggplot() +
geom_polygon(data = world_map, aes(x = long, y = lat, group = group), fill = "lightgray", color = "white") +
# Graficar los puntos ubicación de cada persona
geom_point(data = dados, aes(x = Longitude, y = Latitude), alpha = 0.7) +
labs(title = "R course students", x = "Longitud", y = "Latitud") +
theme_minimal() +
theme(legend.position = "bottom")
## Warning: Removed 4 rows containing missing values or values outside the scale range
## (`geom_point()`).
# color por profesión
ggplot() +
geom_polygon(data = world_map, aes(x = long, y = lat, group = group), fill = "lightgray", color = "white") +
# Graficar los puntos ubicación de cada persona
geom_point(data = dados, aes(x = Longitude, y = Latitude, color = Present_Occupation), alpha = 0.7) +
labs(title = "R course students", x = "Longitud", y = "Latitud") +
theme_minimal() +
theme(legend.position = "bottom")
## Warning: Removed 4 rows containing missing values or values outside the scale range
## (`geom_point()`).
# amigable con daltonismo
ggplot() +
geom_polygon(data = world_map, aes(x = long, y = lat, group = group), fill = "lightgray", color = "white") +
# Graficar los puntos ubicación de cada persona
geom_point(data = dados, aes(x = Longitude, y = Latitude, color = Present_Occupation), alpha = 0.7) +
scale_colour_viridis_d() +
labs(title = "R course students", x = "Longitud", y = "Latitud") +
theme_minimal() +
theme(legend.position = "bottom")
## Warning: Removed 4 rows containing missing values or values outside the scale range
## (`geom_point()`).