library(learnr) knitr::opts_chunk$set(echo = FALSE)
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.
El objetivo de aprendizaje del presente tutorial es el siguiente:
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:
typeof()).length()).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.
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.
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
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.
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.
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.
:: permite generar series numéricas correspondientes al intervalo ascendente (incrementos de +1) o descendente (decrementos de -1) cuyos extremos son proporcionados a izquierda y derecha del operador. Los vectores creados pueden corresponder a enteros o double.#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)
seq(): permite crear series numéricas especificando únicamente el final de la serie (siendo 1 el principio por defecto), el principio y el final, e incluso el incremento o decremento (argumento by, para no aplicar la unidad por defecto). El funcionamiento es muy similar al operador : con la posibilidad de incorporar el parámetro del incremento o decremento.#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.
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:
número de repeticiones, consistente en el número de veces que se repite el vector proporcionado para generar el nuevo vector. Se incluye proporcionando el número que lo representa junto al vector de repetición.
each, número de veces que se repetirá cada elemento del vector de repetición para crear el nuevo vector.
vector de número de repeticiones, consistente en un vector de la misma longitud que el vector de repetición que indica en cada posición el número de veces que se repetirá el elemento de su misma posición en el vector de repetición.
len, determina la longitud deseada para el vector generado, por lo que se realizará repetición tantas veces como sea necesario hasta completar dicha longitud.
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))
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.
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.
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).
rnorm(): genera un vector de valores aleatorios con el número de elementos indicado por longitud. Por defecto se asume que la media de esos valores será cero y la desviación típica la unidad, pero podemos usar los parámetros opcionales mean, proporcionando la media, y sd, proporcionando la desviación típica, para ajustar la distribución: rnorm(longitud,mean=media,sd=desviacion).
runif(): Genera un vector de valores aleatorios con el número de elementos indicado por longitud. Por defecto se asume que el valor mínimo será cero y el máximo la unidad, pero podemos usar los parámetros opcionales min, proporcionando el mínimo, y max, proporcionando el máximo, para ajustar la distribución: runif(longitud,min=minimo,max=maximo).
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
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)]
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.
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]
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:
+):"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).
-):"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:
Un resultado superior a cinco en la primera prueba y
Un resultado en la segunda prueba al menos un punto superior a la primera prueba."
#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.
*):"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.
/):"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.
%/%):"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
%%):"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.
^):"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
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:
"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:
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
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.
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.
"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:
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.
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
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.
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.
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.
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")
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.
A continuación veremos un conjunto de ejemplos de aplicación de algunas funciones matemáticas en vectores:
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)
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")
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)
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")
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.
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.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.