ULTIMA ACTUALIZACIÓN:

La última actualización de este artículo se realizó el 3 de November del 2019.

1 Tabla de Contenidos

2 Básicos

R es un entorno y lenguaje de programación con un enfoque al análisis estadístico1. En palabras sencillas, R es un idioma con el que podemos pedirle a nuestra computadora que haga ciertas cosas para nosotros. En estos tutoriales usaremos R a través de RStudio2.

Debido a que casi todo lo que puedes hacer con R se hace a través de objetos, empezaremos presentando dos de los más comunes: los operadores y las funciones. Iremos conociendo otros tipos de objetos a medida que avancemos en los tutoriales.

2.1 Operadores

Los operadores, como dice su nombre, nos permiten realizar operaciones entre ciertos valores de manera similar a como lo haríamos con una calculadora. Los siguientes nos permiten realizar operaciones aritméticas básicas:

Operador Operación
+ Adición
- Sustracción
* Multiplicación
/ División real
** o ^ Potencia
() Para priorizar operaciones al interior de los paréntesis

Podemos ver cómo lucen los operadores en funcionamiento al usarlos en R.

## [1] 27

R primero opera el 1+2 al ser el nivel más profundo, obteniendo como resultado 3. Inmediatamente después, R realiza la operación 3*3 y obtiene 9. Después de esto, R opera el 9**2obteniedo 81, y finaliza con la operación 81/3, obteniedo 27 como resultado. Hasta este punto, R está siendo utilizado como una simple calculadora, pero podemos exigirle mucho más.

Pero antes de pasar a ello es importante conocer a otro operador fundamental, el de asignamiento. Está compuesto por el signo “menor que” (<) y el signo de resta (-), que al juntarse lucen como una flecha que apunta hacia la izquierda (<-). Este operador sirve para asignar un nombre a cualquier objeto o valor, de tal modo podamos acceder a él con mayor facilidad. Por ejemplo, podemos asignarle el nombre “result” al resultado de la operación que realizamos anteriormente.

A simple vista, nada ha cambiado3, pero cuando accedemos al objeto result ahora obtenemos inmediatamente la respuesta de nuestra operación.

## [1] 27

Si por algún motivo necesitamos actualizar el valor asignado a nuestro objeto, basta con volver a asignar el mismo nombre a otro valor. Incluso se puede hacer referencia al valor anterior para modificarlo. No hay un límite de veces que el valor de un objeto puede ser modificado. En el siguiente ejemplo, sumaremos 3 a result para obtener 30.

## [1] 30

Hemos visto que podemos usar el operador ** para elevar un número a cualquier potencia, pero no tenemos un operador para obtener la raíz. Podemos solucionar esto haciendo uso de funciones.

2.2 Funciones

Las funciones nos permiten aplicar transformaciones a los valores u objetos que ingresemos en ellas. Para crear una función, debemos asignarle un nombre, argumentos y código que será utilizado para la transformación. Su forma general en R es la siguiente:

Para que sea más entendible, haremos nuestra función para hallar la raíz cuadrada de cualquier número4 y la llamaremos raiz_cuadrada. Siempre es importante asignar un nombre significativo y que dé una buena idea del funcionamiento de la función.

Como vemos en el cuerpo de la función, esta obtiene un número “x” y calcula su raíz cuadrada. Probemos su funcionamiento.

## [1] 5

R ha calculado de manera correcta que la raíz cuadrada de 25 es 5. También podemos hacer una función para determinar la raíz cúbica de un número “x” de la misma manera.

## [1] 3

Al probar su funcionamiento vemos que nos arroja el cálculo correcto. Podríamos hacer una función de raíz para cada número, pero como las funciones pueden tener más de un argumento, podemos usar eso para nuestra ventaja y hacer una función que aplique una raiz “n” a cualquier número “x”.

## [1] 2

Ese es el poder de las funciones, nos permiten hacer nuestras transformaciones de manera generalizada. Incluso podemos usar funciones en el cuerpo y argumento de otras funciones. En el siguiente ejemplo, usaremos la función predefinida paste(), que nos permite pegar textos para formar una oración.

## [1] "La raiz  10  de 1024 es  2"

Los argumentos de una función no necesitan ir en la misma línea de código. Para una más fácil lectura, es posible separarlos por líneas (respetando las comas entre argumentos) siempre y cuando sigan dentro del mismo paréntesis de la función. Utilizaremos la función paste() para ejemplificar.

## [1] "Un texto largo se imprime"
## [1] "Un texto largo se imprime"

Una vez que hemos entendido cómo usar funciones, estamos listos para conocer los paquetes.

2.3 Usando paquetes

R es un lenguaje utilizado por muchas personas y cada quien escribe sus funciones según sus propias necesidades. Sin embargo, no resulta extraño que varios usuarios necesiten lo mismo. Por ejemplo, resulta lógico pensar que no somos las únicas personas que necesitan obtener la raíz “n” de un número.

Es en este punto que entran en juego los paquetes, una colección de funciones y datos que los usuarios de R comparten entre sí para facilitar el trabajo a los demás y evitar la repetición innecesaria de creación de funciones de uso común o de alta utilidad5. Hay paquetes de todo tipo, desde los que te permiten realizar una función muy específica (como clipr que es usado para copiar y pegar información contenida en el portapapeles del sistema) hasta los que te permiten expandir los límites de lo que R es capaz de hacer (como reticulate, que te permite ejecutar código del lenguaje de programación Python en tu entorno R).

Cuando inicias R se activa un grupo base de paquetes. Estos han sido desarrollados por el R Core Team y son la pieza fundamental de su funcionalidad.

Puedes instalar paquetes usando la función install.packages() y poniendo como argumento el nombre del paquete entre comillas "". Este procedimiento sólo será necesario una vez, ya que después de instalados, los paquetes son conservados en la memoria de la computadora. Aquí puedes ver algunos ejemplos:

Pero tenerlos instalados no es suficiente. Cada vez que necesitas usar un paquete lo puedes llamar con library(paquete). Esto hará que sus funciones y objetos estén disponibles para el uso. Te darás cuenta que no has llamado al paquete si corres un código y el resultado es un error como este:

## Error in glue("texto", "de", "ejemplo"): could not find function "glue"

Esto significa que no has llamado al paquete necesario usando library(). En cambio, si al llamar al paquete te da como resultado un error de este tipo:

## Error in library(testpackage): there is no package called 'testpackage'

Significa que necesitas instalarlo. No hay que asustarse al obtener un mensaje de error alguna vez, por lo general suelen ser bastante explicativos respecto a por qué son causados y nos permiten corregir aquello en lo que nos equivocamos.

3 Vectores

Los siguientes objetos fundamentales para el manejo de R son los vectores. Estos pueden ser de dos tipos: atómicos y listas. La diferencia entre ellos radica en el tipo de información que pueden contener. Para efectos de estos tutoriales, consideraremos las listas como vectores “especiales” junto a otros que explicaremos más adelante.

3.1 Vectores atómicos

Los cuatro principales tipos de vectores atómicos son: logical, double, integer y character6. Los vectores de tipo logical pueden asumir dos valores: TRUE o FALSE(o en su forma abreviada T o F). Los de tipo double e integer asumen valores numéricos, los double pueden asumir valores racionales y los integer sólo valores enteros. Los vectores de tipo character asumen cualquier cadena de texto. En el siguiente recuadro de código podemos ver un ejemplo de cada uno:

Si estamos atentos, vemos que el integer va acompañado de una “L” al final. Esto es necesario porque R interpreta por defecto cualquier número como double. Tanto los double como los integer pertenecen a la categoría de vectores numéricos. Los character siempre estarán rodeados de comillas (""). Para comprobar si nuestro vector es de un tipo determinado utilizamos una función de forma is.XXX() reemplazando el “XXX” por el tipo que queremos comprobar.

## [1] TRUE
## [1] TRUE
## [1] FALSE

Podemos ver que por cada consulta obtenemos un valor logical TRUE cuando se cumple la condición y FALSE cuando no se cumple. Es decir, es cierto que v_logicales logical, es cierto que v_double es numérico y es falso que v_double es integer. El valor logical obtenido con cada consulta es un vector en sí mismo.

Otra manera de verificar el tipo de vector que tenemos es con la función typeof(). Esta nos devuelve un character indicando el tipo de vector que tenemos.

## [1] "character"
## [1] "integer"

3.1.1 Vectores con más de un elemento y operador de secuencia simple

Hasta el momento hemos visto vectores que contienen un solo elemento. Sin embargo, es sumamente común encontrarse con vectores de mayor longitud. Por ejemplo, el vector letters contiene todas las letras minúsculas del alfabeto. Podemos consultar la longitud de un vector con la función length(). Esto es muy útil cuando sabemos que nuestro vector podría contener una gran cantidad de elementos y no queremos inspeccionarlos todos. El número que vemos rodeado entre corchetes ([]) en nuestro resultado nos indica el índice que el elemento siguiente tiene en el vector. Es por ello que hasta el momento en cada operación que realizábamos hemos obtenido un “[1]” antes de cada resultado.

## [1] 1
## [1] 26
##  [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"

Para formar vectores de longitud mayor a uno se utiliza la función c() agregando como argumentos todos los elementos que queremos.

## [1] "elemento1" "elemento2" "elemento3" "elemento4"

Para vectores numéricos, también es posible utilizar el signo dos puntos (:) como operador para crear una secuencia, que avanza de uno en uno, desde un número a otro. El vector resultado incluirá a los dos números utilizados en la operación.

## [1] 1 2 3 4 5 6

Podemos hacer uso de c() nuevamente para seguir haciendo crecer nuestro vector. Incluso podemos usar una operación de secuencia como argumento. Al consultar el tipo de vector que hemos creado, vemos que mantiene el mismo tipo que sus “ancestros”: integer.

##  [1]  1  2  3  4  5  6 11 12 13 14 15 16 21 22 23 24 25 26
## [1] "integer"

3.1.2 Coerción de vectores

Crear vectores más largos puede tener efectos inesperados para el usuario que no está atento. Veamos el siguiente ejemplo:

## [1] "character"

Al agregar "1" a nuestro vector, su tipo ha cambiado a character. ¿Por qué sucede esto? En primer lugar, hay que tener claro que "1" no es lo mismo que 1. Recordemos que todo valor que está entre comillas es de tipo character, incluso si se trata de números.

En segundo lugar, tengamos en cuenta que los vectores atómicos sólo pueden tener un tipo. Esto quiere decir que cuando los tipos de los elementos que se combinan dentro del vector son diferentes, R debe decidir cuál de los tipos de vector mantener, eligiéndo sólo uno. Este procedimiento es llamado coerción.

Aunque suena complicado, las reglas de coerción son bastante sencillas. R le dará prioridad a mantener el tipo de vector según el siguiente orden:

  1. Character
  2. Double
  3. Integer
  4. Logical

Es decir, ante cualquier conflicto en el tipo de vectores a combinar se preservará el tipo que tenga más alta prioridad. Si nos detenemos a analizar por qué sucede, es bastante evidente. Los valores logical son en realidad leídos por la computadora como 1 cuando son TRUE y como 0 cuando son FALSE. Es por ello que la siguiente operación no nos arroja un error.

## [1] 2

Del mismo modo, sabemos que cualquier número entero también puede ser expresado como número racional. Es por ello que los integer son coercionados a double cuando hay conflicto entre ellos.

## [1] "double"

¿Es posible convertir texto a números en R? No7. Es por ello que cuando un vector tipo character se combina con cualquier otro tipo de vector, prevalece el tipo character, como en el ejemplo que vimos al inicio de esta sección.

3.1.3 Coerción explícita y valores NA

En todos los casos de coerción que hemos mencionado hasta el momento R ha decidido mediante sus propias reglas qué tipo de vector debe prevalecer, aplicando coerción implícita. Este procedimiento puede ocasionar problemas cuando el usuario no tiene suficientemente claras las reglas de coerción.

La coerción explícita permite decidir de antemano qué tipo de vector queremos obtener. Para ello se hace uso de una función de la forma as.XXX() donde XXX representa el tipo deseado.

## [1] "integer"

En este ejemplo, hemos usado as.integer() para cambiar el tipo de nuestro vector, de logical a integer. Es posible hacer lo mismo para otros tipos de vectores. Tomemos en cuenta que la transformación se realiza de manera directa, sin respetar el orden de prioridad.

## [1] "TRUE"

Es por ello que TRUE se convierte directamente en el character "TRUE" sin convertirse primero en el integer 1L, luego en el double 1 y luego en el character "1". De aquí viene el verdadero poder de la coerción explícita, porque nos permite incluso “revertir” el orden de prioridad que R usa en la coerción implícita. Es decir, podemos convertir cualquier tipo de vector a otro.

## [1] "logical"
## [1] "integer"
## [1] "integer"
## [1] "double"

De todos modos, esto se debe usar con precaución. Sabemos que todo logical puede convertirse a integer, estos a su vez pueden convertirse a double y estos a character sin perder ninguna información. No sucede lo mismo en el procedimiento reverso. Por ejemplo, esto sucede cuando queremos convertir un double con cifras decimales a integer.

## [1] 5

El contenido decimal se pierde, porque R no lo necesita en el integer, y no es posible recuperarlo aún retransformando el valor a double en la misma línea de código.

## [1] 5

Algo similar sucede cuando intentamos convertir a logical valores numéricos mayores a 1.

## [1] TRUE
## [1] TRUE

R interpreta como TRUE todo número diferente a 0. Es probable que no sea el resultado que esperábamos en esta transformación. Pero todavía hay más. ¿Qué sucederá si intentamos convertir una palabra a número?

## Warning: NAs introduced by coercion
## [1] NA

R no es capaz de asignar un valor numérico a "sustantivo" y como resultado nos arroja un advertencia o warning: NAs introduced by coercion. El valor NA representa un valor perdido y no es posible transformarlo. Los valores perdidos pueden aparecer en nuestros datos por diferentes motivos, desde la recolección hasta la transformación de nuestra data. Debemos ser extremadamente cuidadosos al trabajar con ellos, porque pueden generar algunos problemas indeseados. Por ejemplo, si queremos obtener la suma de todos los elementos de un vector, usando la función sum(), y resulta que uno de ellos es un NA.

## [1] NA

El resultado obtenido es simplemente NA. El mismo problema se extiende al querer obtener un promedio usando la función mean().

## [1] NA

Felizmente, estas funciones permiten proporcionar el argumento na.rm = TRUE para ignorar los valores NA y trabajar sólo con valores válidos.

## [1] 23
## [1] 3.833333

Sin embargo, no necesariamente encontraremos esta herramienta en todas las funciones que trabajan con vectores. Por ello es indispensable estar atentos al trabajar nuestros datos y revisar la documentación de las funciones con las que estamos trabajando.

3.2 Vectores especiales

Hasta el momento hemos trabajado con vectores atómicos. Hemos comprendido que hay cuatro tipos de ellos, que podemos agregarles elementos y que pueden ser coercionados implícita y explícitamente a otros tipos.

Es posible crear vectores que tengan un comportamiento particular al asignarles atributos (attributes). Este es el caso de los factores y los datetimes.

La función attributes() nos permite consultar los atributos que contiene un objeto. Veamos qué sucede cuando consultamos por los atributos de los vectores que creamos antes.

## NULL
## NULL

Por defecto, los vectores atómicos no tienen ningún atributo, es por ello que en la consulta nos arroja el resultado NULL. Veremos que con los factores y datetimes no sucede lo mismo.

No es propósito de este tutorial enseñar a agregar o modificar los atributos de los vectores, sino de dar a conocer algunos de los más utilizados.

3.2.1 Factores

Los factor son vectores con un conjunto predefinido de valores. Pueden ser formados a partir de otros vectores con la función factor(), cuyo primer argumento es el vector en cuestión.

## [1] uno dos dos uno uno
## Levels: dos uno

Vemos que al ser impresos se parecen a un vector character. Sin embargo, al consultar por su tipo podemos ver qué son internamente.

## [1] "integer"

Consultemos sus attributes() para entender qué está sucediendo con este vector.

## $levels
## [1] "dos" "uno"
## 
## $class
## [1] "factor"

Lo primero que debemos notar es el atributo class. Este será una característica común de los vectores especiales. La clase es la que determina el comportamiento que tendrán estos vectores.

El siguiente es el atributo levels, que nos indica qué valores pueden asumir los elementos que pertenecen a este vector. Este atributo se imprime automáticamente junto al vector. En el caso de factor_numeros, los levels fueron detectados automáticamente por R. Sin embargo, la función factor() nos permite indicar manualmente estos valores.

## [1] uno dos dos uno uno
## Levels: uno dos tres

Vemos que ahora "tres" forma parte de los levels a pesar de que no existe en nuestro vector.

Además de ello, los factor son muy útiles como paso intermedio para cambiar de tipo nuestros character. Recordemos que al coercionar explícitamente un character a un valor numérico, R nos arrojaba como resultado un NA. Si transformamos primero nuestro character a un factor, esto sí es posible sin incurrir en un NA.

## [1] 1 2 2 1 1

Es por todo ello que los factor son bastante utilizados para tratar con datos categóricos.

3.2.2 Datetimes

Soon…

3.2.3 Listas

Soon…


  1. Definición obtenida de https://es.wikipedia.org/wiki/R_(lenguaje_de_programaci%C3%B3n)

  2. RStudio es un Entorno de desarrollo integrado (IDE) para R. Para instalar ambos, recomendamos seguir las instrucciones del punto 1.4.1 y 1.4.2 del siguiente enlace https://es.r4ds.hadley.nz/introducci%C3%B3n.html

  3. Si estamos usando RStudio podemos ver que en en la sección Values de la pestaña “Environment” ha aparecido nuestro objeto “result” asociado al resultado de la operación.

  4. Teniendo en cuenta que la raíz cuadrada de X puede ser expresada como potencia de X en la forma X(1/2)

  5. Podemos obtener la mayor parte de paquetes del CRAN (Comprehensive R Archive Network). La función install.packages() busca allí los paquetes que le pedimos que descargue.

  6. No se conoce una traducción oficial al castellano para los tipos de vectores. En la versión en español de “R for data science” son llamados lógicos, dobles, enteros y caracter.

  7. Al menos no de manera automática, como sí se puede en otros lenguajes de programación.