Aprender R Iniciación y Perfeccionamiento
Aprender R Iniciación y Perfeccionamiento
François Rebaudo
2019-04-10
2
Contents
1 Preámbulo 5
1.2 Agradecimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.3 Licencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2 Introducción 9
I Conceptos básicos 11
3 Primeros pasos 13
3.1 Instalar R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.5 Conclusión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
4.2 RStudio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.4 Geany . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.6 Conclusión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3
4 CONTENTS
5 Tipos de datos 37
5.5 Acerca de NA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
5.6 Conclusión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
6 Contenedores de datos 47
6.6 Conclusión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
7 Las funciones 87
7.6 Otras funciones desarrolladas por la comunidad de usuarios: los packages . . . . . . . . . . . . . . . . . . . 120
9 Algorítmico 131
Preámbulo
Este libro está diseñado para actualizarse de acuerdo con las nuevas características de R y según la disponibilidad de sus
colaboradores. Es un libro de colaboración, así que siéntase libre de compartir sus comentarios o colaborar directamente para
mejorarlo.
Si tiene algún comentario, sugerencia o si identifica errores, no dude en enviarme un correo electrónico ([Link]@
ird.fr1 ), o si está familiarizado con GitHub en el sitio web del proyecto ([Link]
Este libro es colaborativo, se basa en su participación.
Este libro también está disponible en francés ([Link] Más allá de este libro, puede acceder
a las diapositivas del último curso de R realizado en marzo de 2019 en Quito, Ecuador2 .
10/04/2019
28/03/2019
22/01/2019
10/12/2018
29/11/2018
7
8 CHAPTER 1. PREÁMBULO
09/11/2018
08/11/2018
19/10/2018
28/09/2018
17/09/2018
• Introducción
10/09/2018
06/09/2018
30/08/2018
24/08/2018
27/07/2018
25/07/2018
17/07/2018
16/07/2018
12/07/2018
06/07/2018
04/07/2018
02/07/2018
• tres capítulos en línea (primeros pasos, elegir un entorno de desarrollo, tipos de datos)
1.2 Agradecimientos
Agradezco a todos los colaboradores que ayudaron a mejorar este libro con sus consejos, sugerencias de cambios y correcciones
(en orden alfabético):
## Colaboradores :
Camila Benavides Frias (Bolivia)
Marc Girondot (France ; UMR 8079 ESE)
Susi Loza Herrera (Bolivia)
Estefania Quenta Herrera (Bolivia)
Baptiste Régnier (France)
Las versiones de gitbook, html y epub de este libro usan los iconos de fuente abierta de Font Awesome (https:
//[Link]). La versión en PDF utiliza los iconos del proyecto Tango disponibles en openclipart (https:
//[Link]/). Este libro fue escrito con el paquete R bookdown ([Link] El código fuente
está disponible en GitHub ([Link] La versión en línea se aloja y actualiza a través
de Netlify ([Link]
10 CHAPTER 1. PREÁMBULO
1.3 Licencia
• Reconocimiento — Debe reconocer adecuadamente la autoría, proporcionar un enlace a la licencia e indicar si se han
realizado cambios<. Puede hacerlo de cualquier manera razonable, pero no de una manera que sugiera que tiene el
apoyo del licenciador o lo recibe por el uso que hace.
• SinObraDerivada — Si remezcla, transforma o crea a partir del material, no puede difundir el material modificado.
• No hay restricciones adicionales — No puede aplicar términos legales o medidas tecnológicas que legalmente restrinjan
realizar aquello que la licencia permite.
Avisos:
No tiene que cumplir con la licencia para aquellos elementos del material en el dominio público o cuando su utilización esté
permitida por la aplicación de una excepción o un límite. No se dan garantías. La licencia puede no ofrecer todos los permisos
necesarios para la utilización prevista. Por ejemplo, otros derechos como los de publicidad, privacidad, o los derechos morales
pueden limitar el uso del material.
Chapter 2
Introducción
Porque R se ha convertido en una herramienta esencial para el análisis y la gestión de datos científicos, y en este contexto se
vuelve esencial dominar al menos los conceptos básicos. El éxito de R no es una coincidencia: R es un software que todos
pueden obtener libremente garantizando la transparencia y la reproducibilidad de los resultados científicos (sujeto a cumplir
con algunas reglas que abordará este libro). R también se basa en una comunidad muy activa con varios miles de módulos
adicionales (paquetes) para realizar el análisis estadístico más avanzado.
El propósito de este libro es proporcionar a los estudiantes y aquellos que deseen aprender sobre R una base sólida para luego
implementar sus propios proyectos científicos y la valoración de sus resultados. Hay muchos libros dedicados a R, pero ninguno
cubre los elementos básicos de este lenguaje con el fin de hacer que los resultados científicos sean publicables y reproducibles.
En general, este libro está dirigido a toda la comunidad científica y en particular a aquellos interesados en las ciencias de la vida,
y los ejemplos en este libro se basarán en estudios de biología.
Este libro nació de la solicitud de los estudiantes de las universidades que colaboran con el IRD en América del Sur. Por lo
tanto, su primera versión está escrita en español (hay pocos documentos de calidad en R en español). Comencé su traducción
al francés en 2018 y hoy ambas versiones coevolucionan con contenido que puede variar (por ejemplo, para estudios de casos).
11
12 CHAPTER 2. INTRODUCCIÓN
Part I
Conceptos básicos
13
Chapter 3
Primeros pasos
3.1 Instalar R
El programa para instalar el software R se puede descargar desde el sitio web de R: [Link] En
el sitio web de R, primero es necesario elegir un espejo CRAN (servidor desde el cual se debe descargar R, y desde el más
cercano a su ubicación geográfica), luego descargue el archivo base. Los usuarios de Linux pueden preferir un sudo apt-get
install r-base.
El software R se puede descargar de muchos servidores CRAN (Comprehensive R Archive Network) de todo el mundo. Estos
servidores se llaman espejos. La elección del espejo es manual.
Una vez que se inicia el programa, aparece una ventana cuya apariencia puede variar dependiendo de su sistema operativo
(Figura 3.1). Esta ventana se llama consola.
La consola corresponde a la interfaz donde se interpretará el código, es decir, donde el código será transformado en lenguaje de
máquina, ejecutado por la computadora y retransmitido en forma legible por humanos. Esto es análogo a lo que sucede en una
calculadora (Figura 3.2). Así es como se usará R más adelante en esta sección.
A lo largo de este libro, los ejemplos del código R aparecerán sobre un fondo gris. Se pueden copiar y pegar directamente en la
consola, aunque es mejor reproducir los ejemplos escribiéndolos en la consola (o más adelante en los scripts) para una mejor
comprensión del manejo del programa R. El resultado de lo que se envía en la consola también aparecerá en un fondo gris con
## delante del código para hacer la distinción entre el código y el resultado del código.
5 + 5
## [1] 10
Si escribimos 5 + 5 en la consola y luego Enter, el resultado aparece precedido por el número [1] entre corchetes. Este
número corresponde al número del resultado (en nuestro caso, solo hay un resultado, volveremos a este aspecto más adelante).
También podemos observar en este ejemplo el uso de espacios antes y después del signo +. Estos espacios no son necesarios,
15
16 CHAPTER 3. PRIMEROS PASOS
Label Operador
adición +
resta -
multiplicación *
división /
potencia ^
módulo %%
cociente decimal %/%
pero permiten que el código sea más legible para los humanos (es decir, más agradable de leer tanto para nosotros como para
las personas con las que queremos compartir nuestro código). Los operadores aritméticos disponibles en R se resumen en la
tabla 3.1.
Clásicamente, las multiplicaciones y divisiones tienen prioridad sobre las adiciones y sustracciones. Si es necesario, podemos
usar paréntesis.
5 + 5 * 2
## [1] 15
3.2. R COMO CALCULADORA 17
(5 + 5) * 2
## [1] 20
(5 + 5) * (2 + 2)
## [1] 40
(5 + 5) * ((2 + 2) / 3)^2
## [1] 17.77778
El operador módulo corresponde al resto de la división euclidiana. Se usa en ciencias de la computación, por ejemplo, para saber
si un número es par o impar (un número módulo 2 devolverá 1 si es impar y 0 si es par).
451 %% 2
## [1] 1
18 CHAPTER 3. PRIMEROS PASOS
288 %% 2
## [1] 0
(5 + 5 * 2) %% 2
## [1] 1
((5 + 5) * 2) %% 2
## [1] 0
R también incorpora algunas constantes que incluyen pi. Además, el signo infinito está representado por Inf.
pi
## [1] 3.141593
pi * 5^2
## [1] 78.53982
1/0
## [1] Inf
El estilo del código es importante porque el código está destinado a ser leído por nosotros y por otras personas. Para tener un
estilo legible, se recomienda colocar espacios antes y después de los operadores aritméticos, excepto “*”, “/” y “^”, aunque a
veces es útil agregarlos como es el caso en nuestro ejemplos.
Sin embargo, R es mucho más que una simple calculadora porque permite otro tipo de operadores: operadores de comparación,
para comparar los valores (Table 3.2).
Por ejemplo, si queremos saber si un numero es más grande que otro, podemos escribir:
3.2. R COMO CALCULADORA 19
Label Operador
más pequeño que <
mayor que >
más pequeño o igual a <=
más grande o igual a >=
igual a ==
diferente de !=
5 > 3
## [1] TRUE
5 > 3
## [1] TRUE
2 < 1.5
## [1] FALSE
2 <= 2
## [1] TRUE
## [1] TRUE
(5 + 8) > (3 * 45/2)
## [1] FALSE
En la comparación (5 + 8) > (3 * 45/2) no se necesitan paréntesis, pero permiten que el código sea más fácil de leer.
Un operador de comparación particular es igual a. Veremos en la siguiente sección que el signo = está reservado para otro uso:
permite asignar un valor a un objeto. El operador de comparación igual a debe ser diferente, por eso R usa ==.
20 CHAPTER 3. PRIMEROS PASOS
42 == 53
## [1] FALSE
58 == 58
## [1] TRUE
Otro operador particular es diferente de. Se usa con un signo de admiración seguido de igual, !=. Este operador permite obtener
la respuesta opuesta a ==.
42 == 53
## [1] FALSE
42 != 53
## [1] TRUE
(3 + 2) != 5
## [1] FALSE
10/2 == 5
## [1] TRUE
R usa TRUE y FALSE, que también son valores que se pueden probar con operadores de comparación. Pero R también asigna
un valor a TRUE y FALSE:
TRUE == TRUE
## [1] TRUE
## [1] TRUE
3.2. R COMO CALCULADORA 21
1 == TRUE
## [1] TRUE
0 == FALSE
## [1] TRUE
TRUE + 1
## [1] 2
FALSE + 1
## [1] 1
(FALSE + 1) == TRUE
## [1] TRUE
El valor de TRUE es 1 y el valor de FALSE es 0. Veremos más adelante cómo usar esta información en los próximos capítulos.
R es también un lenguaje relativamente permisivo, significa que admite cierta flexibilidad en la forma de escribir el código. Debatir
sobre la idoneidad de esta flexibilidad está fuera del alcance de este libro, pero podemos encontrar en el código R en Internet o
en otras obras el atajo T para TRUE y F for FALSE.
T == TRUE
## [1] TRUE
F == FALSE
## [1] TRUE
T == 1
## [1] TRUE
22 CHAPTER 3. PRIMEROS PASOS
Label Operador
no es !
y &
o |
o exclusivo xor()
F == 0
## [1] TRUE
(F + 1) == TRUE
## [1] TRUE
Aunque esta forma de referirse a TRUE y FALSE por T y F está bastante extendida, en este libro siempre usaremos TRUE y
FALSE para que el código sea más fácil de leer. Como mencionado anterioramente, el objetivo de un código no solo es ser
funcional sino también fácil de leer y volver a leer.
Hay un último tipo de operador, los operadores lógicos. Estos son útiles para combinar operadores de comparación (Table 3.3).
!TRUE
## [1] FALSE
!FALSE
## [1] TRUE
## [1] FALSE
## [1] TRUE
3.2. R COMO CALCULADORA 23
## [1] FALSE
## [1] TRUE
El operador lógico xor() es o exclusivo. Es decir, uno de los dos argumentos de la función xor() debe ser verdadero, pero
no ambos. Más adelante volveremos a las funciones y sus argumentos, pero recuerde que identificamos una función por sus
paréntesis que contienen argumentos separados por comas.
xor((3 + 2) == 5, (3 + 3) == 6)
## [1] FALSE
xor((3 + 2) == 5, (3 + 2) == 6)
## [1] TRUE
xor((3 + 3) == 5, (3 + 2) == 6)
## [1] FALSE
xor((3 + 3) == 5, (3 + 3) == 6)
## [1] TRUE
Se recomienda que las comas , sean seguidas de un espacio para que el código sea más agradable de leer.
El archivo de ayuda en inglés sobre operadores aritméticos se puede obtener con el comando ?'+'. El de los operadores de
comparación con el comando ?'==' y el de los operadores lógicos con el comando ?'&'.
24 CHAPTER 3. PRIMEROS PASOS
Un aspecto importante de la programación con R, pero también la programación en general es la noción de objeto. Como se
indica en la página web de wikipedia ([Link] en ciencias de
la computación, un objeto es un contenedor, es decir, algo que contendrá información. La información contenida en un objeto
puede ser muy diversa, pero por el momento contendremos en un objeto el número 5. Para hacer esto (y para reutilizarlo más
adelante), debemos darle un nombre a nuestro objeto. En R, los nombres de los objetos no deben contener caracteres especiales
como ^ $ ? | + () [] {}, entre otros. No deben comenzar con un número ni contener espacios. El nombre del objeto debe ser
representativo de lo que contiene, sin ser demasiado corto ni demasiado largo. Imagine que nuestro número 5 corresponde al
número de repeticiones de un experimento. Nos gustaría darle un nombre que se refiera a numero y repeticiones, que podríamos
reducir a nbr y rep, respectivamente (nbr para number en ingles). Hay varias posibilidades que son bastante comunes bajo R:
Todas estas formas de nombrar un objeto son equivalentes. En este libro usaremos el estilo lowerCamelCase. En general,
debemos evitar los nombres que son demasiado largos, como miNumeroDeRepeticionesDeMiExperimento o demasiado
cortos como nR, y los nombres que no permiten identificar los contenidos como miVariable o miNumero, asi que nombres
como a o b. El objetivo es de tener una idea de lo que hay en cada objeto en base a su nombre.
Hay diferentes maneras de definir un nombre para los objetos que crearemos con R. En este libro, utilizamos el estilo lowerCamel-
Case. Lo importante no es la elección del estilo, sino la consistencia en su elección. El objetivo es tener un código funcional,
pero también un código que sea fácil y agradable de leer para nosotros y para los demás.
Ahora que hemos elegido un nombre para nuestro objeto, debemos crearlo y hacer que R entienda que nuestro objeto debe
contener el número 5. Hay tres maneras de crear un objeto bajo R:
• con <-
• con =
• o con ->
nbrRep <- 5
nbrRep = 5
5 -> nbrRep
En este libro siempre usaremos la forma <- para coherencia y también porque es la forma más común.
nbrRep <- 5
Acabamos de crear un objeto nbrRep y establecerlo con el valor 5. Este objeto ahora está disponible en nuestro entorno de
computación y puede ser utilizado. Algunos ejemplos :
nbrRep + 2
## [1] 7
3.3. EL CONCEPTO DE OBJETO 25
nbrRep * 5 - 45/56
## [1] 24.19643
pi * nbrRep^2
## [1] 78.53982
El valor asociado con nuestro objeto nbrRep se puede modificar de la misma manera que cuando se creó:
nbrRep <- 5
nbrRep + 2
## [1] 7
nbrRep <- 10
nbrRep + 2
## [1] 12
## [1] 14.33333
El uso de objetos tiene sentido cuando tenemos operaciones complejas para realizar y hace que el código sea más agradable
de leer y entender.
## [1] 0.4696418
## [1] 0.4696418
26 CHAPTER 3. PRIMEROS PASOS
R es un lenguaje de programación denominado lenguaje de scripting. Esto se refiere al hecho de que la mayoría de los usuarios
escribirán pequeñas piezas de código en lugar de programas completos. R se puede usar como una simple calculadora, y en este
caso no será necesario mantener un historial de las operaciones que se han realizado. Pero si las operaciones a implementar
son largas y complejas, puede ser necesario e interesante guardar lo que se ha hecho para poder continuar más adelante. El
archivo en el que se almacenarán las operaciones es lo que comúnmente se llama el script. Un script, por lo tanto, es un archivo
que contiene una sucesión de información comprensible por R y que es posible ejecutar.
Para crear un nuevo script basta con abrir un documento vacío de texto, que será editado por un editor de texto como el bloc
de notas en Windows o Mac OSX, o Gedit o incluso nano en Linux. Por convención, este archivo toma la extensión “.r” o “.R”
(lo mas comun). Esta última convención se usará en este libro (“miArchivo.R”). Desde la interfaz gráfica de R, es posible crear
un nuevo script en Mac OS y Windows a través de file, luego new script y save as. Al igual que el nombre de los objetos,
el nombre del script es importante para que podamos identificar fácilmente su contenido. Por ejemplo, podríamos crear un
archivo formRConceptsBase.R que contenga los objetos que acabamos de crear y los cálculos que hicimos. Pero incluso
con nombres de objetos y archivos bien definidos, será difícil recordar el significado de este archivo sin la documentación que
acompaña a este script. Para documentar un script utilizaremos comentarios. Los comentarios son elementos que R identificará
como tales y no se ejecutarán. Para especificar a R que vamos a hacer un comentario, debemos usar el carácter octothorpe
(corsé o numeral) #. Los comentarios se pueden insertar en una nueva línea o al final de la línea.
Todo lo que hay despues del simbolo numeral # no sera ejecutado. Significa que podriamos usar comentarios como ### o
#comentario, aun que se recomienda hacer comentarios con un solo simbolo numeral seguido por un espacio y despues su
comentario: # mi comentario.
Los comentarios también se pueden usar para hacer que una línea ya no se ejecute. En este caso no queremos ejecutar la
secunda linea:
nbrRep <- 5
# nbrRep + 5
Para volver a la documentación del script, se recomienda comenzar cada uno de nuestros scripts con una breve descripción de
su contenido, luego cuando el script sea extenso, estructurarlo en diferentes partes para facilitar su lectura.
# ------------------------------------------------------------
# Aquí hay un script para adquirir los conceptos básicos
# con R
# fecha de creación : 27/06/2018
# autor : François Rebaudo
# ------------------------------------------------------------
nbrRep <- 5
3.5. CONCLUSIÓN 27
pi * nbrRep^2
## [1] 78.53982
Para ir más allá en el estilo del código, una guía completa de recomendaciones está disponible en línea en el sitio web tidyverse
(en ingles ; [Link]
Como tenemos un script, no trabajamos directamente en la consola. Pero solo la consola puede entender el código R y devolver-
nos los resultados que queremos obtener. Por ahora, la técnica más simple es copiar y pegar las líneas que queremos ejecutar
desde nuestro script hasta la consola. A partir de ahora, ya no utilizaremos editores de texto como bloc de notas, sino editores
especializados para la creación de scripts R. Sera es el objetivo del siguiente capítulo.
3.5 Conclusión
Felicitaciones, hemos llegado al final de este primer capítulo sobre la base de R. Sabemos:
• Instalar R
• Usar R como una calculadora
• Crear objetos y utilisarlos para los calculos aritméticos, comparativos y logicos
• Elejir nombres pertinentes para los objetos
• Crear un nuevo script
• Elejir un nombre pertinente para el archivo del script
• Ejecutar el codigo de un script
• Documentar los scripts con comentarios
• Usar un estilo de código para que sea agradable de leer y facil de entender
28 CHAPTER 3. PRIMEROS PASOS
Chapter 4
Hay muchos editores de texto, el capítulo anterior permitió introducir algunos de los más simples como el bloc de notas de
Windows. Sin embargo, los límites de estos editores han hecho tediosa la tarea de escribir un script. De hecho, incluso estruc-
turando su script con comentarios, sigue siendo difícil entenderlo. Aquí es donde entran los editores de texto especializados
para facilitar la escritura y la lectura de scripts. El editor de texto para R más común es Rstudio, pero hay muchos más. Hacer
una lista exhaustiva de todas las soluciones disponibles está más allá del alcance de este libro, por lo que nos centraremos en
las tres soluciones que utilizo a diario: Notepad++, Rstudio y Geany. No necesita instalar más de un editor de texto. Aquí
recomendamos RStudio para principiantes a R.
4.2 RStudio
El programa para instalar el software RStudio se encuentra en la parte Products del sitio web de RStudio ([Link]
[Link]/). Instalaremos RStudio para uso local (en nuestra computadora), por lo que la versión que nos interesa es
Desktop. Usaremos la versión Open Source que es gratuita. Luego, seleccionamos la versión que corresponde a nuestro sistema
operativo (Windows, Mac OS, Linux), descargamos el archivo correspondiente y lo ejecutamos para comenzar la instalación.
Podemos mantener las opciones predeterminadas durante la instalación.
Podemos abrir RStudio. En la primera apertura, la interfaz se divide en dos con la consola R a la izquierda que vimos en el
capítulo anterior (Figura 4.2). Para abrir un nuevo script, vamos al menú Archivo (o File), Nuevo archivo (o New File), R script.
Por defecto, este archivo tiene el nombre Untitled1. Hemos visto en el capítulo anterior la importancia de dar un nombre pertinente
a nuestros scripts, por lo que lo cambiaremos de nombre a selecEnvDev.R, en el menú Archivo (o File), con la opción Guardar
29
30 CHAPTER 4. ELEGIR UN ENTORNO DE DESARROLLO
como … (o Save As…). Podemos notar que el lado izquierdo de RStudio ahora está dividido en dos, con la consola en la parte
inferior de la pantalla y el script en la parte superior.
Luego podemos comenzar a escribir nuestro script con los comentarios que describan lo que vamos a encontrar allí, y agregar
un cálculo simple. Una vez que hayamos copiado o escrito un código, podemos guardar nuestro script con el comando CTRL +
S o yendo a Archivo (o File, luego Guardar (o Save).
# ------------------------------------------------------------
# Un script para seleccionar su entorno de desarrollo
# fecha de creación : 27/06/2018
# autor : François Rebaudo
# ------------------------------------------------------------
## [1] 78.53982
Para ejecutar nuestro script, simplemente seleccionamos las líneas que deseamos ejecutar y usamos la combinación de teclas
CTRL + ENTER. El resultado aparece en la consola (Figura 4.3).
Podemos ver que, de forma predeterminada, en la parte del script, los comentarios aparecen en verde, los números en azul
y el resto del código en negro. En la parte de la consola, lo que se ejecutó aparece en azul y los resultados de la ejecución
en negro. También podemos observar que en la parte del código cada línea tiene un número correspondiente al número de
línea a la izquierda sobre un fondo gris. Este es el resaltado de preferencias de sintaxis predeterminado con RStudio. Estas
preferencias de sintaxis pueden modificarse yendo al menú Herramientas (o Tools), Opciones globales … (o Global Options…),
Aspecto (o Appearance), y luego seleccionando otro tema del Editor de tema: (o Editor theme:). Elegiremos el tema Cobalt,
luego OK (Figura 4.4).
4.2. RSTUDIO 31
Figure 4.3: Captura de pantalla de RStudio en Windows: ejecutar nuestro script con CTRL + ENTER.
Sabemos cómo crear un nuevo script, guardarlo, ejecutar su contenido y cambiar la apariencia de RStudio. Veremos los muchos
otros beneficios de RStudio a lo largo de este libro, ya que es el entorno de desarrollo que se utilizará. Sin embargo, seremos
especialmente cuidadosos de que todos los scripts desarrollados a lo largo de este libro se ejecuten de la misma manera,
independientemente del entorno de desarrollo utilizado.
Al abrir por primera vez, Notepad++ muestra un archivo vacío new 1 (Figura 4.6).
Como ya hemos creado un script para probarlo con RStudio, lo abriremos de nuevo con Notepad++. En Archivo, seleccionamos
Abrir … luego elijemos el script selecEnvDev.R creado previamente. Una vez que el script está abierto, vamos a Idioma, luego
R, y de nuevo R. Aparece el resaltado de sintaxis (Figura 4.7).
La ejecución del script solo se puede realizar si se está ejecutando Npp2R. Para hacerlo, es necesario ejecutar el programa
Npp2R desde el prompt de Windows. Un icono debe aparecer en la parte inferior de su pantalla demostrando que Npp2R está
prendido. La ejecución automática del código de Notepad++ se realiza seleccionando el código para ejecutar y luego usando el
comando F8. Si el comando no funciona, puede ser necesario reiniciar la computadora. Si el comando funciona, se abrirá una
nueva ventana con una consola que ejecuta las líneas deseadas (Figura 4.8).
Al igual que con RStudio, el resaltado de sintaxis se puede cambiar desde el menú Configuración, y se puede seleccionar un
nuevo tema (por ejemplo, Solarized en la Figura 4.9)
Comparado con otros editores de texto, Notepad++ tiene la ventaja de ser muy liviano, rapido y ofrece una amplia gama de
opciones para personalizar la escritura de códigos.
4.3. NOTEPAD++ AVEC NPP2R 33
Figure 4.7: Captura de pantalla de Notepad++ en Windows: ejecutar nuestro script con F8.
34 CHAPTER 4. ELEGIR UN ENTORNO DE DESARROLLO
4.4 Geany
El programa para instalar Geany se puede encontrar en la pestaña Downloads en el menú de la izquierda Releases de la
página web ([Link] Luego solo descargamos el ejecutable para Windows o el dmg para Mac OSX.
Los usuarios de Linux preferirán un sudo apt-get install geany.
Al abrir por primera vez, como para RStudio y Notepad++, se crea un archivo vacío (Figura 4.11).
Para ejecutar nuestro script, la versión de Geany para Windows no tiene un terminal incorporado, lo que hace que su uso sea
limitado bajo este sistema operativo. La ejecución de un script se puede hacer abriendo R en una ventana separada y copiando
y pegando las líneas que se ejecutarán. En Linux y Mac OSX, podemos abrir R en el terminal en la parte inferior de la ventana de
Geany con el comando R. Podemos configurar Geany para una combinación de teclas para ejecutar el código seleccionado (por
ejemplo CTRL + R). Para esto hay que permitir el envío de selección al terminal (send_selection_unsafe = true) in
archivo [Link] y elegir el comando para enviar al terminal (en Editar, Preferencias, Combinaciones). Para cambiar el
tema de Geany, hay una colección de temas disponibles en GitHub ([Link] El
tema se puede cambiar a través del menú Ver, cambiar Esquema del color … (un ejemplo con el tema Solarized Figura @ref(Fig:
screenCapGeany03)).
Hay muchas otras soluciones, algunas especializadas para R como Tinn-R ([Link]
tinn-r/), y otras más generales para programación como Atom ([Link] Sublime Text (https:
36 CHAPTER 4. ELEGIR UN ENTORNO DE DESARROLLO
4.6 Conclusión
Felicitaciones, llegamos al final de este capítulo sobre el entorno de desarrollo para el uso de R. Hasta ahora sabemos:
A partir de acá podremos concentrarnos en el lenguaje de programación R en un ambiente, facilitando el trabajo de lectura y de
escritura del código. Esto ya es un gran paso para manejar R.
38 CHAPTER 4. ELEGIR UN ENTORNO DE DESARROLLO
Chapter 5
Tipos de datos
Vimos anteriormente cómo crear un objeto. Un objeto es como una caja en la que almacenaremos información. Hasta ahora
solo hemos almacenado números, pero en este capítulo veremos que es posible almacenar otra información y nos detendremos
en los tipos más comunes. En este capítulo utilizaremos funciones sobre las cuales volveremos más adelante.
El tipo numeric es lo que hemos hecho hasta ahora, almacenando números. Hay dos tipos principales de números en R: enteros
(integer) y números decimales (double). Por defecto, R considera todos los números como números decimales y asigna el tipo
double. Para verificar el tipo de datos utilizaremos la función typeof() que toma como argumento un objeto (o directamente la
información que queremos probar). También podemos usar la función [Link]() que devolverá TRUE si el número está en
formato double y FALSE en caso contrario. La función genérica [Link]() devolverá TRUE si el objeto está en formato
numeric y FALSE en caso contrario.
nbrRep <- 5
typeof(nbrRep)
## [1] "double"
typeof(5.32)
## [1] "double"
[Link](5)
## [1] TRUE
39
40 CHAPTER 5. TIPOS DE DATOS
[Link](5)
## [1] TRUE
Si queremos decirle a R que vamos a trabajar con un entero, entonces necesitamos convertir nuestro número decimal en un
entero con la función [Link](). También podemos usar la función [Link]() que devolverá TRUE si el número
está en formato integer y FALSE en caso contrario.
## [1] "integer"
typeof(5.32)
## [1] "double"
typeof([Link](5.32))
## [1] "integer"
[Link](5.32)
## [1] 5
[Link](5.99)
## [1] 5
[Link](nbrRep)
## [1] TRUE
Vemos aquí que convertir un número como 5.99 a integer solo devolverá la parte entera, 5.
5.1. EL TIPO NUMERIC 41
[Link](5)
## [1] FALSE
[Link](5)
## [1] TRUE
[Link]([Link](5))
## [1] TRUE
[Link]([Link](5))
## [1] TRUE
La suma de un número entero integer y un número decimal double devuelve un número decimal.
## [1] "double"
## [1] "integer"
Para resumir, el tipo numeric contiene dos subtipos, los tipos integer para enteros y el tipo double para los números
decimales. Por defecto, R asigna el tipo double a los números.
Tenga cuidado, hay una trampa para usar la función [Link](). No nos dice si el número es un número entero, pero si es
de tipo integer. De hecho, uno puede almacenar un entero en una variable de tipo double.
Los números almacenados en una variable de tipo integer son codificados en 32 bits y, por lo tanto, pueden tomar valores
entre 0 y 2^32-1 = 4294967295. Hay otra forma de decirle a R que un número es un número entero, usando el sufijo L. Por
ejemplo, 5L es lo mismo que [Link](5). El origen del sufijo L, que se remonta a una época en que las computadoras
usaban palabras de 16 bits y 32 bits, era un tipo Long. ¡Ahora las computadoras usan palabras de 64 bits y 32 bits es bastante
corto!
No podemos dejar esta sección sin mencionar las funciones round() ceiling() trunc() o floor() que devuelven la
parte entera de un número, pero déjelo en el tipo double. Para obtener más información, podemos usar la ayuda de R con
?round.
42 CHAPTER 5. TIPOS DE DATOS
## [1] "double"
El tipo character es texto. De hecho, R permite trabajar con texto. Para especificar a R que la información contenida en un
objeto está en formato de texto (o generalmente para todos los textos), usamos las comillas dobles (") o las comillas simples (').
## [1] "character"
Tanto las comillas dobles y simples son útiles en nuestro texto. También podemos escapar un carácter especial como comillas
gracias al signo de barra invertida \.
De forma predeterminada, cuando creamos un objeto, su contenido no es devuelto por la consola. En Internet o en muchos libros
podemos encontrar el nombre del objeto en una línea para devolver sus contenidos:
En este libro, no lo usaremos de esta manera y preferiremos el uso de la función print(), que permite mostrar en la consola
el contenido de un objeto. El resultado es el mismo, pero el código es más fácil de leer y más explícito sobre lo que hace.
nbrRep <- 5
print(nbrRep)
## [1] 5
También podemos poner números en formato de texto, pero no debemos olvidar poner comillas para especificar el tipo
character o usar la funció[Link](). Una operación entre un texto y un número devuelve un error. Por ejemplo,
si agregamos 10 a 5, R nos dice que un argumento de la función + no es un tipo numeric y que, por lo tanto, la operación
no es posible. Tampoco podemos agregar texto a texto, pero veremos más adelante cómo concatenar dos cadenas de texto.
## [1] "character"
myText2 <- 5
typeof(myText2)
## [1] "double"
44 CHAPTER 5. TIPOS DE DATOS
## [1] "character"
myText2 + 10
## [1] 15
[Link](5)
## [1] "5"
Para resumir, el tipo character permite el ingreso de texto, podemos reconocerlo con comillas simples o dobles.
El tipo factor corresponde a los factores. Los factores son una elección dentro de una lista finita de posibilidades. Por ejemplo,
los países son factores porque existe una lista finita de países en el mundo en un momento dado. Un factor puede definirse con
la función factor() o transformarse utilizando la función [Link](). Al igual que con otros tipos de datos, podemos usar
la función [Link]() para verificar el tipo de datos. Para obtener una lista de todas las posibilidades, existe la función
levels() (esta función tendrá más sentido cuando nos acerquemos a los tipos de contenedores de información).
## [1] aaa
## Levels: aaa
typeof(factor01)
## [1] "integer"
5.4. EL TIPO LOGICAL 45
[Link](factor01)
## [1] TRUE
levels(factor01)
## [1] "aaa"
Un factor se puede transformar en texto con la función [Link]() pero también en número con [Link](). Al
cambiar al tipo numeric, cada factor toma el valor de su posición en la lista de posibilidades. En nuestro caso, solo hay una
posibilidad, por lo que la función [Link]() devolverá 1:
## [1] "aaa"
[Link](factor01)
## [1] 1
El tipo logical corresponde a los valores TRUE y FALSE (y NA) que ya hemos visto con los operadores de comparación.
## [1] TRUE
typeof(aLogic)
## [1] "logical"
[Link](aLogic)
## [1] TRUE
46 CHAPTER 5. TIPOS DE DATOS
aLogic + 1
## [1] 2
[Link](aLogic)
## [1] 1
[Link](aLogic)
## [1] "TRUE"
5.5 Acerca de NA
El valor NA se puede usar para especificar que no hay datos o datos faltantes. Por defecto, NA es logical, pero se puede usar
para texto o números.
print(NA)
## [1] NA
typeof(NA)
## [1] "logical"
typeof([Link](NA))
## [1] "integer"
typeof([Link](NA))
## [1] "character"
5.6. CONCLUSIÓN 47
NA == TRUE
## [1] NA
NA == FALSE
## [1] NA
NA > 1
## [1] NA
NA + 1
## [1] NA
5.6 Conclusión
Felicitaciones, hemos llegado al final de este capítulo sobre los tipos de datos. Ahora sabemos:
Contenedores de datos
Hasta ahora hemos creado objetos simples que contienen solo un valor. Sin embargo, pudimos ver que un objeto tenía atributos
diferentes, como su valor, pero también el tipo de datos contenidos (e.g., numeric, character). Ahora vamos a ver que hay
diferentes tipos de contenedores para almacenar datos múltiples.
En R, un vector es una combinación de datos con la particularidad de que todos los datos contenidos en un vector son del
mismo tipo. Podemos almacenar por ejemplo múltiples elementos del tipo character o numeric en un vector, pero no
ambos. El contenedor vector es importante porque es el elemento básico de R.
Para crear un vector utilizaremos la función c() que permite combinar elementos en un vector. Los elementos para combinar
deben estar separados por comas.
## [1] 1 2 3 4
typeof(miVec01)
## [1] "double"
[Link](miVec01)
## [1] TRUE
49
50 CHAPTER 6. CONTENEDORES DE DATOS
typeof(miVec02)
## [1] "character"
[Link](miVec02)
## [1] TRUE
typeof(miVec03)
## [1] "logical"
[Link](miVec03)
## [1] TRUE
## [1] 1 NA 3 NA 5
typeof(miVecNA)
## [1] "double"
6.1. EL CONTENEDOR VECTOR 51
[Link](miVecNA)
## [1] TRUE
typeof(miVec04)
## [1] "character"
[Link](miVec04)
## [1] TRUE
Si combinamos diferentes tipos de datos, R intentará transformar los elementos en un tipo de forma predeterminada. Si como
aquí en el objeto miVec03 tenemos los tipos character y numeric, R convertirá todos los elementos en character.
typeof(miVec05)
## [1] "character"
typeof(miVec06)
## [1] "character"
## [1] 1 55
typeof(miVec07)
## [1] "double"
## [1] 1 55
typeof(miVec08)
## [1] "double"
## [1] "aaa" "aa" "a" "b" "c" "d" "e" "f" "d" "e" "f"
6.1. EL CONTENEDOR VECTOR 53
print(miVec01)
## [1] 1 2 3 4
miVec01 + 1
## [1] 2 3 4 5
miVec01 - 1
## [1] 0 1 2 3
miVec01 * 2
## [1] 2 4 6 8
miVec01 /10
Las operaciones de un vector a otro también son posibles, pero se debe tener cuidado para asegurar que el número de
elementos en un vector sea el mismo que el otro, de lo contrario R realizará el cálculo comenzando desde el inicio del vector
mas pequeño. Aquí hay un ejemplo para ilustrar lo que R hace:
## [1] 1 1 1 1 1 1 1 1 1
54 CHAPTER 6. CONTENEDORES DE DATOS
## [1] 10 20 30
## [1] 11 21 31 11 21 31 11 21 31
miVec14 <- c(10, 20, 30, 40, 50, 60, 70, 80, 90)
print(miVec14)
## [1] 10 20 30 40 50 60 70 80 90
## [1] 11 21 31 41 51 61 71 81 91
## [1] 1 1 1 1
## Warning in miVec15 + miVec13: la taille d'un objet plus long n'est pas
## multiple de la taille d'un objet plus court
## [1] 11 21 31 11
Suele pasar que sea necesario poder acceder a los valores de un vector, es decir, recuperar un valor o un grupo de valores
dentro de un vector. Para acceder a un elemento de un vector usamos los corchetes []. Entre los corchetes, podemos
usar un número correspondiente al número del elemento en el vector.
6.1. EL CONTENEDOR VECTOR 55
miVec20 <- c(10, 20, 30, 40, 50, 60, 70, 80, 90)
miVec21 <- c("a", "b", "c", "d", "e", "f", "g", "h", "i")
print(miVec20)
## [1] 10 20 30 40 50 60 70 80 90
print(miVec21)
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i"
print(miVec20[1])
## [1] 10
print(miVec21[3])
## [1] "c"
print(miVec20[c(1, 5, 9)])
## [1] 10 50 90
print(miVec21[c(4, 3, 1)])
print(miVec21[c(4, 4, 3, 4, 3, 2, 5)])
## [1] 50 60 70 80 90
## [1] 50 60 70
print(miVec20[miVec20 != 50])
## [1] 10 20 30 40 60 70 80 90
print(miVec20[miVec20 == 30])
## [1] 30
## [1] 30 50
print(miVec21[miVec21 == "a"])
## [1] "a"
Otra característica interesante es la posibilidad de condicionar los elementos a seleccionar en base a otro vector.
print(miVec21[miVec20 != 50])
print(miVec21[miVec20 == 30])
## [1] "c"
print(miVec20[-1])
## [1] 20 30 40 50 60 70 80 90
print(miVec21[-5])
print(miVec20[-c(1, 2, 5)])
## [1] 30 40 60 70 80 90
print(miVec21[-c(1, 2, 5)])
Los elementos de un vector también se pueden seleccionar sobre la base de un vector tipo logical. En este caso, solo
se seleccionarán elementos con un valor TRUE.
58 CHAPTER 6. CONTENEDORES DE DATOS
miVec22 <- c(TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE)
print(miVec21[miVec22])
Los elementos de un vector se pueden nombrar para referenciarlos y luego selectionarlos. La función names() recupera los
nombres de los elementos de un vector.
miVec23 <- c(aaa = 10, bbb = 20, ccc = 30, ddd = 40, eee = 50)
print(miVec23)
print(miVec23["bbb"])
## bbb
## 20
names(miVec23)
Para modificar un vector, operamos de la misma manera que para modificar un objeto simple, con el signo <- y el elemento o
los elementos a modificar entre corchetes.
print(miVec21)
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i"
6.1. EL CONTENEDOR VECTOR 59
## [1] "a" "b" "zzz" "d" "e" "f" "g" "h" "i"
print(miVec23)
También podemos cambiar los nombres asociados con los elementos de un vector.
print(miVec23)
Podemos hacer mucho más con un vector y volveremos a su manejo y operaciones posibles en el capítulo sobre funciones.
60 CHAPTER 6. CONTENEDORES DE DATOS
El segundo tipo de contenedor que vamos a presentar es el contenedor list, que es también el segundo contenedor después
del tipovector debido a su importancia en la programación con R. El contenedor de tipo list le permite almacenar listas de
elementos. Contrariamente a lo que vimos antes con el tipo vector, los elementos del tipo list pueden ser diferentes (por
ejemplo, un vector de tipo numeric, luego un vector de tipo character). Los elementos del tipo list también pueden
ser contenedores diferentes (por ejemplo, un vector, luego una list). El tipo de contenedor list tendrá mas sentido cuando
hayamos estudiado los bucles y funciones de la familia apply.
Para crear una list usaremos la función list(), que toma elementos (objetos) como argumentos.
## list()
## [[1]]
## [1] 5
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "a" "b" "c"
## [[1]]
## [1] 5
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [[3]][[1]]
## [1] 4 5 6
##
## [[3]][[2]]
## [1] "a" "b" "c"
6.2. EL CONTENEDOR LIST 61
La función [Link]() se usa para probar si hemos creado un objeto de tipo list.
[Link](miList02)
## [1] TRUE
typeof(miList02)
## [1] "list"
Los elementos del contenedor list son identificables por los corchetes dobles [[ ]].
print(miList02)
## [[1]]
## [1] 5
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "a" "b" "c"
En el objeto de tipo list miList02, hay cuatro elementos identificables con [[1]], [[2]], [[3]] y [[4]]. Cada uno
de los elementos es de tipo vector. El primer elemento tiene un tamaño de 1 con elementos del tipo double, el segundo
elemento tiene un tamaño de 1 con elementos del tipo character, el tercero elemento tiene un tamaño de 3 con elementos
del tipo double, y el cuarto elemento tiene un tamaño de 3 con elementos del tipo character.
typeof(miList02)
## [1] "list"
print(miList02[[1]])
## [1] 5
62 CHAPTER 6. CONTENEDORES DE DATOS
typeof(miList02[[1]])
## [1] "double"
print(miList02[[2]])
## [1] "qwerty"
typeof(miList02[[2]])
## [1] "character"
print(miList02[[3]])
## [1] 4 5 6
typeof(miList02[[3]])
## [1] "double"
print(miList02[[4]])
typeof(miList02[[4]])
## [1] "character"
El acceso al segundo elemento del vector ubicado en la cuarta posición de la list se hace con miList02[[4]][2].
Usamos doble corchetes para el cuarto elemento de la list, luego corchetes simples para el segundo elemento del vector.
print(miList02[[4]][2])
## [1] "b"
Como una list puede contener una o más list, podemos acceder a la información buscada combinando corchetes dobles.
El objeto miList04 es una list de dos elementos: la list miList02 y la list miList03. El objeto miList03 en sí
contiene una list como tercer elemento. Para acceder al primer elemento del vector en la primera posición del elemento
en la tercera posición del segundo elemento del list miList04, podemos usar miList04[[2]][[3]][[1]][1]. No hay
límite en cuanto a la profundidad de list pero en la práctica raramente hay necesidad de hacer list de list de list.
6.2. EL CONTENEDOR LIST 63
## [[1]]
## [[1]][[1]]
## [1] 5
##
## [[1]][[2]]
## [1] "qwerty"
##
## [[1]][[3]]
## [1] 4 5 6
##
## [[1]][[4]]
## [1] "a" "b" "c"
##
##
## [[2]]
## [[2]][[1]]
## [1] 5
##
## [[2]][[2]]
## [1] "qwerty"
##
## [[2]][[3]]
## [[2]][[3]][[1]]
## [1] 4 5 6
##
## [[2]][[3]][[2]]
## [1] "a" "b" "c"
print(miList04[[2]][[3]][[1]][1])
## [1] 4
Para concretar el ejemplo anterior, podemos imaginar especies de barrenadores del maíz (Sesamia nonagrioides y Ostrinia
nubilalis), muestreados en diferentes sitios, con diferentes abundancias en cuatro fechas. Aquí daremos nombres a los elementos
de las list.
bddInsect <- list(Snonagrioides = list(site01 = c(12, 5, 8, 7), site02 = c(5, 23, 4, 41), site03 = c(12,
print(bddInsect)
## $Snonagrioides
## $Snonagrioides$site01
## [1] 12 5 8 7
##
## $Snonagrioides$site02
## [1] 5 23 4 41
64 CHAPTER 6. CONTENEDORES DE DATOS
##
## $Snonagrioides$site03
## [1] 12 0 0 0
##
##
## $Onubilalis
## $Onubilalis$site01
## [1] 12 1 2 3
##
## $Onubilalis$site02
## [1] 0 0 0 1
##
## $Onubilalis$site03
## [1] 1 1 2 3
Leer una larga línea de código como la línea para crear el objeto bddInsect resulta difícil porque la profundidad de los elementos
solo se puede deducir de los paréntesis. Es por eso que vamos a reorganizar el código para que sea más legible mediante el
margen adicional. El margen adicional implica poner información en diferentes niveles para que podamos identificar rápidamente
los diferentes niveles de un código. Para aplicar el margen adicional se presiona la tecla de tabulación. Volveremos al margen
adicional con más detalles en el capítulo sobre bucles. Recordemos por el momento que si una línea de código es demasiado
larga, podemos saltar de línea y usar el margen adicional. R leerá todo como una sola línea de código.
Podemos seleccionar los datos de abundancia del segundo sitio de la primera especie como previamente bddInsect[[1]][[2]],
o alternativamente usando los nombres de los elementos bddInsect$Snonagrioides$site02. Para hacer esto usamos el
signo $, o como alternativa el nombre de los elementos con comillas simples o dobles bddInsect[['Snonagrioides']][['sitio02']].
print(bddInsect[[1]][[2]])
## [1] 5 23 4 41
print(bddInsect$Snonagrioides$site02)
## [1] 5 23 4 41
6.2. EL CONTENEDOR LIST 65
print(bddInsect[['Snonagrioides']][['site02']])
## [1] 5 23 4 41
En cuanto a los vectores, podemos recuperar los nombres de los elementos con la función names().
names(bddInsect)
names(bddInsect[[1]])
Cuando usamos los corchetes dobles [[]] o el signo $, R devuelve el contenido del elemento seleccionado. En nuestro ejemplo,
los datos de abundancia están contenidos como un vector, por lo que R devuelve un elemento del tipo vector. Si queremos
seleccionar un elemento de una list pero manteniendo el formato list, entonces podemos usar corchetes simples [].
print(bddInsect[[1]][[2]])
## [1] 5 23 4 41
typeof(bddInsect[[1]][[2]])
## [1] "double"
[Link](bddInsect[[1]][[2]])
## [1] FALSE
print(bddInsect[[1]][2])
## $site02
## [1] 5 23 4 41
66 CHAPTER 6. CONTENEDORES DE DATOS
typeof(bddInsect[[1]][2])
## [1] "list"
[Link](bddInsect[[1]][2])
## [1] TRUE
El uso de corchetes simples [] es útil cuando queremos recuperar varios elementos de una list. Por ejemplo, para seleccionar
las abundancias de insectos de los primeros dos sitios de la primera especie, usaremos bddInsect [[1]][c(1, 2)] o
alternativamente bddInsect[[1]][c("site01", "sitio02")].
print(bddInsect[[1]][c(1, 2)])
## $site01
## [1] 12 5 8 7
##
## $site02
## [1] 5 23 4 41
print(bddInsect[[1]][c("site01", "site02")])
## $site01
## [1] 12 5 8 7
##
## $site02
## [1] 5 23 4 41
Una list se puede modificar de la misma manera que para el contenedor vector, es decir, haciendo referencia con corchetes
al elemento que queremos modificar.
print(miList02)
## [[1]]
## [1] 5
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "a" "b" "c"
6.2. EL CONTENEDOR LIST 67
miList02[[1]] <- 12
print(miList02)
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "a" "b" "c"
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "d" "e" "f"
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i"
68 CHAPTER 6. CONTENEDORES DE DATOS
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 4 5 6
##
## [[4]]
## [1] "a" "b" "c" "d" "eee" "f" "g" "h" "i"
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 39 49 59
##
## [[4]]
## [1] "a" "b" "c" "d" "eee" "f" "g" "h" "i"
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 39 1200 59
##
## [[4]]
## [1] "a" "b" "c" "d" "eee" "f" "g" "h" "i"
6.2. EL CONTENEDOR LIST 69
print(bddInsect)
## $Snonagrioides
## $Snonagrioides$site01
## [1] 12 5 8 7
##
## $Snonagrioides$site02
## [1] 5 23 4 41
##
## $Snonagrioides$site03
## [1] 12 0 0 0
##
##
## $Onubilalis
## $Onubilalis$site01
## [1] 12 1 2 3
##
## $Onubilalis$site02
## [1] 0 0 0 1
##
## $Onubilalis$site03
## [1] 1 1 2 3
## $Snonagrioides
## $Snonagrioides$site01
## [1] 12 5 8 7
##
## $Snonagrioides$site02
## [1] 2 4 6 8
##
## $Snonagrioides$site03
## [1] 12 0 0 0
##
##
## $Onubilalis
## $Onubilalis$site01
## [1] 12 1 2 3
##
## $Onubilalis$site02
## [1] 0 0 0 1
##
## $Onubilalis$site03
## [1] 1 1 2 3
Para combinar dos list, simplemente usamos la función c() que hemos usado para crear un vector.
70 CHAPTER 6. CONTENEDORES DE DATOS
## [[1]]
## [1] 12
##
## [[2]]
## [1] "qwerty"
##
## [[3]]
## [1] 39 1200 59
##
## [[4]]
## [1] "a" "b" "c" "d" "eee" "f" "g" "h" "i"
##
## [[5]]
## [1] 5
##
## [[6]]
## [1] "qwerty"
##
## [[7]]
## [[7]][[1]]
## [1] 4 5 6
##
## [[7]][[2]]
## [1] "a" "b" "c"
Un objeto de tipo list se puede transformar en vector con la función unlist() si el formato de los elementos de la lista lo
permite (un vector solo puede contener elementos del mismo tipo).
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "b" "c"
##
## [[3]]
## [1] "d"
## [[1]]
## [1] 1 2 3
##
## [[2]]
## [1] 4 5 6 7
##
## [[3]]
## [1] 8
##
## [[4]]
## [1] 9
##
## [[5]]
## [1] 10 11
## [1] 1 2 3 4 5 6 7 8 9 10 11
Para agregar un elemento a una list, podemos usar la función c() o los corchetes dobles [[ ]].
print(miList05)
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "b" "c"
##
## [[3]]
## [1] "d"
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "b" "c"
##
72 CHAPTER 6. CONTENEDORES DE DATOS
## [[3]]
## [1] "d"
##
## [[4]]
## [1] "e"
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "b" "c"
##
## [[3]]
## [1] "d"
##
## [[4]]
## [1] "e"
##
## [[5]]
## [1] "fgh" "ijk"
Para eliminar un elemento de una list, la técnica más rápida es establecer NULL en el elemento que deseamos eliminar.
print(miList05)
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "b" "c"
##
## [[3]]
## [1] "d"
##
## [[4]]
## [1] "e"
##
## [[5]]
## [1] "fgh" "ijk"
## [[1]]
## [1] "a"
##
## [[2]]
## [1] "d"
##
## [[3]]
## [1] "e"
##
## [[4]]
## [1] "fgh" "ijk"
El contenedor [Link] se puede comparar a una tabla. Este es en realidad un caso especial de list donde todos los
elementos de la list tienen el mismo tamaño.
Para crear un [Link] usamos la función [Link]() que toma como argumentos los elementos de la tabla que
queremos crear. Los elementos son del tipo vector y son todos del mismo tamaño. Podemos dar un nombre a cada columna
(vector) de nuestra tabla ([Link]).
# crear un [Link]
miDf01 <- [Link](
numbers = c(1, 2, 3, 4),
logicals = c(TRUE, TRUE, FALSE, TRUE),
characters = c("a", "b", "c", "d")
)
print(miDf01)
El acceso a los diferentes valores de un [Link] se puede hacer de la misma manera que para un contenedor de tipo
list.
print(miDf01$numbers) # vector
## [1] 1 2 3 4
print(miDf01[[1]]) # vector
## [1] 1 2 3 4
print(miDf01[1]) # list
## numbers
## 1 1
## 2 2
## 3 3
## 4 4
print(miDf01["numbers"]) # list
## numbers
## 1 1
## 2 2
## 3 3
## 4 4
print(miDf01[["numbers"]]) # vector
## [1] 1 2 3 4
También podemos usar otra forma que consiste en especificar la línea o las líneas seguidas de una coma (con un espacio después
de la coma), y luego la columna o columnas entre corchetes. Si se omite la información de línea o columna, R mostrará todas
las líneas o columnas. Nuevamente podemos usar el número correspondiente a un elemento o el nombre del elemento que
queremos seleccionar.
myRow <- 2
myCol <- 1
print(miDf01[myRow, myCol])
## [1] 2
6.3. EL CONTENEDOR [Link] 75
print(miDf01[myRow, ])
print(miDf01[, myCol])
## [1] 1 2 3 4
## [1] 1 2 3 4
## numbers logicals
## 1 1 TRUE
## 2 2 TRUE
## 3 3 FALSE
## 4 4 TRUE
print(miDf01[c(2, 1), ])
Como cada columna está en formato vector, también podemos hacer una selección que depende del contenido con operadores
de comparación y operadores lógicos.
Para agregar un elemento a un [Link], procedemos como para un contenedor de tipo list. Es necesario asegurarse
de que el nuevo elemento sea del mismo tamaño que los otros elementos de nuestro [Link]. Por defecto, un nuevo
elemento en [Link] toma el nombre de la letra V seguido del número de la columna. Podemos cambiar los nombres de
las columnas con la función colnames(). Podemos nombrar las líneas con la función rownames().
print(colnames(miDf01))
print(rownames(miDf01))
Como el contenedor de tipo [Link] es un caso especial de list, la selección y modificación se realiza como un con-
tenedor de tipo list. Dado que los elementos de un [Link] son del tipo vector, la selección y la modificación de los
elementos de un [Link] se hace como para un contenedor vector.
miDf01$newVec2 + miDf01$newVec
miDf01$newVec2[2] <- 0
print(miDf01)
print(newVec2)
## [1] 40 50 60 70
print([Link](newVec2))
## newVec2
## 1 40
## 2 50
## 3 60
## 4 70
[Link](newVec2)
## [1] FALSE
[Link]([Link](newVec2))
## [1] TRUE
El contenedor matrix se puede ver como un vector de dos dimensiones: líneas y columnas. Corresponde a una matriz en
matemáticas, y puede contener solo un tipo de datos (logical, numeric, character, …).
6.4. EL CONTENEDOR MATRIX 79
Para crear una matrix primero creamos un vector, luego especificamos el número deseado de líneas y columnas en la
función matrix().
No tenemos que especificar el número de líneas nrow y el número de columnas ncol. Si usamos uno u otro de estos argumen-
tos, R calculará automáticamente el número correspondiente.
Observamos que los diferentes elementos del vector inicial aparecen por columna. Si queremos llenar la matrix empezando
por línea, entonces tenemos que dar como valor TRUE al argumento byrow.
También podemos dar un nombre a las líneas y columnas de nuestra matrix cuando se crea con el argumento dimnames que
toma como valor una list de dos elementos: el nombre de las líneas y luego el nombre de las columnas. También podemos
cambiar el nombre de las líneas y columnas a posteriori con las funciones rownames() y colnames().
80 CHAPTER 6. CONTENEDORES DE DATOS
## c1 c2 c3 c4
## r1 1 2 3 4
## r2 5 6 7 8
## r3 9 10 11 12
Es posible crear una matrix desde un [Link] con la función [Link](). Tenemos que verificar que nuestra
[Link] contenga solo elementos del mismo tipo (por ejemplo, elementos de tipo numeric).
[Link](dfForMat)
## [1] FALSE
[Link](dfForMat)
[Link]([Link](dfForMat))
## [1] TRUE
También podemos crear una matrix desde un vector con la función [Link]() (matriz de una sola columna).
[Link](vecForMat01)
## [,1]
## [1,] 1
## [2,] 2
## [3,] 3
## [4,] 4
## [5,] 5
## [6,] 6
## [7,] 7
## [8,] 8
## [9,] 9
## [10,] 10
## [11,] 11
## [12,] 12
Todas las operaciones término a término son posibles con una matrix.
82 CHAPTER 6. CONTENEDORES DE DATOS
miMat01 + miVecOp
miMat01 / miMat01
miMat01 - 10
# operaciones algebraicas
miVecConf <- c(1, 10, 100)
miMat01 %*% miVecConf
## [,1]
## [1,] 951
## [2,] 1062
## [3,] 1173
## [4,] 1284
6.4. EL CONTENEDOR MATRIX 83
La diagonal de una matrix se puede obtener con la función diag() y el determinante de una matrix con la función det().
print(miMat02)
diag(miMat02)
## [1] 1 5 9
det(miMat02)
## [1] 0
Suele ser útil poder hacer una transposición de matrix (columnas en líneas o líneas en columnas). Para eso, están las funciones
aperm() o t(). la función t() es más genérica y también funciona con [Link].
aperm(miMat01)
t(miMat01)
Tal como hemos hecho con los [Link], podemos acceder a los elementos de una matrix especificando un número de
línea y un número de columna entre corchetes simples [ ], y separados por una coma. Si i es el número de línea y j es el
número de columna, entonces miMat01[i, j] devuelve el elemento en la línea i y en la columnaj. miMat01[i,] devuelve
todos los elementos de la línea i, y miMat01[, j] todos los elementos de la columna j. Múltiples selecciones son posibles.
También podemos acceder a un elemento de acuerdo con su posición en la matrix entre corchetes simples [ ] contando por
columna y luego por línea. En nuestro ejemplo, el valor del décimo elemento es 10.
i <- 2
j <- 1
print(miMat01[i, j])
## [1] 2
print(miMat01[i, ])
## [1] 2 6 10
print(miMat01[, j])
## [1] 1 2 3 4
## [,1] [,2]
## [1,] 5 9
## [2,] 6 10
print(miMat01[10])
## [1] 10
6.5. EL CONTENEDOR ARRAY 85
El contenedor array es una generalización del contenedor de tipo matrix. Donde el tipo matrix tiene dos dimensiones
(líneas y columnas), el tipo array tiene un número indefinido de dimensiones. Podemos saber el número de dimensiones de
un array (y por lo tanto una matrix) con la función dim().
dim(miMat01)
## [1] 4 3
La creación de una array es similar a la de una matrix con una dimensión extra.
## , , 1
##
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
##
## , , 2
##
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
dim(miArray)
## [1] 3 3 2
[Link](miArray)
## [1] TRUE
## , , 1
##
## [,1] [,2] [,3]
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
##
## , , 2
##
## [,1] [,2] [,3]
## [1,] 10 40 70
## [2,] 20 50 80
## [3,] 30 60 90
dim(miArray02)
## [1] 3 3 2
[Link](miArray02)
## [1] TRUE
## , , matrix1
##
## c1 c2 c3
## r1 1 4 7
## r2 2 5 8
## r3 3 6 9
##
## , , matrix2
##
## c1 c2 c3
## r1 10 40 70
## r2 20 50 80
## r3 30 60 90
6.6. CONCLUSIÓN 87
La manipulación de un array se hace de la misma manera que para una matrix. Para acceder a los diferentes elementos de
un array, simplemente hay que especificar la línea i, la columna j, y la matrix k.
i <- 2
j <- 1
k <- 1
print(miArray02[i, j, k])
## [1] 2
print(miArray02[, j, k])
## r1 r2 r3
## 1 2 3
print(miArray02[i, , k])
## c1 c2 c3
## 2 5 8
print(miArray02[i, j, ])
## matrix1 matrix2
## 2 20
6.6 Conclusión
Felicitaciones! Ahora conocemos los principales tipos de objetos que usaremos con R. Un objeto se caracteriza por sus atributos:
Todos estos objetos se almacenan temporalmente en el entorno global de R (en la memoria RAM de nuestra computadora).
El siguiente capítulo tratará las funciones y resaltará uno de los aspectos que hace que R sea tan poderoso para analizar y
administrar nuestros datos.
88 CHAPTER 6. CONTENEDORES DE DATOS
Chapter 7
Las funciones
Con este capítulo vamos a echar un primer vistazo al poder de R a través de las funciones. Una función es un conjunto de
líneas de código para realizar una tarea en particular. Hemos visto muchas funciones en capítulos anteriores, unas simples
como la función + para añadir números, o otras más complejas como c() o [Link]() que permiten crear un vector o
[Link]. En cualquier caso, se puede reconocer una función gracias a los paréntesis que la siguen en los cuales vamos
a ingresar argumentos. Los argumentos corresponden a la información que queremos transmitir a nuestra función para que
realice la tarea que queremos lograr.
Para funciones simples como +, los paréntesis han sido eliminados para que el código sea más fácil de leer, pero es una función
que puede usarse con paréntesis si usamos el signo + entre comillas. Los argumentos son los números que queremos agregar.
5 + 2
## [1] 7
'+'(5, 2)
## [1] 7
En este capítulo nos enfocaremos en las funciones más comunes. No se trata de aprender todo de memoria, sino de saber que
existen estas funciones y de poder consultar más adelante este capítulo como referencia. ¡Con tiempo y práctica eventualmente
los sabremos de memoria! Hay más de 1000 funciones en la versión básica de R, y más de 10000 paquetes adicionales que
se pueden instalar, cada uno con docenas de funciones. Antes de comenzar a escribir una nueva función, siempre debemos
verificar que ya no exista.
Para trabajar con las funciones, vamos a usar los datos iris que están incluidos con la versión básica de R y que corresponden
a la longitud y el ancho de los sépalos y pétalos de diferentes especies de iris. Los datos iris estan en una [Link] de
5 columnas y 150 líneas. Para obtener más información sobre los datos iris, podemos consultar la documentación R con la
función help(iris). El acceso a la documentación es el tema de la siguiente sección.
89
90 CHAPTER 7. LAS FUNCIONES
[Link] help()
La función esencial de R es acceder a la documentación (en ingles). Todas las funciones R tienen documentación. Podemos
acceder a la documentación con la función help() o usando el atajo ?.
La documentación siempre está estructurada de la misma manera. Primero tenemos el nombre de la función buscada matrix,
seguida entre llaves por el nombre del paquete R cuya función depende. Veremos cómo instalar paquetes adicionales más
adelante. Por ahora tenemos los que vienen con la versión básica de R. Aquí podemos ver que la función matrix() depende
del paquete base.
Podemos ver la etiqueta de la función (Matrices), seguida de los parafos Description, Usage, y Arguments. Algunas
veces se agregan los párrafos Details, Note, References y See also. El último párrafo es Ejemplos. La última línea
de la documentación permite volver al índice del paquete del que depende la función consultada.
Al copiar help(matrix) en nuestra consola R, podemos ver que el párrafo Description indica lo que hace la función. En
el caso de help(matrix), hay tres funciones: matrix(), [Link]() y [Link]().
# Description
# matrix creates a matrix from the given set of values.
# [Link] attempts to turn its argument into a matrix.
# [Link] tests if its argument is a (strict) matrix.
El párrafo Usage explica cómo usar la función y cuáles son los valores predeterminados para cada parámetro.
# Usage
# matrix(data = NA, nrow = 1, ncol = 1, byrow = FALSE,
# dimnames = NULL)
La función matrix() puede tomar 5 argumentos: data, nrow, ncol, byrow, y dimnames. Podemos ver que por defecto
una matrix consistirá de una sola línea y una sola columna, y que la información se completará por columna.
El párrafo Arguments detalla los valores y el tipo de contenedor de cada argumento de nuestra función. Por ejemplo, podemos
ver que el argumento dimnames debe ser del tipo list. Es por eso que hemos usado este formato en la sección matrix.
# Arguments
# data an optional data vector (including a list or expression vector).
# Non-atomic classed R objects are coerced by [Link] and all
# attributes discarded.
# nrow the desired number of rows.
# ncol the desired number of columns.
# byrow logical. If FALSE (the default) the matrix is filled by columns,
# otherwise the matrix is filled by rows.
# dimnames A dimnames attribute for the matrix: NULL or a list of length 2
# giving the row and column names respectively. An empty list is
# treated as NULL, and a list of length one as row names. The
# list can be named, and the list names will be used as names for
# the dimensions.
7.2. LAS FUNCIONES MÁS COMUNES 91
El párrafo Details proporciona elementos adicionales en la función. El párrafo Examples proporciona ejemplos reproducibles
en la consola.
El nombre de los argumentos no es necesario para que una función sea interpretada correctamente por R. Sin embargo, es mejor
usar explicitamente el nombre de los argumentos seguidos por el signo = para que el código sea más legible.
# buen ejemplo
mdat <- matrix(c(1, 2, 3, 11, 12, 13), nrow = 2, ncol = 3, byrow = TRUE)
# mal ejemplo
mdat <- matrix(c(1, 2, 3, 11, 12, 13), 2, 3, TRUE)
[Link] [Link]()
La función [Link]() o ?? permite buscar una expresión en toda la documentación. Es útil cuando buscamos una
función sin saber el nombre exacto de la función en R.
[Link]("average")
La función [Link]() devuelve una página que contiene la lista de páginas donde se encontró la expresión en la forma
package-name::function-name.
[Link] str()
La función str() permite visualizar la estructura interna de un objeto, como se indica en la documentación que podemos
consultar con help(str).
str(iris)
La función str() devuelve el tipo de objeto ([Link]), el número de observaciones (150), el número de variables (5), el
nombre de cada variable ([Link] , [Link], [Link], [Link], y Species), el tipo de cada
variable (num,Factor), y los primeros valores de cada una de las variables. Es una función útil para echar un vistazo a un
conjunto de datos, pero también para verificar que los datos sean del tipo requirido antes de realizar un análisis estadístico.
La función head() devuelve los primeros valores de un objeto, y la función tail() devuelve los últimos valores de un objeto.
Por defecto, se devuelven seis valores, el argumento n controla el número de valores a devolver.
head(iris)
tail(iris)
head(iris, n = 2)
[Link] names()
Ya hemos visto la función names(), que permite conocer los nombres de los elementos de un objeto, pero también asignar
nombres a los elementos de un objeto como a un matrix, a una list o a un [Link].
names(iris)
La función cat() se usa para mostrar el contenido de un objeto mientras que la función print() devuelve el valor de un objeto
con la capacidad de realizar conversiones.
cat(names(iris))
print(names(iris))
cat(iris[1, 1])
## 5.1
print(iris[1, 1])
## [1] 5.1
## [1] 5
[Link] rank()
La función rank() devuelve el número de la posición ordenada de cada elemento de un conjunto de elementos. En el caso
de elementos del mismo valor, el argumento [Link] hace posible hacer una elección sobre la clasificación. Como con
todas las funciones, los detalles están presentes en la documentación.
94 CHAPTER 7. LAS FUNCIONES
## [1] 1 2 3 7 6 5 4
## [1] 2 4 5 2 7 2 6
## [1] 1 4 5 2 7 3 6
## [1] 1 4 5 1 7 1 6
print(iris[, 1])
## [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8 4.3 5.8 5.7 5.4
## [18] 5.1 5.7 5.1 5.4 5.1 4.6 5.1 4.8 5.0 5.0 5.2 5.2 4.7 4.8 5.4 5.2 5.5
## [35] 4.9 5.0 5.5 4.9 4.4 5.1 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 5.3 5.0 7.0
## [52] 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 5.0 5.9 6.0 6.1 5.6 6.7 5.6 5.8
## [69] 6.2 5.6 5.9 6.1 6.3 6.1 6.4 6.6 6.8 6.7 6.0 5.7 5.5 5.5 5.8 6.0 5.4
## [86] 6.0 6.7 6.3 5.6 5.5 5.5 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7 6.3 5.8
## [103] 7.1 6.3 6.5 7.6 4.9 7.3 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5 7.7 7.7
## [120] 6.0 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2 7.4 7.9 6.4 6.3 6.1 7.7
## [137] 6.3 6.4 6.0 6.9 6.7 6.9 5.8 6.8 6.7 6.7 6.3 6.5 6.2 5.9
## [1] 37.0 19.5 10.5 7.5 27.5 49.5 7.5 27.5 3.0 19.5 49.5
## [12] 14.0 14.0 1.0 77.0 69.5 49.5 37.0 69.5 37.0 49.5 37.0
## [23] 7.5 37.0 14.0 27.5 27.5 43.5 43.5 10.5 14.0 49.5 43.5
## [34] 56.0 19.5 27.5 56.0 19.5 3.0 37.0 27.5 5.0 3.0 27.5
## [45] 37.0 14.0 37.0 7.5 46.0 27.5 138.0 112.0 135.5 56.0 118.0
## [56] 69.5 104.0 19.5 121.5 43.5 27.5 82.0 86.5 92.5 62.5 126.5
## [67] 62.5 77.0 97.5 62.5 82.0 92.5 104.0 92.5 112.0 121.5 132.0
## [78] 126.5 86.5 69.5 56.0 56.0 77.0 86.5 49.5 86.5 126.5 104.0
7.2. LAS FUNCIONES MÁS COMUNES 95
## [89] 62.5 56.0 56.0 92.5 77.0 27.5 62.5 69.5 69.5 97.5 37.0
## [100] 69.5 104.0 77.0 139.0 104.0 118.0 145.0 19.5 143.0 126.5 141.0
## [111] 118.0 112.0 132.0 69.5 77.0 112.0 118.0 147.5 147.5 86.5 135.5
## [122] 62.5 147.5 104.0 126.5 141.0 97.5 92.5 112.0 141.0 144.0 150.0
## [133] 112.0 104.0 92.5 147.5 104.0 112.0 86.5 135.5 126.5 135.5 77.0
## [144] 132.0 126.5 126.5 104.0 118.0 97.5 82.0
# help(rank)
# ...
# Usage
# rank(x, [Link] = TRUE,
# [Link] = c("average", "first", "last",
# "random", "max", "min"))
[Link] order()
La función order() devuelve el número de la reorganización de los elementos en función de su posición. Es muy útil, por
ejemplo, para ordenar un [Link] en función de una columna.
print(vecManip2)
## [1] 10 20 30 10 50 10 40
rank(vecManip2)
## [1] 2 4 5 2 7 2 6
order(vecManip2)
## [1] 1 4 6 2 3 7 5
print(iris[, 1])
## [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8 4.3 5.8 5.7 5.4
## [18] 5.1 5.7 5.1 5.4 5.1 4.6 5.1 4.8 5.0 5.0 5.2 5.2 4.7 4.8 5.4 5.2 5.5
## [35] 4.9 5.0 5.5 4.9 4.4 5.1 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 5.3 5.0 7.0
## [52] 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 5.0 5.9 6.0 6.1 5.6 6.7 5.6 5.8
## [69] 6.2 5.6 5.9 6.1 6.3 6.1 6.4 6.6 6.8 6.7 6.0 5.7 5.5 5.5 5.8 6.0 5.4
## [86] 6.0 6.7 6.3 5.6 5.5 5.5 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7 6.3 5.8
## [103] 7.1 6.3 6.5 7.6 4.9 7.3 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5 7.7 7.7
## [120] 6.0 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2 7.4 7.9 6.4 6.3 6.1 7.7
## [137] 6.3 6.4 6.0 6.9 6.7 6.9 5.8 6.8 6.7 6.7 6.3 6.5 6.2 5.9
96 CHAPTER 7. LAS FUNCIONES
rank(iris[, 1])
## [1] 37.0 19.5 10.5 7.5 27.5 49.5 7.5 27.5 3.0 19.5 49.5
## [12] 14.0 14.0 1.0 77.0 69.5 49.5 37.0 69.5 37.0 49.5 37.0
## [23] 7.5 37.0 14.0 27.5 27.5 43.5 43.5 10.5 14.0 49.5 43.5
## [34] 56.0 19.5 27.5 56.0 19.5 3.0 37.0 27.5 5.0 3.0 27.5
## [45] 37.0 14.0 37.0 7.5 46.0 27.5 138.0 112.0 135.5 56.0 118.0
## [56] 69.5 104.0 19.5 121.5 43.5 27.5 82.0 86.5 92.5 62.5 126.5
## [67] 62.5 77.0 97.5 62.5 82.0 92.5 104.0 92.5 112.0 121.5 132.0
## [78] 126.5 86.5 69.5 56.0 56.0 77.0 86.5 49.5 86.5 126.5 104.0
## [89] 62.5 56.0 56.0 92.5 77.0 27.5 62.5 69.5 69.5 97.5 37.0
## [100] 69.5 104.0 77.0 139.0 104.0 118.0 145.0 19.5 143.0 126.5 141.0
## [111] 118.0 112.0 132.0 69.5 77.0 112.0 118.0 147.5 147.5 86.5 135.5
## [122] 62.5 147.5 104.0 126.5 141.0 97.5 92.5 112.0 141.0 144.0 150.0
## [133] 112.0 104.0 92.5 147.5 104.0 112.0 86.5 135.5 126.5 135.5 77.0
## [144] 132.0 126.5 126.5 104.0 118.0 97.5 82.0
order(iris[, 1])
## [1] 14 9 39 43 42 4 7 23 48 3 30 12 13 25 31 46 2
## [18] 10 35 38 58 107 5 8 26 27 36 41 44 50 61 94 1 18
## [35] 20 22 24 40 45 47 99 28 29 33 60 49 6 11 17 21 32
## [52] 85 34 37 54 81 82 90 91 65 67 70 89 95 122 16 19 56
## [69] 80 96 97 100 114 15 68 83 93 102 115 143 62 71 150 63 79
## [86] 84 86 120 139 64 72 74 92 128 135 69 98 127 149 57 73 88
## [103] 101 104 124 134 137 147 52 75 112 116 129 133 138 55 105 111 117
## [120] 148 59 76 66 78 87 109 125 141 145 146 77 113 144 53 121 140
## [137] 142 51 103 110 126 130 108 131 106 118 119 123 136 132
[Link] sort()
La función sort() se usa para ordenar los elementos de un objeto. No permite la clasificación por más de una variable, como
es el caso de order().
7.2. LAS FUNCIONES MÁS COMUNES 97
print(vecManip2)
## [1] 10 20 30 10 50 10 40
sort(vecManip2)
## [1] 10 10 10 20 30 40 50
print(iris[, 1])
## [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8 4.3 5.8 5.7 5.4
## [18] 5.1 5.7 5.1 5.4 5.1 4.6 5.1 4.8 5.0 5.0 5.2 5.2 4.7 4.8 5.4 5.2 5.5
## [35] 4.9 5.0 5.5 4.9 4.4 5.1 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 5.3 5.0 7.0
## [52] 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2 5.0 5.9 6.0 6.1 5.6 6.7 5.6 5.8
## [69] 6.2 5.6 5.9 6.1 6.3 6.1 6.4 6.6 6.8 6.7 6.0 5.7 5.5 5.5 5.8 6.0 5.4
## [86] 6.0 6.7 6.3 5.6 5.5 5.5 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7 6.3 5.8
## [103] 7.1 6.3 6.5 7.6 4.9 7.3 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5 7.7 7.7
## [120] 6.0 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2 7.4 7.9 6.4 6.3 6.1 7.7
## [137] 6.3 6.4 6.0 6.9 6.7 6.9 5.8 6.8 6.7 6.7 6.3 6.5 6.2 5.9
sort(iris[, 1])
## [1] 4.3 4.4 4.4 4.4 4.5 4.6 4.6 4.6 4.6 4.7 4.7 4.8 4.8 4.8 4.8 4.8 4.9
## [18] 4.9 4.9 4.9 4.9 4.9 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.0 5.1 5.1
## [35] 5.1 5.1 5.1 5.1 5.1 5.1 5.1 5.2 5.2 5.2 5.2 5.3 5.4 5.4 5.4 5.4 5.4
## [52] 5.4 5.5 5.5 5.5 5.5 5.5 5.5 5.5 5.6 5.6 5.6 5.6 5.6 5.6 5.7 5.7 5.7
## [69] 5.7 5.7 5.7 5.7 5.7 5.8 5.8 5.8 5.8 5.8 5.8 5.8 5.9 5.9 5.9 6.0 6.0
## [86] 6.0 6.0 6.0 6.0 6.1 6.1 6.1 6.1 6.1 6.1 6.2 6.2 6.2 6.2 6.3 6.3 6.3
## [103] 6.3 6.3 6.3 6.3 6.3 6.3 6.4 6.4 6.4 6.4 6.4 6.4 6.4 6.5 6.5 6.5 6.5
## [120] 6.5 6.6 6.6 6.7 6.7 6.7 6.7 6.7 6.7 6.7 6.7 6.8 6.8 6.8 6.9 6.9 6.9
## [137] 6.9 7.0 7.1 7.2 7.2 7.2 7.3 7.4 7.6 7.7 7.7 7.7 7.7 7.9
[Link] append()
Esta función se usa para agregar un elemento a un vector en una posición determinada por el argumento after. Esta función
también es más rápida que su alternativa c().
print(vecManip2)
## [1] 10 20 30 10 50 10 40
98 CHAPTER 7. LAS FUNCIONES
append(vecManip2, 5)
## [1] 10 20 30 10 50 10 40 5
append(vecManip2, 5, after = 2)
## [1] 10 20 5 30 10 50 10 40
Las funciones cbind() y rbind() permiten combinar elementos por columna o por línea.
cbind(vecManip2, vecManip2)
## vecManip2 vecManip2
## [1,] 10 10
## [2,] 20 20
## [3,] 30 30
## [4,] 10 10
## [5,] 50 50
## [6,] 10 10
## [7,] 40 40
rbind(vecManip2, vecManip2)
Estas son dos funciones que usaremos mucho a partir de ahora. Las funciones paste() y paste0() se usan para concatenar
cadenas de texto. La función paste0() es equivalente a paste() sin proponer un separador entre los elementos a concatenar.
La función paste0() también es más rápida.
paste(1, "a")
paste0(1, "a")
## [1] "1a"
## [1] "1_a"
[Link] rev()
print(vecManip2)
## [1] 10 20 30 10 50 10 40
rev(vecManip2)
## [1] 40 10 50 10 30 20 10
[Link] %in%()
La función %in%() se puede comparar con un operador de comparación. Esta función toma dos objetos como argumentos y
devuelve TRUE o FALSE para cada elemento del primer objeto de acuerdo con su presencia o ausencia en el segundo objeto.
Para acceder a la documentación de la función, use help('%in%') (con comillas simples).
100 CHAPTER 7. LAS FUNCIONES
print(vecManip)
## [1] 10 20 30 70 60 50 40
print(vecManip2)
## [1] 10 20 30 10 50 10 40
Ya hemos visto las funciones +, -, *, /, ^, %% y otros operadores aritméticos. R también tiene funciones matemáticas bási-
cas como exponencial exp(), raíz cuadrada sqrt(), valor absoluto abs(), sinus sin(), coseno cos(), tangente tan(),
logaritmo log(), logaritmo base 10 log10(), arco coseno acos(), arco sinus asin(), y arco tangente atan().
print(vecManip2)
## [1] 10 20 30 10 50 10 40
exp(vecManip2)
sqrt(vecManip2)
abs(-vecManip2)
## [1] 10 20 30 10 50 10 40
sin(vecManip2)
cos(vecManip2)
tan(vecManip2)
log(vecManip2)
log10(vecManip2)
acos(vecManip2/100)
asin(vecManip2/100)
atan(vecManip2/100)
También podemos realizar estadísticas descriptivas de forma muy simple a partir de un conjunto de datos.
[Link] mean()
La función mean() devuelve la media. Para ignorar los valores faltantes NA, hay que afectar el valor TRUE al argumento
[Link]().
mean(iris[, 1])
## [1] 5.843333
## [1] NA
## [1] 13.16667
[Link] sd()
sd(iris[, 1])
## [1] 0.8280661
print(vecManip3)
## [1] 1 5 6 8 NA 45 NA 14
7.2. LAS FUNCIONES MÁS COMUNES 103
sd(vecManip3)
## [1] NA
## [1] 16.16684
max(iris[, 1])
## [1] 7.9
print(vecManip3)
## [1] 1 5 6 8 NA 45 NA 14
max(vecManip3)
## [1] NA
## [1] 45
min(iris[, 1])
## [1] 4.3
min(vecManip3)
## [1] NA
104 CHAPTER 7. LAS FUNCIONES
## [1] 1
[Link] quantile()
quantile(iris[, 1])
[Link] summary()
La función summary() devuelve un resumen con el mínimo, primer cuartil, mediana, promedio, tercer cuartil y máximo.
summary(iris[, 1])
[Link] median()
median(iris[, 1])
## [1] 5.8
7.2. LAS FUNCIONES MÁS COMUNES 105
print(vecManip3)
## [1] 1 5 6 8 NA 45 NA 14
median(vecManip3)
## [1] NA
## [1] 7
[Link] length()
length(iris[, 1])
## [1] 150
print(vecManip3)
## [1] 1 5 6 8 NA 45 NA 14
length(vecManip3)
## [1] 8
La función nrow() devuelve el número de líneas y la función ncol() el número de columnas en un objeto.
nrow(iris)
## [1] 150
106 CHAPTER 7. LAS FUNCIONES
ncol(iris)
## [1] 5
La función round() le permite seleccionar una cierta cantidad de decimales (0 por defecto)
round(5.56874258564)
## [1] 6
round(5.56874258564, digits = 2)
## [1] 5.57
La función ceiling() devuelve el entero más pequeño que no es inferior al valor especificado.
ceiling(5.9999)
## [1] 6
ceiling(5.0001)
## [1] 6
La función floor() devuelve el entero más grande que no excede el valor especificado.
floor(5.9999)
## [1] 5
floor(5.0001)
## [1] 5
trunc(5.9999)
## [1] 5
trunc(5.0001)
## [1] 5
## [1] 10.2 9.5 9.4 9.4 10.2 11.4 9.7 10.1 8.9 9.6 10.8 10.0 9.3 8.5
## [15] 11.2 12.0 11.0 10.3 11.5 10.7 10.7 10.7 9.4 10.6 10.3 9.8 10.4 10.4
## [29] 10.2 9.7 9.7 10.7 10.9 11.3 9.7 9.6 10.5 10.0 8.9 10.2 10.1 8.4
## [43] 9.1 10.7 11.2 9.5 10.7 9.4 10.7 9.9 16.3 15.6 16.4 13.1 15.4 14.3
## [57] 15.9 11.6 15.4 13.2 11.5 14.6 13.2 15.1 13.4 15.6 14.6 13.6 14.4 13.1
## [71] 15.7 14.2 15.2 14.8 14.9 15.4 15.8 16.4 14.9 12.8 12.8 12.6 13.6 15.4
## [85] 14.4 15.5 16.0 14.3 14.0 13.3 13.7 15.1 13.6 11.6 13.8 14.1 14.1 14.7
## [99] 11.7 13.9 18.1 15.5 18.1 16.6 17.5 19.3 13.6 18.3 16.8 19.4 16.8 16.3
## [113] 17.4 15.2 16.1 17.2 16.8 20.4 19.5 14.7 18.1 15.3 19.2 15.7 17.8 18.2
## [127] 15.6 15.8 16.9 17.6 18.2 20.1 17.0 15.7 15.7 19.1 17.7 16.8 15.6 17.5
## [141] 17.8 17.4 15.5 18.2 18.2 17.2 15.7 16.7 17.3 15.8
## [1] 2.550 2.375 2.350 2.350 2.550 2.850 2.425 2.525 2.225 2.400 2.700
## [12] 2.500 2.325 2.125 2.800 3.000 2.750 2.575 2.875 2.675 2.675 2.675
## [23] 2.350 2.650 2.575 2.450 2.600 2.600 2.550 2.425 2.425 2.675 2.725
## [34] 2.825 2.425 2.400 2.625 2.500 2.225 2.550 2.525 2.100 2.275 2.675
## [45] 2.800 2.375 2.675 2.350 2.675 2.475 4.075 3.900 4.100 3.275 3.850
## [56] 3.575 3.975 2.900 3.850 3.300 2.875 3.650 3.300 3.775 3.350 3.900
108 CHAPTER 7. LAS FUNCIONES
## [67] 3.650 3.400 3.600 3.275 3.925 3.550 3.800 3.700 3.725 3.850 3.950
## [78] 4.100 3.725 3.200 3.200 3.150 3.400 3.850 3.600 3.875 4.000 3.575
## [89] 3.500 3.325 3.425 3.775 3.400 2.900 3.450 3.525 3.525 3.675 2.925
## [100] 3.475 4.525 3.875 4.525 4.150 4.375 4.825 3.400 4.575 4.200 4.850
## [111] 4.200 4.075 4.350 3.800 4.025 4.300 4.200 5.100 4.875 3.675 4.525
## [122] 3.825 4.800 3.925 4.450 4.550 3.900 3.950 4.225 4.400 4.550 5.025
## [133] 4.250 3.925 3.925 4.775 4.425 4.200 3.900 4.375 4.450 4.350 3.875
## [144] 4.550 4.550 4.300 3.925 4.175 4.325 3.950
[Link] aggregate()
La función aggregate() permite agrupar los elementos de un objeto de acuerdo con un valor. El argumento by define el
elemento sobre el que se realiza la agrupación. Debe ser del tipo list.
[Link] range()
range(iris[, 1])
print(vecManip3)
## [1] 1 5 6 8 NA 45 NA 14
range(vecManip3)
## [1] NA NA
## [1] 1 45
[Link] unique()
unique(iris[, 1])
## [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.4 4.8 4.3 5.8 5.7 5.2 5.5 4.5 5.3 7.0 6.4
## [18] 6.9 6.5 6.3 6.6 5.9 6.0 6.1 5.6 6.7 6.2 6.8 7.1 7.6 7.3 7.2 7.7 7.4
## [35] 7.9
print(vecManip3)
## [1] 1 5 6 8 NA 45 NA 14
unique(vecManip3)
## [1] 1 5 6 8 NA 45 14
110 CHAPTER 7. LAS FUNCIONES
No podemos abordar todas las funciones útiles, aquí solo abordaremos ciertas funciones. A lo largo de este libro, se usarán
nuevas funciones. Cuando se utiliza una nueva función, nuestro reflejo siempre debe ser el mismo: consultar la documentación
con la función help().
7.3.1 seq_along()
La función seq_along() se usa para crear un vector del tamaño del objeto rellenado y tomando como valores los números
de 1 a N (N corresponde al número de elementos del objeto). Esta función nos servirá mucho en el capítulo sobre bucles.
print(vecManip3)
## [1] 1 5 6 8 NA 45 NA 14
seq_along(vecManip3)
## [1] 1 2 3 4 5 6 7 8
7.3.2 :
La función : permite crear una secuencia desde a hacia b por pasos de 1. Ha sido difícil escribir los capítulos anteriores sin
usarlo ya que esta función es muy útil. Aquí estan algunos ejemplos.
5:10
## [1] 5 6 7 8 9 10
## [1] -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6
## [18] 7 8 9 10 11 12
5:-5
## [1] 5 4 3 2 1 0 -1 -2 -3 -4 -5
## [1] "X_1" "X_2" "X_3" "X_4" "X_5" "X_6" "X_7" "X_8" "X_9" "X_10"
7.3.3 rep()
rep(1:3, time = 3)
## [1] 1 2 3 1 2 3 1 2 3
## [1] 1 2 3 1 2 3 1 2 3 1
112 CHAPTER 7. LAS FUNCIONES
rep(1:3, each = 3)
## [1] 1 1 1 2 2 2 3 3 3
7.3.4 seq()
seq(from = 0, to = 1, by = 0.2)
## [1] "a" "c" "e" "g" "i" "k" "m" "o" "q" "s" "u" "w" "y"
## [1] 1.0 1.5 2.0 1.0 1.5 2.0 1.0 1.5 2.0
7.3.5 getwd()
La función getwd() establece la carpeta de trabajo. Esto corresponde a la ubicación relativa desde la cual R se posiciona para
identificar los archivos. Este concepto tendrá sentido cuando veamos cómo importar y exportar datos.
getwd()
## [1] "D:/GitHub/myRbook_SP"
7.3.6 setwd()
La función setwd() se usa para definir un nuevo directorio de trabajo (carpeta de trabajo).
7.3. OTRAS FUNCIONES ÚTILES 113
## [1] "D:/GitHub/myRbook_SP"
setwd("..")
getwd()
## [1] "D:/GitHub"
setwd(oldWd)
getwd()
## [1] "D:/GitHub/myRbook_SP"
7.3.7 [Link]()
La función [Link] () se usa para listar todos los archivos en el directorio de trabajo.
## [1] "google_analytics_SP.html"
## character(0)
7.3.8 ls()
Al igual que la función [Link]() hace posible listar todos los archivos presentes en el directorio de trabajo, la función
ls() permite listar todos los objetos presentes en el entorno de trabajo de R.
ls()
7.3.9 rm()
rm(zzz)
ls()
Aquí hay algunos ejercicios para mejorar el uso de las funciones y aprender nuevas gracias a la documentación. Algunos
ejercicios son difíciles, podremos volver a resolverlos más tarde.
7.4.1 Secuencias
-3 -4 -5 -6 -7 -8 -9 -10 –11
-3 -1 1 3 5 7 9 11
20 18 16 14 12 10 8 6
“a” “a” “a” “a” “a” “f” “f” “f” “f” “f” “k” “k” “k” “k” “k” “p” “p” “p” “p” “p” “u” “u” “u” “u” “u” “z” “z” “z” “z” “z”
-3:-11
## [1] -3 -1 1 3 5 7 9 11
## [1] "a" "a" "a" "a" "a" "f" "f" "f" "f" "f" "k" "k" "k" "k" "k" "p" "p"
## [18] "p" "p" "p" "u" "u" "u" "u" "u" "z" "z" "z" "z" "z"
En el conjunto de datos iris, ¿cuántos valores de ancho del sépalo son mayores que 3? Entre 2.8 y 3.2?
Si la distribución de los datos era Normal, ¿cuál sería el valor teórico de este intervalo del 90% (función qnorm())?
Soluciones:
## [1] 67
## [1] 47
7.5. ESCRIBIR UNA FUNCIÓN 117
table(iris$[Link])
##
## 2 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8
## 1 3 4 3 8 5 9 14 10 26 11 13 6 12 6 4 3 6
## 3.9 4 4.1 4.2 4.4
## 2 1 1 1 1
table(round(iris$[Link]))
##
## 2 3 4
## 19 106 25
## [1] 2.0 2.2 2.2 2.2 2.3 2.3 2.3 2.3 2.4 2.4
## 5% 95%
## 2.345 3.800
qnorm(
p = c(0.05, 0.95),
mean = mean(irisSepWCopy),
sd = sd(irisSepWCopy)
)
Cuando reproducimos las mismas operaciones varias veces, el código se vuelve difícil de escribir y de mantener porque si
tenemos que hacer una modificación, tendremos que repetirla cada vez que la usemos. Esto es un signo de la necesidad de
usar una función. En el siguiente ejemplo, sera largo modificar el código si queremos agregar +45 en lugar de +20 para cada
línea.
118 CHAPTER 7. LAS FUNCIONES
35 + 20
## [1] 55
758 + 20
## [1] 778
862 + 20
## [1] 882
782 + 20
## [1] 802
Como todas las funciones básicas de R, nuestras funciones tendrán un nombre y argumentos. Al igual que con los nombres de
los objetos y los nombres de los archivos, es importante elegir bien el nombre de nuestra función (ver la sección sobre objetos).
Para crear una función utilizaremos la función function() que toma como argumento los argumentos de nuestra función. La
función devolverá el resultado deseado. Por defecto, el resultado devuelto es el último utilizado, pero es mejor usar la función
return(). La siguiente función addX() toma como argumento x y devuelve x + 20.
addX(35)
## [1] 55
addX(758)
## [1] 778
7.5. ESCRIBIR UNA FUNCIÓN 119
addX(862)
## [1] 882
addX(782)
## [1] 802
Si queremos cambiar el código para agregar 45 en lugar de 20, simplemente cambiamos la función addX().
## [1] 80
addX(758)
## [1] 803
addX(862)
## [1] 907
addX(782)
## [1] 827
Aquí podríamos haber usado el formato vector para evitar la repetición, pero eso no siempre es posible.
Vamos a esribir una nueva función que contará el número de consonantes y vocales en minúsculas en una palabra. Primero
separaremos todas las letras de la palabra con la función strsplit (podemos consultar la ayuda para saber más acerca de
esta función). Luego contaremos las vocales y las consonantes con la función length(). Para la lista de letras, usaremos el
objeto letters incluido en R que contiene las 26 letras en minuscula (consulte la ayuda con ?letters).
120 CHAPTER 7. LAS FUNCIONES
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q"
## [18] "r" "s" "t" "u" "v" "w" "x" "y" "z"
## [1] 11 9
Esta función se puede modificar mostrando un mensaje más explícito. Aunque en general se debe evitar este tipo de mensaje
para evitar sobrecargar las funciones, puede ser útil verificar que todo esté funcionando correctamente (luego lo borraremos).
## [1] 11 9
Por otro lado, si usamos countVowelConso(word = 5), se devolverá un error porque nuestra función espera un objeto de
tipo character. En general, se recomienda manejar los errores devueltos por nuestras funciones para que nuestro código sea
más fácil de mantener. Aquí simplemente comprobaremos que el argumento sea de tipo character, en un vector de tamaño
1. También comentaremos nuestra función para encontrar rápidamente lo que hace (comentario insertado en la primera línea,
que a veces encontramos en la última línea de las funciones).
7.5. ESCRIBIR UNA FUNCIÓN 121
## [1] 11 9
countVowelConso(word = 5)
Con R como para cualquier lenguaje de programación, para un problema siempre hay múltiples soluciones. Recordamos la
sección sobre tipos de datos (tipo de datos logical), así como la sección sobre operadores de comparación que el valor de
TRUE es 1 y el valor de FALSE es 0. Hemos visto anteriormente que la función % in% devuelve TRUE o FALSE para cada
elemento del primer objeto dependiendo de su presencia o ausencia en el segundo objeto. Nuestra función podría haber usado
otra función en lugar de length() para contar vocales y consonantes (función sum()).
## [1] 11 9
No existe una solución óptima en absoluto, todo depende de los objetivos deseados. La primera solución puede ser más fácil
de entender, y la segunda puede ser más rápida en términos de velocidad de ejecución (repitiendo el uso de la función 10000
veces, el ahorro de tiempo es casi cero en nuestro caso).
122 CHAPTER 7. LAS FUNCIONES
Una función puede tener valores predeterminados para sus argumentos. Este es el caso para la mayoría de las funciones
existentes. Por defecto, nuestra función ahora contará el número de vocales y consonantes en la palabra qwerty (los paréntesis
son necesarios incluso en ausencia de argumentos).
## [1] 2 4
R tiene muchas funciones, por lo tanto, antes de comenzar a escribir una nueva función, siempre debemos verificar que ya no
exista en la versión básica de R o en los packages desarrollado por la comunidad de usuarios. Para esto podemos usar la ayuda
con la función ??miBusqueda, pero también nuestro navegador de Internet.
Un package (o paquete) es un conjunto de archivos que agregaremos a R para usar funciones (o conjuntos de datos) que
otras personas hayan desarrollado. Actualmente hay más de 10,000 paquetes en los servidores CRAN de R (CRAN; https:
//[Link]/web/packages/), más de 1000 en los servidores de BioConductor (para análisis genómicos)
y varios cientos en GitHub. Cada paquete hace posible usar nuevas funciones para casi todo … Por lo tanto, puede ser difícil
encontrar el paquete adecuado para lo que queremos lograr, y es importante dedicar tiempo a la busqueda del paquete adecuado
y probar varios soluciones.
Para usar un paquete, primero debemos instalarlo, y luego cargarlo en nuestra sesión R.
7.6. OTRAS FUNCIONES DESARROLLADAS POR LA COMUNIDAD DE USUARIOS: LOS PACKAGES 123
Una vez que hemos seleccionado nuestro paquete, podemos descargarlo e instalarlo con la función [Link](),
que toma el nombre del paquete entre comillas como argumento (la función tolera la ausencia de comillas, pero es mejor usarlas
para que el código sea más legible). Algunos paquetes ya son instalados por defecto con R, como stats (que también se carga
de forma predeterminada).
La instalación de un paquete debe hacerse una vez, luego el paquete está en nuestra computadora.
Para poder usar las funciones de un paquete, tenemos que cargarlo en nuestra sesión R. Hay tantos paquetes disponibles que
R no cargará todos los que tenemos instalados por defecto, sino solo los que necesitaremos para nuestro estudio actual. Para
cargar un paquete usamos la función library() o require().
library("stats")
La carga del paquete debe hacerse cada vez que queremos ejecutar nuestro código, por lo tanto, es una parte integral de nuestro
script.
Acabamos de ver que la instalación de un paquete solo se debe hacer una vez por computadora, y que la carga de un paquete se
debe lograr para cada nueva sesión de R. Si uno cambia de computadora o si compartimos un script con colegas, puede haber
errores de ejecución relacionados con la falta de instalación de un paquete. Para superar este problema, se recomienda utilizar
una función que verifique si los paquetes necesarios para ejecutar un script están instalados; si es necesario, instálelos y luego
cárguelos. Hay muchas funciones para hacer esto en Internet. La solución que proponemos aquí es una mezcla adaptada de
diferentes fuentes. No es necesario comprender los detalles de este script por el momento, sino simplemente comprender lo que
hace. Este es un ejemplo para el paquete stats y graphics, dos paquetes que ya estan presente con la versión básica de R,
pero podemos tratar todos los paquetes disponibles en CRAN; la lista se puede encontrar aquí: [Link]
org/web/packages/available_packages_by_name.html.
Alternativamente, podemos usar la función .packages() para listar los paquetes disponibles en el CRAN en orden alfabético.
124 CHAPTER 7. LAS FUNCIONES
La función pkgCheck() asegura la portabilidad de nuestros scripts: funcionarán en todas las computadoras sin tener que
realizar ningún cambio. Por lo tanto, nuestros scipts pueden adjuntarse, por ejemplo, a nuestros artículos científicos y así
garantizar la reproducibilidad de nuestros resultados.
7.7 Conclusión
Felicitaciones! Ahora sabemos reconocer y usar una función, sabemos cómo buscar ayuda para una función e incluso sabemos
escribir nuestras propias funciones. También sabemos que hay muchas funciones desarrolladas por la comunidad de usuarios
de R dentro de paquetes (packages) que sabemos cómo instalar y cargar, y asegurar la portabilidad de nuestros scripts de una
computadora a otra (importante para la reproducibilidad de los resultados). El próximo capítulo se enfocará en leer y escribir
archivos porque nuestros datos suelen estar en archivos de texto u hojas de cálculo.
Chapter 8
Hay muchas maneras de leer el contenido de un archivo con R. Sin embargo, nos enfocaremos en leer los archivos TXT y CSV
que son los más comunes y los más confiables. Con raras excepciones, todos los archivos de datos se pueden transformar
fácilmente en formatos TXT y CSV. Esta es la práctica preferida para el análisis de datos con R.
En concreto, desde Microsoft Excel, simplemente vamos a Archivo, luego Guardar como, seleccionamos el lugar donde queremos
guardar nuestro archivo (hablaremos en el siguiente capítulo sobre la gestión de un proyecto R) y luego en el la ventana de copia
de seguridad cambiamos el Tipo desde XLSX hacia CSV. Desde LibreOffice Calc, simplemente vamos a Archivo, luego Guardar
como, luego seleccionamos el tipo CSV. Es importante saber que el archivo CSV no admite el formato de archivos de hoja de
cálculo con, por ejemplo, colores, y que el archivo CSV contiene solo una pestaña. Si tenemos un archivo de hoja de cálculo con
varias pestañas, tendremos que guardar tantos archivos CSV como pestañas.
Una vez que se obtiene el archivo TXT o CSV, la lectura del contenido desde R es fácil, aun que requiere un poco de rigor.
Esta es la fuente de error más común para los principiantes en R. Es por eso que es importante leer y volver a leer este capítulo
y lo siguiente sobre la gestión de un proyecto R con mucha atención.
R funciona en un directorio definido por defecto. Los usuarios de Rstudio u otro entorno de desarrollo especializado para R
intentarán usar las opciones disponibles a través de los menús para establecer su directorio de trabajo o cargar el contenido de
un archivo. En este libro, estas técnicas nunca se usarán porque no permiten la reproducibilidad de los resultados. Un script
debe poder funcionar para todos los sistemas operativos y sin tener en cuenta el entorno de desarrollo del usuario.
El directorio de trabajo por defecto se puede obtener con la función getwd() y cambiar con la función setwd().
125
126 CHAPTER 8. IMPORTAR Y EXPORTAR DATOS
## [1] "D:/GitHub/myRbook_SP"
setwd("..")
getwd()
## [1] "D:/GitHub"
setwd(oldWd)
getwd()
## [1] "D:/GitHub/myRbook_SP"
• podemos leer el contenido de un archivo indicando a R su ruta completa (limitacion para la reproducibilidad de los resul-
tados)
• podemos leer el contenido de un archivo indicando a R su ruta relativa
• podemos mover el archivo en el directorio de trabajo de R
• podemos modificar el directorio de trabajo de R para que coincida con la ubicación de nuestro archivo (con su ruta relativa)
• myName/[Link]
Para navegar por las rutas relativas, podemos usar .. que permite volver al directorio de origen. Por ejemplo, si el directorio de
trabajo es myScripts y el árbol de mis archivos es:
## -myProject
## |-myFiles
## |-|-[Link]
## |-|-[Link]
## |-myScripts
## |-|-myFirstScript.R
Entonces, para leer el contenido del archivo [Link], privilegiaremos la opción 2 (leer el contenido de un archivo que
indicando su ruta relativa) o la opción 4 (modificar el directorio de trabajo de R para que coincida con la ubicación de nuestro
archivo). En el último caso:
8.1. LEER DATOS DE UN ARCHIVO 127
## Error in setwd("../myFiles/") :
## no se puede cambiar el directorio de trabajo
Esto significa que el directorio no existe (se debe verificar que la sintaxis sea correcta y que el directorio exista con esta ruta).
Una vez que el directorio de trabajo está definido correctamente o la ruta relativa al archivo está establecida correctamente,
podemos leer el archivo con la función [Link](). Algunos usan la función [Link]() pero este es solo un caso
especial de [Link]().
o alternativamente:
[Link](file = "../myFiles/[Link]")
Si todo está bien, R muestra el contenido del archivo [Link]. Advertencia a los usuarios de Windows porque por defecto
no aparece la extensión de los archivos… Así que cuando navegamos a través de directorios con el explorador de archivos,
no hay [Link], pero sólo un archivo data01. Es esencial remediar este problema para evitar errores. Para hacer
esto, simplemente abrimos las ‘Opciones del Explorador de archivos’ a través de la tecla ‘Windows’, luego en la pestaña ‘Ver’,
verificamos que la opción ‘Ocultar extensiones de archivos cuyo tipo es conocido’ no está marcado.
Consultando la ayuda sobre la función [Link](), podemos ver que tiene muchos argumentos. Los principales son:
• header = FALSE: ¿el archivo contiene nombres de columna? Si es así, cambiamos el valor a header = TRUE
• sep =" ": ¿cómo se separan los datos de la tabla? En un archivo CSV es la coma o el punto y coma, así que cambiamos
a sep = "," o sep = ";"
• dec =". ": ¿cuál es el separador de los números decimales? Si es la coma, entonces debes cambiar a dec = ","
Con estos tres argumentos, la mayoría de los archivos se pueden leer sin ningún problema. En caso de necesidad, la ayuda de
esta función es muy completa.
La función [Link] () devuelve el contenido del archivo como [Link]. Para poder usar el contenido del archivo,
almacenaremos el [Link] en un objeto.
128 CHAPTER 8. IMPORTAR Y EXPORTAR DATOS
El estudio de caso sobre el análisis de datos de datalogger se basa en un archivo CSV. Aquí hay un extracto:
## id date temp
## 1 1 11/12/15 [Link] 4.973
## 2 2 11/12/15 [Link] 4.766
## 3 3 11/13/15 [Link] 4.844
## 4 4 11/13/15 [Link] 4.844
## 5 5 11/13/15 [Link] 5.076
## 6 6 11/13/15 [Link] 5.282
tail(bdd)
## id date temp
## 32781 32781 09/25/17 [Link] 7.091
## 32782 32782 09/25/17 [Link] 6.914
## 32783 32783 09/25/17 [Link] 6.813
## 32784 32784 09/25/17 [Link] 6.611
## 32785 32785 09/25/17 [Link] 6.331
## 32786 32786 09/25/17 [Link] 5.385
str(bdd)
La función más simple para leer un archivo que contiene texto es readlines(). Aquí hay un ejemplo con el archivo
[Link] de este libro, que se encuentra en GitHub.
8.2. GUARDAR DATOS PARA R 129
También está la función scan() que devolve todas las palabras separadas por espacios. Podemos consultar la ayuda para
obtener más información.
A veces es útil poder guardar un objeto R para poder reutilizarlo más tarde. Este es el caso, por ejemplo, cuando el tiempo de
cálculo para llegar a un resultado es muy largo, o cuando queremos liberar espacio en la RAM. Para hacer esto, existe la función
save() que toma como argumento principal el nombre de los objetos que queremos guardar.
El objeto guardado se almacenará en un archivo. Por convención, es bueno dar como nombre de extensión .RData a los
archivos que contienen objetos R, preferir un solo objeto por archivo, y dar el nombre del objeto como nombre del archivo.
myObject <- 5
ls(pattern = "myObject")
## [1] "myObject"
## character(0)
Si necesitamos el objeto guardado en el archivo, podemos volver a cargarlo con la función load().
ls(pattern = "myObject")
## character(0)
130 CHAPTER 8. IMPORTAR Y EXPORTAR DATOS
load("myFiles/[Link]")
ls(pattern = "myObject")
## [1] "myObject"
print(myObject)
## [1] 5
La mejor forma de comunicar sus resultados o datos es enviar sus scripts y archivos de datos. A veces esto no es posible o
no es adecuado, y puede ser útil exportar sus datos en un archivo de texto o CSV. Para hacer esto, existe la función genérica
write() y la función [Link]() para [Link].
Por ejemplo, crearemos un [Link] con los números del 1 al 26 y las letras correspondientes, luego los guardaremos en
un archivo CSV, luego volveremos a leer los datos contenidos en este archivo.
## num letters
## 1 1 a
## 2 2 b
## 3 3 c
## 4 4 d
## 5 5 e
## 6 6 f
## 7 7 g
## 8 8 h
## 9 9 i
## 10 10 j
## 11 11 k
## 12 12 l
## 13 13 m
## 14 14 n
## 15 15 o
## 16 16 p
## 17 17 q
## 18 18 r
## 19 19 s
## 20 20 t
## 21 21 u
## 22 22 v
## 23 23 w
## 24 24 x
## 25 25 y
## 26 26 z
8.4. CONCLUSIÓN 131
8.4 Conclusión
Felicitaciones! Ahora sabemos cómo leer datos de un archivo de texto o CSV, guardar y cargar datos de RData, y escribir en un
archivo. El error más común entre los principiantes en R es la lectura de archivos de datos. Es por eso que este capítulo es para
leer y volver a leer sin moderación.
132 CHAPTER 8. IMPORTAR Y EXPORTAR DATOS
Chapter 9
Algorítmico
Si queremos realizar una operación diferente según una condición, podemos configurar una prueba lógica del tipo SI esto EN-
TONCES esto SINO esto. Con R esto dará como resultado la función if(cond) [Link] [Link] como se mues-
tra en la función help.
myVar <- 2
if(myVar < 3) print("myVar < 3")
Cuando hay varias líneas de código para ejecutar basadas en la prueba lógica, o simplemente para hacer que el código sea más
fácil de leer, utilizamos varias líneas con {} y con identacion.
myVar <- 2
myResult <- 0
if(myVar < 3){
print("myVar < 3")
myResult <- myVar + 10
} else {
print("myVar > 3")
myResult <- myVar - 10
}
133
134 CHAPTER 9. ALGORÍTMICO
print(myResult)
## [1] 12
En este ejemplo definimos una variable myVar. Si esta variable es menor que 3, la variable myResult se establece en myVar
+ 10, y de lo contrario myResult se establece en myVar - 10.
Ya hemos visto el uso de la prueba lógica if en el capítulo sobre las funciones. Habiamos probado si la variable ingresada como
argumento en nuestra función era de tipo character.
## [1] "ok"
También es posible estipular varias condiciones, como vimos en el capítulo sobre operadores de comparación.
myVar <- 2
if(myVar > 1 & myVar < 50){
print("ok")
}
## [1] "ok"
9.1. PRUEBAS LÓGICAS CON IF 135
En este ejemplo, myVar está en formato numeric, por lo que la primera condición (> 1) y la segunda condición (< 50) son
verificables. Por otro lado, si asignamos una variable de tipo character a myVar entonces R transformará 0 y 10 en objetos
de tipo character y probará si myVar> "1" y despues si myVar < "50" basandose en la clasificación alfabética. En el
siguiente ejemplo, "azerty" no está ubicado segun el orden alfabético entre "1" y "50", pero para "2azerty" es el caso,
lo que resulta problematico.
Entonces, lo que nos gustaría hacer es probar si myVar está en formato numeric, y entonces solo si es el caso probar las
siguientes condiciones.
A veces es posible que necesitemos probar una primera condición y luego una segunda condición solo si la primera es verdadera
en la misma prueba. Por ejemplo, para un sitio nos gustaría saber si hay una sola especie y probar si su abundancia es mayor que
10. Imagine un conjunto de datos con abundancia de vectores. Probaremos el número de especies con la función length().
136 CHAPTER 9. ALGORÍTMICO
R devuelve un error porque no puede dentro de una prueba lógica con if() verificar la segunda condición. De hecho,
mySpecies > 10 devuelve TRUE TRUE TRUE TRUE TRUE. Podemos separar el código en dos condiciones:
Una alternativa más elegante es decirle a R que verifique la segunda condición solo si la primera es verdadera. Para eso podemos
usar && en lugar de &.
## [1] "ok!"
mySpecies <- 5
if(length(mySpecies) == 1 && mySpecies > 10){
print("ok!")
}
Con & R comprobará todas las condiciones, y con && R tomará cada condición una después de la otra y continuará solo si es
verdadera. Esto puede parecer anecdótico, pero es bueno saber la diferencia entre & y && porque a menudo los encontramos
en los códigos disponibles en Internet o en los paquetes.
La función switch() es una variante de if() que es útil cuando tenemos muchas opciones posibles para la misma expresión.
El siguiente ejemplo muestra cómo transformar el código usando if() a switch().
9.3. EL BUCLE FOR 137
x <- "aa"
if(x == "a"){
result <- 1
}
if(x == "aa"){
result <- 2
}
if(x == "aaa"){
result <- 3
}
if(x == "aaaa"){
result <- 4
}
print(result)
## [1] 2
x <- "aa"
switch(x,
a = result <- 1,
aa = result <- 2,
aaa = result <- 3,
aaaa = result <- 4)
print(result)
## [1] 2
En programación, cuando tenemos que repetir la misma línea de código varias veces, es un signo que indica que debemos usar
un bucle. Un bucle es una forma de iterar sobre un conjunto de objetos (o los elementos de un objeto) y repetir una operación.
Imaginamos un [Link] con mediciones de datos de campo en dos fechas.
## date01 date02
## 1 10.018288 9.001038
## 2 10.629828 12.771839
## 3 9.291223 9.594611
## 4 12.476939 9.926380
## 5 9.665082 8.852094
## 6 9.232240 9.805178
Nos gustaría cuantificar la diferencia entre la primera y la segunda fecha, luego poner un indicador para saber si esta diferencia
es pequeña o grande, por ejemplo, con un umbral arbitrario de 3. Entonces, para cada línea podríamos hacer:
138 CHAPTER 9. ALGORÍTMICO
bdd$dif <- NA
bdd$isDifBig <- NA
Esta forma de hacer las cosas sería extremadamente tediosa de lograr, y casi imposible de lograr si la tabla contuviera 1000 o
100000 líneas. Puede parecer lógico querer iterar sobre las líneas de nuestro [Link] para obtener las nuevas columnas.
Es lo que vamos a hacer aun que no es la solución que retendremos más adelante.
Vamos a usar un bucle for(). El bucle for() recorrerá los elementos de un objeto que vamos a dar como argumento. Por
ejemplo, aquí hay un bucle que para todos los números del 3 al 9 calculará su valor al cuadrado. El valor actual del número está
simbolizado por un objeto que puede tomar el nombre que queramos (aquí será i).
## [1] 9
## [1] 16
## [1] 25
## [1] 36
## [1] 49
## [1] 64
## [1] 81
for(i in 3:9){
print(i^2)
}
## [1] "a"
## [1] "z"
## [1] "e"
## [1] "r"
## [1] "t"
## [1] "y"
Volvamos a nuestro caso. Vamos a iterar sobre el número de líneas de nuestro [Link] bdd. Antes de eso crearemos las
columnas dif y isDifBig con los valores NA. Luego usaremos la función nrow() para encontrar el número de líneas.
bdd$dif <- NA
bdd$isDifBig <- NA
for(i in 1:nrow(bdd)){
bdd$dif[i] <- sqrt((bdd$date01[i] - bdd$date02[i])^2)
if(bdd$dif[i] > 3){
bdd$isDifBig[i] <- "big"
}else{
bdd$isDifBig[i] <- "small"
}
}
print(head(bdd, n = 20))
En la práctica, esta no es la mejor manera de realizar este ejercicio porque se trata de cálculos simples en vectores contenidos
en un [Link]. R es particularmente potente para realizar operaciones en vectores. Donde sea posible, siempre tenemos
que enfócarnos en operaciones vectoriales. Aquí nuestro código se convierte en:
La mayoría de los ejemplos que se pueden encontrar en Internet sobre el bucle for() pueden reemplazarse por operaciones
vectoriales. Aquí hay algunos ejemplos adaptados de varias fuentes:
## [1] 6
# [2] VECTOR
sum(x %% 2 == 0)
## [1] 6
# calcular cuadrados
# [1] FOR
x <- rep(0, 20)
for (j in 1:20){
x[j] <- j^2
}
print(x)
# [2] VECTOR
(1:20)^2
## [1] 3.393
# [2] VECTOR
mean(sample(1:6, ntrials, replace = TRUE))
## [1] 3.517
142 CHAPTER 9. ALGORÍTMICO
Es un buen ejercicio explorar los muchos ejemplos disponibles en Internet en el bucle for() e intentar convertirlos en opera-
ciones vectoriales. Esto nos permite adquirir buenos reflejos de programación con R. El bucle for() es muy útil, por ejemplo,
para leer varios archivos y tratar la información que contienen de la misma manera, hacer gráficos, o Cuando las operaciones
vectoriales se vuelven tediosas. Imagina una matriz de 10 columnas y 100 líneas. Queremos la suma de cada línea (veremos
cómo hacer con la función apply() mas adelante).
## [1] 596 537 540 471 501 640 487 552 494 533 558 368 389 354 479 545 482
## [18] 495 441 560 627 489 412 388 604 461 417 476 477 430 488 664 423 446
## [35] 394 527 363 587 692 663 412 467 442 510 414 487 553 478 476 432 401
## [52] 467 410 466 502 484 291 448 349 521 550 693 465 375 556 546 675 458
## [69] 475 502 468 634 654 553 606 567 532 420 517 552 487 319 560 621 582
## [86] 389 546 441 477 388 423 545 577 550 436 419 332 342 622 417
# FOR
sumRow <- rep(NA, times = nrow(myMat))
for(j in 1:nrow(myMat)){
sumRow[j] <- sum(myMat[j, ])
}
print(sumRow)
## [1] 596 537 540 471 501 640 487 552 494 533 558 368 389 354 479 545 482
## [18] 495 441 560 627 489 412 388 604 461 417 476 477 430 488 664 423 446
## [35] 394 527 363 587 692 663 412 467 442 510 414 487 553 478 476 432 401
## [52] 467 410 466 502 484 291 448 349 521 550 693 465 375 556 546 675 458
## [69] 475 502 468 634 654 553 606 567 532 420 517 552 487 319 560 621 582
## [86] 389 546 441 477 388 423 545 577 550 436 419 332 342 622 417
En conclusión, se recomienda no usar el bucle for() con R siempre que sea posible, y en este capítulo veremos alternativas
como los bucles familiares apply().
El bucle while(), a diferencia del bucle for(), significa MIENTRAS. Mientras no se cumpla una condición, el bucle continuará
ejecutándose. Atención porque en caso de error, podemos programar fácilmente bucles que nunca terminan. Este bucle es
menos común que el bucle for(). Tomemos un ejemplo:
i <- 0
while(i < 10){
print(i)
i <- i + 1
}
9.4. EL BUCLE WHILE 143
## [1] 0
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
En este ejemplo, la variable i tiene como valor inicial 0. MIENTRAS QUE i < 10, mostramos i con print(). Para que este
bucle finalice, no olvidamos cambiar el valor de i, esto se hace con la línea i <- i + 1. Cuando la condición i < 10 ya no
se cumple, el bucle se detiene.
El bucle while() es muy útil para crear scripts que realizarán cálculos en variables cuyo valor cambia con el tiempo. Por
ejemplo, imaginamos un número entre 0 y 10000 y un generador aleatorio que intentará determinar el valor de este número. Si
queremos limitar los intentos de R a 2 segundos, podemos escribir el siguiente script (que debería funcionar cada vez en una
computadora de escritorio típica que pueda realizar fácilmente 35000 pruebas en 2 segundos):
En este script generamos un número aleatorio para adivinar con la función sample(), y cada uno de los intentos con la misma
función sample(). Luego usamos la función [Link]() (con una S mayúscula a Sys), para saber la hora de inicio del
bucle. Siempre que la diferencia entre cada iteración del bucle y la hora de inicio sea inferior a 2 segundos, el bucle while()
verificará si el número correcto estaba adivinando en la prueba lógica con if() y luego si es el caso nos informa que se encontró
el número, y nos indica el tiempo restante antes de los dos segundos. Luego para finalizar el bucle usamos la palabra clave
“break” en la que volveremos. En resumen, break, permite salir de un bucle. Si no se ha adivinado el número, el bucle realiza
otra prueba con la función sample().
Más concretamente, podríamos imaginar algoritmos para explorar un espacio de soluciones a un problema con un tiempo limitado
para lograrlo. El bucle while() también puede ser útil para que un script se ejecute solo cuando un archivo de otro programa
esté disponible … En la práctica, el bucle while() se usa poco con R.
144 CHAPTER 9. ALGORÍTMICO
El bucle repeat() permite repetir una operación sin condiciones para verificar. Para salir de este bucle debemos usar la palabra
clave break.
i <- 1
repeat{
print(i^2)
i <- i + 1
if(i == 5){
break
}
}
## [1] 1
## [1] 4
## [1] 9
## [1] 16
Si volvemos al ejemplo anterior, podemos usar un bucle repeat() para repetirlo cinco veces.
numTry <- 0
repeat{
myNumber <- sample(x = 10000, size = 1)
myGuess <- sample(x = 10000, size = 1)
startTime <- [Link]()
numberGuess <- 0
while([Link]() - startTime < 2){
if(myGuess == myNumber){
numberGuess <- numberGuess + 1
print(round([Link]([Link]() - startTime), digits = 3))
break
}else{
myGuess <- sample(x = 10000, size = 1)
numberGuess <- numberGuess + 1
}
}
numTry <- numTry + 1
if(numTry == 5){break}
}
## [1] 0.565
## [1] 0.476
## [1] 0.511
## [1] 0.233
## [1] 0.007
## [1] 128
Aunque hemos visto que en la práctica podemos evitar el bucle for() con una operación vectorial:
(111:1000)[111:1000 %% 32 == 0][1]
## [1] 128
La palabra clave next permite pasar a la siguiente iteración de un bucle si se cumple una determinada condición. Por ejemplo,
si queremos imprimir las letras del alfabeto sin las vocales:
for(myLetter in letters){
if(myLetter %in% c("a", "e", "i", "o", "u", "y")){
next
}
print(myLetter)
}
## [1] "b"
## [1] "c"
## [1] "d"
## [1] "f"
## [1] "g"
## [1] "h"
## [1] "j"
## [1] "k"
## [1] "l"
## [1] "m"
## [1] "n"
## [1] "p"
## [1] "q"
## [1] "r"
## [1] "s"
## [1] "t"
## [1] "v"
## [1] "w"
## [1] "x"
## [1] "z"
146 CHAPTER 9. ALGORÍTMICO
## [1] "b" "c" "d" "f" "g" "h" "j" "k" "l" "m" "n" "p" "q" "r" "s" "t" "v"
## [18] "w" "x" "z"
En conclusión, si usamos bucles, las palabras clave next y break suelen ser muy útiles, pero siempre que sea posible es mejor
usar operaciones vectoriales. Cuando no es posible trabajar con vectores, es mejor usar los bucles del tipo apply que son el
tema de la siguiente sección.
9.7.1 apply
La función apply() permite aplicar una función a todos los elementos de un array o un matrix. Por ejemplo, si queremos
saber la suma de cada fila de una matriz de 10 columnas y 100 líneas:
## [1] 399 496 413 426 465 460 400 655 697 639 522 594 286 430 507 418 512
## [18] 559 532 372 586 554 423 456 480 366 375 590 480 462 554 475 651 647
## [35] 604 444 502 561 561 488 530 582 624 403 454 467 559 422 609 671 518
## [52] 483 648 633 588 476 534 553 571 551 394 481 359 656 538 470 421 530
## [69] 494 425 435 438 523 582 511 552 505 614 566 525 614 506 671 559 481
## [86] 665 455 496 459 496 592 471 646 590 500 343 330 637 510 513
## [1] 60.5 46.0 64.0 45.5 56.0 49.0 52.0 59.5 41.0 50.0
El argumento X es el objeto en el que el bucle apply se repetirá. El argumento MARGEN corresponde a la dimensión a tener
en cuenta (1 para las filas y 2 para las columnas). El argumento FUN es la función a aplicar. En un objeto array, el argumento
MARGIN puede tomar tantos valores como dimensiones. En este ejemplo, MARGIN = 1 es el promedio de cada fila - dimensión
1 - (todas las dimensiones combinadas), MARGIN = 2 es el promedio de cada columna - dimensión 2 - (todas las dimensiones
combinadas), y MARGEN = 3 es el promedio de cada dimensión 3. Debajo cada cálculo se realiza de dos maneras diferentes
para explicar su operación.
myArr <- array(sample(1:100, size = 1000, replace = TRUE), dim = c(10, 20, 5))
apply(X = myArr, MARGIN = 1, FUN = mean)
## [1] 50.48 52.80 53.41 52.57 50.18 51.07 53.88 52.48 52.43 49.51
9.7. LOS BUCLES DE LA FAMILIA APPLY 147
## [1] 50.48 52.80 53.41 52.57 50.18 51.07 53.88 52.48 52.43 49.51
## [1] 50.54 51.76 52.08 49.24 49.46 49.94 47.08 49.72 52.68 52.82 48.68
## [12] 49.62 56.90 51.14 56.48 57.92 57.72 55.96 53.92 43.96
## [1] 50.54 51.76 52.08 49.24 49.46 49.94 47.08 49.72 52.68 52.82 48.68
## [12] 49.62 56.90 51.14 56.48 57.92 57.72 55.96 53.92 43.96
También podemos calcular el promedio de cada fila y valor de columna (la función luego itera en la dimensión 3):
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13]
## [1,] 45.8 46.4 73.8 50.0 39.0 64.0 49.8 52.8 42.8 48.2 19.0 41.4 62.4
## [2,] 73.2 57.0 39.2 58.2 30.0 32.6 50.4 44.0 58.0 53.0 57.0 50.2 49.6
## [3,] 41.6 64.8 48.8 48.2 66.0 46.8 56.4 57.8 53.4 62.4 58.0 62.0 44.2
## [4,] 42.4 67.0 70.6 49.8 36.0 66.4 43.2 52.8 59.4 47.0 41.2 45.0 41.4
## [5,] 29.2 44.0 28.0 36.6 55.6 39.2 56.8 34.8 50.2 75.0 53.2 27.0 77.8
## [6,] 67.2 37.2 51.4 42.0 49.0 50.2 32.4 57.6 47.0 33.8 46.0 47.0 75.6
## [7,] 71.8 61.2 36.8 60.6 59.0 50.4 61.6 49.0 63.6 43.8 44.0 53.8 36.6
## [8,] 35.2 58.8 66.6 39.4 52.0 48.6 42.0 56.0 45.8 64.2 47.4 60.0 65.6
148 CHAPTER 9. ALGORÍTMICO
## [9,] 54.4 39.4 60.2 55.2 43.6 46.2 24.4 48.4 57.0 64.0 59.6 45.0 69.0
## [10,] 44.6 41.8 45.4 52.4 64.4 55.0 53.8 44.0 49.6 36.8 61.4 64.8 46.8
## [,14] [,15] [,16] [,17] [,18] [,19] [,20]
## [1,] 50.6 51.8 69.4 52.8 55.2 62.4 32.0
## [2,] 59.2 63.2 58.2 61.6 51.8 65.8 43.8
## [3,] 45.8 56.2 43.4 49.0 62.4 40.0 61.0
## [4,] 79.2 49.8 48.6 63.8 52.4 55.4 40.0
## [5,] 31.4 66.4 76.6 63.6 59.4 35.8 63.0
## [6,] 45.6 37.6 51.8 84.2 57.6 63.4 44.8
## [7,] 64.2 71.2 56.4 54.0 74.2 47.4 18.0
## [8,] 36.6 71.0 55.6 53.4 64.8 38.2 48.4
## [9,] 58.2 57.2 61.2 56.2 33.8 61.0 54.6
## [10,] 40.6 40.4 58.0 38.6 48.0 69.8 34.0
9.7.2 lapply
Como se indica en la documentación, lapply() devuelve una lista de la misma longitud que X, y cada elemento resulta de
la aplicación FUN al elemento X correspondiente. Si X es una list que contiene vector y estamos tratando de obtener el
promedio de cada elemento de list, podemos usar la función lapply():
## $a
## [1] 97 55 25 39 56 68 94 51 86 31
##
## $b
## [1] 14 41 73 98 78 15 35 88 53 42
##
## $c
## [1] 25 65 85 6 8 78 7 79 43 71
##
## $d
## [1] 20 76 47 89 62 16 97 82 54 38
##
## $e
## [1] 6 75 3 86 60 56 12 26 65 28
## $a
## [1] 60.2
##
9.7. LOS BUCLES DE LA FAMILIA APPLY 149
## $b
## [1] 53.7
##
## $c
## [1] 46.7
##
## $d
## [1] 58.1
##
## $e
## [1] 41.7
Al igual que con la función apply(), podemos pasar argumentos adicionales a la función lapply() agregándolos después
de la función. Esto es útil, por ejemplo, si nuestra list contiene estos valores faltantes NA y queremos ignorarlos para calcular
los promedios (con el argumento [Link] = TRUE).
## $a
## [1] 5 1 5 5 2 5 NA 3 2 NA
##
## $b
## [1] 4 4 1 3 5 4 NA 2 1 3
##
## $c
## [1] NA 1 4 5 1 4 3 3 5 2
##
## $d
## [1] NA NA 5 3 5 3 5 NA 5 1
##
## $e
## [1] 4 1 4 4 4 2 3 3 3 4
## $a
## [1] NA
##
## $b
## [1] NA
##
## $c
## [1] NA
150 CHAPTER 9. ALGORÍTMICO
##
## $d
## [1] NA
##
## $e
## [1] 3.2
## $a
## [1] 3.5
##
## $b
## [1] 3
##
## $c
## [1] 3.111111
##
## $d
## [1] 3.857143
##
## $e
## [1] 3.2
Para mayor legibilidad o si se debemos realizar varias operaciones dentro del argumento FUN, podemos usar el siguiente script:
## $a
## [1] 3.5
##
## $b
## [1] 3
##
## $c
## [1] 3.111111
##
## $d
## [1] 3.857143
##
## $e
## [1] 3.2
Por ejemplo, si queremos obtener i^2 si el promedio es mayor que 3, y i^3 de lo contrario:
9.7. LOS BUCLES DE LA FAMILIA APPLY 151
## $a
## [1] 25 1 25 25 4 25 NA 9 4 NA
##
## $b
## [1] 64 64 1 27 125 64 NA 8 1 27
##
## $c
## [1] NA 1 16 25 1 16 9 9 25 4
##
## $d
## [1] NA NA 25 9 25 9 25 NA 25 1
##
## $e
## [1] 16 1 16 16 16 4 9 9 9 16
9.7.3 sapply
La función sapply() es una versión modificada de la función lapply() que realiza la misma operación pero devuelve el
resultado en un formato simplificado siempre que sea posible.
## $a
## [1] 3.5
##
## $b
## [1] 3
##
## $c
## [1] 3.111111
##
## $d
## [1] 3.857143
##
## $e
## [1] 3.2
152 CHAPTER 9. ALGORÍTMICO
## a b c d e
## 3.500000 3.000000 3.111111 3.857143 3.200000
La función sapply() es interesante para recuperar, por ejemplo, el elemento “n” de cada elemento de una list. La función
que se llama para hacer esto es '[['.
## a b c d e
## 1 4 1 NA 1
9.7.4 tapply
La función tapply() permite aplicar una función tomando como elemento para iterar una variable existente. Imaginamos
información sobre especies representadas por letras mayúsculas (por ejemplo, A, B, C) y valores de mediciones biologicas en
diferentes ubicaciones.
Podemos obtener fácilmente un resumen de las mediciones para cada especie con la función tapply() y la función
summary().
## $A
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.397 9.628 9.944 9.898 10.188 10.946
##
## $B
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.582 9.616 9.969 9.931 10.249 11.432
##
## $C
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.594 9.667 10.001 10.034 10.433 11.163
##
## $D
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.849 9.704 9.922 10.022 10.320 11.313
##
## $E
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.276 9.643 9.919 9.945 10.305 11.153
##
## $F
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.484 9.784 10.126 10.050 10.441 11.263
##
## $G
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.834 9.750 10.008 10.035 10.323 11.297
##
## $H
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.805 9.761 10.010 9.980 10.254 11.456
##
## $I
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.705 9.731 10.048 10.017 10.375 10.873
##
## $J
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.608 9.773 10.043 10.024 10.325 10.876
También podemos obtener el valor promedio de cada mediciones combinando una función sapply() con la función tapply()
y usando la función mean().
9.7.5 mapply
La función mapply() es una versión de la función sapply() que usa múltiples argumentos. Por ejemplo, si tenemos una lista
de dos elementos 1:5 y 5:1 y queremos agregar 10 al primer elemento y 100 al segundo elemento:
## [,1] [,2]
## [1,] 11 105
## [2,] 12 104
## [3,] 13 103
## [4,] 14 102
## [5,] 15 101
9.8 Conclusión
Felicitaciones, hemos llegado al final de este capítulo sobre algoritmos. Recordemos este mensaje clave: cuando una operación
debe realizarse más de dos veces en un script y repetir el código que ya se ha escrito, es un signo que nos debe llevar a utilizar un
bucle. Sin embargo, siempre que sea posible, se recomienda no usar los bucles tradicionales for(), while(), y repeat(),
sino preferir operaciones sobre vectores o bucles de la familia apply. Esto puede ser difícil de integrar al principio, pero veremos
que nuestros scripts serán más fáciles de mantener y leer, y mucho más eficientes si seguimos estos hábitos.
Chapter 10
Ahora que hemos visto los conceptos básicos de R, todavía tenemos que abordar un elemento decisivo para el buen fun-
cionamiento de nuestras actividades científicas con R: gestión de proyectos. Consiste en integrar sus desarrollos en un entorno
y con una lógica orientada a facilitar su trabajo y aumentar así su eficiencia. Esta es solo una manera de hacer dentro de las
infinitas posibilidades, a adaptar para todos y cada uno.
Entre los archivos de entrada (es decir, los archivos que contienen nuestros datos en bruto), los archivos de salida (por ejemplo,
con la función write()), los gráficos (siguiente capítulo) y los muchos scripts asociados con un proyecto, se necesita un
mínimo de organización para ser eficaz y reanudar rápidamente su proyecto. La solución más sencilla es estructurar su entorno
de trabajo en carpetas según cada categoría de archivo. Por ejemplo, con una carpeta “myProject” para el proyecto, que contiene
las carpetas “myFiles” para los archivos de entrada, una carpeta “myScripts” para el script R y una carpeta “myOutputs” para los
archivos salida (por ejemplo, gráficos y análisis).
## -myProject
## |-myFiles
## |-|-[Link]
## |-|-[Link]
## |-myScripts
## |-|-myFirstScript.R
## |-myOutputs
## |-|-[Link]
## |-|-[Link]
El trabajo en un script es iterativo: incluso si los objetivos se definen desde el principio, volveremos a trabajar algunas partes
para obtener, por ejemplo, información adicional, o para optimizar esta o aquella función, o hacer un script generalizable para
comunicarlo a La comunidad científica o simplemente un colega. A veces, lo que veremos como una mejora finalmente será un
error, y volver al estado inicial puede ser difícil. Así que tenemos que gestionar las versiones.
En la mayoría de los laboratorios hay servicios de control de versiones, el más conocido es GIT ([Link] y
Subversion ([Link] Cuando GIT o Subversion están disponibles, se recomienda usarlos. Si
no tenemos acceso a estos servicios, hay servicios en línea gratuitos como GitHub ([Link] este libro utiliza
GitHub). Hay muchas otras soluciones como GitLab ([Link] Bitbucket ([Link]
155
156 CHAPTER 10. GESTIÓN DE PROYECTOS CON R
## -myProject
## |-myFiles
## |-|-[Link]
## |-|-[Link]
## |-myScripts
## |-|-myFirstScript04.R
## |-|-ARCHIVES
## |-|-|-myFirstScript01.R
## |-|-|-myFirstScript02.R
## |-|-|-myFirstScript03.R
## |-myOutputs
## |-|-[Link]
## |-|-[Link]
La documentación de su código es esencial para volver fácilmente al trabajo o comunicar su trabajo con colegas y la comunidad
científica. Un código bien documentado será comprensible por un número mayor y, por lo tanto, se utilizará más. Por eso es
importante adoptar buenas técnicas y practicas.
Ya hemos visto que hay varias formas de escribir su código con R porque es un lenguaje bastante permisivo. El primer paso
hacia un código legible y reproducible es adoptar un estilo de código claro y coherente y … ¡hecho para humanos! Porque incluso
si nuestro código está destinado a ser ejecutado por máquinas, debe seguir siendo comprensible de todas las personas que lo
consultarán. Es por ejemplo poner espacios después de las comas, o usar la identación. Por supuesto, la legibilidad del código
debe equilibrarse con la optimización del código para grandes conjuntos de datos, pero en la mayoría de los casos podemos
asociar un código claro y optimizado. Entonces, el primer paso de la documentación y su administración es escribir primero su
código pensando en las personas que lo leerán y lo reproducirán.
El segundo paso es comentar su código. Los comentarios son esenciales cuando privilegiamos el código optimizado para
el rendimiento pero que pierde en legibilidad. Los comentarios son superfluos si el código está bien escrito y los objetos y
funciones están bien nombrados. Esto significa que los comentarios no deben usarse para explicar un código mal escrito,
sino que desdemos desde el principio escribir bien nuestro código. Los comentarios son útiles para proporcionar elementos
contextuales (por ejemplo, la elección de un método sobre otro en la literatura). El lugar de los comentarios puede estar al final
de las líneas o en líneas separadas.
Para un proyecto pequeño en R es esencial que cada script comience con una descripción de sus contenidos para que podamos
saber rápidamente de qué se trata. Eso es lo que hicimos al principio de este libro:
# ------------------------------------------------------------
# Aquí hay un script para adquirir los conceptos básicos
# con R
# fecha de creación : 25/06/2018
# autor : François Rebaudo
10.3. GESTION DE DOCUMENTACION 157
# ------------------------------------------------------------
nbrRep <- 5
pi * nbrRep^2
Aquí los comentarios que siguen al encabezado no son necesarios porque el nombre del objeto se entiende por sí mismo. Nuestro
archivo se convierte en:
# ------------------------------------------------------------
# Aquí hay un script para adquirir los conceptos básicos
# con R
# fecha de creación : 25/06/2018
# autor : François Rebaudo
# ------------------------------------------------------------
nbrRep <- 5
pi * nbrRep^2
Para un proyecto grande con muchas funciones para ser utilizado por otros usuarios, es preferible que la documentación del
código esté separada, en un archivo de ayuda específico. Este es el caso de todos los paquetes R! Para gestionar la docu-
mentación de un paquete (y por lo tanto de todas las funciones), de nuevo hay muchas posibilidades. Lo más común es usar el
paquete R roxigen2. Sin entrar en detalles, aquí hay algunos ejemplos de la documentación del paquete.
Esto nos permite escribir la documentación de cada función junto a la función. El paquete roxigen2 generará a partir de estos
comentarios un documento de ayuda accesible con la función '?'. A menos que escribamos un nuevo paquete, los comentarios
simples serán suficientes, y el desarrollo de un paquete está fuera del alcance de este libro.
10.4 Conclusión
Felicitaciones. Este capítulo marca el final de la primera parte de este libro. Ahora tenemos lo básico para llevar a cabo nuestros
proyectos con R. En la siguiente parte veremos los gráficos y cómo hacer figuras en el marco de los artículos científicos.
Part II
Los gráficos
159
Chapter 11
Gráficos simples
11.1 plot
El primer tipo de gráfico que veremos es la nube de puntos. En un diagrama de dispersión, cada punto está representado por su
valor en x e y. La función para hacer un diagrama de dispersión es plot().
10
9
8
−3 −2 −1 0 1
myX
161
162 CHAPTER 11. GRÁFICOS SIMPLES
Al igual que con todos los tipos de gráficos, podemos agregar una leyenda en los ejes x e y.
10
9
8
−3 −2 −1 0 1
13
12
11
10
Y
9
8
7
−3 −2 −1 0 1 2 3
El tipo de punto se puede establecer con el argumento pch que puede tomar un carácter o un número del 1 al 25.
5
rep(seq(1:5), each = 5)
4
3
2
1
1 2 3 4 5
rep(seq(1:5), 5)
a
12
l
= i = 0
of
n o #k
11
_ j O @ c g
@
g dh a
myY
e O f
m o dk
10
m
1 o i 1−b ac _
b#
e jl
a
9
n
0 −
8
−3 −2 −1 0 1
myX
12
11
myY
10
9
8
−3 −2 −1 0 1
myX
El color de los puntos se puede definir con el argumento col. Volveremos a los colores en un próximo capítulo.
12
11
myY
10
9
8
−2 −1 0 1 2
myX
Para representar nuestros puntos, el color y el tamaño de los puntos pueden representar información adicional. Aquí repre-
sentaremos por un gradiente de tamaño la variable myY y por un gradiente de color la variablemyX.
2
1
0
−1
−2
−2 −1 0 1 2
R ofrece la posibilidad de conectar puntos de nube de puntos de diferentes maneras. Las diferentes opciones están disponibles
en la ayuda de las funciones plot() y [Link]().
12
11
myY
10
9
5 10 15 20
myX
Una última opción muy útil es el argumento [Link] que permite realizar una operación gráfica en una capa debajo de
nuestro gráfico. Aquí hay un ejemplo ilustrativo con una cuadrícula hecha con y sin [Link]. La cuadrícula se realiza
gracias a la función grid(). Para poner los gráficos lado a lado usaremos mfrow.
12
12
11
11
myY
myY
10
10
9
5 10 15 20 9 5 10 15 20
myX myX
La función par() proporciona acceso a parámetros gráficos. Entre estos parámetros hay mfrow que permite dividir el espacio
gráfico como una matriz. mfrow toma como argumentos un vector numérico de tamaño 2: el primer elemento corresponde al
número de líneas y el segundo elemento al número de columnas. El parámetro mar controla los márgenes en la parte inferior,
izquierda, superior y derecha, respectivamente, utilizando un vector digital de tamaño 4. Después de cambiar la configuración de
gráficos predeterminada, se recomienda restablecerlos para que no afecte a los futuros gráficos. Los valores predeterminados
para mfrow son c(1, 1) y mar = c (4, 4, 4, 4). Podemos restablecer estos valores predeterminados como antes,
redefiniendo cada parámetro. También podemos guardar los valores actuales (en un objeto op) de antemano, modificarlos para
los propósitos de nuestros gráficos y luego recuperar los valores contenidos en el objeto op. Aquí usamos lapply para hacer
rápidamente cuatro gráficos.
3
2
2
1
rnorm(100)
1
0
0
−1
−1
−2
−2
−2 −1 0 1 2 3 4 −2 −1 0 1 2
3
rnorm(100) rnorm(100)
3
2
2
1
rnorm(100)
1
0
0
−2
−1
−2
−4
−2 −1 0 1 2 −3 −2 −1 0 1 2
par(op)
Es útil incluir líneas verticales u horizontales para representar valores particulares. Estas líneas se pueden agregar con la función
abline().
4
2
myY
0
−2
−4
−4 −2 0 2 4
myX
11.2 hist
Para hacer un histograma usamos la función hist(). Esta es una función gráfica útil para visualizar rápidamente la distribución
de un conjunto de datos.
600
150
Frequency
400
100
200
50
0
0
−3 −2 −1 0 1 2 3 0 2 4 6 8 10
Uniform Beta
myX[[i]] myX[[i]]
150
80
Frequency
100
60
40
50
20
0
par(op)
11.3 barplot
8
6
4
2
0
A B C
Cuando el objeto enviado a esta función es un vector, entonces la función barplot() devuelve un gráfico de barras simple.
Cuando es un matrix entonces las barras son múltiples.
12
15
10
8
10
6
4
5
2
0
A B C A B C
par(op)
La función barplot() también se puede usar para representar el equivalente de un histograma. Esto puede ser útil para
representar la distribución de una variable en función del eje x el eje y. En el siguiente ejemplo tenemos n puntos tomados
aleatoriamente en una distribución normal con la configuración mean = 0 y sd = 1 (myX <- rnorm(n)). Estos puntos son
para ser mostrado en azul o en rojo (el color azul se codifica con el valor 4 y el color rojo con el valor 2, discutiremos en un capítulo
posterior). La eleccion aleatoria del color se realiza con la función sample() (myCol <- sample(c(4, 2), size = n,
replace = TRUE)). Aquí queremos representar una nube de puntos con puntos rojos o azules, y histogramas de los ejes
X y Y para ver la distribución de puntos (con un degradado de color de azul a rojo dependiendo La proporción de puntos de
color en cada categoría con un degradado de color con 100 valores entre azul y rojo ; Mycolors <- colorRampPalette
(c("azul", "rojo"))(100)).
Para hacer el histograma, cortaremos los datos con la función cut(), especificando que queremos que las separaciones se
realicen entre -4 y 4 en pasos de 1 (myYCut <- cut(myY, breaks = -4:4)). Para contar el número de puntos en cada
categoría y para cada color, solo usamos la función table() (myYCutCol <- table(myCol, myYCut)). En esta tabla,
la primera línea corresponde al primer color encontrado en el conjunto de datos y la segunda línea al otro color. Es por eso que
necesitamos cambiar el dibujo aleatorio de los colores para que la primera línea siempre corresponda a azul y la segunda línea
a rojo: myCol <- c(2, sample(c(4, 2), size = (n - 1), replace = TRUE)).
Luego podemos calcular la proporción de rojo dividiendo la primera línea por la suma de las dos líneas que representaremos en
porcentaje multiplicando por 100: myXCutCol[1,] / (myXCutCol[1,] + myXCutCol[2,]) * 100. Para que este
número coincida con un color, solo mantendremos su parte entera con la función round(). Si el porcentaje es cero o si el
resultado no es posible debido a una división por cero, debemos reemplazarlo con 1 para que corresponda a un color en nuestro
gradiente que va de 1 a 100 (xCol[[Link](xCol) | xCol == 0] <- 1).
Todo lo que nos queda es organizar el espacio gráfico con la función layout() que toma como argumento una matriz cuyos
176 CHAPTER 11. GRÁFICOS SIMPLES
valores y su posición corresponderán al diseño de los diferentes gráficos que queremos lograr. El gráfico 1 corresponde al gráfico
de barras superior, el gráfico 2 a la nube de puntos y el gráfico 3 al gráfico de barras derecho.
n <- 50
myX <- rnorm(n)
myY <- rnorm(n)
myCol <- c(2, sample(c(4, 2), size = (n - 1), replace = TRUE))
myColors <- colorRampPalette(c("blue", "red"))(100)
myYCut <- cut(myY, breaks = -4:4)
myXCut <- cut(myX, breaks = -4:4)
myYCutCol <- table(myCol, myYCut)
myXCutCol <- table(myCol, myXCut)
xCol <- round(
myXCutCol[1,] / (myXCutCol[1,] + myXCutCol[2,]) * 100
)
xCol[[Link](xCol) | xCol == 0] <- 1
yCol <- round(
myYCutCol[1,] / (myYCutCol[1,] + myYCutCol[2,]) * 100
)
yCol[[Link](yCol) | yCol == 0] <- 1
op <- par([Link] = TRUE)
par(mar = c(2, 3, 1, 1))
layout(matrix(c(1, 1, 0,
2, 2, 3,
2, 2, 3), ncol = 3, byrow = TRUE))
barplot(table(myXCut), las = 1, col = myColors[xCol])
plot(x = myX, y = myY, col = myCol, pch = 16,
xlim = c(-4, 4), ylim = c(-4, 4), cex = 1.5,
[Link] = grid())
barplot(table(myYCut), las = 1, horiz = TRUE, col = myColors[yCol])
11.3. BARPLOT 177
15
10
0
(−4,−3] (−3,−2] (−2,−1] (−1,0] (0,1] (1,2] (2,3] (3,4]
4
(3,4]
(2,3]
2
(1,2]
(0,1]
myY
(−1,0]
(−2,−1]
−2
(−3,−2]
(−4,−3]
−4
−4 −2 0 2 4 0 5 10 15
par(op)
Luego podemos integrar este script en una función para, por ejemplo, estudiar el efecto de la variable n.
layout(matrix(c(1, 1, 0,
2, 2, 3,
2, 2, 3), ncol = 3, byrow = TRUE))
barplot(table(myXCut), las = 1, col = myColors[xCol])
plot(x = myX, y = myY, col = myCol, pch = 16,
xlim = c(-4, 4), ylim = c(-4, 4), cex = 1.5,
[Link] = grid())
barplot(table(myYCut), las = 1, horiz = TRUE, col = myColors[yCol])
par(op)
}
graphBarplotCol(n = 1000)
300
250
200
150
100
50
0
(−4,−3] (−3,−2] (−2,−1] (−1,0] (0,1] (1,2] (2,3] (3,4]
4
(3,4]
(2,3]
2
(1,2]
(0,1]
myY
(−1,0]
(−2,−1]
−2
(−3,−2]
(−4,−3]
−4
−4 −2 0 2 4 0 50 150 250
−1 0 1 2
El barplot también se puede usar para hacer una pirámide de edades (hay funciones para realizar las las pirámides de edades,
aquí el objetivo es educativo).
(60,70]
(40,50]
(40,50]
(20,30]
(20,30]
(0,10]
(0,10]
par(op)
11.4 boxplot
Los diagramas de caja son gráficos muy comunes con R porque ofrecen una buena vista de un conjunto de datos al representar
los valores extremos (valores atípicos), la mediana, los cuartiles, los mínimos y los máximos.
df <- [Link](
box1 = rnorm(1000),
box2 = rgamma(1000, shape = 1),
box3 = sample(-3:3, size = 1000, replace = TRUE),
box4 = rbeta(1000, shape1 = 1, shape2 = 2)
)
boxplot(df, col = c(rgb(0, 94, 255, maxColorValue = 255),
rgb(255, 0, 174, maxColorValue = 255),
rgb(255, 136, 0, maxColorValue = 255),
rgb(119, 255, 0, maxColorValue = 255)))
11.4. BOXPLOT 181
6
4
2
0
−2
Si una variable es de tipo factor, la función boxplot() facilita la representación de cada categoría. También funciona con
variables numéricas, pero se debe tener cuidado de no tener demasiados valores diferentes para que el gráfico permanezca
legible.
df$cat <- sample(c("w", "x", "y", "z"), size = 1000, replace = TRUE)
boxplot(df$box3 ~ df$cat, col = c(rgb(0, 94, 255, maxColorValue = 255),
rgb(255, 0, 174, maxColorValue = 255),
rgb(255, 136, 0, maxColorValue = 255),
rgb(119, 255, 0, maxColorValue = 255)), ylab = "Box3")
182 CHAPTER 11. GRÁFICOS SIMPLES
3
2
1
Box3
0
−1
−2
−3
w x y z
1.0
0.8
0.6
Box4
0.4
0.2
0.0
w.1 x.1 y.1 z.1 w.2 x.2 y.2 z.2 w.3 x.3 y.3 z.3
df$cat <- sample(c("w", "x", "y", "z"), size = 1000, replace = TRUE)
boxplot(df$box2 ~ df$cat, horizontal = TRUE,
col = c(rgb(255, 110, 0, maxColorValue = 255),
rgb(230, 255, 0, maxColorValue = 255),
rgb(0, 178, 255, maxColorValue = 255),
rgb(166, 0, 255, maxColorValue = 255)), xlab = "Box2")
184 CHAPTER 11. GRÁFICOS SIMPLES
z
y
x
w
0 1 2 3 4 5 6 7
Box2
Hay muchos otros gráficos, pero los que acabamos de ver son la base. Para obtener más información e ideas para representar
sus datos, podemos consultar el hermoso sitio [Link] o la galería gráfica R [Link]
[Link]/ (la mayoría de los gráficos se realizan con el paquete ggplot2 que veremos más adelante). Para
obtener más ideas, también podemos usar la demostración del paquete graphics usando el comando demo('graphics')
(la tecla “Enter” se usa para mostrar los gráficos).
11.6 Conclusión
Felicitaciones, hemos llegado al final de este capítulo sobre gráficos simples. Ahora sabemos cómo hacer que los gráficos
principales plot(), hist(), barplot(), y boxplot(). A lo largo de este capítulo, hemos utilizado diferentes colores y
diferentes formas de representar los colores: es hora de formalizar el uso y la gestión de los colores. ¡Este es el tema del
próximo capítulo!
Chapter 12
Hemos visto diferentes formas de usar los colores: con su nombre (por ejemplo, "salmón"), con un número del 1 al 8, con
la función rgb() (para “rojo / red”, “verde / green”, “azul / blue”), y con la función colors(). Hay otros pero estos son los
principales.
El uso de los números del 1 al 8 corresponde a negro, rojo, verde, azul, cian, magenta, amarillo y gris. Este uso es útil para
visualizar rápidamente nuestros resultados, pero proporciona gráficos generales visualmente promedio. Es preferable evitar
estos colores para comunicar nuestros gráficos o para construir figuras en revistas científicas.
1 2 3 4 5 6 7 8
185
186 CHAPTER 12. GESTIÓN DEL COLOR
12.1 colors()
Para elegir colores más agradables y resaltar nuestros resultados, una opción es elegir de la lista de colores pregrabados en R.
Podemos acceder a la lista de colores con la función colors()
head(colors(), n = 20)
Podemos usar estos colores con sus nombres (por ejemplo, "white", "azure3"), o con su número (por ejemplo, “white” =
colors()[1], “azure3” = colors()[16]).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650
651 652 653 654 655 656 657
par(op)
12.2 rgb()
Otra opción es crear nuestros propios colores con la función rgb(), que toma la cantidad de rojo, verde y azul como argumentos.
De forma predeterminada, estos valores se encuentran entre 0 y 1. Esta configuración predeterminada se puede cambiar con
el argumento maxColorValue para, por ejemplo, tener valores entre 0 y 255 (maxColorValue = 255, estándar para la
representación del color RGB) .
Vamos a reanudar nuestra función para representar la distribución de puntos en un diagrama de dispersión por medio de barplot
con este tiempo tres colores de puntos (rojo, verde, azul) y un barplot cuyo color corresponderá a la cantidad de cada color
con la función rgb().
myXCutCol[3,])
gColX <- myXCutCol[2,] / (myXCutCol[1,] + myXCutCol[2,] +
myXCutCol[3,])
bColX <- myXCutCol[3,] / (myXCutCol[1,] + myXCutCol[2,] +
myXCutCol[3,])
rColX[[Link](rColX)] <- 0
gColX[[Link](gColX)] <- 0
bColX[[Link](bColX)] <- 0
rColY <- myYCutCol[1,] / (myYCutCol[1,] + myYCutCol[2,] +
myYCutCol[3,])
gColY <- myYCutCol[2,] / (myYCutCol[1,] + myYCutCol[2,] +
myYCutCol[3,])
bColY <- myYCutCol[3,] / (myYCutCol[1,] + myYCutCol[2,] +
myYCutCol[3,])
rColY[[Link](rColY)] <- 0
gColY[[Link](gColY)] <- 0
bColY[[Link](bColY)] <- 0
op <- par([Link] = TRUE)
par(mar = c(2, 3, 1, 1))
layout(matrix(c(1, 1, 0,
2, 2, 3,
2, 2, 3), ncol = 3, byrow = TRUE))
barplot(table(myXCut), las = 1, col = rgb(rColX, gColX, bColX))
plot(x = myX, y = myY, col = myCol, pch = 16,
xlim = c(-4, 4), ylim = c(-4, 4), cex = 1.5,
[Link] = grid())
barplot(table(myYCut), las = 1, horiz = TRUE,
col = rgb(rColY, gColY, bColY))
par(op)
}
graphBarplotCol(n = 50)
12.3. PALETAS DE COLORES 189
15
10
0
(−4,−3] (−3,−2] (−2,−1] (−1,0] (0,1] (1,2] (2,3] (3,4]
4
(3,4]
(2,3]
2
(1,2]
(0,1]
myY
(−1,0]
(−2,−1]
−2
(−3,−2]
(−4,−3]
−4
−4 −2 0 2 4 0 5 10 15 20
Con la función rgb() podemos representar 256^3 colores, o 167 777 216 colores diferentes. Nuestro objetivo, sin embargo, es
hacer gráficos que sean divertidos de leer y que hagan un buen uso de nuestros resultados científicos. Por lo tanto, debemos
elegir los colores adecuados para nuestro propósito. Por eso utilizaremos paletas de colores.
Las paletas son esquemas de color representados como un vector con colores en formato hexadecimal (valor devuelto por la
función rgb()).
myPal <- c(
rgb(0, 94, 255, maxColorValue = 255),
rgb(255, 0, 174, maxColorValue = 255),
rgb(255, 136, 0, maxColorValue = 255),
rgb(119, 255, 0, maxColorValue = 255))
print(myPal)
2
1
0
−1
−2
−3
1 2 3 4 5
[Link]() rainbow()
También hay una función colorRampPalette() que nos permite crear un degradado de color.
par(op)
También podemos crear nuestras propias paletas utilizando sitios web de selección de colores como [Link]
o [Link] (hay muchos más), y luego utilizarlos en R copiando en un vector los valores hexadecimales o
rgb.
R es un lenguaje de programación muy poderoso. Podemos imaginar muchas formas de crear paletas automáticamente de
acuerdo con varios criterios. Por ejemplo, podemos importar una imagen cuyos tonos nos parezcan relevantes, luego extraer
la información de cada uno de los puntos y luego seleccionar los colores dominantes a través de una agrupación tipo kmeans.
Eso es lo que hace la siguiente función.
Primero, cargaremos los paquetes raster,rgdal y jpeg que se utilizarán para manipular nuestra imagen en R.
Luego usaremos la función kmeans() para realizar grupos de colores usando los valores RGB de cada punto en nuestra imagen.
Aquí tenemos dos métodos posibles, el primero usa la función kmeans() para los tres valores RGB, y el segundo usa la función
kmeans() para cada valor RGB individualmente (esta segunda función proporciona una paleta que puede ser bastante alejado
de los colores de la imagen original).
15000
10000
5000
0
#E0BC6C
#5D1C97
#B98F22
#8E6843
#293F08
La función nos devuelve los colores de la paleta con un gráfico de barras que representa el número de puntos de la imagen en
cada uno de los grupos de colores. Ahora podemos usar nuestra nueva paleta para hacer nuestros gráficos.
par(op)
12.4 Conclusión
Felicitaciones ! Este es el final de este capítulo sobre la gestión del color. Ahora sabemos cómo usar colores y paletas, y cómo
guiar la selección de colores para resaltar nuestros resultados. En el siguiente capítulo veremos algunos ejemplos de paquetes
de gráficos y las últimas tendencias, como los gráficos dinámicos.
Chapter 13
Paquetes gráficos
13.1.1 RColorBrewer
El paquete RColorBrewer es un paquete de referencia porque contiene paletas adicionales a las disponibles en la versión
básica de R. Una vez que el paquete está instalado, solo llamamos a las paletas para utilizarlas. Aquí están las paletas disponibles
y un ejemplo de uso.
197
198 CHAPTER 13. PAQUETES GRÁFICOS
YlOrRd
YlOrBr
YlGnBu
YlGn
Reds
RdPu
Purples
PuRd
PuBuGn
PuBu
OrRd
Oranges
Greys
Greens
GnBu
BuPu
BuGn
Blues
Set3
Set2
Set1
Pastel2
Pastel1
Paired
Dark2
Accent
Spectral
RdYlGn
RdYlBu
RdGy
RdBu
PuOr
PRGn
PiYG
BrBG
13.1.2 palettesForR
El paquete palettesForR es otro paquete que contiene paletas listas para usar de los proyectos ‘Gimp’ y ‘Inkscape’. Una vez
que el paquete está instalado, solo llamamos a las paletas para utilizarlas. Las muchas paletas disponibles se enumeran en la
ayuda del paquete (hay 48 paletas). Aquí hay un ejemplo de uso.
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
25 26 27
1 2 3 4 5 6 7
1 2 3 4 5 6 7
• viridis ([Link]
• jcolors ([Link]
• scico ([Link]
• …
El paquete ggplot2 es una alternativa a las funciones básicas de R para realizar gráficos. Se basa en “La Gramática de Gráficos”
Leland Wilkinson y permite gráficos en capas, por lo general con un resultado superior si consideramos el aspecto estético en
comparacion con las funciones básicas de R. Si para explorar un conjunto de datos ggplot2 es a veces más potente, nuestros
gráficos nunca vienen solas y se acompañan de análisis estadísticos que a menudo exigen un trabajo minucioso sobre la gestión
de datos. Una vez que nuestras hipótesis de trabajo estan probadas estadísticamente, resulta fácil realizar gráficos cual que
sea su nivel de complejidad (con las funciones básicas o con ggplot2). Además veremos en el siguiente capítulo que desde
la gráfica a la figura en el artículo científico, hay una serie de tratamientos a realizar y el manejo de los parámetros estéticos
se puede hacer de forma independiente de R. Así que ggplot2 es un paquete interesante porque ofrece una alternativa con
una filosofía diferente en la construcción de gráficos, pero no reemplaza lo que hemos aprendido hasta ahora. En la práctica
podemos utilizar uno u otro en función de los datos y de las manipulaciones que queremos hacer.
Para volver a ggplot2, empezamos con un ejemplo con los datos iris.
13.2. GGPLOT2 PACKAGE 203
ggplot2
4.5
4.0
3.5
[Link]
3.0
2.5
2.0
5 6 7 8
[Link]
# base
plot(x = iris$[Link], y = iris$[Link],
main = "base", pch = 16)
204 CHAPTER 13. PAQUETES GRÁFICOS
base
4.0
iris$[Link]
3.5
3.0
2.5
2.0
iris$[Link]
# ggplot2
p <- ggplot(data = iris, aes(x = [Link], y = [Link], colour = Species))
p + geom_point() + ggtitle("ggplot2")
13.2. GGPLOT2 PACKAGE 205
ggplot2
4.5
4.0
3.5 Species
[Link]
setosa
versicolor
3.0
virginica
2.5
2.0
5 6 7 8
[Link]
# base
plot(x = iris$[Link], y = iris$[Link],
main = "base", pch = 16, col = iris$Species)
206 CHAPTER 13. PAQUETES GRÁFICOS
base
4.0
iris$[Link]
3.5
3.0
2.5
2.0
iris$[Link]
Parece haber una relación entre el ancho y el largo de los sépalos por especie.
# linear regressions
lmFits <- lapply(1:3, function(i){
fitSp1 <- lm(iris$[Link][[Link](iris$Species) == i] ~
iris$[Link][[Link](iris$Species) == i])
fStat1 <- summary(fitSp1)$fstatistic
rSq1 <- summary(fitSp1)$[Link]
pVal1 <- summary(fitSp1)$coefficients[2, 4]
stat1 <- paste0("F=", round(fStat1[1], digits = 2),
"; DF=", fStat1[2], "/", fStat1[3], "; r-sq=", round(rSq1, digits = 2),
"; p-val=", round(pVal1, digits = 6))
return(list(fitSp1, stat1))
})
# ggplot2
p <- ggplot(data = iris, aes(x = [Link], y = [Link], colour = Species))
p <- p + geom_point() + ggtitle("ggplot2") + stat_smooth(method = "lm", se = FALSE)
p <- p + annotate(geom = "text", x = 6, y = 2.250, label = lmFits[[1]][[2]], colour = 2)
p <- p + annotate(geom = "text", x = 6, y = 2.125, label = lmFits[[2]][[2]], colour = 3)
p <- p + annotate(geom = "text", x = 6, y = 2.000, label = lmFits[[3]][[2]], colour = 4)
p
13.2. GGPLOT2 PACKAGE 207
ggplot2
4.5
4.0
3.5 Species
[Link]
setosa
versicolor
3.0
virginica
2.5
# base
plot(x = iris$[Link], y = iris$[Link],
main = "base", pch = 16, col = iris$Species)
abline(lmFits[[1]][[1]], col = 1)
abline(lmFits[[2]][[1]], col = 2)
abline(lmFits[[3]][[1]], col = 3)
text(x = 5.5, y = 2.2, labels = lmFits[[1]][[2]], pos = 4)
text(x = 5.5, y = 2.1, labels = lmFits[[2]][[2]], pos = 4, col = 2)
text(x = 5.5, y = 2.0, labels = lmFits[[3]][[2]], pos = 4, col = 3)
208 CHAPTER 13. PAQUETES GRÁFICOS
base
4.0
iris$[Link]
3.5
3.0
2.5
iris$[Link]
Podemos ver en estos ejemplos que los gráficos con ggplot2 comienzan con una llamada a la función ggplot(), en la cual
el primer argumento datos coincide con nuestros datos (generalmente un [Link]), y El segundo argumento aes() es
la información que queremos usar. Por convención, esta información se almacena en un objeto p. Luego agregaremos capas
adicionales usando +.
En las capas podemos agregar aspectos geométricos (el tipo de gráfico, por ejemplo, geom_point()), estadísticas (por ejem-
plo, stat_smooth()), anotaciones (por ejemplo, annotate()), y otras cosas relacionadas con los ejes, los colores, …
La documentación completa se puede consultar en la dirección [Link] (hoja de resumen:
[Link] Muchas exten-
siones a ggplot2 están disponibles en [Link]
Plotly es un paquete para gráficos interactivos y dinámicos. Esto puede ser particularmente útil para los resultados que se
difunden a través de Internet. El paquete se instala como cualquier otro con [Link]("plotly"). El paquete
es gratuito y de código abierto.
Este ejemplo se ha copiado del libro de Carson Sievert ([Link] El código usado para
hacer este gráfico está licenciado bajo la licencia de Estados Unidos Creative Commons Attribution-NonCommercial-NoDerivs
3.0 (Carson Sievert; [Link]
13.4. CONCLUSIÓN 209
80
Africa
lifeExp
60 Americas
Asia
40 Europe
Oceania
2 5 1000 2 5 10k 2 5 100k
gdpPercap
year: 1952
Play
13.4 Conclusión
Este capítulo nos permitió ver otras opciones gráficas y, en particular, los paquetes ggplot2 y plotly. Existen libros es-
pecíficos (en inglés) que cubren todos los aspectos de estos paquetes, aquí el objetivo es saber que existen estas opciones
para usarlos si es necesario. Los sitios web “Data to Viz” y “r-graph gallery” ([Link] https:
//[Link]/) son buenos recursos para tener ideas de las posibilidades que ofrece R en cuanto a repre-
sentaciones gráficas. El siguiente capítulo analiza los procesos necesarios para transformar un gráfico R en una figura publicable
en un artículo científico. Hasta muy pronto !
210 CHAPTER 13. PAQUETES GRÁFICOS
Part III
Estudio de caso
211
Chapter 14
En estudios de biología, ecología, o agronomía, frecuentemente usamos datos de temperatura de dataloggers. En este estudio
vamos a ver como analizar esos datos usando datos de temperatura del altiplano Boliviano cerca de la ciudad de El Alto. El
primer paso es transformar los datos del datalogger en un formato que sea fácil de leer para R. Usaremos un archivo CSV
y la función [Link](). El archivo se puede descargar desde el sitio web del libro en GitHub ([Link]
com/frareb/myRBook_SP/blob/master/myFiles/[Link] ; el archivo se puede leer desde su destino en GitHub
[Link]
## id date temp
## 1 1 11/12/15 [Link] 4.973
## 2 2 11/12/15 [Link] 4.766
## 3 3 11/13/15 [Link] 4.844
## 4 4 11/13/15 [Link] 4.844
## 5 5 11/13/15 [Link] 5.076
## 6 6 11/13/15 [Link] 5.282
tail(bdd)
## id date temp
## 32781 32781 09/25/17 [Link] 7.091
## 32782 32782 09/25/17 [Link] 6.914
## 32783 32783 09/25/17 [Link] 6.813
## 32784 32784 09/25/17 [Link] 6.611
## 32785 32785 09/25/17 [Link] 6.331
## 32786 32786 09/25/17 [Link] 5.385
213
214 CHAPTER 14. ANALIZAR DATOS DE LOGGERS DE TEMPERATURA
str(bdd)
Podemos observar que la fecha esta al formato character, y que contiene la fecha con el mes, el día, y el año separados con
/, un espacio, y la hora con horas de 0 a 24, minutos, y segundos, separados con : (ejemplo: 11/12/15 [Link] para el
12 de Noviembre de 2015 a las 11 de la noche). Vamos a separar la información en varios objetos para ver todas las opciones
segun el tipo de datos que se puede tener.
Primero vamos a separar la fecha de la hora. Para esto vamos a usar la función strsplit() usando como separador el espacio
entre la fecha y la hora.
## [[1]]
## [1] "11/12/15" "[Link]"
Como indican los corchetes dobles, la función devuelve un objeto en el formato list. Nosotros queremos el vector que
corresponde al primer elemento de la list entonces vamos a añadir [[1]].
El primer elemento del vector es la fecha. Para tener todas las fechas vamos a hacer un bucle con la función sapply().
A continuación vamos a necesitar las fechas en el formato Date. Entonces necesitamos transformar el objeto en el formato
Date con la función [Link]().
bddDay <- [Link](sapply(strsplit(bdd[, 2], split = " "), "[[", 1), format = "%m/%d/%y")
head(bddDay)
Vamos a añadir la information al formato Date en nuestro objeto bdd. Con la función str(), podemos ver que el formato de
bdd$day es Date.
215
Si necesitamos la información del horario, usaremos el formato POSIX con la función [Link](). Vamos a añadir la
information al formato POSIX en nuestro objeto bdd. Con la función str(), podemos ver que el formato de bdd$posix es
POSIXct.
En las funciones [Link]() y [Link]() tenemos que especificar el formato en el cual esta indicado la fecha con el
argumento format(format = "%m/%d/%y" y format = "%m/%d/%y %H:%M:%S").
código Valor
20
10
0
−10
2016 2017
Fecha
Podemos simplificar la información calculando únicamente las temperaturas mínimas, promedias, y máximas del dia con la
función tapply().
40
min
max
30
promedio
Temperatura (°C)
20
10
0
−10
2016 2017
Fecha
Podemos representar la misma información por semana. Para esto vamos a usar la información de los datos en el formato
POSIXct para transformala en semanas.
min
max
30
promedio
Temperatura (°C)
20
10
0
−10
2016 2017
Fecha
Para no perder la información sobre la variabilidad de la temperatura podemos hacer boxplot en lugar de plot.
30
20
10
0
−10
2015−11
2015−12
2016−01
2016−02
2016−03
2016−04
2016−05
2016−06
2016−07
2016−08
2016−09
2016−10
2016−11
2016−12
2017−01
2017−02
2017−03
2017−04
2017−05
2017−06
2017−07
2017−08
2017−09
Podemos elegir colores para representar la temperatura promedia. Para esto podemos normalizar la temperatura en numeros
integrados entre 1 y 101 y hacer corresponder los numeros en una escala de color del azul al rojo.
30
20
10
0
−10
2015−11
2015−12
2016−01
2016−02
2016−03
2016−04
2016−05
2016−06
2016−07
2016−08
2016−09
2016−10
2016−11
2016−12
2017−01
2017−02
2017−03
2017−04
2017−05
2017−06
2017−07
2017−08
2017−09
Para los que usan ggplot2:
30
20
temp
10
−10
También podemos calcular la diferencia entre la temperatura máxima y la temperatura mínima (variación de temperatura diurna).
40
30
20
10
2016 2017
Fecha
Otra posibilidad es de agrupar los datos para tener la temperatura promedia de un día con la función aggregate() (como
alternativa a la función tapply).
40
30
Temperatura (°C)
20
10
0
−10
00:00
00:30
01:00
01:30
02:00
02:30
03:00
03:30
04:00
04:30
05:00
05:30
06:00
06:30
07:00
07:30
08:00
08:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
17:00
17:30
18:00
18:30
19:00
19:30
20:00
20:30
21:00
21:30
22:00
22:30
23:00
23:30
Tambien podemos calcular las temperaturas de los dias para cada mes.
Temperatura (°C)
−10 0 10 20 30 40
type
points(x
type
points(x
=
=
=
=
00:00
00:30
01:00
01:30
02:00
02:30
'l', col
hours, y
'l', col
hours, y
03:00
=
=
=
=
03:30
04:00
04:30
05:00
05:30
06:00
06:30
07:00
07:30
2, lwd = 2)
4, lwd = 2)
08:00
08:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
Enero
13:00
tempDayEachMonth[[i]][, 6],
tempDayEachMonth[[i]][, 4],
13:30
14:00
14:30
15:00
15:30
16:00
16:30
17:00
17:30
18:00
18:30
19:00
19:30
20:00
20:30
21:00
21:30
22:00
22:30
23:00
23:30
CHAPTER 14. ANALIZAR DATOS DE LOGGERS DE TEMPERATURA
225
Febrero
40
30
Temperatura (°C)
20
10
0
−10
00:00
00:30
01:00
01:30
02:00
02:30
03:00
03:30
04:00
04:30
05:00
05:30
06:00
06:30
07:00
07:30
08:00
08:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
17:00
17:30
18:00
18:30
19:00
19:30
20:00
20:30
21:00
21:30
22:00
22:30
23:00
23:30
O todo en un mismo grafico, y la variación de temperatura diurna para cada mes.
00:00
00:30
01:00
01:30
02:00
02:30
03:00
03:30
04:00
04:30
05:00
05:30
06:00
06:30
07:00
07:30
08:00
08:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
17:00
17:30
18:00
18:30
19:00
19:30
20:00
20:30
21:00
21:30
22:00
22:30
23:00
23:30
plot(x = hours, y = tempDayEachMonth[[1]][, 2], type = 'n', ylim = c(0, 30),
xlab = "", ylab = "Variación de temperatura diurna (°C)",
xaxt = "n",
[Link] = {
abline(v = hours, col = "gray", lty = 2)
abline(h = 0, lty = 2)
})
axis(side = 1, at = hours, labels = tempHourMean[, 1], las = 2)
myColors <- c("#A6CEE3", "#1F78B4", "#B2DF8A", "#33A02C", "#FB9A99",
"#E31A1C", "#FDBF6F", "#FF7F00", "#CAB2D6", "#6A3D9A", "#FFFF99",
"#B15928")
for (i in seq_along(tempDayEachMonth)){
points(x = hours,
y = tempDayEachMonth[[i]][, 6] - tempDayEachMonth[[i]][, 4],
type = 'l', col = myColors[i], lwd = 2)
}
legend("topright", ncol = 4, legend = meses, col = myColors,
lty = 1, lwd = 2, cex = 0.8)
227
30
00:00
00:30
01:00
01:30
02:00
02:30
03:00
03:30
04:00
04:30
05:00
05:30
06:00
06:30
07:00
07:30
08:00
08:30
09:00
09:30
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
17:00
17:30
18:00
18:30
19:00
19:30
20:00
20:30
21:00
21:30
22:00
22:30
23:00
23:30
También podemos representar las temperaturas diarias con gráficos “ridgeline” y el package ggplot2 (https:
//[Link]/graph/[Link]).
Enero
Febrero
Marzo
Abril
Mayo
Junio
Julio
Agosto
Septiembre
Octubre
Noviembre
Diciembre
0 10 20
Temperature