library(learnr)
knitr::opts_chunk$set(echo = FALSE)

Introducción

knitr::include_graphics("images/vectores.jpg")

El presente tutorial pretende ser un vehículo de aprendizaje interactivo para los novatos en el lenguaje R.

Ha sido desarrollado a través del paquete learnr que permite utilizar documentos RMarkdown para generar tutoriales interactivos.

Como se explica en la página de learnr, los tutoriales consisten en contenido (texto, figuras, ilustraciones, ecuaciones, vídeos, etc.) junto con componentes interactivos, como preguntas con múltiples opciones y fragmentos de código de R que los usuarios pueden editar y ejecutar directamente, para verificar y reforzar la comprensión.

Estos tutoriales conservan automáticamente el avance que un usuario realizó, por lo que si un estudiante trabaja en algunos ejercicios o preguntas y vuelve al tutorial más tarde, puede retomarlo exactamente donde lo dejó.

Este tutorial ha sido publicado como el paquete fundamentosr.

Objetivo de aprendizaje

El objetivo de aprendizaje del presente tutorial es el siguiente:

Naturaleza y características básicas

El tipo más básico de estructura de dato en R es el vector. El vector es una estructura compuesta de un número de elementos finitos, homogéneos y donde dicha estructura tiene un tamaño fijo.

knitr::include_graphics("images/vectores2.jpg")

Los vectores en R son objetos de una única dimensión que pueden contener tipos de datos simples: datos numéricos, cadena de caracteres o datos lógicos, entre otros. Al contener un solo tipo de datos se conocen como vectores atómicos.

Cada vector tiene dos propiedades clave:

Con respecto a valores especiales para los vectores encontramos NULL y NA. NULL es a menudo utilizado para representar la ausencia de un vector y se comporta típicamente como un vector de longitud nula. Por otra parte, NA se utiliza para representar la ausencia de un valor en un vector.

Los cuatro tipos más importantes de vectores son lógico, numérico y carácter. Existen otros tipos como los de tipo raw (secuencias de bytes sin procesar) y complejo que son raramente usados durante el análisis de datos y de los que no hablaremos aquí.

Como los vectores son la estructura de datos más sencilla de R, datos simples como el número 3, el valor lógico TRUE o la cadena "Hola" son en realidad vectores. En este caso, un vector de tipo numérico y longitud la unidad.

Creación e inicialización

Existen multitud de formas de crear e inicializar vectores en R. A continuación veremos algunos de los métodos más importantes para llevarlo a cabo.

Elemento a elemento

Los vectores atómicos pueden ser creados con la función c(), que corresponde a la sigla de combinar. Dentro de los paréntesis aparecerá la lista de valores, expresiones y/o variables del tipo de datos correspondiente al vector.

Veamos algunos ejemplos de creación de vectores con valores literales:

# Vector flotante o double
vector_flotantes <- c(1, 2.5, 4.5)
vector_flotantes
# Con el sufijo L, conseguimos un vector de enteros en lugar de un flotante o double
vector_enteros <- c(1L, 6L, 10L)
vector_enteros
# Usamos TRUE y FALSE (o T y F) para crear vectores lógicos
vector_logicos <- c(TRUE, FALSE, T, F)
vector_logicos
# Vector de cadenas de caracteres
vector_cadenas <- c("Hola", "Mundo!")
vector_cadenas

La presencia en RStudio de los vectores creados puede comprobarse tras incluir el código en un script y realizar la ejecución de las líneas correspondientes.

knitr::include_graphics("images/vectores_rstudio.jpg")

Veamos ahora algunos ejemplos de creación de vectores con variables y expresiones:

# Vector flotante o double
flotante<-1.0
vector_flotantes <- c(flotante, flotante+1.5, flotante*2)
vector_flotantes
# Con el sufijo L, conseguimos un vector de enteros en lugar de un flotante o double
entero<-10L
vector_enteros <- c(as.integer(10), as.integer(90%/%2), entero)
vector_enteros
# Usamos TRUE y FALSE y expresiones relacionales y lógicas para crear vectores lógicos
numero1<-10.5
numero2<-12
logico1<-TRUE
logico2<-FALSE
vector_logicos <- c(3>2, numero1>=numero2, logico1&&logico2, logico2)
vector_logicos
# Vector de cadenas de caracteres
cadena1<-"Adios"
vector_cadenas <- c("Hola","Mundo!", cadena1,class(logico1))
vector_cadenas

Podemos además, con c(), unir varios vectores para generar uno nuevo o bien unir varios vectores y valores para generar uno nuevo. Veamos un ejemplo:

# Vector flotante o double
flotante<-1.0
vector_flotantes <- c(flotante, flotante+1.5, flotante*2)
#Unimos varios vectores flotantes y valores flotantes
vector_flotantes <- c(vector_flotantes, 3.0, vector_flotantes)
vector_flotantes
# Vector de cadenas de caracteres
cadena1<-"Adios"
cadena2<-"amigos!"
vector_cadenas <- c("Hola","Mundo!", cadena1,cadena2)
#Unimos varios vectores cadena y valores cadena
vector_cadenas <- c(vector_cadenas,vector_cadenas,cadena1)
vector_cadenas

Valores por defecto

Existe la posibilidad de crear vectores de una longitud determinada con valores por defecto de un tipo determinado. Para ello se puede utilizar la función vector(). Esta función recibe en un argumento el tipo de datos, como cadena de caracteres, correspondiente al vector (mode) y en el otro argumento la longitud del vector.

A continuación, crearemos varios vectores de ejemplo con valores por defecto para cada uno de los tipos de datos simples: flotante (double), entero, lógico y cadena.

#Longitud del vector a crear
longitud<-5
# Vector flotante o double
vector_flotantes <- vector(mode="double",length=longitud)
vector_flotantes
# Vector de enteros 
vector_enteros <- vector(mode="integer",length=longitud+1)
vector_enteros
# Vector lógico
vector_logicos <- vector(mode="logical", length=longitud*2)
vector_logicos
# Vector de cadenas de caracteres
vector_cadenas <- vector(mode="character", length=4)
vector_cadenas

Podemos comprobar cómo los valores por defecto para los vectores de double (números de punto flotante de doble precisión) y enteros son cero, para los vectores lógicos FALSE (como sabemos equivalente a cero en caso de coerción a numérico) y para las cadenas la cadena vacía (sin caracteres, sólo comillas).

Así mismo, podemos consultar el tipo de los vectores creados con la función typeof junto a la variable del vector y además la estructura (contenido) del objeto mediante la función str.

#Longitud del vector a crear
longitud<-5
# Vector flotante o double
vector_flotantes <- vector(mode="double",length=longitud)
typeof(vector_flotantes)
str(vector_flotantes)
# Vector de enteros 
vector_enteros <- vector(mode="integer",length=longitud+1)
typeof(vector_enteros)
str(vector_enteros)
# Vector lógico
vector_logicos <- vector(mode="logical", length=longitud*2)
typeof(vector_logicos)
str(vector_logicos)
# Vector de cadenas de caracteres
vector_cadenas <- vector(mode="character", length=4)
typeof(vector_cadenas)
str(vector_cadenas)

Otra posibilidad para crear vectores con los valores por defecto viene determinada por el uso de funciones existentes para cada tipo de datos con el nombre del propio tipo. Veamos el equivalente al código anterior con este tipo de funciones.

#Longitud del vector a crear
longitud<-5
# Vector flotante o double
vector_flotantes <- double(longitud)
typeof(vector_flotantes)
# Vector de enteros 
vector_enteros <- integer(longitud+1)
typeof(vector_enteros)
# Vector lógico
vector_logicos <- logical(longitud*2)
typeof(vector_logicos)
# Vector de cadenas de caracteres
vector_cadenas <- character(4)
typeof(vector_cadenas)

Esta forma es mucho más legible, aunque se debe emplear una función diferente para cada tipo de datos. El argumento que se recibe es la longitud del vector a crear.

Tipos de datos diferentes y coerción

Veamos lo que ocurre en caso de querer crear un vector con tipos de datos diferentes:

v<-c("Hola",5,FALSE)
v

Nos damos cuenta de que en el vector que se crea, todos los elementos corresponden a un único tipo de datos: cadena de caracteres. Se ha llevado a cabo una coerción implícita. Siempre que tengamos algún elemento de tipo de datos character, en caso de haber elementos del vector de otro tipo de datos serán convertidos automáticamente a cadena de caracteres.

Veamos a continuación otro ejemplo de vector creado con tipos de datos diferentes: en este caso, números y valores lógicos.

v<-c(1,5,FALSE,TRUE)
v

En el vector creado los valores lógicos son transformados a números, concretamente el valor FALSE corresponde a 0 y el valor TRUE a 1. Este tipo de coerción también es implícita.

Así mismo, se pueden aplicar las diferentes funciones de coerción explícita a un determinado vector. Veamos diferentes ejemplos de ello a continuación. En primer lugar, llevaremos a cabo la coerción de un vector lógico a numérico (double). El efecto sobre los valores lógicos es el ya comprobado en la coerción implícita.

v<-c(TRUE,FALSE,TRUE,FALSE,FALSE)
v_numeric<-as.numeric(v)
is.numeric(v_numeric)
typeof(v_numeric)
v_numeric

En el caso de coerción de vectores de double a vectores de lógicos, tenemos que los valores cero son coercionados a FALSE y el resto a TRUE.

v<-c(5,3,0,0.25,-3)
v_logical<-as.logical(v)
is.logical(v_logical)
typeof(v_logical)
v_logical

Existen también casos en los que tal coerción proporciona valores especiales, por ejemplo cuando se quiere coercionar desde cadena de caracteres a otro tipo de datos como numérico. En este caso, el vector resultado tendrá todos sus elementos con valor NA, indicador de que no se puede llevar a cabo la coerción de valores.

v<-c("Hola","Adios","Hasta luego","Hasta pronto")
v_numeric<-as.numeric(v)
typeof(v_numeric)
v_numeric

La coerción para vectores es idéntica en sus efectos a la de los tipos de datos simples.Para mayor información acerca de la coerción, tanto explícita como implícita, puedes comprobar el contenido del tutorial Operadores Relacionales y Lógicos.

Series numéricas

Existe además la posibilidad de crear un vector de valores literales o un conjunto de valores literales con la estructura de vector. Ocurre con las secuencias numéricas que se pueden generar de varias formas diferentes.

#Serie creciente de enteros
v1<-1:10
v1
typeof(v1)
#Serie decreciente de enteros
v2<-10:1
v2
typeof(v2)
#Serie creciente de double
v3<-10.5:20.5
v3
typeof(v3)
#Serie creciente de enteros (de negativo a positivo)
v4<--4:4
v4
typeof(v4)
#Serie creciente de double (de negativo a positivo)
v5<--3.25:10.25
v5
typeof(v5)
#Serie creciente (incrementos de 1 hasta superar el límite)
v6<-20.25:30.75
v6
typeof(v6)

Los operandos de : no tienen por qué ser necesariamente valores literales, pues pueden ser expresiones. Veamos algunos ejemplos de ello:

#Serie creciente de enteros
lim<-1
v1<-lim:(lim+10)
v1
typeof(v1)
#Serie decreciente de enteros
dim<-2
v2<-(10*dim):1
v2
typeof(v2)
#Serie creciente de double
dif<-0.5
v3<-(10-dif):(20+dif)
v3
typeof(v3)
#Serie creciente de enteros (de negativo a positivo)
mul<-4
v4<-(-1*mul):mul
v4
typeof(v4)
#Serie creciente de enteros
v1<-1:10
v1_seq<-seq(10)
v1
v1_seq
#Serie decreciente de enteros
v2<-10:1
v2_seq<-seq(10,1)
v2
v2_seq
#Serie creciente de double
v3<-10.5:20.5
v3_seq<-seq(10.5,20.5)
v3
v3_seq
#Serie creciente de enteros (de negativo a positivo) con incremento de 2
v4_seq<-seq(-14,14,by=2)
v4_seq
#Serie decreciente de double (de positivo a negativo) con decrementos de 0.25
v5_seq<-seq(2.25,-1.5,by=-0.25)
v5_seq

El argumento by para seq tendrá signo positivo si la serie es incremental y signo negativo si la serie es decreciente.

Repetición de valores

Otra de las formas de creación e inicialización de vectores está basada en la repetición de valores. Partimos de un vector previo dado, para el que se realiza un determinado número de repeticiones de los elementos de este vector y un determinado número de repeticiones del propio vector.

La función que lo permite es rep() recibiendo como primer parámetro al vector de repetición junto a una serie de posibles argumentos:

Veamos una serie de ejemplos que muestren el funcionamiento de la función rep():

#Repetición de un solo valor (vector de un elemento) un número de veces determinado
v1_rep<-rep(1,8)
v1_rep
cat("Longitud =",length(v1_rep))
#Repetición de varios valores (un vector) un número de veces determinado
v2_rep<-rep(1:4,3)
v2_rep
cat("Longitud =",length(v2_rep))
#Repetición de cada elemento del vector varias veces
v3_rep<-rep(1:4,each=3)
v3_rep
cat("Longitud =",length(v3_rep))
#Repetición de cada elemento del vector un número diferente de veces
v4_rep<-rep(c(1,2,3),c(3,2,1))
v4_rep
cat("Longitud =",length(v4_rep))
v5_rep<-rep(1:5,c(2,3,2,3,2))
v5_rep
cat("Longitud =",length(v5_rep))
#Longitud deseada para el vector generado
v6_rep<-rep(1:5,len=8)
v6_rep
cat("Longitud =",length(v6_rep))
#Repetición de cada elemento del vector varias veces hasta alcanzar la longitud deseada
v7_rep<-rep(1:5,each=2,len=14)
v7_rep
cat("Longitud =",length(v7_rep))

Generación con valores aleatorios

Vamos a ver dos formas de generación de valores aleatorios. La primera de ellas será una posibilidad para la creación de una muestra aleatoria generada desde un conjunto de valores. La segunda vendrá determinada por el uso de una distribución como referencia para la generación de valores numéricos aleatorios.

Valores de referencia

En ocasiones es necesario crear una muestra aleatoria usando unos determinados valores como referencia. La función sample permite conseguir este cometido. De un vector universal permite crear otro vector en donde los elementos han sido escogidos aleatoriamente.

Para generar una muestra de manera aleatoria necesitamos un vector donde se encuentra el universo de elementos (vector_universal) y los parámetros que determinan el tamaño del vector a generar, es decir, la cantidad de elementos deseados (size), si la selección de elementos se dará con reemplazo o no (replace que por defecto será FALSE) y, por último, opcionalmente la probabilidad de ocurrencia de los elementos del vector universal proporcionada en un vector (prob).

Veamos a continuación algunos ejemplos del uso de esta función sample.

#Generaremos 30 valores lógicos
aleatorios<-sample(c(TRUE,FALSE),size=30,replace=TRUE)
aleatorios

Al tratarse de dos valores posibles el parámetro de reemplazamiento debe permitir repetidos.

#Generaremos 15 enteros del intervalo [1,30] sin repetición
aleatorios<-sample(1:30,size=15,replace=FALSE)
aleatorios

Podemos comprobar como no aparecen enteros repetidos en la muestra.

#Generaremos 25 cadenas de caracteres del conjunto (A,B,C)
aleatorios<-sample(c("A","B","C"),size=25,replace=TRUE,prob=c(0.5,0.35,0.15))
aleatorios

En este caso, se otorga más probabilidad a la aparición de la cadena "A" y tras ella "B" y finalmente "C". La suma de todos los pesos es la unidad.

Cada vez que se ejecuta cada código se crearán vectores diferentes. Por tanto para que la aleatorización de elementos sea reproducible se debe establecer una semilla con set.seed(). Así podremos reproducir los resultados obtenidos en cualquier momento.

#Generaremos 20 elementos entre 1 y 2 con semilla.
set.seed(102)
muestra<-sample(c(1,2), size = 20, replace = TRUE) 
muestra

La semilla puede ser cualquier entero, que debemos usar si queremos reproducir la misma generación de muestra.

Distribución estadística

Por otra parte, en el caso numérico, hay vectores con valores que no son secuencias ni valores repetidos, sino que provienen de datos aleatorios que siguen una cierta distribución. Es usual crearlos cuando se diseñan experimentos y no se dispone de datos reales.

R cuenta con un conjunto de funciones capaces de generar valores aleatorios siguiendo una distribución concreta. Las dos más usuales son rnorm(), asociada a la distribución normal, y runif(), que corresponde a la distribución uniforme. Existen muchas más distribuciones estadísticas incluidas dentro de las funciones estadísticas predefinidas de R y que presentan funciones para generar números aleatorios (véase el tutorial de Funciones Predefinidas).

Antes de utilizar las funciones de generación de valores aleatorios, podemos establecer la semilla del generador de valores aleatorios con objeto de que el experimento sea reproducible (a partir de una misma semilla, el conjunto de valores generados sería el mismo). Para ello podemos utilizar la función set.seed() proporcionando como argumento la semilla correspondiente.

#Generaremos 25 valores aleatorios siguiendo una distribución normal de media 5 y desviación típica 2
aleatorios<-rnorm(25,mean=5,sd=2)
aleatorios
#Generaremos 25 valores aleatorios siguiendo una distribución uniforme con mínimo 1 y máximo 50
aleatorios<-runif(25,min=1,max=50)
aleatorios

Acceso a los elementos

Sabemos que podemos saber cuántos elementos contiene un vector mediante la función length(). Esta información nos será útil a la hora de acceder a cualquiera de los elementos de un vector v, usando para ello la notación v[indice], siendo indice la posición dentro del vector a la que queremos acceder.

La función length(), además de devolver el número de elementos contenidos en el vector, también permite establecer el tamaño del mismo.

v<-seq(10,100,by=10)
cat("Creamos vector de longitud",length(v))
v
cat("El primer elemento del vector es:",v[1])
cat("El último elemento del vector es:",v[length(v)])
cat("Acortamos el vector reduciendo 3 la longitud:",length(v)-3)
length(v)<-length(v)-3
v
cat("El último elemento del vector es:",v[length(v)])
cat("Ampliamos el vector incrementando 5 la longitud:",length(v)+5)
length(v)<-length(v)+5
v
cat("El último elemento del vector es:",v[length(v)])

Cabe destacar que la reducción de la longitud del vector supone la pérdida de los elementos del vector correspondientes. Por otra parte, el incremento de la longitud del mismo incorpora valores NA para los nuevos elementos.

Al acceder al contenido de un vector se pueden obtener uno o más elementos, facilitando entre corchetes uno o más índices. Para usar más de un índice es necesario facilitar un vector entre los corchetes. También pueden utilizarse números negativos que, en este contexto, indican qué elementos se excluirán. A continuación veremos algunos ejemplos:

dias_semana <- c("Lunes","Martes","Miércoles","Jueves","Viernes","Sábado","Domingo")
dias_semana
cat("El tercer dia de la semana es",dias_semana[3])
cat("El ultimo dia de la semana es",dias_semana[length(dias_semana)])
print("Mostraremos todos los dias de la semana excepto el Sábado")
dias_semana[-6]
print("Mostraremos el primer, tercer y quinto día de la semana")
dias_semana[c(1,3,5)]
print("Mostraremos todos los días de la semana excepto del quinto al séptimo")
dias_semana[-(5:7)]
print("Mostraremos los dias de la semana pares")
dias_semana[seq(2,7,by=2)]
print("Mostraremos dos veces cada día de la semana")
dias_semana[rep(1:length(dias_semana),each=2)]

Nombre de elementos

Podemos asignar nombre a los distintos elementos de un vector. Lo que se hace realmente es adjudicar nombres a los distintos índices del vector.

Para ello se utiliza la función names. Esta función recibirá como argumento el vector al que queremos asignar nombres y para llevar a cabo la asignación usaremos el operador <- junto a un vector a la derecha que contenga tantos elementos como contiene el vector, siendo cada uno de ellos el nombre que sustituirá a cada índice del vector.

Veamos un ejemplo con los meses del año.

dias_meses <- c(31,28,31,30,31,30,31,31,30,31,30,31)
dias_meses
names(dias_meses)<-c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
dias_meses

Al utilizar el operador [] para acceder al contenido de un elemento podemos utilizar como índice el nombre proporcionado a dicho elemento. Teniendo en cuenta el ejemplo anterior seríadias_meses[nombre_del_mes], siendo nombre_del_mes una cadena de caracteres.

Por otra parte, para conocer el nombre asignado a un elemento del vector basta con llamar a la función names proporcionando como argumento el elemento. Teniendo en cuenta el ejemplo de los meses del año, para obtener el nombre asignado al primer mes sería names(dias_meses[1]).

dias_meses <- c(31,28,31,30,31,30,31,31,30,31,30,31)
names(dias_meses)<-c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
cat("El mes de",names(dias_meses[1]),"tiene",dias_meses["Enero"],"días.")
cat("El mes de Febrero tiene",dias_meses[2],"días.")
mes<-3
cat("El mes de",names(dias_meses[mes]),"tiene",dias_meses[names(dias_meses[mes])],"días.")
cat("El mes de Abril tiene",dias_meses["Abril"],"días.")

Cómo vemos existen múltiples formas de obtener tanto el nombre de un elemento como el valor de un elemento dentro de un vector.

Selección de elementos

Sabemos que podemos crear un nuevo vector a partir del acceso a un conjunto de los elementos de otro vector: enumerando el conjunto de índices a los que deseamos acceder.

Las posibilidades se incrementan teniendo en cuenta que podemos usar condiciones sobre los elementos del vector, dentro del operador [], para seleccionar elementos del mismo.

Las condiciones se aplicarán elemento a elemento y mediante operadores relacionales y/o lógicos. Para saber más acerca de operadores relacionales y lógicos puedes comprobar el contenido del tutorial Operadores Relacionales y Lógicos.

Las condiciones sobre los elementos del vector se crean utilizando el nombre del propio vector para la comparación y/o operación lógica.

Veamos a continuación dos ejemplos diferentes de selección con operadores relacionales:

dias_meses <- c(31,28,31,30,31,30,31,31,30,31,30,31)
names(dias_meses)<-c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
# Meses de 30 días
meses_30_dias<-dias_meses[dias_meses==30]
meses_30_dias
# Otra forma de representar los meses del año que tienen 30 días
dias_meses[c("Abril","Junio","Septiembre","Noviembre")]
# Meses que no tienen 30 días
meses_no_30_dias<-dias_meses[dias_meses!=30]
meses_no_30_dias
#Generaremos 25 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 1 y máximo 50
aleatorios<-as.integer(runif(25,min=1,max=50))
cat("Enteros aleatorios entre 1 y 50")
aleatorios
#Aleatorios menores que un valor
valor<-25
aleatorios_menores_valor<-aleatorios[aleatorios<valor]
cat("Enteros menores que",valor)
aleatorios_menores_valor
#Aleatorios mayores a un valor
valor<-40
aleatorios_mayores_valor<-aleatorios[aleatorios>valor]
cat("Enteros mayores que",valor)
aleatorios_mayores_valor

La aparición del nombre del vector en el interior del operador [] permite crear la condición. Vamos a presentar ejemplos en los que se utilizarán operadores lógicos y relacionales para la selección.

dias_meses <- c(31,28,31,30,31,30,31,31,30,31,30,31)
names(dias_meses)<-c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
# Meses de 28-30 días
meses_28_30_dias<-dias_meses[(dias_meses>=28) & (dias_meses<=30)]
meses_28_30_dias
# Meses que no tienen 30 días
meses_no_30_dias<-dias_meses[!(dias_meses==30)]
meses_no_30_dias
#Generaremos 25 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 1 y máximo 50
aleatorios<-as.integer(runif(25,min=1,max=50))
cat("Enteros aleatorios entre 1 y 50")
aleatorios
#Aleatorios entre dos valores (intervalo)
valor1<-20
valor2<-40
aleatorios_intervalo<-aleatorios[(aleatorios>=valor1) & (aleatorios<=valor2)]
cat("Enteros entre",valor1,"y",valor2)
aleatorios_intervalo
#Aleatorios de dos intervalos diferentes [a1,b1], [a2,b2]
a1<-10
b1<-20
a2<-30
b2<-40
aleatorios_dos_intervalos<-aleatorios[(aleatorios>=a1 & aleatorios <=b1) | (aleatorios>=a2 & aleatorios <=b2)]
cat("Enteros de los intervalos [",a1,",",b1,"] y","[",a2,",",b2,"].")
aleatorios_dos_intervalos

Hemos podido comprobar que los operadores lógicos que se utilizan son los que se aplican elemento a elemento (& en vez de && para el AND lógico y | en vez de || para el OR lógico).

Por otra parte, R dispone de la función predefinida which que nos permite encontrar índices que cumplen cierta característica. La función which nos da los números de orden del vector en los que se cumple una condición dada. Comprobemos su uso tomando como referencia uno de los ejemplos anteriores:

dias_meses <- c(31,28,31,30,31,30,31,31,30,31,30,31)
names(dias_meses)<-c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
# Meses de 28-30 días
meses_28_30_dias<-which((dias_meses>=28) & (dias_meses<=30))
dias_meses[meses_28_30_dias]
# Meses que no tienen 30 días
meses_no_30_dias<-which(!(dias_meses==30))
dias_meses[meses_no_30_dias]

Operaciones aritméticas

La mayor parte de funciones y operadores con que cuenta R están preparados para actuar sobre vectores de datos. Ello simplifica y hace eficiente la operación con vectores. Tanto los operadores aritméticos, como los operadores relaciones y lógicos, así como multitud de funciones predefinidas se pueden aplicar directamente sobre vectores.

En R se puede operar sobre vectores igual que se opera sobre números. De hecho, en R, un número es un vector numérico de longitud 1. Las operaciones aritméticas en R están vectorizadas, es decir, admiten un vector como argumento y operan sobre cada uno de los elementos.

Veamos un ejemplo para cada una de las operaciones aritméticas:

Suma (+):

"Tenemos en dos vectores el resultado de dos pruebas (entre 0 y 10) realizadas por treinta candidatos diferentes y queremos obtener el resultado global obtenido." Podemos sumar los vectores para calcularlo.

#Generaremos (emulando los resultados de cada prueba) 30 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 0 y máximo 10
prueba1<-runif(30,min=0,max=10)
names(prueba1)<-1:30
print("Resultados de la primera prueba:")
prueba1
prueba2<-runif(30,min=0,max=10)
names(prueba2)<-1:30
print("Resultados de la segunda prueba:")
prueba2
#Resultado global
print("Suma primera prueba y segunda prueba:")
resultado_global<-prueba1+prueba2
resultado_global

En el ejemplo se puede comprobar como proporcionamos nombre a los elementos del vector mediante la coerción implícita de una serie numérica entre 1 y 30 (que representaría al número de candidato).

Resta (-):

"Tenemos en dos vectores el resultado de dos pruebas (entre 0 y 10) realizadas por treinta candidatos diferentes. Queremos quedarnos únicamente con los candidatos que hayan obtenido:

#Generaremos (emulando los resultados de cada prueba) 30 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 0 y máximo 10
prueba1<-runif(30,min=0,max=10)
names(prueba1)<-1:30
print("Resultados de la primera prueba:")
prueba1
prueba2<-runif(30,min=0,max=10)
names(prueba2)<-1:30
print("Resultados de la segunda prueba:")
prueba2
#Diferencia segunda prueba y primera prueba
diferencia_pruebas<-prueba2-prueba1
#Seleccion: primera prueba > 5 y diferencia entre segunda y primera prueba
seleccionados<-diferencia_pruebas[(prueba1>5)&(diferencia_pruebas>1)]
#Candidatos seleccionados
print("Candidatos seleccionados")
names(seleccionados)

Podemos comprobar cómo se usan condiciones de selección, dentro del operador [], en las que intervienen otros vectores diferentes (prueba1 y prueba2) a aquel dentro del que seleccionamos (diferencia_pruebas). Para mostrar los candidatos seleccionados mostramos los nombres del vector.

Multiplicación (*):

"Tenemos en dos vectores el resultado de dos pruebas (entre 0 y 10) realizadas por treinta candidatos diferentes. En otro vector tenemos el nivel de afinidad para cada candidato que será entre 0 y 1. La valoración de cada candidato será el producto del nivel de afinidad por el resultado de las pruebas." Vamos a calcular la valoración de cada candidato.

#Generaremos (emulando los resultados de cada prueba) 30 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 0 y máximo 10
prueba1<-runif(30,min=0,max=10)
names(prueba1)<-1:30
print("Resultados de la primera prueba:")
prueba1
prueba2<-runif(30,min=0,max=10)
names(prueba2)<-1:30
print("Resultados de la segunda prueba:")
prueba2
afinidad<-runif(30)
names(afinidad)<-1:30
print("Nivel de afinidad:")
afinidad
#Cálculo de valoración para los candidatos
print("Valoración candidatos:")
valoracion_candidatos<-(prueba1+prueba2)*afinidad
valoracion_candidatos

Es muy sencillo y eficiente aplicar el producto elemento a elemento entre vectores.

División (/):

"Tenemos en dos vectores el resultado de dos pruebas (entre 0 y 10) realizadas por treinta candidatos diferentes. Calcula la calificación media de las dos pruebas." Para ello haremos uso de la división.

#Generaremos (emulando los resultados de cada prueba) 30 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 0 y máximo 10
prueba1<-runif(30,min=0,max=10)
names(prueba1)<-1:30
print("Resultados de la primera prueba:")
prueba1
prueba2<-runif(30,min=0,max=10)
names(prueba2)<-1:30
print("Resultados de la segunda prueba:")
prueba2
#Cálculo de media de las pruebas para los candidatos
print("Media pruebas:")
media_pruebas<-(prueba1+prueba2)/2
media_pruebas
media_pruebas_int<-(prueba1+prueba2)%/%2
media_pruebas_int

En este caso, el número 2 actúa como vector de un único elemento que se recicla o extiende (repitiéndose continuamente) hasta un vector de la misma longitud que prueba1 y prueba2 para realizar la operación de división elemento a elemento.

División entera (%/%):

"Comprueba qué ocurriría en el caso anterior si como media de las pruebas solamente se admitiese un número entero." Tendríamos que cambiar el tipo de división únicamente.

#Generaremos (emulando los resultados de cada prueba) 30 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 0 y máximo 10
prueba1<-runif(30,min=0,max=10)
names(prueba1)<-1:30
print("Resultados de la primera prueba:")
prueba1
prueba2<-runif(30,min=0,max=10)
names(prueba2)<-1:30
print("Resultados de la segunda prueba:")
prueba2
#Cálculo de media de las pruebas para los candidatos
print("Media entera pruebas:")
media_pruebas_int<-(prueba1+prueba2)%/%2
media_pruebas_int

Módulo (%%):

"Indica a qué candidatos se les quitaría más puntuación (superior al 90%) en caso de tomar como media de las pruebas el valor entero." Para calcularlo nos quedaremos con el resto de calcular la media de las pruebas, lo llevaremos al intervalo [0,1] y nos quedaríamos con aquellos candidatos con esta valor superior a 0.9.

#Generaremos (emulando los resultados de cada prueba) 30 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 0 y máximo 10
prueba1<-runif(30,min=0,max=10)
names(prueba1)<-1:30
print("Resultados de la primera prueba:")
prueba1
prueba2<-runif(30,min=0,max=10)
names(prueba2)<-1:30
print("Resultados de la segunda prueba:")
prueba2
#Cálculo de media de las pruebas para los candidatos
print("Media pruebas")
media_pruebas<-(prueba1+prueba2)/2
media_pruebas
print("Media entera pruebas")
media_entera_pruebas<-(prueba1+prueba2)%/%2
media_entera_pruebas
print("Resto media entera pruebas:")
resto_media_entera_pruebas<-(prueba1+prueba2)%%2
resto_media_entera_pruebas
print("Resto media entera pruebas [0,1]:")
#Llevamos el resto de 0 a 1
resto_media_entera_pruebas<-resto_media_entera_pruebas/2
resto_media_entera_pruebas
print("Candidatos más perjudicados")
mas_perjudicados<-resto_media_entera_pruebas[resto_media_entera_pruebas>0.9]
names(mas_perjudicados)

Podemos comprobar cómo se usan condiciones de selección, dentro del operador [], para obtener los candidatos más perjudicados. Para mostrar tales candidatos mostramos los nombres del vector correspondiente.

Potenciación (^):

"Tenemos en dos vectores el resultado de dos pruebas (entre 0 y 10) realizadas por treinta candidatos diferentes. En otro vector tenemos el nivel de afinidad para cada candidato que será entre 0 y 1. La valoración de cada candidato será la suma del cuadrado de la puntuación de cada prueba multiplicado por el nivel de afinidad: $(prueba1^2+prueba2^2)*afinidad$."

Vamos a calcular la valoración de cada candidato.

#Generaremos (emulando los resultados de cada prueba) 30 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 0 y máximo 10
prueba1<-runif(30,min=0,max=10)
names(prueba1)<-1:30
print("Resultados de la primera prueba:")
prueba1
prueba2<-runif(30,min=0,max=10)
names(prueba2)<-1:30
print("Resultados de la segunda prueba:")
prueba2
afinidad<-runif(30)
names(afinidad)<-1:30
print("Nivel de afinidad:")
afinidad
#Cálculo de valoración para los candidatos
print("Valoración candidatos:")
valoracion_candidatos<-(prueba1^2+prueba2^2)*afinidad
valoracion_candidatos

Operaciones relacionales y lógicas

Las operaciones relacionales y lógicas también están vectorizadas en R. La aplicación de este tipo de operaciones sobre vectores amplía enormemente el abanico de posibilidades para la operación con vectores. Veamos ejemplos del uso de los diferentes operadores relacionales y lógicos con vectores:

Operaciones relacionales

"Disponemos de dos vectores que contienen la edad de un conjunto de veinte parejas. El primer vector contiene la edad del primer miembro de la pareja y el segundo vector contiene la edad del segundo miembro. Vamos a utilizar los operadores relacionales para comprobar lo siguiente:

Ejercicio parejas: misma edad

Para comprobar si ambos miembros de la pareja tienen la misma edad podemos utilizar el operador relacional igual que (==) entre ambos vectores (comparador elemento a elemento). Para obtener las parejas cuyos miembros tienen una edad diferente usaríamos por tanto el operador no es igual que (!=).

#Primer miembro: Generaremos (emulando las edades de cada miembro) 20 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 18 y máximo 100
pareja1<-as.integer(runif(20,min=18,max=100))
names(pareja1)<-1:20
print("Edades del primer miembro de cada pareja:")
pareja1
#Segundo miembro: Generaremos (emulando las edades de cada miembro) 20 valores enteros aleatorios siguiendo una distribución uniforme con mínimo -6 y máximo 6 usando como punto de partida la edad del primer miembro. 
pareja2<-pareja1+as.integer(runif(20,min=-6,max=6))
names(pareja2)<-1:20
print("Edades del segundo miembro de cada pareja:")
pareja2
#Parejas con miembros de la misma edad
misma_edad<-pareja1==pareja2
names(misma_edad)<-1:20
misma_edad<-misma_edad[misma_edad==TRUE]
print("Parejas con miembros de la misma edad:")
misma_edad
#Las parejas con miembros de diferente edad serán el resto
diferente_edad<-pareja1!=pareja2
diferente_edad<-diferente_edad[diferente_edad==TRUE]
print("Parejas con miembros de diferente edad:")
diferente_edad

Ejercicio parejas: primer miembro menor

Para comprobar si el primer miembro de la pareja es menor que el segundo miembro podemos utilizar el operador relacional menor que (<) entre ambos vectores (comparador elemento a elemento). Para obtener las parejas cuyos miembros tienen una edad mayor o igual, usaríamos el operador mayor o igual que (>=).

#Primer miembro: Generaremos (emulando las edades de cada miembro) 20 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 18 y máximo 100
pareja1<-as.integer(runif(20,min=18,max=100))
names(pareja1)<-1:20
print("Edades del primer miembro de cada pareja:")
pareja1
#Segundo miembro: Generaremos (emulando las edades de cada miembro) 20 valores enteros aleatorios siguiendo una distribución uniforme con mínimo -6 y máximo 6 usando como punto de partida la edad del primer miembro. 
pareja2<-pareja1+as.integer(runif(20,min=-6,max=6))
names(pareja2)<-1:20
print("Edades del segundo miembro de cada pareja:")
pareja2
#Parejas con primer miembro de menor edad
print("Parejas con primer miembro de menor edad")
(pareja1<pareja2)[(pareja1<pareja2)==TRUE]
names((pareja1<pareja2)[(pareja1<pareja2)==TRUE])
#Parejas con primer miembro de igual o mayor edad
print("Parejas con primer miembro de igual o mayor edad")
(pareja1>=pareja2)[(pareja1>=pareja2)==TRUE]

Se debe tener en cuenta que el resultado de aplicar un operador relacional entre dos vectores es otro vector. De ahí que se pueda usar el operador [] sobre una expresión relacional entre dos vectores.

Lo mismo ocurre al comparar la expresión relacional entre dos vectores con un valor lógico (se compara elemento a elemento).

Incluso se puede aplicar la función para extraer los nombres de ese vector correspondiente a la expresión relacional entre vectores.

Ejercicio parejas: edad tope

Para verificar en cuántas parejas tiene el primer miembro una edad de al menos 30 años (mayor o igual a 30 años) podemos utilizar el operador mayor o igual que (>=). De esta forma compararíamos el vector del primer miembro de las parejas con el vector unitario que contenga esta edad. En caso de tener que determinar las parejas cuyo primer miembro tiene como edad máxima este valor se usaría, por tanto, el operador mayor que (<=).

#Primer miembro: Generaremos (emulando las edades de cada miembro) 20 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 18 y máximo 100
pareja1<-as.integer(runif(20,min=18,max=100))
names(pareja1)<-1:20
print("Edades del primer miembro de cada pareja:")
pareja1
#Segundo miembro: Generaremos (emulando las edades de cada miembro) 20 valores enteros aleatorios siguiendo una distribución uniforme con mínimo -6 y máximo 6 usando como punto de partida la edad del primer miembro. 
pareja2<-pareja1+as.integer(runif(20,min=-6,max=6))
names(pareja2)<-1:20
print("Edades del segundo miembro de cada pareja:")
pareja2
#Parejas con primer miembro de edad al menos 30
print("Parejas con primer miembro de edad al menos 30")
primer_miembro_min30<-pareja1>=30
primer_miembro_min30[primer_miembro_min30==TRUE]
#Parejas con primer miembro de edad máxima 30
print("Parejas con primer miembro de edad máxima 30")
primer_miembro_max30<-pareja1<=30
primer_miembro_max30[primer_miembro_max30==TRUE]

Veamos a continuación el uso de los operadores lógicos junto con operadores relacionales en vectores.

Operaciones lógicas

"Disponemos de dos vectores que contienen para un conjunto de 25 personas si están o no casados y si tienen hijos. El primer vector es un vector lógico que indica para cada persona si está casado (TRUE) o si no lo está (FALSE). El segundo vector indica para cada persona si tiene hijos (TRUE) o no (FALSE). Existe además un tercer vector que indicará para cada persona el número de hijos que tiene. Vamos a utilizar los operadores lógicos para comprobar lo siguiente:

Ejercicio: casados con hijos

Para comprobar si una persona cumple ambos criterios (casado y con hijos) podemos utilizar el operador lógico and (&: comparador elemento a elemento) entre ambos vectores. Para obtener las personas que no cumplen el segundo criterio basta con hacer uso del operador not (!) sobre la segundo operando de la operación lógica anterior.

#Casados: Generaremos (emulando si cada persona está o no casada) 25 valores lógicos aleatorios.
casados<-sample(c(TRUE,FALSE),size=25,replace=TRUE)
names(casados)<-1:25
print("Casados:")
casados
#Tienen hijos: Generaremos (emulando si cada persona tiene o no hijos) 25 valores lógicos aleatorios. 
tienen_hijos<-sample(c(TRUE,FALSE),size=25,replace=TRUE)
names(tienen_hijos)<-1:25
print("Tienen hijos:")
tienen_hijos
#Personas casadas y con hijos
casados_con_hijos<-casados&tienen_hijos
casados_con_hijos<-casados_con_hijos[casados_con_hijos==TRUE]
print("Casados con hijos:")
names(casados_con_hijos)
#Resto de personas: no son casados con hijos
casados_sin_hijos<-casados&(!tienen_hijos)
casados_sin_hijos<-casados_sin_hijos[casados_sin_hijos==TRUE]
print("Casados sin hijos:")
names(casados_sin_hijos)

Ambos vectores de valores (casados y tienen_hijos) han sido generados aleatoriamente con la función sample ya descrita en la sección de este tutorial de Creación e inicialización.

Ejercicio: sin casarse o sin hijos

Para comprobar si una persona no cumple alguno de los dos criterios (no casado o no tiene hijos) podemos utilizar el operador lógico or (|: comparador elemento a elemento) entre ambos vectores. Para obtener las personas que no cumplen el criterio sin casarse o sin hijos bastaría comprobar que las únicas personas que no lo cumplen son las que están casadas y tienen hijos: respuesta a la primera parte del ejercicio anterior.

#Casados: Generaremos (emulando si cada persona está o no casada) 25 valores lógicos aleatorios.
casados<-sample(c(TRUE,FALSE),size=25,replace=TRUE)
names(casados)<-1:25
print("Casados:")
casados
#Tienen hijos: Generaremos (emulando si cada persona tiene o no hijos) 25 valores lógicos aleatorios. 
tienen_hijos<-sample(c(TRUE,FALSE),size=25,replace=TRUE)
names(tienen_hijos)<-1:25
print("Tienen hijos:")
tienen_hijos
#Personas no casadas o sin hijos
nocas_o_sinhij<-(!casados)|(!tienen_hijos)
nocas_o_sinhij<-nocas_o_sinhij[nocas_o_sinhij==TRUE]
print("No casados o sin hijos:")
nocas_o_sinhij

Ejercicio: casado y con más de un hijo

Para comprobar si una persona cumple los dos criterios ya hemos visto que habría que hacer uso del operador lógico and (&). Así mismo, para la comprobación del número de hijos basta usar el operador relacional mayor que (>).

#Casados: Generaremos (emulando si cada persona está o no casada) 25 valores lógicos aleatorios.
casados<-sample(c(TRUE,FALSE),size=25,replace=TRUE)
names(casados)<-1:25
print("Casados:")
casados
#Tienen hijos: Generaremos (emulando si cada persona tiene o no hijos) 25 valores lógicos aleatorios. 
tienen_hijos<-sample(c(TRUE,FALSE),size=25,replace=TRUE)
names(tienen_hijos)<-1:25
print("Tienen hijos:")
tienen_hijos
#Numero hijos: Generaremos (emulando el numero de hijos que tiene cada persona con hijos) 25 valores con una distribución uniforme de mínimo 1 y máximo 5. 
numero_hijos<-as.integer(tienen_hijos)
names(numero_hijos)<-1:25
numero_hijos<-numero_hijos*as.integer(runif(25,min=1,max=5))
print("Numero hijos:")
numero_hijos
#Personas casadas con más de un hijo
casadas_masdeuno<-casados&(numero_hijos>1)
casadas_masdeuno<-casadas_masdeuno[casadas_masdeuno==TRUE]
print("Casados con más de un hijo:")
names(casadas_masdeuno)

Hemos de destacar que la generación del número de hijos se ha realizado inicializando como entero el vector del número de hijos (numero_hijos) desde el vector lógico que indica si tienen o no hijos (tienen_hijos). De esta forma para los que no tienen hijos la inicialización del número de hijos ha sido 0. Para inicializar el número de hijos para aquellos que tienen hijos basta con multiplicar el valor 1 del vector numero_hijos por el aleatorio generado que determina el número de hijos.

Para comprobar los criterios del ejercicio la operación es muy sencilla mediante el enlace del operadores relacionales con operadores lógicos.

Funciones predefinidas

Muchas de las funciones predefinidas de R son aplicables sobre vectores. En particular, de las ya conocidas (tutorial Funciones predefinidas) ejemplificaremos las funciones que permiten la manipulación de cadenas de caracteres, matemáticas y estadística.

No obstante, comenzaremos presentando un conjunto de funciones predefinidas útiles con vectores, entre las que encontramos por ejemplo la representación gráfica básica en R en la que el tipo de dato vector juega un papel fundamental.

Tras ello, veremos algunos ejemplos en los que se utilizan los diferentes tipos de funciones predefinidas indicados con vectores.

Funciones útiles con vectores

Comenzaremos presentando un conjunto de funciones útiles con vectores:

Función | Descripción | :--|:--| min() | mínimo de un vector max()| máximo de un vector range()| rango de valores: mínimo y máximo which.min() | posición del valor mínimo which.max() | posición del valor máximo length()| longitud de un vector sum() | suma de todos los elementos prod()| producto de todos los elementos cumsum()| sumas acumuladas diff()| diferencias sucesivas rev() | inversión de un vector sort()| ordena un vector unique()| elimina duplicados de un vector plot() | representación gráfica

Comenzaremos mostrando varios ejemplos con las funciones relacionadas con el mínimo y máximo de un vector en función del tipo de datos albergado por el vector (numérico o cadena de caracteres).

# Generamos 20 valores enteros del intervalo [0,100]
v_num<-sample(0:100,20,replace=TRUE)
names(v_num)<-1:length(v_num)
print("Valores enteros:")
v_num
cat("Mínimo en posición",which.min(v_num))
min(v_num)
cat("Máximo en posición",which.max(v_num))
max(v_num)
print("Rango")
range(v_num)
#Partimos ahora de un vector de cadenas de caracteres
v_char<-c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
names(v_char)<-1:length(v_char)
print("Valores cadena:")
v_char
print("Mínimo")
min(v_char)
print("Máximo")
max(v_char)
print("Rango")
range(v_char)

Podemos comprobar como el mínimo y máximo para las cadenas de caracteres viene determinado por orden alfabético. Por otra parte, las funciones which.min() y which.max() no se aplican a vectores de cadenas de caracteres.

Continuaremos ahora presentando varios ejemplos de las funciones que permiten sumar (sumatorio) y multiplicar (productorio) todos los elementos de un vector. Añadiremos también ejemplos del uso de las funciones de suma acumulada y diferencias sucesivas. Podremos comprobar la diferencia entre tipo de datos numérico y tipo de datos lógico (coercionado implícitamente a entero).

# Generamos 10 valores enteros del intervalo [1,5]
v_num<-sample(1:5,10,replace=TRUE)
names(v_num)<-1:length(v_num)
print("Valores enteros:")
v_num
print("Sumatorio")
sum(v_num)
print("Productorio")
prod(v_num)
print("Suma acumulada")
cumsum(v_num)
print("Diferencias sucesivas")
diff(v_num)
# Generamos 20 valores lógicos
v_log<-sample(c(TRUE,FALSE),20,replace=TRUE)
names(v_log)<-1:length(v_log)
print("Valores lógicos:")
v_log
print("Sumatorio")
sum(v_log)
print("Productorio")
prod(v_log)
print("Suma acumulada")
cumsum(v_log)
print("Diferencias sucesivas")
diff(v_log)

Se puede comprobar como diff() calcula el vector formado por las diferencias sucesivas entre entradas del vector original y cumsum() calcula el vector formado por las sumas acumuladas de las entradas del vector original: cada entrada del vector resultante es la suma de las entradas del vector de partida hasta la posición correspondiente.

Finalmente, presentaremos ejemplos del uso de las funciones de ordenación, eliminación de duplicados (repetidos) e inversión de vectores de diferentes tipos de datos.

# Generamos 10 valores enteros del intervalo [1,5]
v_num<-sample(1:5,10,replace=TRUE)
names(v_num)<-1:length(v_num)
print("Valores enteros:")
v_num
print("Inversión:")
rev(v_num)
print("Ordenación ascendente:")
sort(v_num)
print("Eliminación repetidos:")
unique(v_num)
# Generamos 10 valores lógicos
v_log<-sample(c(TRUE,FALSE),10,replace=TRUE)
names(v_log)<-1:length(v_log)
print("Valores lógicos:")
v_log
print("Inversión:")
rev(v_log)
print("Ordenación descendente:")
sort(v_log,decreasing=TRUE)
print("Eliminación repetidos:")
unique(v_log)
#Partimos ahora de un vector de cadenas de caracteres
v_char<-c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre")
names(v_char)<-1:length(v_char)
print("Valores cadena:")
v_char
print("Inversión:")
rev(v_char)
print("Ordenación ascendente:")
sort(v_char)
print("Eliminación repetidos:")
unique(v_char)

Cabe destacar que se puede llevar a cabo orden ascendente y descendente, siendo el ascendente el utilizado por defecto y el descendente determinado por el argumento decreasing. Obviamente, el orden es diferente de un tipo de datos a otro, siendo el tipo de datos lógico coercionado implícitamente a entero.

Representación gráfica básica

En R, la función plot() es usada de manera general para crear gráficos. Esta función tiene un comportamiento especial, pues dependiendo del tipo de dato que le demos como argumento, generará diferentes tipos de gráfica. Además, para cada tipo de gráfico, podremos ajustar diferentes parámetros que controlan su aspecto, dentro de esta misma función.

La función plot() siempre pide un argumento x, que corresponde al eje X de una gráfica. El argumento x requiere un vector y si no especificamos este argumento, obtendremos un error y no se creará una gráfica.

El resto de los argumentos de plot() son opcionales, pero el más importante es y. Este argumento también requiere un vector y corresponde al eje Y de nuestra gráfica.

En este caso, usaremos la función plot() para diagramas de dispersión, aunque se puede utilizar para multitud de gráficos diferentes en función de los tipos de datos y argumentos proporcionados como entrada.

Cuando llamamos a la función plot() o alguna otra similar, R abre una ventana mostrando ese gráfico. Si estamos usando RStudio, el gráfico aparece en el panel Plot. Si llamamos de nuevo a la función plot(), el gráfico generado más reciente reemplazará al más antiguo y en RStudio se creará una nueva pestaña en en el planel Plot. El gráfico reemplazado se perderá.

Veamos un ejemplo de uso de la función plot():

# Vamos a representar gráficamente x=y de 0 a 10
X=0:10
Y=0:10
plot(X,Y,main="Gráfico de ejemplo")

Manipulación de cadenas

A continuación veremos un conjunto de ejemplos de manipulación de cadenas de caracteres en vectores:

Función | Descripción | :--|:--| nchar() | número de caracteres tolower()| conversión a minúsculas toupper()| conversión a mayúsculas casefold()| conversión a mayúsculas o minúsculas chartr() | traducción de caracteres abbreviate()| abreviación substr() | extracción o reemplazamiento de caracteres

Comenzamos con varios ejemplos de manipulación básica de cadenas de caracteres.

# Partimos de un vector de cadenas de caracteres
peliculas_mas_taquilleras<-c("Avatar","Avengers: Endgame","Titanic","Star Wars: Episodio VII - El despertar de la Fuerza","Avengers: Infinity War", "Jurassic World", "El rey leon","The Avengers","Furious 7","Frozen II")
peliculas_mas_taquilleras
#Ponemos todas las cadenas en minúscula
print("Películas en minúscula")
tolower(peliculas_mas_taquilleras)
#Ponemos todas las cadenas en mayúscula
print("Películas en mayúscula")
toupper(peliculas_mas_taquilleras)
#Seleccionamos las cadenas más cortas
longitud_titulo_corto<-7
cat("Películas con título corto (<=",longitud_titulo_corto,")")
peliculas_titulo_corto<-peliculas_mas_taquilleras[nchar(peliculas_mas_taquilleras)<=7]
peliculas_titulo_corto
#Cambiamos las cadenas a mayúscula y sustituimos las vocales por _
print("Adivina las películas:")
peliculas_a_adivinar<-casefold(peliculas_mas_taquilleras,upper=TRUE)
peliculas_a_adivinar<-chartr("A","_",peliculas_a_adivinar)
peliculas_a_adivinar<-chartr("E","_",peliculas_a_adivinar)
peliculas_a_adivinar<-chartr("I","_",peliculas_a_adivinar)
peliculas_a_adivinar<-chartr("O","_",peliculas_a_adivinar)
peliculas_a_adivinar<-chartr("U","_",peliculas_a_adivinar)
peliculas_a_adivinar
#Obtenemos la abreviatura de las cadenas
print("Películas abreviadas:")
peliculas_abrev<-abbreviate(peliculas_mas_taquilleras)
peliculas_abrev
#Primeros caracteres de cada película
print("¿Puedes adivinar la película por el principio del título?")
longitud_principio_titulo<-5
principio_titulo<-substr(peliculas_mas_taquilleras,1,longitud_principio_titulo)
principio_titulo

Puedes verificar cómo las diferentes funciones de manipulación de cadenas de caracteres trabajan elemento a elemento y producen su efecto en cada uno de ellos.

Función | Descripción | :--|:--| print() | visualización genérica noquote()| visualización sin comillas cat()| concatenación paste()| concatenación (vector de cadenas) format()| formatos especiales sprintf()| visualización según el estilo del lenguaje Continuaremos con varios ejemplos de visualización y formateo de cadenas de caracteres.

# Partimos de un vector de cadenas de caracteres
peliculas_mas_taquilleras<-c("Avatar","Avengers: Endgame","Titanic","Star Wars: Episodio VII - El despertar de la Fuerza","Avengers: Infinity War", "Jurassic World", "El rey leon","The Avengers","Furious 7","Frozen II")
#Visualizamos normalmente
print(peliculas_mas_taquilleras)
#Visualizamos sin comillas
noquote(peliculas_mas_taquilleras)
#Lista de películas (concatenación con separador)
cat(peliculas_mas_taquilleras,sep="|||")
paste("PELICULA",1:length(peliculas_mas_taquilleras),":",peliculas_mas_taquilleras,sep="_")
#Formato de lista de películas: todas las cadenas con la misma longitud y justificación.
format(peliculas_mas_taquilleras,justify="centre")
#Lista de películas (concatenación con cadena)
sprintf("Película %d: %s",1:length(peliculas_mas_taquilleras),peliculas_mas_taquilleras)

La función paste() une todos los vectores de caracteres que se le proporcionan y construye una sola cadena de caracteres. También admite argumentos numéricos, que convierte automáticamente (coerción implícita) en cadenas de caracteres. En su forma predeterminada, en la cadena generada, cada argumento original se separa del siguiente por un espacio en blanco, aunque ello puede cambiarse utilizando el argumento sep=cadena, que sustituye el espacio en blanco por cadena, la cual podría ser incluso vacía.

Matemáticas

A continuación veremos un conjunto de ejemplos de aplicación de algunas funciones matemáticas en vectores:

De signo

Disponemos de dos vectores que contienen la edad de los miembros de veinte parejas diferentes. Deseamos calcular la diferencia de edades y las parejas cuyo primer miembro es menor al segundo de ellos.

# Partimos de dos vectores que contienen la edad de los miembros de 20 parejas diferentes.
#Primer miembro: Generaremos (emulando las edades de cada miembro) 20 valores enteros aleatorios siguiendo una distribución uniforme con mínimo 18 y máximo 100
pareja1<-as.integer(runif(20,min=18,max=100))
names(pareja1)<-1:20
print("Edades del primer miembro de cada pareja:")
pareja1
#Segundo miembro: Generaremos (emulando las edades de cada miembro) 20 valores enteros aleatorios siguiendo una distribución uniforme con mínimo -6 y máximo 6 usando como punto de partida la edad del primer miembro. 
pareja2<-pareja1+as.integer(runif(20,min=-6,max=6))
names(pareja2)<-1:20
print("Edades del segundo miembro de cada pareja:")
pareja2
#Vamos a calcular la diferencia de edad entre los miembros de cada pareja
diferencia_edad<-abs(pareja1-pareja2)
print("Diferencia de edad:")
diferencia_edad
#Vamos a calcular las parejas en las que el primer miembro es menor que el segundo miembro
names(pareja1)<-NULL
names(pareja2)<-NULL
signo_diferencia<-sign(pareja1-pareja2)
print("Parejas primer miembro menor que el segundo:")
which(signo_diferencia==-1)

Trigonométricas, Hiperbólicas

Vamos a generar en un vector una muestra correspondiente al intervalo $[0,2\pi]$ y vamos a representar gráficamente la aplicación a este intervalo de varias funciones trigonométricas e hiperbólicas.

#Partimos de una muestra de 50 valores del intervalo [0,2pi]. Generaremos 50 valores numéricos siguiendo una distribución uniforme con mínimo 0 y máximo 2pi
angulo<-runif(50,min=0,max=2*pi)
plot(angulo,sin(angulo),main="Función seno")
plot(angulo,cos(angulo),main="Función coseno")
plot(angulo,tan(angulo),main="Función tangente")
plot(angulo,sinh(angulo),main="Función seno hiperbólico")
plot(angulo,cosh(angulo),main="Función coseno hiperbólico")
plot(angulo,tanh(angulo),main="Función tangente hiperbólica")

De redondeo

Vamos a comprobar la diferencia entre la aplicación de las funciones de redondeo usando como argumento un vector de valores aleatorios que generaremos utilizando la distribución uniforme.

#Partimos de una muestra de 20 valores del intervalo [-10,10]. Generaremos 20 valores numéricos siguiendo una distribución uniforme con mínimo -10 y máximo 10
valores<-runif(20,min=0,max=2*pi)
names(valores)<-1:20
print("Valores:")
valores
print("Redondeo:")
round(valores)
print("Primer entero mayor:")
ceiling(valores)
print("Primer entero menor:")
floor(valores)
print("Truncamiento:")
trunc(valores)

Exponenciales / Logarítmicas

Vamos a representar gráficamente la función exponencial y dos funciones logarítmicas utilizando las funciones matemáticas predefinidas de R. Para ello generaremos previamente una muestra representativa en un vector.

#Partimos de una muestra de 100 valores del intervalo [0,100]. Generaremos 100 valores numéricos siguiendo una distribución uniforme con mínimo 0 y máximo 100.
muestra<-runif(100,min=0,max=100)
plot(muestra,log10(muestra),main="Logaritmo en base 10")
plot(muestra,log2(muestra),main="Logaritmo en base 2")
plot(muestra,exp(muestra),main="Exponencial")

Estadística

Vamos a ejemplificar el uso de las funciones predefinidas estadísticas en R, en las que el tipo de datos vector juega un papel fundamental.

Las funciones estadísticas básicas se pueden aplicar directamente sobre el tipo de datos vector. Estas funciones son, entre otras, las que realizan el cálculo de la media, la mediana, los cuartiles, la varianza y la desviación típica. Algunas de las funciones más importantes de R orientadas a Estadística básica son las siguientes:

Función | Descripción | :--|:--| mean()| Media var()| Cuasi varianza sd()| Desviación típica median() | Mediana quantile() | Cuantiles fivenum() | Cuantiles

Veamos un ejemplo del uso de las funciones predefinidas de Estadística básica en R:

#Partimos de una muestra de 20 valores del intervalo [0,100]. Generaremos 20 valores numéricos siguiendo una distribución uniforme con mínimo 0 y máximo 100.
muestra<-runif(20,min=0,max=100)
names(muestra)<-1:20
print("Muestra:")
muestra
print("Media")
mean(muestra)
print("Varianza")
var(muestra)
print("Desviación típica")
sd(muestra)
print("Mediana")
median(muestra)
print("Cuartiles")
quantile(muestra)
fivenum(muestra)

En el ejemplo podemos comprobar la diferencia en los resultados entre las funciones que devuelven los cuartiles.

Conclusión

La utilidad del tipo de datos vector es fundamental para la gestión de conjuntos de datos de un mismo tipo de datos simple. En este tutorial has podido experimentar cómo crear, inicializar, extraer datos y operar con vectores, así como, conocer las funciones predefinidas que dispone R para trabajar con este tipo de datos compuesto.

Felicidades, has completado el tutorial de Vectores. Puedes continuar con el siguiente tutorial: Factores.



eyeguas/fundamentosr documentation built on March 31, 2021, 5:20 p.m.