Capítulo 5 Variables individuales: números y caracteres

 

Tras los primeros ejercicios planteados deberíamos saber más o menos usar R como una calculadora, definiendo variables que nos guardan números, como a <- 1. Vamos a ir más allá: ¿existen variables más allá de los números? En este capítulo vamos a empezar a familiarizarnos con los tipos de datos que podemos necesitar. Piensa por ejemplo en los datos guardados de una persona en cualquier registro:

  • La edad será un número (sin decimales)
  • Su peso o estatura será otro número (ahora con decimales).
  • Su nombre será una cadena de texto.
  • Su fecha de nacimiento será precisamente eso, un dato de tipo fecha.
  • A la pregunta «¿está usted soltero/a?» la respuesta será lo que llamamos una variable binaria o lógica: una variable que solo puede valer TRUE (si está soltero/a) y FALSE (en otro caso), guarada internamente como un 1 o 0.

Existen más tipos de datos (por ejemplo, números complejos, listas, etc) pero con estos nos valdrá de momento.

5.1 Variables numéricas (individuales)

Probablemente el dato más sencillo y obvio de entender sean los datos numéricos, datos que ya hemos usado en nuestros primeros pasos como calculadora.

a <- 1
b <- 2
a + b
## [1] 3

En el código anterior, tanto a como b, como la suma a + b, son de tipo numérico, algo que podemos comprobar con la función class() (nos devuelve numeric).

# Clase de las variables
class(a)
## [1] "numeric"
## [1] "numeric"
class(a + b)
## [1] "numeric"

También podemos comprobar su naturaleza con typeof(), que nos devuelve la naturaleza del dato tal cual es guardada en R.

# Tipología interna
typeof(a)
## [1] "double"
## [1] "double"
typeof(a + b)
## [1] "double"

Aunque no es especialmente relevante profundizar en ello de momento, fíjate que ambas órdenes combinadas nos dicen que las variables son de tipo numérico pero concretamente de tipo double: dichas variables son entendidas internamente como números con decimales (aunque no los veamos), lo que en matemáticas se llaman números reales (por curiosidad: el término double viene de lenguajes de programación antiguos como C, que significa «doble precisión», para indicarle que reserve 8 bytes - 64 bits - de memoria). Durante el curso no distinguiremos entre distintos tipos de números, para nosotros serán siempre de clase numeric y de tipo double, pero podríamos definir números enteros o integer (sin decimales, ahorrando huecos en memoria).

# Dato numérico (entero)
a <- 1L
class(a)
## [1] "integer"
## [1] "integer"

Con los datos numéricos podemos realizar todas las operaciones que se nos ocurriría hacer en una calculadora, como sumar (+), restar (-), multiplicar (*), dividir (/), raíz cuadrada (sqrt()), valor absoluto (abs()), elevar al cuadrado (^2), elevar al cubo (^3), etc.

# Definimos dos variables numéricas
a <- 1
b <- -2

# Suma y resta
a + b
## [1] -1
a - b
## [1] 3
# Multiplicación y división
a * b
## [1] -2
a / b
## [1] -0.5
# Raíz cuadrada
sqrt(a)
## [1] 1
# Potencias
a^2
## [1] 1
b^3
## [1] -8

5.2 Variables de tipo caracter (texto)

Pero no solo de números viven los datos: imagina que además de la edad de una persona queremos guardar su nombre.

edad <- 32
nombre <- "Javier"

class(nombre)
## [1] "character"
typeof(nombre)
## [1] "character"

Fíjate que ahora tenemos guardado en la variable nombre una variable de tipo character, es decir, una cadena de texto (conocido en otros lenguajes como string o char): caracteres entre comillas.

Es importante el concepto de las comillas, ya que todo lo que vaya entre comillas será un texto: "1" no representa un número, representa un texto (igual que "hola" o "adios")

5.3 Nuestra primera función: paste

Las cadenas de texto son un tipo especial de dato, con los que obviamente no podremos hacer operaciones aritméticas, pero si podemos hacer operaciones propias de cadenas de texto como puede ser la función paste(). Dicha función nos permite pegar dos cadenas de caracteres.

nombre <- "Javier"
apellido <- "Álvarez"
paste(nombre)
## [1] "Javier"

Si queremos pegar cadenas de texto sin ningún tipo de caracter en medio (ahora tenemos un espacio), existe una forma más abreviada y limpia de ejecutar la orden, usando la función paste0()

paste0(nombre, apellido) # todo junto sin espacio
## [1] "JavierÁlvarez"

Cuando hemos ejecutado paste() y paste0() estamos ejecutando lo que se conoce como una función: una palabra reservada que representa un conjunto de órdenes encapsuladas, y que se ejecuta a partir de unos argumentos de entrada. En este caso, solo hemos introducido como argumentos las cadenas de texto.

¿Qué sucededería si queremos pegar cadenas de texto usando el punto o la coma o cualquier otro caracter En el caso de la función paste(), podremos hacer uso de lo que se conoce como argumento opcional llamado sep, que podemos darle un valor en concreto o dejarlo sin especificar. Lo que hará R será tomar su valor por defecto igual a sep = " " (por defecto, la función paste() pega cadenas de texto con un espacio entre ellas porque en realidad ejecuta por defecto paste(..., sep = " ")).

paste(nombre, apellido, sep = "") # todo junto
## [1] "JavierÁlvarez"
paste(nombre, apellido, sep = " ") # separados por un espacio
## [1] "Javier Álvarez"
paste(nombre, apellido, sep = ".") # separados por un punto .
## [1] "Javier.Álvarez"
paste(nombre, apellido, sep = ",,") # separados por dos comas.
## [1] "Javier,,Álvarez"

Prueba a ejecutar ? paste en consola para ver las opciones de la función en el panel de ayuda.

5.4 Nuestro primer paquete: glue

Otra forma más intuitiva de trabajar con textos y variables numéricas es usar el paquete glue, que nos permite pegar cadenas de texto a variables numéricas de forma simbólica.

install.packages("glue") # solo la primera vez

Recuerda que install.packages() es solo necesario la primera que «compramos el libro»: nos bajamos una serie de archivos a nuestro ordenador. Una vez que hemos comprado el libro, cada vez que queramos usarlo bastará con indicarle que nos traiga ese libro concreto con library().

El paquete glue nos permite pegar de una forma mucho más legible cadenas de texto. Por ejemplo, supongamos que queremos construir la frase "La edad es de X años", donde X será la edad guardada e una variable.

edad <- 32
paste("La edad es de", edad, "años")
## [1] "La edad es de 32 años"

Con paste() podemos mezclar texto y números pero de una forma un poco aparatosa ya que debemos de ir cerrando la frase con comillas. Para evitarlo, glue() nos proporciona una forma más cómoda, sin salirnos de la cadena de texto, encapsulando las variables en llaves.

glue("La edad es de {edad} años")
## La edad es de 32 años
unidades <- "años"
glue("La edad es de {edad} {unidades}")
## La edad es de 32 años

También podemos hacer uso de dicha función sin tener los valores numéricos previamente guardados en variables.

# Otra forma sin definir variables a priori
glue("La edad es de {32} años")
## La edad es de 32 años

5.5 Manejando textos: paquete stringr

El paquete stringr nos proporciona un abanico de funciones y utilidades para poder trabajar con variables de tipo texto, permitiendo desde la búsqueda hasta la extracción de cadenas de texto dentro de la variable.

# install.packages("stringr") # solo la primera vez
library(stringr)

Aunque no es el objetivo de este manual introductorio adentrarnos en lo que se conoce como text mining o minería de textos, he aquí una lista de funciones útiles que podemos encontrar en dicho paquete

  • La función str_length() nos proporciona la longitud de una cadena de caracteres (reminder: un espacio cuenta como caracter).
str_length("hola")
## [1] 4
str_length("espejo")
## [1] 6
  • La función str_sub() nos permite extraer subcadenas de caracteres, indicándole no solo la cadena sino las posiciones iniciales y finales.
x <- "ornitorrinco"
str_sub(x, 3, 3) # tercer caracter
## [1] "n"
str_sub(x, 3, 5) # del tercero al quinto (ambos inclusive)
## [1] "nit"
str_sub(x, 2, -3) # del segundo al antepenúltimo caracter
## [1] "rnitorrin"

Dicha función se puede usar incluso para modificar subcadenas

str_sub(x, 3, 6) <- "jeje" # del tercero al sexto colamos un "jeje"
x
## [1] "orjejerrinco"
  • La función str_dup() nos permite duplicar cadenas de caracteres
str_sub("ja", 2) # duplicamos 2 veces "ja"
## [1] "a"
str_sub("ja", 5) # duplicamos 5 veces "ja"
## [1] ""
  • La función str_remove() nos permite eliminar subcadenas de caracteres (reminder: el espacio porque cuenta como caracter)
# eliminamos de la variable la subcadena o patrón "DNI:"
str_remove("DNI: 41378292", "DNI:") # nos deja ese espacio
## [1] " 41378292"
  • La función str_trim() nos permite eliminar espacios en blanco que nos hayan quedado en el texto, algo bastante habitual cuando lees cadenas de caracteres de archivos o de internet.
# eliminamos de la variable la subcadena o patrón "DNI:"
x <- str_remove("DNI: 41378292", "DNI:") # nos deja ese espacio
str_trim(x) # eliminamos ese espacio
## [1] "41378292"
str_trim("  calle mayor ", side = "left") # solo los de la izquierda
## [1] "calle mayor "
str_trim("  calle mayor ", side = "right") # solo los de la derecha
## [1] "  calle mayor"
str_trim("  calle mayor ", side = "both") # ambos (pro defecto)
## [1] "calle mayor"
  • La función str_pad() nos permite añadir espacios en blanco
x <- "mochila"
# un espacio en la izquierda (cadena resultante de longitud dada)
str_pad(x, 8) # longitud 8 ==> mochila tiene 7, así que añade un espacio
## [1] " mochila"
str_pad(x, 15) # longitud 15 ==> mochila tiene 7, así que añade 8 espacios
## [1] "        mochila"
str_pad(x, 12, "right") # a la derecha
## [1] "mochila     "
str_pad(x, 13, "both") # a ambos lados
## [1] "   mochila   "
  • La función str_to_upper() nos permite convertir un texto a mayúscula y str_to_title() pone en mayúscula solo la primera letra de cada palabra. La función str_to_lower() nos permite convertir un texto a minúscula
x <- "Hola, me llamo Javi"
str_to_upper(x)
## [1] "HOLA, ME LLAMO JAVI"
## [1] "Hola, Me Llamo Javi"
str_to_lower("¡PARA! No puedes pasar")
## [1] "¡para! no puedes pasar"
  • La función str_detect() nos permite detectar subcadenas de caracteres
subcadena <- "ministerio"
x <- "En un documento del Ministerio del Interior..."
str_detect(x, subcadena) # no lo detecta porque se sensitive a mayúsculas
## [1] FALSE
str_detect(str_to_lower(x), subcadena)
## [1] TRUE

Haciendo además uso de expresiones regulares podemos afinar nuestra búsqueda

telefono <- "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})"
x <- "mi telefono es 219 733 8965"
y <- "mi telefono es 329-293-8753"
z <- "mi telefono es 32-293-87"
str_detect(x, telefono)
## [1] TRUE
str_detect(y, telefono)
## [1] TRUE
str_detect(z, telefono)
## [1] FALSE
  • La función str_locate() nos permite localizar inicio y final donde se sitúan cadenas de caracteres
str_locate("hola me llamo Javi", "Javi")
##      start end
## [1,]    15  18
  • La función str_replace() nos permite reemplazar subcadenas en base a un patrón pero solo lo hace con la primera que detecta. Con str_replace_all() podemos reemplazar todos
str_replace("la vida del oso panda", "panda", "pardo") # reemplazamos panda por pardo
## [1] "la vida del oso pardo"
str_replace("la vida del oso pardo y el oso polar", "oso", "delfín")
## [1] "la vida del delfín pardo y el oso polar"
str_replace_all("la vida del oso pardo y el oso polar", "oso", "delfín")
## [1] "la vida del delfín pardo y el delfín polar"

5.6 Consejos

CONSEJOS

 

Recuperar un comando y autocompletar

Si haces click con el ratón en la consola y pulsas la flecha «arriba» del teclado, te irá apareciendo todo el historial de órdenes ejecutadas. Es una manera de ahorrar tiempo para ejecutar órdenes similares a las ya ejecutadas. Si empiezas a escribir el nombre de una variable pero no te acuerdas exactamente de su nombre, pulsando tabulador te autocompletará solo.

 

Convertir tipos de datos

A veces la lectura de variables numéricas de nuestros archivos puede hacer que un número, por ejemplo 1, sea leído como la cadena de texto "1", con la que no podemos operar como un número. Las funciones as.numeric(), o as.character() nos permiten convertir una variable en tipo numérico, caracter o lógico, respectivamente.

"1" + 1
## Error in "1" + 1: argumento no-numérico para operador binario
as.numeric("1") + 1
## [1] 2
## [1] "1"

 

5.7 📝 Ejercicios

(haz click en las flechas para ver soluciones)

📝Ejercicio 1: define una variable edad que guarde tu edad y otra nombre con tu nombre.

  • Solución:
edad <- 32 # tipo numeric
nombre <- "Javier" # tipo caracter

edad
## [1] 32
nombre
## [1] "Javier"

 

📝Ejercicio 2: define otra variable con tus apellidos y junta las variables nombre y apellidos en una sola cadena de texto que guardes en nombre_completo.

  • Solución:
# Apellidos
apellidos <- "Álvarez Liébana"

# Pegamos
nombre_completo <- glue("{nombre} {apellidos}")
nombre_completo
## Javier Álvarez Liébana
# Otra forma
nombre_completo <- paste(nombre, apellidos)
nombre_completo
## [1] "Javier Álvarez Liébana"

 

📝Ejercicio 3: define dos variables numéricas y realiza la suma de ambas. Obtén con class() la clase de dicha variable suma

  • Solución:
# Definimos dos variables numéricas
a <- 1
b <- -2

a + b
## [1] -1
class(a + b)
## [1] "numeric"

 

📝Ejercicio 4: construye una frase que diga «Hola, me llamo … y tengo … años».

  • Solución:
edad <- 32
glue("Hola, me llamo {nombre_completo} y tengo {edad} años")
## Hola, me llamo Javier Álvarez Liébana y tengo 32 años

 

📝Ejercicio 5: define una cadena de texto con "mi código postal es 28045". Calcula la longitud de la cadena y extrae la subcadena del lugar 3 al 17 con str_sub() (guarda dicha subcadena en una variable y)

  • Solución:
x <- "mi código postal es 28045"
y <- str_sub(x, 3, 17)
y
## [1] " código postal "

 

📝Ejercicio 6: con la subcadena y del ejercicio anterior, elimina los espacios solo de la izquierda y convierte a mayúsculas

  • Solución:
# Todo en una línea
str_to_upper(str_trim(y, side = "left"))
## [1] "CÓDIGO POSTAL "
# Paso a paso
z <- str_trim(y, side = "left")
str_to_upper(z)
## [1] "CÓDIGO POSTAL "

 

📝Ejercicio 7: con la cadena x original, sustituye la subcadena “código postal” por “cp”.

  • Solución:
str_sub(x, 4, 16) <- "cp"