jueves, 6 de abril de 2017

Introducción al R

es un entorno de programación

En esta página se hará una brevísima introducción al lenguaje R como entorno de programación. Sin pretender que esto sea una guía completa, se exponen los conceptos necesarios para poder utilizar este lenguaje como complemento instruccional a los cursos de estadística y probabilidades de la Universidad Nacional Abierta.

Un entorno de programación es una aplicación que permite crear, ejecutar y depurar programas. Los programas son esencialmente secuencias de instrucciones que le indican al computador de manera muy precisa lo que este debe hacer. Estas instrucciones se especifican en algo llamado lenguaje de programación y cada lenguaje de programación tiene su "gramática" particular y sus reglas de sintaxis. R es un lenguaje de programación interpretado, lo cual quiere decir que el programador ingresa instrucciones a través de una consola y el interprete de R va procesando cada instrucción a medida que esta se ingresa y va dando la salida respectiva a cada instrucción de forma secuencial.

En vez de escribir las instrucciones una por una en la consola, podemos indicar la secuencia de instrucciones que queremos ejecutar a través de un archivo de texto (cómo los que creamos cuando usamos el bloc de notas). Esto es lo que se conoce como un script. Un script es una especie de programa que necesita siempre de un interprete para poderse ejecutar. En esta guía, aprenderemos a crear nuestros propios scripts.

Primer contacto con el intérprete

Antes de comenzar, suponemos que ya ha instalado el lenguaje R en su computadora o tiene acceso a un RWeb server a través del navegador. Según vaya a utilizar uno u otro tipo de configuración, ingresaremos los comandos al interprete R mediante la cónsola en windows o el recuadro de comandos del RWeb server. Para comenzar, ingrese la siguiente expresión en la consola, seguida de la tecla [ENTER]:

2+2

El interprete R evaluará esta expresión y devolverá el resultado:

[1] 4

Más adelante se explicará el significado de "[1]" que precede al resultado de la expresión "2+2" que usted ingresó. Por ahora, lo importante es resaltar que todo comando o expresión ingresada en la consola es evaluada por el interprete y siempre devuelve algo, aunque ese "algo" que devuelve no siempre sea visible. También es importante resaltar que todo lenguaje de programación (el R es un lenguaje de programación) tiene sus reglas de sintaxis muy estrictas. Por ejemplo, si ingresamos esto en la consola:

suma 2 más 2

El interprete R nos devolvería el siguiente error:

Error: inesperado constante numérica en "suma 2"

Lo cual es una forma de indicar que "suma 2 más 2" no es una expresión o comando válido en R y que por lo tanto el interprete no lo puede procesar porque no lo "entiende". Efectivamente, iremos poco a poco aprendiendo como formular comandos y expresiones correctamente en lenguaje R a través de los ejemplos en esta página. Por lo pronto debe recordar que debe ingresar los comandos en la consola estrictamente como aparecen en los ejemplos- no cambie letras mayúsculas por minúsculas ni otras cosas por el estilo. En caso de violentar las reglas de sintaxis de R, el interprete devolverá un mensaje de error como el de arriba y no podrá ejecutar exitosamente el resto de las instrucciones en su script.

Tipos de datos fundamentales en y algunas funciones sobre ellos

R, siendo un lenguaje de programación de propósito general, provee ciertos tipos de datos fundamentales de uso común y a partir de los cuales se construyen estructuras de datos más complejas. Uno de estos tipos de datos fundamentales es el numérico, como en la expresión "2+2" en el ejemplo de arriba. Escriba las siguientes expresiones en la consola:

(2+2)/2
2/2+2
1-3*5
2^5+1
sqrt(3)
log(3)

Las primeras dos expresiones son dos respuestas a la adivinanza "¿Cuanto es la mitad de dos más dos?". En realidad, la pimera expresión se corresponde a "la mitad de dos más dos" y la segunda a "la mitad de dos, más dos". En todo caso, obsérvese cómo los parentesis establecen el orden de precedencia en los cálculos. En las siguientes dos expresiones - "1-3*5" y "2^5+1" - se observa que el orden de precedencia de los operadores aritméticos es el siguiente:

  • Primero, se calculan las potencias. El operador "^" eleva la expresión a la izquierda a la potencia indicada a la derecha). Así por ejemplo, "2^5" se corresponde a "dos elevado a la quinta potencia", que es igual a 32.
  • Luego se calculan las multiplicaciones y las divisiones, indicadas mediante los operadores "*" y "/", respectivamente.
  • Por último, se evalúan las sumas y restas. El operador "-" también denota el negativo de un número.

En las últimas dos expresiones del ejemplo arriba se introduce lo que se conoce en el argot computacional como funciones. Las funciones toman los valores indicados entre paréntesis (estos son los argumentos de la función), operan sobre ellos de alguna forma y devuelven un resultado. Así por ejemplo, sqrt devuelve la raíz cuadrada de su argumento (en este caso, sqrt(3) es la raiz cuadrada de 3) y log es el logaritmo natural de una expresión (en este ejemplo, log(3) es el logaritmo natural de 3, que es un poco mayor que 1). Existen muchas funciones en R e inclusive, es posible definir uno mismo sus propias funciones.

Otra característica importante en este ejemplo de expresiones numéricas es el uso de "." y no de "," como el punto decimal.

Otro tipo de dato fundamental importante en R son las cadenas de caracteres alfanuméricos, que se usan para representar información textual. Toda cadena se indica encerrándola entre comillas (""), como en los siguientes ejemplos:

"esto es una cadena que contiene números también: 1,2 y 3"
[1] "esto es una cadena que contiene números también: 1,2 y 3"
paste("pedro","juan","jose")
[1] "pedro juan jose"
cat("El numero",1^3+12^3,"y",9^3+10^3,"es el menor entero que se puede expresar como la suma de dos cubos de dos formas diferentes.\n")
El numero 1729 y 1729 es el menor entero que se puede expresar como la suma de dos cubos de dos formas diferentes.

En los ejemplos de arriba, la función paste toma sus argumentos (que pueden ser varios y de distintos tipos), los concatena y devuelve la concatenación como una sola cadena de caracteres. La función cat permite enviar salidas a la consola.

Por último, el otro tipo de dato fundamental importante es el lógico o booleano, el cual puede asumir solamente uno de dos valores: verdadero o falso. La constante utilizada para designar verdadero es TRUE. El valor de falso se designa por la constante FALSE. Es importante recalcar que estas constantes se escriben en R con todas sus letras en mayúsculas, como en los siguientes ejemplos:

2>-3
[1] TRUE
2+2==5
[1] FALSE
!(TRUE | FALSE) & TRUE
[1] FALSE

El primer ejemplo muestra el uso de los operadores relacionales. En efecto, 2 es mayor que -3 y por lo tanto la expresión 2>-3 devuelve TRUE. En la segunda expresión se intenta averiguar el valor lógico de la proposición "dos más dos es igual a cinco", la cual es obviamente falsa. La tercera expresión muestra el uso de otros operadores lógicos: ! es el operador de negación, | es el operador de disyunción (ó lógico) e & es el operador de conjunción (y lógico). Nótese el uso de los paréntesis para indicar el orden de precedencia en los cálculos con expresiones lógicas.

Las expresiones lógicas se utilizan en R más que todo para controlar el flujo de ejecución de instrucciones en un script (realizar tal acción si se verifica tal condición). Como veremos más adelante, las expresiones lógicas también se utilizan para selecionar ciertos elementos de un vector, lo cual se conoce como indexación, que es una característica muy particular de R.

Variables

En este punto, es necesario introducir uno de los conceptos más importantes de la programación: el concepto de variable. En los ejemplos precedentes hemos realizado cálculos mediante expresiones numericas, lógicas o de cadenas de texto, pero eventualmente, necesitaremos de algún mecanismo para "recordar" algunos resultados para proseguir con el procesamiento de datos. Para esto sirven las variables. En programación, podemos considerar la variable como una caja en la cual colocamos datos, con una etiqueta para identificar los datos contenidos dentro de esa caja (Fig. 1).

Fig. 1 - Esquema gráfico de una variable

En el argot computista, las etiquetas de estas "cajas" se conocen como identificadores. En el lenguaje R, los nombres de las variables (los identificadores) se designan mediante secuencias de letras, números y algunos caracteres especiales permitidos (. y ). Cuando se trabaja con variables, se deben nombrar de modo que los identificadores sean significativos para el programador, pero existen algunas restricciones:

  1. El identificador no debe comenzar por un carácter de piso (_), un número o un punto (.) seguido de un número. Así por ejemplo, resultado, A1, b2, .total.anterior son ejemplos de identificadores válidos.
  2. No utilice letras acentuadas u otros caracteres extraños en un identificador. Los únicos caracteres permitidos son las letras a-z sin acentos, en mayúsculas o en minúsculas, los digitos 0-9, el punto (.) y el piso (_).
  3. Evite el uso de identificadores asociados a funciones u objetos existentes en el lenguaje R, como por ejemplo paste, sqrt, pi y otros. Esto puede crear ambigüedad.
  4. Tenga presente que en lenguaje R, se distingue entre mayúsculas y minúsculas. Así, por ejemplo, jose y Jose son dos identificadores distintos.

Continuando con nuestra metáfora de las variables como cajas, necesitamos conocer el mecanísmo mediante el cual colocamos contenidos dentro de cajas. Esto se conoce como asignación de variables. En R, el operador de asignación es este: <- (un signo de "menor que" seguido de un guión). A continuación damos un ejemplo de asignación de variables:

mi_variable <- 1/2 mi_variable
[1] 0.5
mi_variable <- mi_variable*4 mi_variable
[1] 2

Vectores

Los vectores son un tipo de estructura de datos construida a partir de los tipos fundamentales de datos mencionados arriba. Un vector en R es algo parecido a los vectores matemáticos o a los arreglos unidimensionales en otros lenguajes de programación. Para nuestros efectos, vamos a considerar al vector en R como una secuencia (numerada) de datos del mismo tipo. Así, hablamos de vectores de valores numéricos, vectores de cadenas de caracteres o vectores lógicos. Para hacer referencia a los elementos de un vector, se indica el índice (numerico) del elemento encerrado entre corchetes ([]). El primer elemento es el número 1 y no el 0, como en otros lenguajes de programación. Cuando nos referimos a un o unos elementos particulares de un vector encerrando el o los índices entre corcehtes estamos realizando una indexación.

En R, los vectores se construyen mediante la función de concatenación c, como ilustramos en los siguientes ejemplos:

un.vector <- c(4,5,6)
un.vector
[1] 4 5 6
un.vector[2]
[1] 5
otro.vector <- c(7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26)
dos.vectores.en.uno <- c(1,2,3,un.vector,otro.vector)
dos.vectores.en.uno
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
[26] 26

En estos ejemplos podemos ver el uso del índice para referirse a un elemento particular del vector, como en un.vector[2]. Tambien podemos apreciar que la funcion de concatenación c permite concatenar elementos individuales y vectores. Si los elementos concatenados no son todos del mismo tipo, c intenta convertirlos al mismo tipo. Por otro lado, hemos podido construir dos.vectores.en.uno de una forma más directa, utilizando el generador de secuencias :, como en el siguiente ejemplo:

dos.vectores.en.uno <- 1:26
dos.vectores.en.uno
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
[26] 26

Podemos referirnos a varios sub-elementos de un vector colocando un vector de números entre los corchetes. Cómo la función c y el operador : generan tales vectores, podemos usarlos como mecanismo de indexación:

dos.vectores.en.uno[10:15]
[1] 10 11 12 13 14 15
dos.vectores.en.uno[c(1,2,3,10:15)]
[1]  1  2  3 10 11 12 13 14 15

A propósito, se puede explicar ahora la presencia de los numeros entre corchetes como el [1] y el [26] cuando visualizamos un vector- estos numeros entre corchetes hacen referencia a la posición del primer elemento en la fila dentro del vector. Al principio, cuando mencionamos los tipos de datos elementales y dabamos algunos ejemplos de expresiones sobre ellos, siempre aparecía el [1] a la izquierda del valor. En realidad, los datos elementales son simplemente vectores de longitud uno.

Uno de los atributos más importantes de un vector es su longitud, o la cantidad de elementos que lo constituyen. Este atributo se puede consultar mediante la función length:

vector1 <- 0:15
vector2 <- vector1[c(2,4,6,7,8,9)]
vector1
 [1]  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
vector2
[1] 1 3 5 6 7 8
cat("El vector 1 tiene ",length(vector1)," elementos y el vector 2 tiene ",length(vector2),".\n")
El vector 1 tiene 16 elementos y el vector 2 tiene 6.

R tiene toda clase de funciones que operan sobre vectores. La función sum devuelve la suma de todos los elementos de un vector, la función mean devuelve la media aritmética de un vector, que es simplemente equivalente a la expresión sum(x)/length(x) para cualquier vector x. Existen muchas más funciones sobre vectores, pero por lo pronto solo daremos ejemplos de estas:

sum(vector1)
[1] 120
mean(vector1)
[1] 7.5

Los operadores aritmeticos como +,-,* y /, entre otros, realizan las operaciones aritmeticas respectivas entre los elementos de cada vector, intentado generar un resultado vectorial de forma que su longitud sea consistente o tenga significado:

vector2 <- vector1*2
vector2
 [1]  0  2  4  6  8 10 12 14 16 18 20 22 24 26 28 30
vector1+vector2
 [1]  0  3  6  9 12 15 18 21 24 27 30 33 36 39 42 45

Por último, referirse a los elementos individuales de un vector que cumplan cierta condición lógica si en vez de colocar un vector como índice entre corchetes colocamos una expresión lógica vectorial, como por ejemplo en el siguiente ejemplo, el cual primero le asigna a la variable vector3 el mismo vector1 pero con signos alternados y luego se devuelve aquellos elementos de vector3 que sean negativos:

vector3 <- vector1*((-1)^vector1)
vector3
 [1]   0  -1   2  -3   4  -5   6  -7   8  -9  10 -11  12 -13  14 -15
vector3[vector3<0]
[1]  -1  -3  -5  -7  -9 -11 -13 -15

La última expresión - vector3[vector3<0] - se evalúa literalmente a "todos aquellos elementos de vector3 que sean menores a cero (o sea, negativos).

La importancia de los vectores para nosotros radica en que las muestras estadisticas son representadas por vectores, pues una muestra es una secuencia numerada de observaciones, después de todo.

Data frames

Cuando analizamos muestras con varias características o variables en conjunto, necesitamos representarlas de forma tabular, en donde cada columna de la tabla se corresponderá una variable o característica y cada fila se corresponderá a un renglón o elemento individual de la muestra. En R, estas estructuras de datos tabulares se conocen como data frames. A continuación colocamos un ejemplo de un data frame, mostrando los primeros renglones de la data a partir de la cual se realizan los trabajos prácticos del lapso 2012-1 en la U.N.A. (Nota: para tener acceso a la variable d20121, es necesario cargar la librería estUNA primero).

d20121
     X2    X3 X4    X5   X6  X7      X8  X9 X10
1  9.31  9.08  0 28.70 1.27   1  989.29 196  73
2 12.04 11.48  0 39.65 1.52 1.4 1566.00 212  73
3 12.32 10.28  1 39.94 1.51 1.8 2463.19 221  68
4 12.29  9.41  1 42.61 1.54 1.2 1530.94 198  88
5  6.17  5.28  1 21.71 1.23 1.4 1479.20 173  95
:     :     :  :     :    :   :       :   :   :

Observese en el ejemplo de data frame precedente que el primer renglón visualizado contiene los identificadores de las variables que componen el data frame- X2, X3, X4, X5, X6, X7, X8, X9 y X10. Cada una de estas variables son vectores de la misma longitud todos y dispuestos como columnas en el data frame. La primera columna que no tiene rótulo y que consta de los números consecutivos 1,2,3,... representa simplemente el índice de cada renglón o elemento respectivo dentro de los otros vectores columnas. Es posible referirse (o identificar, más bien) a estos vectores por separado, colocando el identificador del data frame seguido de un símbolo "$" y el identificador de la columna correspondiente. Así, por ejemplo:

d20121$X2
  [1]  9.31 12.04 12.32 12.29  6.17  8.20  9.32  8.45 10.20 10.30  6.84  8.77
 [13]  8.87 10.66  7.55  7.97  7.13 10.05 10.78 11.56  5.34 12.52  8.01  9.57
 [25]  6.82 11.58  6.03 12.98  9.48  9.14  6.54  9.72  9.69 10.21 10.70  7.44
    :     :     :     :     :     :     :     :     :     :     :     :     :
[133]  8.08  8.12 11.17  7.05  7.74  8.01  7.04  5.30 12.66 11.12  8.39  5.36
[145]  9.78  9.94 12.71  8.42 11.56  7.67

Cuando realizamos análisis estadísticos sobre los datos en un data frame, comunmente vamos a requerir hacer muchas referencias a estos vectores columnas en las expresiones de nuestro script. Para evitar el tedio de tener que prefijar siempre los vectores columnas por el identificador del data frame seguido de un "$" como lo hacemos en la expresión d20121$X2, utilizamos la función attach. Por ejemplo:

attach(d20121)
X9
  [1] 196 212 221 198 173 215 219 161 213 183 193 167 218 199 204 206 198 222
 [19] 200 215 193 212 201 213 208 213 188 193 195 184 203 216 207 212 214 233
    :   :   :   :   :   :   :   :   :   :   :   :   :   :   :   :   :   :   :
[127] 198 197 172 180 223 200 218 195 201 195 205 195 215 210 216 199 221 220
[145] 215 160 200 203 192 206

Bibliografía

  • Crawley, M. J.: Statistical Computing. An Introduction to Data Analysis Using S-PLUS. Wiley, 2002.
  • R Development Core Team: R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing, Vienna, Austria, 2008. http://www.R-project.org, ISBN 3-900051-07-0.
  • R Development Core Team: R: Introducción al R. R Foundation for Statistical Computing, Vienna, Austria, 2000. Disponible en: http://cran.r-project.org/doc/contrib/R-intro-1.1.0-espanol.1.pdf.