Introducción a R

Anuncio
Introducción a R
Juan Pablo Pérez Grijalbo
9 de febrero de 2007
2
Histograma(velocidad)
Dispersión(vel/dist)
−1
0
1
2
3
0
5
10
15
20
25
5
10
15
20
25
velocidad
velocidad
Histograma(distancia)
Dispersión(dist/vel)
15
velocidad
10
10
0
0.0
5
0.1
5
0.2
frecuencia
0.3
20
0.4
15
25
0.5
Densidad(distancia)
densidad
60
80
−3
0
0
0.0
20
0.1
5
40
distancia
10
frecuencia
0.3
0.2
densidad
0.4
100
15
0.5
120
Densidad(velocidad)
−2
0
1
2
3
4
0
20 40 60 80
distancia
120
0
20
40
60
80
distancia
120
Índice de figuras
3.1. Manual de R en html . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2. Hacer histogramas con hist() . . . . . . . . . . . . . . . . . . . . . .
3.3. Diagrama de dispersión con la función plot . . . . . . . . . . . . . .
17
20
20
5.1. Diagrama de caja con la función boxplot() . . . . . . . . . . .
5.2. Varios diagramas de caja con la función boxplot() . . . . . . .
5.3. Diagramas de caja de anchura variable con el argumento width
5.4. Modificación de las clases del histograma con breaks . . . . .
5.5. Frecuencias relativas con freq=F . . . . . . . . . . . . . . . .
5.6. Histograma con la función hist() . . . . . . . . . . . . . . . .
5.7. Función de densidad con plot(density()) . . . . . . . . . . . .
5.8. Gráfico Q-Q con la función qqnorm() . . . . . . . . . . . . .
5.9. Otro gráfico Q-Q con la función qqnorm . . . . . . . . . . . .
5.10. Gráfico de barras con barplot() . . . . . . . . . . . . . . . . .
5.11. Un gráfico interesante para tablas bidimensionales . . . . . . .
5.12. Representación gráfica de una tabla multidimensional . . . . .
5.13. Representación de parte de una tabla multidimensional . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
39
39
41
41
42
43
43
45
45
54
54
55
56
6.1. Notched boxplots . . . . . . . . . . . . . . . . . . . . . . . . . . . .
63
7.1. Un ejemplo de escasa correlación . . . . . . . . . . . . . . . . . . . .
7.2. En este caso, la correlación es fuerte . . . . . . . . . . . . . . . . . .
7.3. Diagrama de dispersión con dos grupos de datos . . . . . . . . . . . .
7.4. Diagrama mucho más elaborado . . . . . . . . . . . . . . . . . . . .
7.5. Diagrama de dispersión con dos grupos de datos obtenido con coplot()
7.6. Diagrama de dispersión controlando para dos variables . . . . . . . .
7.7. Diagrama de dispersión cruzada entre variables con pairs() . . . . . .
7.8. Relación entre temperatura y distancia . . . . . . . . . . . . . . . . .
7.9. Relación entre temperatura y flujo térmico . . . . . . . . . . . . . . .
7.10. Relación entre las variables de trees . . . . . . . . . . . . . . . . . .
7.11. Inclusión de la recta de regresión con abline() . . . . . . . . . . . . .
7.12. Identificación de casos con identify() . . . . . . . . . . . . . . . . . .
66
66
68
68
69
69
71
75
75
77
79
80
8.1. Personalización de títulos . . . . . . . . . . . . . . . . . . . . . . . .
83
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
ÍNDICE DE FIGURAS
8.2. Ejes logarítmicos . . . . . . . . . . . . . . . . . . . . . . . . . .
8.3. Modificar etiquetas de ejes con axis() . . . . . . . . . . . . . . .
8.4. Millones de colores con rgb() y hsv() . . . . . . . . . . . . . . . .
8.5. Añadir textos con text() . . . . . . . . . . . . . . . . . . . . . . .
8.6. Utilizar funciones para establecer coordenadas de textos con text()
8.7. Personalización de líneas con lty,lwd,col . . . . . . . . . . . . . .
8.8. Personalización de puntos con pch,cex,col . . . . . . . . . . . . .
8.9. Añadir puntos con points() . . . . . . . . . . . . . . . . . . . . .
8.10. Añadir lineas con abline() . . . . . . . . . . . . . . . . . . . . .
8.11. Añadir curvas con curve() . . . . . . . . . . . . . . . . . . . . . .
8.12. Modificación de parámetros gráficos con par() (I) . . . . . . . . .
8.13. Modificación de parámetros gráficos con par() (II) . . . . . . . .
8.14. Modificación de parámetros gráficos con par() (III) . . . . . . . .
8.15. División de la pantalla gráfica con layout() . . . . . . . . . . . . .
8.16. División desigual de la pantalla gráfica con layout() . . . . . . . .
8.17. Dos histogramas con layout() . . . . . . . . . . . . . . . . . . . .
8.18. Figuras múltiples par(mfrow) . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
83
85
85
86
87
87
89
89
90
91
92
92
93
94
94
96
97
Índice general
1. Introducción
1.1. ¿Por qué escribo este libro? . . . . . . . . . . . . . . . . . . . . . . .
1.2. Características principales de R . . . . . . . . . . . . . . . . . . . . .
1.3. Algunas cuestiones sobre el texto . . . . . . . . . . . . . . . . . . . .
7
7
8
9
2. Obtención e instalación
2.1. Instalación en Linux . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2. Instalación en Windows . . . . . . . . . . . . . . . . . . . . . . . . .
11
11
12
3. Primeros pasos
3.1. Iniciar una sesión de trabajo
3.2. Cómo pedir ayuda . . . . . .
3.3. Manos a la obra . . . . . . .
3.4. Primera sesión . . . . . . . .
3.5. Acabar una sesión de trabajo
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
13
13
14
16
17
21
4. Gestión de objetos y ficheros
4.1. Introducción de datos en R . . . . . . . . . . . . .
4.1.1. Importación de tablas externas: read.table()
4.1.2. Edición de datos en R . . . . . . . . . . .
4.2. Salida de información de R . . . . . . . . . . . . .
4.2.1. Exportación de gráficos . . . . . . . . . . .
4.2.2. Exportación de textos . . . . . . . . . . . .
4.3. Manipulación de data.frames . . . . . . . . . . . .
4.3.1. Selección de variables . . . . . . . . . . .
4.3.2. Extracción de variables . . . . . . . . . . .
4.3.3. Selección de casos . . . . . . . . . . . . .
4.3.4. Extracción de casos . . . . . . . . . . . . .
4.3.5. Introducción de variables . . . . . . . . . .
4.3.6. Incorporación de registros . . . . . . . . .
4.3.7. Ordenación de variables . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
23
23
23
25
26
26
27
27
28
28
29
30
31
33
34
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
ÍNDICE GENERAL
6
5. Estadística descriptiva
35
5.1. Análisis exploratorio de los datos . . . . . . . . . . . . . . . . . . . . 35
5.1.1. Medidas características . . . . . . . . . . . . . . . . . . . . . 35
5.1.2. El gráfico stem and leaf . . . . . . . . . . . . . . . . . . . . . 37
5.1.3. El gráfico boxplot . . . . . . . . . . . . . . . . . . . . . . . . 38
5.1.4. El histograma . . . . . . . . . . . . . . . . . . . . . . . . . . 40
5.1.5. Contraste de normalidad . . . . . . . . . . . . . . . . . . . . 40
5.2. Cómo resumir la información contenida en un data.frame . . . . . . 46
5.2.1. Tablas de frecuencias absolutas . . . . . . . . . . . . . . . . 46
5.2.2. Tablas con otras medidas estadísticas . . . . . . . . . . . . . 50
5.2.3. Métodos gráficos para presentar la información contenida en tablas 53
6. Pruebas de significación
6.1. Pruebas no paramétricas . . . . . . . . . . . . . . . . . . . . . . . .
6.1.1. Pruebas basadas en la χ2 . . . . . . . . . . . . . . . . . . . .
6.1.2. Test de Wilcoxon, de Mann-Whitney y de Kolmogorov-Smirnov
6.1.3. Test de Kruskal-Wallis . . . . . . . . . . . . . . . . . . . . .
6.2. Pruebas paramétricas . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2.1. Test basados en la t de Student . . . . . . . . . . . . . . . . .
57
57
57
59
60
62
62
7. Correlación y regresión
7.1. Estudio de la correlación bivariada . . . . . . .
7.1.1. Métodos gráficos . . . . . . . . . . . .
7.1.2. Matrices de correlaciones . . . . . . .
7.1.3. Coeficiente de correlación de Spearman
7.1.4. Coeficiente de correlación parcial . . .
7.2. Regresión lineal simple . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
65
65
65
70
72
73
76
8. Personalización de gráficos
8.1. Títulos . . . . . . . . . . . . . . .
8.2. Ejes . . . . . . . . . . . . . . . .
8.3. Colores . . . . . . . . . . . . . .
8.4. Añadir textos a un gráfico . . . . .
8.5. Tipos de puntos y lineas . . . . . .
8.6. Añadir puntos y lineas a un gráfico
8.7. Plantillas gráficas . . . . . . . . .
8.8. Gráficos múltiples . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
81
81
82
84
84
86
88
90
93
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Capítulo 1
Introducción
1.1. ¿Por qué escribo este libro?
El objetivo de este documento es proporcionar una base en castellano para aquellos
que están interesados, por el motivo que sea, en iniciarse en el uso de R.
Cuando uno se entera de la existencia de R, y se siente interesado por él, lo primero
que necesita es un poco de documentación porque, realmente, no es un programa que
se aprenda a base de trastear. Es entonces cuando se busca por internet.
Por lo general, al que está metido en el mundo de la informática, no le queda otro
remedio que manejarse con el inglés. Es entonces cuando uno siente cierta sana envidia
por esas sociedades que generan tanto conocimiento y, sobre todo, por la gente que
tiene un acceso inmediato a esa información. También es cuando uno se explica que
les haya ido tan bien a algunas naciones en lo que al desarrollo (al menos científico y
tecnológico) se refiere.
Mientras tanto, a los demás no nos queda otra opción que intentar descifrar el lenguaje
imperante; en general porque nos puede más el deseo de saber que la reticencia natural
a aprender un idioma extranjero1
Para los que entienden el inglés hay buenísimos manuales disponibles en la página
oficial de R. Se incluyen, además, documentos de tipo introductorio mucho mejores
que este2 . Sin embargo, hay gente que presenta esas reticencias al inglés y que, por
tanto, no tienen acceso a un entorno estadístico realmente fantástico. Entre esos sectores de población se encuentran especialmente los alumnos de bachillerato e, incluso,
de niveles universitarios. En realidad, este documento fue concebido en principio como
un material de clase para ser utilizado con mis alumnos y alumnas del primer curso de
bachillerato. Decidí entonces redactar un pequeño manual para trabajar con ellos en
el aula cuestiones de estadística básica, puesto que, por un lado, era consciente de lo
1 En realidad, existen algunos documentos en castellano, como la traducción de Introducción a R, del
equipo de desarrollo de R; y Gráficos estadísticos con R, de J.C. Correa y N. González. Ambos están disponibles en la página web de R.
2 En mi opinión, los mejores son simpleR. Using R for introductory statistics de John Verzani y Using R
for data analysis and graphics. An introduction de J.H.Maindonald. Como los anteriores, están disponibles
en la página web de R
7
CAPÍTULO 1. INTRODUCCIÓN
8
inadecuado que podría resultar remitirles a la documentación en inglés pero, por otro,
deseaba introducirles en el mundo del software libre y darles a conocer R.3 .
En fin, espero que estos apuntes sirvan para aquellos hispanoparlantes que se enfrentan por primera vez con R. Para que puedan empezar a descubrir las inmensas
posibilidades que ofrece y, quién sabe, llegar a entusiasmarse con él como lo hace el
que escribe estas lineas.
1.2. Características principales de R
En mi opinión las principales características de R son
1. las operaciones (cálculos estadísticos, gestión de ficheros,. . . ) se realizan tecleando instrucciones en un terminal. No es, por lo tanto, un programa en modo
gráfico
2. hay toda una comunidad internetera girando alrededor de él. En la red podemos
encontrar actualizaciones, paquetes, listas de correo, manuales,. . .
3. además del sistema base, existen paquetes especializados que permiten aplicar R
a campos superespecíficos como la estadística espacial, molecular, social,. . .
4. es un lenguaje de programación, de modo que tenemos la posibilidad de ampliar
su funcionalidad en la medida de nuestros conocimientos sobre programación
5. es un sistema multiplataforma, estando disponible, entre otros, para sistemas Linux, Windows y MacOS
6. es software libre, de modo que podemos adaptar el programa a nuestras necesidades ya que se distribuye con el código fuente
7. es gratuito
Por supuesto, R tiene ventajas e inconvenientes. También por supuesto, qué son
ventajas y qué inconvenientes depende de cada uno, pero (sobretodo) depende de con
qué se compare. R es un entorno estadístico y, por lo tanto, debe ser comparado con
aplicaciones de este tipo no, por ejemplo, con hojas de cálculo o similares.
Para mi son ventajas
1. el no sentirte solo ante el programa. La comunidad R es muy amplia y atenta.
Siempre responde a tus dudas
2. tiene unas capacidades gráficas extraordinarias
3. poder utilizarlo tanto en Linux como en Windows
4. poder definir funciones propias
5. tener acceso a funciones de estadística avazada
3 Sin embargo, a medida que lo he ido escribiendo lo he ido ampliando y, en estos momentos, supera las
posibilidades de aplicación en esos niveles, por lo que a ellos les paso una versión adaptada
1.3. ALGUNAS CUESTIONES SOBRE EL TEXTO
9
6. trabajar con ficheros fácilmente portables
7. aunque parezca extraño, el trabajar en linea de comandos a la larga resulta una
ventaja en muchas ocasiones ya que permite realizar muchas operaciones de forma más rápida que en modo gráfico
8. se actualiza con mucha frecuencia
9. es gratuito, de modo que uno puede responder tranquila y públicamente a la
pregunta ¿con qué programa has hecho esto?, cosa que no pueden hacer muchos
de los usuarios de otras aplicaciones estadísticas
Entre los inconvenientes destacaría
1. al principio, el trabajo en modo texto es incómodo
2. la curva de aprendizaje es, también al principio, algo pendiente, de modo que es
necesario material de apoyo para el aprendizaje
3. el lenguaje del programa es el inglés, y también en inglés está la mayor parte de
la documentación disponible
4. es un programa poco conocido por el usuario normal de estadística ya que no
hay libros de R en las secciones correspondientes de las librerías especializadas
1.3. Algunas cuestiones sobre el texto
En el texto encontraremos en negrita todo aquello que debamos introducir por
teclado en el terminal para realizar alguna operación en R. Por otro lado, aparecerán en
cursiva
1. las salidas por pantalla de las instrucciones que tecleemos
2. los nombres de las funciones y argumentos o parámetros de las mismas
3. los nombres de objetos particulares del espacio de trabajo
4. como sustituto de las comillas allí donde pudieran utilizarse
La operación de asignación puede efectuarse con el signo = o con la combinación de
signos <-. En el texto se utiliza esta última para ser compatible con versiones anteriores
de R.
10
CAPÍTULO 1. INTRODUCCIÓN
Capítulo 2
Obtención e instalación
La versión 1.6.1 de R, de noviembre de 2002, se te proporciona con este documento
en las versiones para Linux y para Windows. Sin embargo, cuando lo leas, casi con
toda seguridad habrá alguna versión más nueva, ya que la intención del equipo que
desarrolla R es liberar dos versiones al año. Por tanto, si deseas lo último en R tendrás
que descargarlo de la página oficial del proyecto CRAN (www.cran.r-project.org).
La instalación difiere si eres usuario de Linux o de Windows.
2.1. Instalación en Linux
Los usuarios habituales de Linux pueden saltarse este apartado (si no lo han hecho
ya) porque no tienen más que obtener R e instalárselo en su ordenador.
Si no lo eres, lo que sigue pretende ayudarte a instalártelo.
Si utilizas una distribución de Linux completa, tal vez se halle incorporada alguna
versión de R en la selección de programas que hayan hecho; en ese caso puedes utilizar
para instalar R la aplicación de gestión de paquetes que te venga con la distribución.
En cualquier caso, no será la última.
Si lo descargas de Internet debes saber que en la página de CRAN vas a encontrar
diferentes versiones del programa. Por un lado están los ficheros con el código fuente y,
por otro, los archivos con ficheros binarios precompilados para las distribuciones más
usuales (Debian, RedHat, Suse y Mandrake). Lo mejor es descargarse el que corresponda a nuestra distribución e instalarlo con la herramienta de gestión de paquetes que
tengamos.
Otra posibilidad es utilizar el CD que te proporciono. En él te encontrarás con un
paquete RPM y varios DEB. Para instalar R desde la linea de comandos sólo tienes que
escribir en un terminal
rpm -i R-1.6.1-2.i386.rpm
lo que instalará R en la mayor parte de las distribuciones. Si tu distribución es Debian
o basada en debian, puedes utilizar los archivos DEB, para lo cual deberás escribir
dpkg -i r-base-core_1.6.1-1_i386.deb
dpkg -i r-recommended_1.6.1-1_all.deb
11
12
CAPÍTULO 2. OBTENCIÓN E INSTALACIÓN
dpkg -i r-doc-pdf_1.6.1-1_i386.deb
Si todo ha ido bien1 , podrás arrancar R desde el terminal simplemente tecleando R.
2.2. Instalación en Windows
Los que utilizan Windows no lo tienen mucho más difícil. Tienen que descargarse
el archivo correspondiente que hay en el directorio base del enlace a Windows de la
página de descarga. Tras descargarlo sólo hay que hacer doble clic sobre el icono del
archivo rw1061.exe e ir superando las pruebas que nos pone el asistente de instalación. Tras concluir y, si así lo queremos, tendremos un icono en el escritorio que nos
permitirá lanzar la aplicación.
1 los problemas más habituales son los de dependencias no satisfechas, en cuyo caso deberás instalar
previamente los paquetes precisos
Capítulo 3
Primeros pasos
3.1. Iniciar una sesión de trabajo
Tras arrancar R nos encontramos con un terminal en el que deberemos teclear los
comandos necesarios para realizar todas las operaciones que vayamos a realizar; desde
la edición y gestión de ficheros de datos, a los análisis estadísticos y generación de
gráficos. Como dijimos en la Introducción, deberemos aprender el idioma de R. Sin
embargo, y aunque es amplio, veremos que con muy poco esfuerzo podremos empezar a trabajar. Además, una característica de R muy útil es que los comandos que se
introducen por teclado se van almacenando en un historial, de manera que podemos
recuperar las órdenes introducidas en un momento anterior con la ayuda de la tecla
flecha-arriba. Esto nos ahorrará mucho trabajo de tecleado y de memorización de la
sintaxis de los comandos ya que una vez introducido podremos recuperarlo posteriormente. Por otro lado, esta facultad nos va a permitir realizar análisis estadísticos de una
manera incluso más rápida de lo que lo haríamos con una aplicación en modo gráfico, en la que deberíamos desplazarnos por diferentes ventanas para realizar un análisis
prácticamente idéntico al realizado en un momento anterior.
En R nos vamos a encontrar con lo que se denomina "espacio de trabajo"(workspace
en inglés). Es una entidad virtual en la que se van a ir almacenando las variables y análisis que vayamos haciendo a lo largo de nuestra sesión de trabajo.
En Linux, el espacio de trabajo se almacena en el directorio desde el que se ha
lanzado R, de modo que al arrancar R se cargará el espacio de trabajo correspondiente
al directorio en el que nos encontremos al lanzar la aplicación. Por ese motivo, antes
de comenzar un estudio estadístico (digamos, Clima de Aragón) es conveniente crear
un directorio (tal vez, Clima de Aragón). Cuando vayamos a trabajar sobre este asunto
acudiremos a ese directorio para, desde allí, arrancar R. Todos los ficheros que vayamos generando (de texto, gráficos,...) en la sesión de R se irán guardando por defecto
en este mismo directorio.
Si no hacemos esto y arrancamos R, sea cual sea el problema estadístico, desde un directorio cualquiera, por ejemplo home, iremos acumulando objetos de diferentes problemas estadísticos en el mismo espacio de trabajo, lo que acabará creando la consi13
14
CAPÍTULO 3. PRIMEROS PASOS
guiente confusión.
Si analizamos los ficheros ocultos contenidos en el directorio de trabajo, vemos que
hay uno llamado .Rhistory que es el que va almacenando el histórico de comandos
introducidos en R. Como es un fichero de texto, podemos visualizarlo con cualquier
editor.
En la versión de R para Windows las cosas son algo distintas porque, aunque el
espacio de trabajo también se guardará en el directorio desde el que se lance la aplicación, lo cierto es que la operación de arranque se suele hacer, bien con un doble clic
sobre el icono colocado en el escritorio o la barra de programas, bien desplegando el
menú de Inicio hasta llegar a la aplicación.
Una vez arrancado R, para saber cuál es el directorio de arranque deberemos teclear
getwd() y anotar la ruta de acceso que nos indica por pantalla que, si hemos hecho una
instalación de Aceptar en Aceptar, estará en C:\Archivos de programa\R\rw1051 .
Cuando hayamos acabado la sesión de trabajo con R y guardado el espacio de trabajo,
nos encontraremos en el directorio que nos haya indicado getwd() con un icono en forma de R. Es conveniente entonces poner un nombre a ese icono (que de momento no
tiene ninguno) y trasladarlo a la carpeta en la que vayamos a guardar todo el material
que vayamos generando en nuestro trabajo estadístico.
Si este procedimiento nos parece demasiado complicado, podemos utilizar el comando /File/Save Workspace, que nos permite guardar una imagen de nuestro espacio
de trabajo en el directorio que deseemos. Tras acabar nuestra sesión de trabajo, deberemos descartar los cambios si queremos que, al abrir de nuevo R desde el icono de la
aplicación, no se cargue ningún workspace.
A partir de ese momento, cuando queramos recuperar ese espacio de trabajo en
concreto, tendremos dos opciones:
1. lanzar R haciendo doble clic sobre el icono situado en la carpeta de trabajo
2. hacer sobre doble clic sobre el icono que abre la aplicación y cargar el espacio
de trabajo desde File/Load workspace. Nos aparecerá una ventana en la que sólo
deberemos indicar la carpeta en la que hemos guardado la imagen del espacio de
trabajo.
Cuando arrancamos R desde el icono de la aplicación, se recupera el último espacio
de trabajo abierto, que puede ser,o no, el que nos interese a nosotros. La mejor manera
de averiguarlo es tecleando ls(); si se ha cargado el que deseamos, es obvio que no es
preciso hacer la operación anterior.
En la versión de R para Windows disponemos de una ventana con menús, una pequeña barra de herramientas y la consola para introducir los comandos por teclado.
Aunque no hay procedimientos estadísticos en modo gráfico, sí que hay algunos comandos útiles, como el que permite la importación de paquetes desde el sitio web de
CRAN o la personalización del entorno.
3.2. Cómo pedir ayuda
R dispone de un sistema de ayuda muy eficaz que nos va a permitir aprender el uso
de los comandos con bastante rapidez. Si conocemos el nombre del comando sobre el
3.2. CÓMO PEDIR AYUDA
15
que deseamos ayuda (p.e. plot) podemos utilizar la función help(). Lo único que debemos teclear es help(plot) o ?plot.
En ese momento, si trabajamos con la versión de Linux, el terminal abandona entorno
de R en el que estamos para arrancar el visualizador de la ayuda. El desplazamiento
por la ayuda se realiza con las teclas de arriba-abajo y de Av.Pag-Re.Pag. Todas las
ayudas suelen acabar con ejemplos de utilización de la función. Para salir de ella sólo
hay que pulsar la tecla q.
Existe la posibilidad de visualizar la ayuda con un navegador web. Para ello, en el caso
anterior se debería teclear help(plot, htmlhelp=T) con lo que arrancaría el navegador
Mozilla. En la página web aparecerá el mismo contenido de la ayuda pero con sus ventajas en cuanto a navegación. Además, en este caso, no se pierde en ningún momento
el controlde edición de comandos en el prompt de R.
El problema viene cuando no conocemos el nombre de los comandos, pero, ni siquiera
en ese caso está todo perdido. Entre otras cosas, tenemos manuales (como este) que nos
van presentando algunos de los comandos más habituales. Sólo es cuestión de empezar
a recordarlos. Además, existen varias posibilidades de ayuda desde R. Si tecleamos
help.start(), arrancará el navegador web en una página de inicio que presenta enlaces
a diferentes documentos. En este momento nos interesa especialmente el enlace a los
paquetes de R (Packages). De este modo podremos obtener una relación de todo lo
que contiene un paquete determinado. De entrada nos viene el nombre del comando
a teclear y una pequeña descripción de lo que hace (si es un procedimiento) o de lo
que contiene (si es un fichero de datos). Aunque tiene infinidad de funciones, es conveniente echar un vistazo al paquete Base porque podremos ir reconociendo las que
utilizaremos con más frecuencia.
Si tenemos alguna idea de cómo puede llamarse la función que queremos emplear podemos utilizar la función apropos(). Por ejemplo, si quiero hacer una media ponderada
pero no sé el nombre exacto de la función que me permita obtenerla, puedo teclear
apropos(mean) cuya salida sería
[1]“mean” “mean.POSIXc” “mean.POSIXl” “mean.default”
[5] “weighted.mean”
Podemos ver entonces que existe una función llamada weighted.mean(). El siguiente
paso sería solicitar ayuda sobre la misma con help(weighted.mean) para aprender a
utilizarla.
Otra herramienta muy útil para pedir ayuda en R es la función help.search(). Esta
nos devuelve todas las entradas de ayuda que presenten en sus tilulos o palabras clave
la cadena de caracteres introducida como argumento de la función. Así,
help.search(“help”)
devuelve
example(base) Run an Examples Section from the Online Help
help(base) Documentation
help.search(base) Search the Help System
help.start(base) Hypertext Documentation
index.search(base) Search Indices for Help Files
Cuando
apropos(help)
devuelve
16
CAPÍTULO 3. PRIMEROS PASOS
[1]“help” “help.search” “help.start”
Otra función muy útil es methods(), que permite conocer diferentes posibilidades de
uso de procedimientos utilizados en R. Por ejemplo, si nos interesa conocer variantes
de uso de la función lines(), podemos teclear
methods(lines)
que nos proporciona la siguiente salida
[1] “lines.default” “lines.formula” “lines.histogram” “lines.ts”.
Tambiém podemos aplicarlo a una clase de objetos, como hacemos en el siguiente
ejemplo con las tablas
methods(class=table)
[1] “pairwise.table” “as.data.frame.table” “as.table”
[4] “is.table” “margin.table” “plot.table”
[7] “print.summary.table” “int.table” “prop.table”
[10] “read.table” “summary.table” “write.table”
Posteriormente, con las funciones normales de ayuda, podemos entrar a estudiar el
funcionamiento de aquellas que nos puedan interesar.
En Windows encontramos en la pantalla un menú de ayuda. Allí nos encontramos
con accesos a las FAQ’s, al manual de R y otras fuentes de documentación. Éstos
están en formato PDF, pero la versión en HTML podemos lanzarla desde la línea de
comandos con la función help.start(). La captura de pantalla de la Figura 3.1 se ha
obtenido de esa manera.
3.3. Manos a la obra
Antes de ponernos a trabajar con nuestros datos, es conveniente echar un vistazo
a alguno de los datos que vienen incorporados con R. Si tecleamos data(), aparecerá
en pantalla una relación de ficheros de datos que podremos cargar en nuestro espacio
de trabajo. Para cargar uno en concreto, debe incluirse como argumento de la función.
Así, data(cars) cargaría el fichero cars.
Para ver qué objetos tenemos en nuestro espacio de trabajo hay que utilizar la función ls() sin argumentos. En este caso el único objeto debe ser el recién cargado fichero
cars.
Para ver el contenido de un objeto de datos tenemos dos posibilidades: la primera
es llamarlo directamente por su nombre. En nuestro caso, si tecleamos cars, aparecerá
por pantalla todo el contenido del fichero. Veremos entonces que consta de cincuenta registros de velocidad y distancia de frenada de otros tantos vehículos. Este modo
de exploración no es conveniente cuando el fichero contiene muchas variables y/o registros. En estos casos es mejor utilizar la función str() para hacernos una idea del
contenido del objeto. Así, str(cars) generaría la siguiente salida
‘data.frame’: 50 obs. of 2 variables:
$ speed: num 4 4 7 7 8 9 10 10 10 11 ...
$ dist : num 2 10 4 22 16 10 18 26 34 17 ...
La función str() nos informa de que cars es un data.frame, es decir, una tabla de datos en la que podemos encontrarnos variables de diferentes tipos. Nos dice que hay 50
observaciones de dos variables que son de tipo numérico y cuyos nombres son speed y
3.4. PRIMERA SESIÓN
17
Figura 3.1: Manual de R en html
dist.
Los data.frame son un tipo de objeto de importancia capital en R ya que en la
mayor parte de los análisis estadísticos los datos serán almacenados en data.frames. La
función str() es la mejor manera de conocer la estructura de un objeto en R.
3.4. Primera sesión
Las estadísticas más básicas que debemos conocer de nuestros datos son las relativas a medidas de tendencia central y de dispersión. La función summary() nos proporciona algunas de ellas. Por ejemplo, summary(cars) nos indica lo siguiente
speed
Min. : 4.0
1st Qu.:12.0
Median :15.0
Mean :15.4
3rd Qu.:19.0
Max. :25.0
dist
Min. : 2.00
1st Qu.: 26.00
Median : 36.00
Mean : 42.98
3rd Qu.: 56.00
Max. :120.00
es decir, proporciona los valores mínimo y máximo de cada variable así como la media
aritmética y los tres cuartiles.
Como veremos, con summary() podemos conocer algunos estadísticos básicos. Las
funciones mean(), median(), max(), min(), sum() y var() aplicadas a una varible proporcionarán por separado la media aritmética, mediana, valor máximo, mínimo, suma
CAPÍTULO 3. PRIMEROS PASOS
18
y varianza respectivamente.
Sin embargo, si nos limitamos a teclear estas funciones, R sólo presentará el valor del
estadístico en la pantalla. Si deseamos almacenar alguno de estos valores para trabajar
con ellos posteriormente (o por el motivo que sea) será preciso guardarlo en nuestro
espacio de trabajo. Para ello debemos hacer una de las operaciones más básicas en R,
que es la asignación.
Llamamos asignación al proceso por el cual almacenamos en un objeto el resultado
obtenido a través de una función de R. El objeto se incorporará automáticamente al
espacio de trabajo. Para llevar a cabo la asignación debemos decidir en primer lugar el
nombre que queremos dar al objeto. Una vez hecho esto, podemos pasar a teclear en
el terminal la orden. Por ejemplo, si quisiéramos almacenar la media de la distancia de
frenado, podríamos teclear lo siguiente
media.frenado<-mean(cars$dist)
Como ya sabemos, mean(cars$dist) le dice a R que obtenga la media de la variable
dist del data.frame cars. La combinación de caracteres < (menor que) y - (guión) indica que el resultado de la función debe asignarse a...1 Finalmente media.frenado es el
nombre que hemos querido dar en este caso al objeto que almacenará la media.
Si hacemos ls() veremos que, efectivamente, el nuevo objeto se ha incorporado al espacio de trabajo. A partir de ahora, para conocer el valor de ese estadistico deberemos
teclear, símplemente, media.frenado y, lo que es más importante, podré manipular el
valor de la media en operaciones algebraicas. Por ejemplo, si desease dividir esa media
entre tres, teclearía media.frenado/3. El proceso sería el siguiente
media.frenado<-mean(cars$dist)
media.frenado
[1] 42.98
media.frenado/3
[1] 14.32667
Como puedes imaginar, el último valor no se almacenará en el espacio de trabajo puesto
que no ha sido asignado a ningún objeto. Sin embargo, si consideras que sería conveniente, ya sabes cómo puedes hacerlo muy rápidamente y casi sin teclear nada. Sólo
debes recuperar con la tecla flecha-arriba la línea en la que introdujiste la orden de
cálculo (en este caso la última), desplazarte en ella con las flechas-derecha-izquierda
hasta el comienzo de la línea y teclear el nombre que quieras dar al objeto seguido del
operador de asignación <-.
La asignación es, como ya hemos dicho, una operación básica en R. En una sesión de
trabajo pueden realizarse multitud de asignaciones. Por ese motivo es muy recomendable que elijamos nombres adecuados para los objetos. Es muy conveniente que el
nombre nos recuerde inmediatamente qué es lo que almacena el objeto, pero tampoco
debe ser excesivamente largo. La experiencia nos irá ayudando en la elección de nombres.
Cuando hacemos ls() y vemos que hay objetos que hemos almacenado, pero que no nos
interesan, podemos quitarlos del espacio de trabajo. Para eso está la función rm(). Así,
rm(media.frenado) haría desaparecer el objeto media.frenado. Si queremos quitar varios objetos, no tenemos más que teclear sus nombres dentro de la función separados
1 recuérdese
que puede sustituirse por el signo = en las versiones 1.5 y posteriores
3.4. PRIMERA SESIÓN
19
por comas. Así, rm(media.frenado,cars) quitaría esos dos objetos que, por el momento, deben ser todo lo que tenemos en el espacio de trabajo.
Podemos comprobarlo con ls():
ls()
[1] “cars” “media.frenado”
rm(cars,media.frenado)
ls()
character(0)
Ese character(0) nos dice que el espacio de trabajo está vacío. De momento, volveremos a cargar el archivo cars.
Aunque estemos en los primeros pasos, seguramente también nos interesará analizar la distribución de frecuencias de las variables. Para generar un histograma de la
variable speed deberemos teclear
hist(cars$speed) lo que viene a traducirse por “coge el data.frame cars, selecciona la
variable speed y haz el histograma con las opciones que tengas por defecto”. El resultado es el que vemos en la Figura 3.2. 2 . Vemos que al pulsar la tecla Intro se abre una
pantalla nueva que R llama Device 2 y dice que está activa.
Si quiero ver el histograma, pero ahora de la variable dist, tengo dos opciones: presentarlo en la pantalla que acaba de abrirse (en cuyo caso desaparecerá el histograma
anterior), o abrir una nueva pantalla. Para ello deberemos teclear, en Linux, X11() y, en
Windows, windows(). En ese momento se abrirá y activará automáticamente un nuevo
dispositivo. Cualquier función gráfica que introduzcamos en R se representará en esa
nueva pantalla.
Abrir dispositivos de esta manera es una de las posibilidades que ofrece R para ver
varios gráficos de forma simultanea. Podemos conocer en cualquier momento cuántos
dispositivos tenemos abiertos tecleando dev.list(). Nos aparecerá por pantalla una lista
que nos informa del tipo de dispositivo, y el número que tiene asignado. El último dispositivo abierto será siempre el que esté en estado activo a no ser que activemos otro.
Esto podemos hacerlo con la función dev.set(). Tecleando dev.set(which=3) activaremos inmediatamente el dispositivo número 3.
Si queremos cerrar un dispositivo, podemos hacerlo con el ratón, pulsando sobre la X
de la esquina superior derecha. Sin embargo, hay dispositivos, como el postscript (que
veremos más adelante), que no presenta ventana alguna. Para cerrarlo en ese caso debemos teclear, por ejemplo, dev.off(4) siendo en este caso 4 el número del dispositivo
a cerrar.
En muchos casos también vamos a interesarnos por la relación existente entre
las distintas variables. Una aproximación gráfica la obtendremos mediante la función plot(). Para ver el gráfico dispersión de speed frente a dist deberemos teclear
plot(cars$speed,cars$dist) lo que genera la Figura 3.3
2 Posteriormente estudiaremos más en profundidad los métodos gráficos y veremos cómo modificar y
personalizar el gráfico resultante
CAPÍTULO 3. PRIMEROS PASOS
20
dist
0
20
40
60
80
100
120
Figura 3.2: Hacer histogramas con hist()
5
10
15
20
25
speed
Figura 3.3: Diagrama de dispersión con la función plot
3.5. ACABAR UNA SESIÓN DE TRABAJO
21
3.5. Acabar una sesión de trabajo
Podemos dar por terminada nuestra primera sesión de R. Para salir sólo hay que
teclear q(). En ese momento nos preguntarán si deseamos guardar los objetos presentes
en el espacio de trabajo que han sido generados en la última sesión. Si pulsamos la tecla
y, se guardarán, y nos los encontraremos de nuevo cuando arranquemos el programa. Si
pulsamos n todos los objetos que no hubieran sido guardados en alguna sesión anterior
de R se perderán sin posibilidad de recuperarlos.
22
CAPÍTULO 3. PRIMEROS PASOS
Capítulo 4
Gestión de objetos y ficheros
Después de conocer las bases de R, estamos en condiciones de comenzar a trabajar
con datos propios y presentar al mundo los resultados de tus análisis. En este capítulo
veremos cómo introducir datos en R, cómo manipularlos y cómo exportar los resultados
para poder incorporarlos a un informe.
4.1. Introducción de datos en R
Al llegar a este punto, podemos encontrarnos con varias situaciones:
1. en algunos casos, los datos los tendremos ya metidos en algún fichero (de hoja
de cálculo, de base de datos,...) bien porque los introdujimos en un momento
anterior, o porque nos los proporcionaron en esos formatos
2. podemos tener datos propios todavía sin digitalizar, y es posible que, después de
conocer las posibilidades que te ofrece R, prefieras introducir los datos en una
aplicación que te permita editarlos de una manera más ágil
3. finalmente, es posible que deseas introducir los datos directamente en R
En primer lugar vamos a ver qué hay que hacer en los dos primeros casos para importar
datos externos.
4.1.1. Importación de tablas externas: read.table()
Por lo general, los datos los tenemos en forma de tablas en las que encontramos
una serie de variables de diferentes tipos dispuestas en columnas; y un número variable
de registros que aparecen ocupando las filas de la tabla.
Sea cual sea la aplicación en la que tengamos la información, siempre podremos exportar la tabla en forma de fichero de texto. Esta es una de las formas más fáciles de
trasladar datos desde cualquier aplicación hacia R. Tal vez lo más frecuente sea exportar las tablas a ficheros de texto en los que cada campo (columna, variable) quede
23
CAPÍTULO 4. GESTIÓN DE OBJETOS Y FICHEROS
24
limitado por tabuladores (tab delimited en inglés). Si tenemos una tabla como la siguiente:
ALTITUD
500
1500
25
ORIENTACIÓN
N
TEMPERATURA
15
6
S
y la exportamos (desde la aplicación en la que la hemos creado) con el nombre datos.txt al directorio de trabajo de R, podremos incorporarla al espacio de trabajo con la
siguiente orden:
datos<-read.table("datos.txt", header=T, sep="\t")
en ella se dice que el fichero (que debe ir entrecomillado) tiene una primera fila en la
que van los nombres de las variables (header=T) y que el separador de columnas es el
tabulador (sep="\t"
). La orden podría funcionar correctamente aun sin colocar esa última opción siempre y cuando no haya ningún valor perdido (celdas en blanco) en la tabla original, pero
como en nuestro caso sí los hay, es preciso introducirla. Si comprobamos el resultado,
obtenemos lo siguiente
datos
ALTITUD
1 500
2 1500
3 25
ORIENTACIÓN
N
S
TEMPERATURA
15
6
NA
vemos que el valor perdido en la variable TEMPERATURA se ha convertido automáticamente en un NA (Not Avalaible en inglés), pero el perdido en la variable ORIENTACIÓN aparece en blanco. Esto se debe a que R transforma en NA’s sólo las varibles
numéricas. Si queremos que los valores perdidos de una variable no numérica se transformen en NA’s para ser tratados como tales en R, debemos indicar a la hora de importar
la tabla qué forma adoptan los valores perdidos en esos casos. Como en el nuestro (y
es lo habitual) son celdas que están en blanco, lo que haremos será introducir la opción
na.strings=""
datos<-read.table("datos.txt", header=T, na.strings=“”, sep="\t")
datos
ALTITUD
1 500
2 1500
3 25
ORIENTACIÓN
N
NA
S
TEMPERATURA
15
6
NA
Con esta orden de importación, las variables numéricas contenidas en la tabla de
origen serán mantenidas como numéricas, pero las variables de tipo carácter serán
transformadas en lo que en R se llama factores. Cuando conozcamos mejor cómo
4.1. INTRODUCCIÓN DE DATOS EN R
25
funciona R podremos decidir si eso nos conviene o no. Cuando deseemos mantener
las variables de tipo carácter como tales, deberemos añadir a la función read.table la
opción as.is=T.
4.1.2. Edición de datos en R
En alguna ocasión es posible que deseemos introducir los datos directamente en R.
Hay dos posibilidades para hacerlo: una es por la línea de comandos, y la otra mediante
una pantalla gráfica.
En la línea de comandos podemos crear un objeto y asignarle al mismo tiempo los
valores que ha de almacenar. Por ejemplo, si quisiéramos introducir directamente los
datos de la tabla anterior podríamos teclear lo siguiente:
ALTITUD<-c(500,1500,25)
ORIENTACIÓN<-c("N",NA,"S")
TEMPERATURA<-c(15,6,NA)
tabla<-data.frame(ALTITUD,ORIENTACIÓN,TEMPERATURA)
En las tres primeras líneas creamos las variables y les asignamos los valores que adoptan. La función c() lo que hace es concatenar los tres valores para crear un vector. Los
valores perdidos los introducimos como NA’s, y los valores de las variables no numéricas deben ir entrecomillados. En la cuarta línea hemos procedido a crear un data.frame
que hemos llamado tabla en el que hemos reunido las tres variables.
También podríamos haber realizado la operación en un sólo paso. Símplemente deberíamos haber tecleado:
tabla<-data.frame(ALTITUD=c(500,1500,25),ORIENTACIÓN=
c( "N",NA,"S"),TEMPERATURA=c(15,6,NA)) Si tecleamos str(tabla) obtenemos:
str(tabla)
‘data.frame’: 3 obs. of 3 variables:
$ALTITUD : num 500 1500 25
$ORIENTACIÓN: Factor w/ 2 levels "N","S": 1 NA 2
$TEMPERATURA: num 15 6 NA
El mensaje nos indica que, efectivamente, hemos generado un data.frame que tiene
tres observaciones y tres variables, dos de las cuales son numéricas y una tercera, la
orientación, es lo que en R se llama un factor; en este caso, el factor presenta sólo dos
modalidades: N y S. También nos advierte de la presencia de valores perdidos.
Este sistema desde luego no es muy práctico si tenemos que introducir muchos
datos. Una alternativa es utilizar un editor tipo hoja de cálculo al que podemos acceder con la función data.entry(). Esta posibilidad sólo está disponible en determinadas
plataformas y GUI’s, por lo que no siempre funciona. Cuando funciona, disponemos
de una herramienta muy útil. La única precaución que debemos guardar es la de crear
previamente el objeto, por ejemplo un data.frame, antes de introducir los datos en él
desde el editor. La secuencia de instrucciones en Windows podría ser la siguiente
datos<-data.frame()
Edit/Data editor...
Con la primera instrucción creamos un data.frame vacío llamado datos. Luego vamos
al menú Edit/Data editor.... Nos saldrá una ventana en la que nos pedirán el nombre
del objeto a editar. Deberemos introducir el nombre, en este caso datos. Tras esta ope-
26
CAPÍTULO 4. GESTIÓN DE OBJETOS Y FICHEROS
ración, se abre una rejilla de filas y columnas en las que podremos introducir nombres
de variables (haciendo clic con el botón izquierdo del ratón en la cabecera de columna)
y los valores que correspondan.
Tras concluir la edición, cerramos la ventana haciendo clic sobre el aspa de la esquina superior derecha. Desde ese momento, podemos ver el contenido del data.frame
tecleando datos.
4.2. Salida de información de R
Como es lógico, parte de la información que obtengamos con R a lo largo de nuestro
análisis (valores de estadísticos, gráficos,...) querremos llevarla fuera para incorporarla
a alguna aplicación que nos permita editarla (por lo general un procesador de texto).
En este apartado veremos algunas funciones que nos van a permitir llevar a cabo estas
operaciones.
4.2.1. Exportación de gráficos
En un apartado anterior hemos visto cómo generar un gráfico con la función plot().
Si quisiéramos exportarlo, podríamos hacerlo con la función dev2bitmap(), que transforma el contenido de la pantalla X11 activa en una imagen en formato bitmap. Lo
único que habría que hacer es decidir con qué nombre quiero guardar el gráfico y teclear
dev2bitmap("GráficoCars", res=300)
con esta función guardamos el gráfico con el nombre de GráficoCars y con una resolución (res de 300 puntos por pulgada. Por supuesto, la resolución puede modificarse. El
fichero gráfico se guarda en el directorio de trabajo, a no ser que en el nombre (que debe
ir entrecomillado) se indique lo contrario. Por ejemplo, dev2bitmap(”/home/pablo/GráficoCars”
, res=150), guardaría el gráfico (siempre que tengamos permiso de escritura) en el directorio /home/pablo. En este caso, lo hará con una resolución de 150 ppp.
En Linux es muy habitual manejar ficheros gráficos en formato PS (Postscript).
Para exportar el gráfico anterior en este formato habría que introducir la orden
dev.print(postscript)
lo que genera un fichero llamado Rplots.ps en la carpeta/directorio de trabajo. Con un
visor PS podremos comprobar que el gráfico es realmente el que nos interesa. Posteriormente deberemos cambiar inmediatamente el nombre del fichero por uno que nos recuerde qué gráfico contiene, porque la próxima vez que ejecutemos dev.print(postscript)
se generará un nuevo fichero Rplots.ps que borrará el contenido del anterior. Como puede apreciarse, este método resulta un poco lioso y arriesgado, de modo que lo habitual
será exportar el gráfico con un nombre ya definido. Esto puede hacerse con la opción
file. Así, si queremos guardar el fichero postscript con el nombre Grafico1, podríamos
teclear
dev.print(postscript, file="Grafico1")
En la versión de Windows podemos acceder al menú para guardar el gráfico sólo
con hacer clic con el botón derecho del ratón sobre la ventana gráfica. Entonces nos
aparecen una serie de opciones y formatos para elegir.
4.3. MANIPULACIÓN DE DATA.FRAMES
27
4.2.2. Exportación de textos
En muchos casos querremos exportar la información obtenida mediante análisis
estadísticos y que R nos presenta por pantalla. Por ejemplo, el resultado de la función
summary(), o de un análisis de regresión entre dos variables. Para ello disponemos de
la función sink(). Esta función lo que hace es dirigir la salida de una orden introducida
en R a un fichero de texto cuyo nombre debemos incluir en la primera llamada a la
función. Tras introducir sink(), todo lo que hagamos en R (salvo gráficos) se almacenará en el fichero externo sin llegar a presentarse por pantalla. Obviamente, hay que
decirle a R cuándo queremos dejar de extaer información. Eso lo haremos con un nueva
llamada a sink(). A continuación se presenta un ejemplo de utilización de esta función
sink(“resultados")
str(cars)
summary(cars)
cor(cars)
sink()
Si exploramos el directorio de trabajo veremos que existe un nuevo fichero, de nombre
resultados, que es el nombre que hemos introducido entrecomillado al llamar a la función. Si lo abrimos con un editor de texto confirmaremos que contiene la información
esperada, en este caso, acerca de la estructura, estadísticas básicas y matriz de correlaciones del data.frame cars. Como hemos cerrado la exportación de resultados son
sink(), los resultados de las operaciones que hagamos en adelante y que tengan salida,
se presentarán en la pantalla. Es muy importante no olvidarse de cerrar la exportación.
De lo contrario iremos llenando el fichero de resultados indeseados.
Cuando queramos exportar un data.frame contenido en nuestro espacio de trabajo,
podremos hacerlo con la función write.table(). La siguiente orden exportaría el data.frame cars al fichero coches
write.table(cars, “coches")
4.3. Manipulación de data.frames
Como hemos comentado anteriormente, los data.frame son un tipo de objeto fundamental en R. La mayor parte de los datos que queramos analizar estadísticamente
estarán almacenados en forma de data.frame ya que, por lo general, tendremos una serie de variables numéricas y otras que no lo serán. Nada impide que en un data.frame
todas las variables sean de un solo tipo. Cuando todas son numéricas, el data.frame
puede transformarse en una matriz, que es otro tipo de objetos presentes en R.
Se entiende, por tanto, que sea imprescindible conocer las técnicas de manipulación
básicas de los data.frame. En unas ocasiones querremos extraer información de ellos;
en otras, eliminar o añadir variables; seleccionar datos;. . . En los siguientes apartados
veremos cómo hacer algunas de estas operaciones.
Para los ejemplos de esta sección utilizaremos los datos contenidos en el fichero
resultados académicos que se adjunta con el CD.
Para cargar esos datos, es recomendable copiar el fichero en nuestro directorio de trabajo. Entonces, sólo con teclear
28
CAPÍTULO 4. GESTIÓN DE OBJETOS Y FICHEROS
resultados<-read.table(resultados.txt",sep=",",header=T)
tendremos en nuestro workspace el data.frame resultados.
Como se puede apreciar, en la instrucción le indicamos a read.table que el fichero es
de tipo delimitado por comas (sep=","
) y que la primera fila contiene el nombre de las variables(header=T). Como este
es el data.frame que vamos a utilizar más a menudo, es una buena idea colocarlo en la
ruta de búsqueda con attach(resultados), de esa manera podremos referirnos a las variables sin necesidad de indicar a R continuamente que se encuentran en el data.frame
resultados. Una vez cargados los datos es conveniente estudiar su estructura con str()
str(resultados)
‘data.frame’: 4838 obs. of 9 variables:
$ Evaluacion: Factor w/ 4 levels "1","2","F","N": 4 3 3 2 2 3 3 3 2 3 ...
$ Curso : num NA 1 2 1 1 1 1 2 2 1 ...
$ B : num NA 0 0 0 0 0 0 0 0 0 ...
$ IN : num NA 0 0 0 0 0 0 0 0 0 ...
$ NT : num NA 0 0 0 1 1 1 1 1 1 ...
$ SB : num NA 9 9 9 8 8 8 8 8 8 ...
$ SF : num NA 0 0 0 0 0 0 0 0 0 ...
$ Año : Factor w/ 9 levels "1994","1995",..: 9 5 6 8 5 7 7 5 6 5 ...
$ Alumno : Factor w/ 4838 levels "1","10","100",..: 4838 4265 374 1973 2200 2431
2593 2598 3310
3311 ...
4.3.1. Selección de variables
Ya sabemos cómo aplicar una función a una variable de un data.frame. Por ejemplo,
length(resultados$NT) nos proporcionará el número de valores (incluidos los perdidos) que tiene la variable NT (número de Notables). Sin embargo, hay otras maneras
equivalentes de obtener el mismo resultado. Entre otras, las siguientes
length(resultados[,6])
length(resultados[[6]])
length(NT)
como puede verse, en los dos primeros casos hemos sustituido el nombre de la variable
(NT) por el número de orden que ocupa en el data.frame (el notable es la variable número 6). En el tercer caso hemos obviado la referencia al nombre del data.frame; esto
sólo funcionará siempre y cuando antes lo hayamos colocado en la ruta de búsqueda
con attach().
4.3.2. Extracción de variables
En ocasiones el fichero de datos original tiene más variables de las que nos interesan
para nuestro análisis. En esos casos, puede interesarnos crear un nuevo data.frame en
el que sólo aparezcan las variables que realmente vayamos a necesitar. Esta operación
puede realizarse con la función subset(). Esta es una función muy útil y la estudiaremos
también en otra sección.
4.3. MANIPULACIÓN DE DATA.FRAMES
29
Para extraer variables hay que indicar a la función el nombre del data.frame y las variables que deseamos extraer. Como queremos generar un data.frame nuevo, deberemos
realizar una operación de asignación. Por ejemplo, para crear un data.frame llamado fracasoescolar con las variables Año, Evaluacion, Curso e IN deberíamos teclear
fracasoescolar<-subset(resultados,select=c(8,1,2,4)). Si solicitamos a R la estructura
del nuevo data.frame con str(fracasoescolar) veremos lo siguiente:
‘data.frame’: 4838 obs. of 4 variables:
$ Año : Factor w/ 8 levels "1994","1995",..: 5 6 8 5 7 7 5 6 5 6 ...
$ Evaluacion: Factor w/ 3 levels "1","2","F": 3 3 2 2 3 3 3 2 3 1 ...
$ Curso : num 1 2 1 1 1 1 2 2 1 2 ...
$ IN : num 0 0 0 0 0 0 0 0 0 0 ...
Como se ve, han desaparecido las variables no deseadas y se han seleccionado las
que queremos, respetando el orden en el que se han introducido en la función subset().
Vamos a estudiar un poco en detalle cómo se indica qué variables se quieren extraer.
Esto de hace con el argumento select. En el ejemplo hemos tecleado select=c(8,1,2,4).
Ese c(8,1,2,4) indica a R que concatene las variables que ocupan el octavo, primero,
segundo y cuarto lugar. La c que precede al paréntesis es imprescindible y se utiliza en
R siempre que se quiere crear lo que se llama un vector.
En lugar de número de orden, podríamos haber utilizado el nombre de las variables,
así
fracasoescolar<-subset(resultados,select=c(Año,Evaluacion,Curso,IN)
habría producido el mismo resultado.
En ocasiones son más las variables que quiero extraer que las que deseo descartar.
En esos casos es más conveniente utilizar otra forma de selección. Por ejemplo
fracasoescolar<-subset(resultados,select=-c(B,NT,SB)
incluiría en el data.frame fracasoescolar todas las notas menos (como le indica el signo
- delante del operador de concatenación) el B, el NT y el SB.
Si, por casualidad, las variables a extraer son consecutivas, podríamos seleccionarlas en bloque. Así,
probatinas<-subset(resultados,select=(1:5))
crearía un data.frame en el que se incluirían las primeras cinco variables. Nótese que,
en este caso, no se introduce la concatenación; R entiende los dos puntos entre el 1 y
el 5 como desde la uno a la cinco, ambas inclusive.
4.3.3. Selección de casos
Al igual que hemos seleccionado variables para aplicarles procedimientos estadísticos, también podemos seleccionar casos para aplicarles funciones. Por lo general, esta
selección se basará en el cumplimiento de determinadas condiciones. Los operadores
habituales en las expresiones condicionales son
1. ==, igual a
2. >=, mayor o igual a
3. <=, menor o igual a
30
CAPÍTULO 4. GESTIÓN DE OBJETOS Y FICHEROS
4. !=, diferente a
5. &, y
6. |, o
En nuestro data.frame sobre resultados académicos se almacenan datos correspondientes a varios cursos escolares. En alguna ocasión, seguro que querremos conocer estadísticas relativas a un año en concreto. Si quisiéramos conocer la mediana del número
de insuficientes en el año 1999, podríamos introducir la siguiente orden
median(IN[Año==1999])
la condición de selección se indica entre corchetes. En este caso se dice: coge los registros correspondientes a 1999, fíjate en la variable IN y calcula su mediana1.
Las condiciones de selección se pueden anidar. Por ejemplo, si queremos analizar
sólo la evaluación final, escribiríamos
median(IN[Año==1999&Evaluación=="F"])
En muchas ocasiones nos interesará (o, incluso, será preciso) eliminar los valores perdidos para efectuar un análisis. Por ejemplo, la función median() no funciona si existen
NA’s en la variable. En muchas ocasiones podemos remediar el problema introduciendo la opción na.rm=T en la función como vemos a continuación.
median(IN)
[1] NA
median(IN,na.rm=T)
[1] 2
En el primer caso la función no actúa correctamente; en el segundo, sí.
4.3.4. Extracción de casos
Esta es otra de las operaciones básicas del análisis estadístico, especialmente cuando tenemos ficheros de datos muy grandes.
Como casi todo en R, hay varias maneras de llevar a cabo tal selección. Una de
ellas es mediante la función subset(). En este caso introduciremos una condición que
afecta a los registros y no a las variables. Por ejemplo, para seleccionar alumnos/as con
más de 3 insuficientes deberíamos proceder de la siguiente manera
granfracasoescolar<-subset(resultados,IN>3)
en este caso, a continuación del nombre del data.frame se introduce el nombre de la
variable, y la condición de selección. Hay que hacer notar que la condición de igualdad
se indica con doble signo igual (==). Para ver el resultado, utilizaremos de nuevo str()
str(granfracasoescolar)
‘data.frame’: 1581 obs. of 9 variables:
$ Evaluacion: Factor w/ 3 levels "1","2","F": 2 1 2 3 1 2 3 3 3 2 ...
$ Curso : num 2 1 1 2 1 2 1 2 1 1 ...
$ B : num 0 0 0 0 0 0 0 0 0 0 ...
$ IN : num 0 0 0 0 0 0 0 0 0 0 ...
$ NT : num 3 3 3 3 3 3 3 3 3 3 ...
1 Como hemos hecho previamente attach(resultados), podemos referirnos directamente a IN. De lo contrario, deberíamos haber tecleado resultados$IN
4.3. MANIPULACIÓN DE DATA.FRAMES
31
$ SB : num 6 6 6 6 6 6 6 6 6 6 ...
$ SF : num 0 0 0 0 0 0 0 0 0 0 ...
$ Año : Factor w/ 8 levels "1994","1995",..: 5 5 8 7 5 8 5 7 6 7 ...
$ Alumno : Factor w/ 4838 levels "1","2","3","4",..: 3117 3208 2692 3834 3619 3896
4024 4188 2693 3835 ...
Podemos ver que el nuevo data.frame sigue teniendo las mismas 9 variables pero el
número de casos se ha reducido de 4838 a 1581.
En muchas ocasiones la condición de selección es múltiple. En ese caso no hay más
que encadenarlas con el signo &. Por ejemplo, para seleccionar el alumnado con más
de tres notables y con tres bienes habría que teclear
selección<-subset(resultados,NT>3 & B==3).
Una manera menos intuitiva de conseguir el mismo resultado es la siguiente
selección<-resultados[resultados$NT>3& resultados$B==3 ]
Combinando las dos posibilidades estudiadas anteriormente, se puede realizar una
extracción simultanea de variables y casos. Así, para crear un data.frame que contenga
sólo el número de caso y el número de insuficientes del alumnado correspondiente al
año 1998 podríamos teclear
otraseleccion<-subset(resultados,Año==1998,select=c(Alumno,IN))
En alguna ocasión puede interesarnos eliminar del análisis todos los datos en los
que haya algún valor perdido. Como veremos, esta puede ser una medida extrema ya
que hay funciones en R que nos permiten ignorar los casos con valores perdidos para
las variables implicadas sin necesidad de eliminarlas del data.frame (ver la sección de
Estadística básica). En cualquier caso, si quisiéramos hacerlo, podríamos teclear
sinNA<-na.omit(resultados)
lo que crearía un nuevo data.frame en el que encontraremos sólo los casos completos.
4.3.5. Introducción de variables
Hay dos situaciones que pueden hacer necesaria la entrada de nuevas variables en
un data.frame.
1. cuando deseamos obtener una nueva variable calculada a partir de variables ya
contenidas en el data.frame
2. cuando necesitamos actualizar los datos que teníamos
El primer problema es de naturaleza matemática; el segundo es un problema más bien
de edición. Veamos cómo podemos afrontar ambas situaciones.
Añadir variables calculadas a un data.frame
Resulta bastante sencillo llevar a cabo esta operación. Supongamos que quisiéramos introducir en nuestro data.frame resultados un índice de resultados académicos
del estilo
indice = (NT + SB/IN + SF + B + NT + SB) ∗ 100
Para llevarlo a cabo deberíamos teclear la siguiente orden
resultados$indice<-(NT+SB)/(IN+SF+B+NT+SB)*100
32
CAPÍTULO 4. GESTIÓN DE OBJETOS Y FICHEROS
que viene a decir calcula la suma de notables y sobresalientes, divídela entre el número total de notas, multiplica el resultado por cien y colócalo en la variable que llamo
indice en el data.frame resultados. (Nótese que, de nuevo, presuponemos que el data.frame resultados está en la ruta de búsqueda. De lo contario, no podríamos llamar
directamente a las variables como hemos hecho en la orden anterior).
Como vemos, el problema se reduce a una operación de asignación; cuestión que ya
hemos analizado anteriormente. El resultado sería el siguiente
str(resultados)
‘data.frame’: 4838 obs. of 10 variables:
$ Evaluacion: Factor w/ 3 levels "1","2","F": 3 3 2 2 3 3 3 2 3 1 ...
$ Curso : num 1 2 1 1 1 1 2 2 1 2 ...
$ B : num 0 0 0 0 0 0 0 0 0 0 ...
$ IN : num 0 0 0 0 0 0 0 0 0 0 ...
$ NT : num 0 0 0 1 1 1 1 1 1 1 ...
$ SB : num 9 9 9 8 8 8 8 8 8 8 ...
$ SF : num 0 0 0 0 0 0 0 0 0 0 ...
$ Año : Factor w/ 8 levels "1994","1995",..: 5 6 8 5 7 7 5 6 5 6 ...
$ Alumno : Factor w/ 4838 levels "1","2","3","4",..: 4838 1334 2774 2979 3186 3331
3336 3978 3979 2607 ...
$ indice : num 100 100 100 100 100 100 100 100 100 100 ...
como podemos observar, en el data.frame resultados aparece en último lugar la nueva
variable indice.
Incorporación de nuevas variables
Puede ocurrir que en un momento determinado de nuestra investigación necesitemos añadir alguna variable a nuestros registros. Como hemos dicho antes, esto es más
bien un problema de edición y, por lo general, resulta mejor idea resolverlo fuera de
R e incorporar el nuevo conjunto de datos por los medios de importación que ya hemos estudiado anteriormente. Sin embargo, vamos a ver algunas maneras de resolver
la cuestión dentro de R.
Si tenemos dos data.frames con uno o varios campos (utilizando la terminología de las
bases de datos) en común, podemos utilizar la función merge() para incorporar campos
(variables) de uno a otro. Como siempre que se desea enlazar dos tablas, debemos indicar sus nombres, y qué campos tienen en común.
Supongamos que tenemos dos data.frame como los siguientes
enfe
Nombre Enero Febrero
1 María 10 20
2 José 20 10
3 Sara 30 40
ma
Nombre Marzo
1 María 13
2 José 45
3 Sara 32
4.3. MANIPULACIÓN DE DATA.FRAMES
33
enfe almacena los puntos acumulados por tres alumnos/as en los meses de enero y febrero. ma almacena los que han almacenado, los mismos alumnos durante marzo. Para
añadir los datos de marzo a los de enero y febrero deberíamos teclear
merge(enfe,ma,by.x="Nombre",by.y="Nombre")
el resultado sería
Nombre Enero Febrero Marzo
1 José 20 10 45
2 María 10 20 13
3 Sara 30 40 32
Como se ve, el resultado es el deseado. En este caso nos ha parecido conveniente
crear un nuevo data.frame (mediante una asignación) con los datos de los tres meses. Si
quisiéramos añadir la variable a un data.frame existente sin crear uno nuevo, lo único
que deberíamos hacer es asignar el resultado de la función merge a dicho data.frame.
En este caso,
enfe<- merge(enfe,ma,by.x="Nombre",by.y="Nombre")
añadiría los datos de marzo al data.frame enfe.
En muchas ocasiones, los data.frames a unir no tienen exactamente los mismos registros. En el caso anterior, por ejemplo, en el mes de marzo podría haberse incorporado
algún alumno nuevo. Para que le resultado de la unión recoja todos los registros contenidos en uno y otro data.frame debemos modificar un poco la orden
merge(enfe,ma,by.x="Nombre",by.y="Nombre",all.x=T,all.y=T)
con esos all.x=T y all.y=T (la T hace referencia al inglés TRUE, VERDAD) le decimos
que incorpore todos los casos (all) del data.frame x (el que ponemos en primer lugar),
y también del data.frame y . Como es natural, en este caso se completarán con NA’s los
valores de las variables para los que no tengamos datos.
Hay que tener en cuenta que sin esos dos argumentos, sólo los casos comunes a ambos
data.frame serían seleccionados.
Finalmente, si sólo quisiéramos considerar los casos incluidos en uno de los data.frame,
deberíamos indicarlo en la orden. Por ejemplo,
merge(enfe,ma,by.x="Nombre",by.y="Nombre",all.y=T)
daría como resultado la unión considerando sólo los alumnos presentes en el mes de
marzo, que es el data.frame y.
4.3.6. Incorporación de registros
Vamos a considerar ahora la posibilidad de añadir a un data.frame nuevos registros
de las mismas variables. En el apartado anterior hemos visto que la función merge()
permitía incorporar casos nuevos cuando añadíamos variables a un data.frame. Sin
embargo, en ese caso, los nuevos registros no presentaban valores para las variables
previas. En el caso de que sí lo hicieran, los valores de los registros nuevos no se
incorporarían a la variable del data.frame previo sino que la variable se duplicaría. Por
lo tanto, para añadir registros a un data.frame utilizaremos otra función: rbind().
Supongamos que al dataframe enfe con el que trabajábamos antes queremos añadirle los casos contenidos en este otro llamado nuevo
Nombre Enero Febrero Marzo
34
CAPÍTULO 4. GESTIÓN DE OBJETOS Y FICHEROS
1 Manuel 45 1 14
2 Aurora 10 2 32
3 Jorge 2 4 20
Si ejecutamos union<-rbind(enfe,nuevo), conseguiremos nuestro cometido. El resultado será:
Nombre Enero Febrero Marzo
1 José 20 10 45
2 María 10 20 13
3 Sara 30 40 32
4 Manuel 45 1 14
5 Aurora 10 2 32
6 Jorge 2 4 20
Hay que hacer notar que no es preciso que el orden de las variables en los dos data.frame sea el mismo, pero sí el nombre de las mismas. Por otro lado, no hay problema
en unir data.frames en los que las variables sean de tipo numérico o de carácter, pero si
alguna de ellas es un factor, de todas las clases contenidas en el data.frame que vamos
a añadir, sólo las que estén presentes en el data.frame de destino serán reconocidas.
Todas las demás serán ignoradas y transformadas en NA’s con la consiguiente pérdida de información. Por lo tanto, si nuestros data.frames contienen factores, puede ser
conveniente transformarlos en vectores (con la función as.vector()) antes de proceder
a incorporar datos de uno a otro. Otra posibilidad sería almacenar las variables de tipo
carácter como tales (sin transformarlas en factores) al leer ficheros externos. Para ello
habría que añadir la opción as.is=T en la función read.table().
4.3.7. Ordenación de variables
En algunas ocasiones es necesario disponer los casos en orden ascendente del valor
de una variable. En R podemos llevar a cabo esta ordenación con la función sort(). Así,
sort(cars$speed) nos devolverá un vector con los valores de la variable de los casos
ordenados de menor a mayor.
La función order() también está relacionada con las operaciones de ordenación de variables. En este caso, la función nos devuelve un vector que nos indica en qué posición
se encuentra el caso con el valor mínimo, el segundo más bajo, el tercero, . . . , hasta
llegar a indicar la posición que ocupa el valor máximo. Obviamente, si la variable está
en orden ascendente, order() proporcionará el vector (1,2,3,....,n) siendo n el número
de casos.
Capítulo 5
Estadística descriptiva
En este capítulo veremos cómo realizar en R una serie de análisis estadísticos básicos. Se da por supuesto que el lector conoce el cometido y significado de todos ellos,
por lo que las referencias en este sentido serán reducidas.
5.1. Análisis exploratorio de los datos
En este apartado vamos a considerar algunas de las posibilidades que ofrece R para
recabar información básica de la naturaleza de las variables que deseamos analizar.
Además estudiaremos algunos procedimientos gráficos: el gráfico stem and leaf, el
boxplot y el histograma.
5.1.1. Medidas características
Como dijimos anteriormente, la función summary() proporciona información básica acerca de una variable. También acepta como argumento un data.frame, en cuyo
caso la salida informará acerca de todas las variables contenidas en el mismo.
Otras funciones nos dan medidas estadísticas de forma aislada. Ya comentamos algunas
de ellas (mean(),median(),max(),min(),sum(), var()). Otras son range(), que nos muestra los valores mínimo y máximo, pero no el rango; sd(), que devuelve la desviación
estandard; y quantile(), que nos va a permitir dividir la variable en partes iguales para
obtener los cuartiles, deciles o percentiles. Veamos su funcionamiento para la variable
IN
quantile(resultados$IN,probs=1:10/10,na.rm=T)
10 % 20 % 30 % 40 % 50 % 60 % 70 % 80 % 90 % 100 %
0
0
0
1
2
3
4
5
7
10
Como vemos, con la función hemos obtenido los diez deciles de la variable.
Sin embargo, no existe ninguna función que nos proporcione un listado o una tabla
con todas las medidas estadísticas que puedan interesarnos. De lo que sí dispone R (por
35
36
CAPÍTULO 5. ESTADÍSTICA DESCRIPTIVA
ser en definitiva un lenguaje de programación) es la posibilidad de editar personalmente operaciones aritméticas y de crear funciones que realicen determinadas operaciones.
En el siguiente ejemplo se puede ver cómo se crea una función que nos devuelva la
media, suma, desviación estandard, variancia y rango de una variable. Una vez creada,
podremos aplicarla a cualquier variable.
estadisticos <-function(x){
+ cat("\n","La media es",mean(x),"\n")
+ cat("\n","La suma es",sum(x),"\n")
+ cat("\n","La desviacion estandard es",sd(x),"\n")
+ cat("\n","La variancia es",var(x),"\n")
+ cat("\n","El rango es","[",range(x),"]","\n") + }1
Las funciones deben tener un nombre, en este caso estadisticos, y su cuerpo va
encerrado entre llaves ({}) . En el ejemplo, la función es una sucesión de funciones
cat() (que encadena secuencias decaracteres) y las funciones estadísticas que queremos
obtener. Por supuesto, pueden añadir todas las que deseen. . .
Una vez creada, se puede aplicar a cualquier variable; por ejemplo cars$speed. Así,
estadisticos(cars$speed)
devuelve
La media es 15.4
La suma es 770
La desviacion estandard es 5.287644
La variancia es 27.95918
El rango es [ 4 25 ]
Esta función estará disponible en el espacio de trabajo siempre y cuando sea guardada
(por ejemplo, al abandonar R, comunicando que deseamos guardar las modificaciones)
y no sea borrada del mismo (con rm(estadisticos).
Si queremos que la función esté disponible en cualquier otro espacio de trabajo,
podemos introducirla en el fichero de funciones de R. Otra posibilidad sería crear un
paquete con nuestras propias funciones, pero esta posibilidad de momento no vamos a
considerarla.
Una de las ventajas de R es que es software libre, de modo que se distribuye con
el código fuente en formato editable. De esta manera, podemos modificar el programa
según nuestros intereses. En este caso, lo que nosotros vamos a hacer es introducir una
función nueva, creada por nosotros mismos, en el paquete base de R.
Para ello (en Linux) no tenemos más que abrir el fichero /usr/lib/R/library/base/R/base
(la localización puede variar en función de la distribución de Linux) con cualquier editor de texto y teclear la función tal y como lo hemos hecho en R. Por supuesto, debemos
tener permiso de escritura sobre el fichero, cuyo propietario será por defecto root. Al
guardar los cambios, la nueva función estará disponible siempre que arranquemos R ya
que el paquete base se carga automáticamente.
Como hemos adelantado anteriormente, en R también podemos construir expresiones algebráicas que nos permiten calcular medidas no implementadas en los paquetes
1 El signo + que aparece en el texto no se introduce por teclado sino que es añadido automáticamente por
R cuando en la linea de comandos pulsamos la tecla Intro para añadir un salto de linea
5.1. ANÁLISIS EXPLORATORIO DE LOS DATOS
37
con los que trabajemos. Por ejemplo, si necesitamos conocer la media geométrica de
una variable, sabiendo que se define como
G=
√
n
x1 · x2 . . . · xn
podemos introducir (en el caso de cars$dist)
prod(cars$dist)^(1/length(cars$dist))
donde prod() es la función que calcula el producto de los elementos de un vector y
length() devuelve el número de elementos de un vector.
Por supuesto, si vamos a requerir a menudo la media geométrica, podemos construir
una función que acepte como argumento cualquier variable. En este caso podría ser
media.geometrica<-function(x) {prod(x)^(1/length(x)) }
Así,
media.geometrica(cars$dist)
devolvería
[1] 34.32615
5.1.2. El gráfico stem and leaf
Este gráfico constituye una manera rápida y efectiva de aproximarnos a la distribución de frecuencias de una variable. La función que debemos utilizar es stem(). Por
ejemplo
stem(cars$speed)
da la siguiente salida por pantalla
The decimal point is at the |
4|
6|
8|
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
00
00
00
00000
00000000
0000000
00000
0000000
00000
00
00000
Podemos expandir la escala (vemos que los intervalos en los que se ha dividido la
variable van de dos en dos) introduciendo la opción scale en la función. A continuación
vemos el resultado
stem(cars$speed, scale=3)
The decimal point is at the |
4|
5|
6|
00
CAPÍTULO 5. ESTADÍSTICA DESCRIPTIVA
38
7|
8|
9|
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
00
0
0
000
00
0000
0000
0000
000
00
000
0000
000
00000
0
0
0000
0
25 |
5.1.3. El gráfico boxplot
Este es uno de los clásicos del análisis exploratorio. Permite hacernos una idea de
la distribución de la variable a partir de los cuartiles y los valores extremos. Existen
muchas posibilidades para personalizar y mejrar el resultado que genera la función
boxplot() sin opciones, pero serán tratadas más en profundidad en el capítulo dedicado
a los procedimientos gráficos. De momento veremos sólo su uso básico. Para obtener
el boxplot de la variable dist del data.frame cars habría que teclear simplemente
boxplot(cars$dist)
obteniéndose la Figura 5.1. También se puede representar más de una variable en el
mismo gráfico. Para ello no hay más que introducirlas como argumentos de la función.
A continuación vemos cómo obtener los boxplot de las variables IN,SF,B,NT,SB del
data.frame resultados
boxplot(resultados$IN,resultados$SF,resultados$B,resultados$NT,
resultados$SB)
(recordar que podríamos evitarnos teclear continuamente la referencia a resultados si
previamente hemos hecho attach(resultados) )
en la pantalla gráfica aparecerá la Figura 5.2. En ella pueden observarse todos los
elementos típicos de los diagramas de caja, como los valores extremos y los valores
atípicos. También queda patente que la figura merece un retoque profundo, pero eso
aprenderemos a hacerlo posteriormente.
Puede ser muy interesante que, en el boxplot, la anchura de las cajas sea variable en
función del número de casos representado en cada categoría. Para ello hay que utilizar
el parámetro width, que permite introducir un vector de anchuras. En nuestro caso la
anchura dependerá del número de IN,SF,B,NT y SB presentes en el data.frame. Para
conseguir la Figura 5.3 hemos hecho lo siguiente
a<-c(sum(IN,na.rm=T),sum(SF,na.rm=T),sum(B,na.rm=T),
5.1. ANÁLISIS EXPLORATORIO DE LOS DATOS
0
20
40
60
80
100
120
39
0
2
4
6
8
10
Figura 5.1: Diagrama de caja con la función boxplot()
1
2
3
4
5
Figura 5.2: Varios diagramas de caja con la función boxplot()
40
CAPÍTULO 5. ESTADÍSTICA DESCRIPTIVA
sum(NT,na.rm=T),sum(SB,na.rm=T))
boxplot(IN,SF,B,NT,IN,width=a)
Con la primera instrucción creamos el vector de anchuras, que es resulta de sumar el
número de IN,SF,B . . . descontando los valores perdidos. En la segunda introducimos
ese vector en el argumento width de la función.
5.1.4. El histograma
El histograma es uno de los gráficos estadísticos más populares, y es uno de los
habituales en el análisis exploratorio de las variables porque conocer la distribución de
frecuencias de las mismas es una cuestión realmente importante.
Ya hemos visto antes cómo usar la función hist() sin más argumento que la serie de datos a representar para obtener la Figura 3.2. Ahora vamos a ver cómo controlar algunas
de las cuestiones básicas en el diseño (no tanto en la presentación, cosa que veremos
en el capítulo final) del histograma.
Una cuestión importante (más bien, importantísima) es la definición de los intervalos de las clases en que vamos a fragmentar la variable. Eso lo haremos con el argumento breaks. A continuación vemos cómo se utiliza con un ejemplo que da lugar a la
Figura 5.4. hist(cars$speed,labels=T,breaks=0:9*3,col=3)
hist(cars$speed,labels=T,breaks=0:9*4,col=3)
hist(cars$speed,labels=T,breaks=0:14*2,col=3)
Con la primera instrucción creamos el histograma de la izquierda. Como vemos, los
límites de clase son 0, 3, 6, 9,. . . ,27. Para evitarnos poner todos esos valores, introducimos la expresión 0:9*3, que multiplica por 3 los enteros que van del 0 al 9 (ambos
incluidos).
Con la segunda obtenemos el histograma del medio. En este caso los intervalos tienen
una amplitud de 4 unidades y el rango va desde 0 a 36.
Finalmente, con la tercera instrucción obtenemos la figura de la derecha, en la que las
clases van de dos en dos desde el 0 hasta el 28.
En todos los casos, con el argumento col=3 hacemos que los histograms sean de color
verde. Con labels=T hacemos que se impriman los valores de frecuencia asociados a
cada clase.
Como puede observarse, la definición de las clases determina la forma del histograma. Veremos más adelante cómo evitar este problema.
Podemos hacer tanto histogramas de frecuencias absolutas como de frecuencias
relativas. Por defecto, son del primer tipo. Para conseguir los segundos no hay más que
incluir el argumento freq=F. Así,
hist(cars$speed,labels=T,col=2,freq=F)
genera la Figura 5.5. En ella se aprecia que el eje de ordenadas está etiquetado como
density y no como frequency.
5.1.5. Contraste de normalidad
Asegurarnos de que una variable se ajusta a la distribución normal es un requisito
previo a la aplicación de muchos procedimientos estadísticos y por ello debe realizarse
5.1. ANÁLISIS EXPLORATORIO DE LOS DATOS
0
2
4
6
8
10
41
1
2
3
4
5
Figura 5.3: Diagramas de caja de anchura variable con el argumento width
15
10
9
6
6
10
4
Frequency
5
Frequency
10
8
6
6
5
4
3
5
6
0
1
0
5
10
15
cars$speed
20
25
1
1
0
5
10
15
20
25
cars$speed
0
0
30
35
0
0
2
2
1
0
2
2
3
2
0
Frequency
8
7
8
4
8
13
4
9
Histogram of cars$speed
8
Histogram of cars$speed
11
15
Histogram of cars$speed
0
0
5
0
10
15
cars$speed
Figura 5.4: Modificación de las clases del histograma con breaks
20
25
CAPÍTULO 5. ESTADÍSTICA DESCRIPTIVA
42
0.07
Histogram of cars$speed
0.068
0.04
0.03
0.028
0.028
0.01
0.02
Density
0.05
0.06
0.068
0.00
0.008
0
5
10
15
20
25
cars$speed
Figura 5.5: Frecuencias relativas con freq=F
en las primeras fases de cualquier análisis estadístico. Vamos a considerar dos posibles
aproximaciones al problema: el método gráfico y el test de Shapiro-Wilk .
Método gráfico
Existen varias posibilidades para llevar a cabo este análisis. La primera y más clásica es la representación del histograma de frecuencias de la variable (por ejemplo,
Figura 5.6)2 .
Sin embargo, el histograma presenta por lo general el problema de la elección del
número y amplitud de las clases. Estos problemas se resuelven si, en lugar de representar el histogrma, representamos la función de densidad de la variable. Para ello, R
dispone de la función density(). Así, tecleando
plot(density(cars$speed))
se obtiene la (Figura 5.7). En este caso, permite apreciar un buen ajuste de los datos a
la ley normal.
Otro método gráfico es la observación del gráfico Q-Q (cuantil-cuantil) de la variable. En este gráfico se representan los valores observados en el eje de ordenadas y
los valores teóricos en el de las abcisas. Cuando la variable sigue una ley normal, los
puntos deben alinearse en línea recta.
Para ilustrar el caso, vamos a considerar si determinado índice de resultados académicos (definido como una combinación lineal del número de IN,SF, B,NT y SB acumulados por el alumnado del data.frame resultados) se ajusta a la distribución normal. La
2 En
el capítulo final se explica cómo añadir al histograma la curva normal
5.1. ANÁLISIS EXPLORATORIO DE LOS DATOS
43
Density
0.0
0.1
0.2
0.3
0.4
Histogram of scale(cars$speed)
−2
−1
0
1
2
scale(cars$speed)
Figura 5.6: Histograma con la función hist()
Density
0.00
0.01
0.02
0.03
0.04
0.05
0.06
density(x = cars$speed)
0
5
10
15
20
25
30
N = 50 Bandwidth = 2.15
Figura 5.7: Función de densidad con plot(density())
44
CAPÍTULO 5. ESTADÍSTICA DESCRIPTIVA
secuencia de instrucciones a introducir sería la siguiente
resultados$indice<-(-2*IN)+SF+(2*B)+(3*NT)+(4*SB)
qqnorm(resultados$indice)
Con la primera instrucción creamos el índice y lo añadimos como una variable nueva al
data.frame resultados. Con la segunda pedimos que dibuje el gráfico Q-Q de la nueva
variable. El resultado es el de la Figura 5.8. En este caso se aprecia claramente que la
variable no sigue la ley normal porque la nube de puntos no se ajusta en absoluto a una
recta. Sin embargo, en muchas ocasiones la valoración visual puede llegar a ser problemática. Por ejemplo, si analizamos la misma variable seleccionando sólo los casos
correspondientes al año 1996 (Figura 5.9), vemos que no es tan fácil decidir si se ajusta
o no a la ley normal ya que parece haber un segmento lineal más definido.
Para estos casos es conveniente aplicar alguna prueba de inferencia no paramétrica
como el test de Shapiro-Wilk que estudiamos a continuación.
Contraste de Shapiro-Wilk
Una de las características que diferencia los métodos numéricos de los gráficos es
que vamos a poder introducir un nivel de significación para aceptar o rechazar la hipótesis de ajuste a la distribución teórica. Para el caso concreto de la distribución normal,
el test que vamos a estudiar es una de las mejores opciones que nos proporciona R. Se
lleva a cabo con la función shapiro.test() y a continuación se aplica al caso anterior con
un nivel de significación del 5 %
shapiro.test(resultados$indice[Año==1996])
Shapiro-Wilk normality test
data: resultados$indice[Año == 1996]
W = 0.9805, p-value = 0.00249
Al ser la probabilidad p < 0,05, se debe rechazar la hipotesis de ajuste a la distribución
normal con ese nivel de significación, eliminando la duda que podía introducir el análisis meramente gráfico.
Sin embargo, aplicado a la variable cars$speed,
shapiro.test(cars$speed)
Shapiro-Wilk normality test
data: cars$speed
W = 0.9776, p-value = 0.4576
En este caso, la probabilidad asociada al estadístico w de Shapiro-Wilk (0,4576) es
mayor que 0,05, por lo que se situa dentro de la zona de aceptación de la hipótesis de
ajuste a la ley normal. Así, el test confirma lo que parecía adelantar la representación
gráfica de la función de densidad (5.7).
5.1. ANÁLISIS EXPLORATORIO DE LOS DATOS
45
10
−20
−10
0
Sample Quantiles
20
30
40
Normal Q−Q Plot
−4
−2
0
2
4
Theoretical Quantiles
Figura 5.8: Gráfico Q-Q con la función qqnorm()
10
−20
−10
0
Sample Quantiles
20
30
40
Normal Q−Q Plot
−3
−2
−1
0
1
2
3
Theoretical Quantiles
Figura 5.9: Otro gráfico Q-Q con la función qqnorm
CAPÍTULO 5. ESTADÍSTICA DESCRIPTIVA
46
5.2. Cómo resumir la información contenida en un data.frame
Desde sus inicios, la Estadística ha sido entendida como una disciplina cuyos fundamentos básicos eran el almacenamiento y análisis de grandes cantidades de datos. En
este apartado vamos a estudiar cómo realizar en R lo que, aun hoy, la mayor parte de la
gente considera como estadísticas, es decir, la síntesis en forma de tablas de recuentos,
frecuencias,. . . de grandes bases de datos. Para ello son fundamentales las funciones
table() y las diferentes variantes de la función apply().
5.2.1. Tablas de frecuencias absolutas
Estas son las tablas más básicas. Nos informan del número de casos que presentan
cada una de las modalidades de determinada variable. Analizaremos por separado la
creación de tablas de diferente dimensión.
Tablas unidimensionales
Estas son las más sencillas de todas. Sólo tomamos en consideración una variable.
Por ejemplo, para hacer un recuento del número total de alumnos con 0, 1, 2, ..,10 insuficentes presentes en el data.frame resultados deberíamos teclear simplemente (siempre que resultados haya sido puesto en ruta de búsqueda con attach())
table(IN)
cuyo resultado es
table(IN)
IN
0
1
2
3
4
5
6
7
8
9
10
1644 703 510 410 329 321 317 225 172 113 93
En muchos casos nos interesa agrupar los casos en intervalos. Para ello, podemos
utilizar la función cut(). Por ejemplo, cut(IN,c(-0.01,2,5,8,10)) agrupará los registros
de resultados en los intervalos definidos por los límites de clase −0,01, 2, 5, 8, 10 . Hay
que hacer notar que cut(), por defecto, genera intervalos semiabiertos por abajo, de
modo que para incluir en la primera clase los casos con 0 insuficientes, hay que definir
un límite de clase ligeramente inferior (en este caso, −0,01).
Ahora, para tabular el número de casos que contiene cada clase podríamos utilizar
la función tapply() de la siguiente manera:
tapply(Alumno,cut(IN,c(-0.01,2,5,8,10)),length)
cuyo resultado es
(-0.01,2] (2,5] (5,8]
2858
1061 715
(8,10]
207
Veamos con más detalle cuál es la sintaxis de la función aplicada: se le dice a R que
coja la variable Alumno y reparta los casos en los intervalos definidos por la función
5.2. CÓMO RESUMIR LA INFORMACIÓN CONTENIDA EN UN DATA.FRAME 47
cut() según el número de IN que tenga cada uno. Una vez hecho este reparto, se aplica
la función length() para ver cuál es la longitud del vector resultante, es decir, el número
de casos. En este ejemplo no podemos utilizar la función sum() para obtener este último
valor, como parecería más normal, porque la variable Alumno no es de tipo numérico
sino que es un factor, de modo que no se le pueden aplicar operaciones de tipo algebráico.
Como vemos, la tabla resultante nos informa de que hay 2858 alumnos/as con 0, 1 o 2
insuficientes, 1061 con 3, 4 o 5,. . . Sin embargo, los datos no coinciden con la primera
tabla, según la cual hay 2857, 1060, . . . Esta diferencia se debe a que la función table()
ignora por defecto los valores perdidos, pero tapply() los toma en consideración y los
incorpora a cada una de las clases. Como en el data.frame resultados hay un caso, el
4838, con NA’s en casi todas las variables, la agrupación tabulada por tapply() da valores superiores en una unidad a los que corresponden eliminando los valores perdidos.
Una manera de evitar esta situación, si así nos interesa, es eliminar previamente el caso
problemático.
Tablas bidimensionales
Constituyen el ejemplo más típico de lo que entendemos por tablas de contingencia
o “de referencias cruzadas” (en terminología de bases de datos). En el caso anterior,
en el que estábamos interesados en el estudio de la variable número de insuficientes,
una tabla bidimensional podría ser la que proporcionara el reparto de la variable en los
diferentes años incluidos en el data.frame. Para conseguir esa tabla podríamos teclear
table(Año,IN)
resultando
Año
1994
1995
1996
1997
1998
1999
2000
2001
IN
0 1 2 3
27 11 2 3
69 20 21 4
104 37 26 24
110 64 29 19
415 160 117 87
383 149 129 94
323 144 101 95
213 118 85 84
4
3
14
7
10
88
69
78
60
5
1
6
7
4
60
78
91
74
6
5
7
10
11
61
81
79
63
7
4
6
6
7
53
39
69
41
8
9
4
5
6
31
30
49
38
9
5
8
6
4
14
37
20
19
10
0
4
4
21
16
18
17
13
En las tablas de contingencia aparecen con frecuencia una columna y una fila con
los valores totales por filas y columnas. En R no hay ninguna función que genere directamente tal tipo de tabla, pero resulta bastante sencillo generarla a partir de la tabla
obtenida anteriormente. Los pasos serían los siguientes:
(1) tabla.normal<-table(Año,IN)
(2) total.filas<-apply(tabla.normal,1,sum)
(3) tabla.intermedia<-cbind(tabla.normal,total.filas)
(4) total.columnas<-apply(tabla.intermedia,2,sum)
(5) tabla.final<-rbind(tabla.intermedia,total.columnas)
En la primera instrucción se crea la tabla original y se asigna a un objeto que llamamos
CAPÍTULO 5. ESTADÍSTICA DESCRIPTIVA
48
tabla.normal.
En la segunda, calculamos el total por filas con la función apply() (no confundir con
tapply()). A apply() debemos indicarle varias cosas. En primer lugar, el objeto sobre el
que aplicar la función (en este caso tabla.normal); en segundo, que se aplica por filas
1; y, finalmente, la acción que queremos aplicar (en este caso, calcular la suma, sum).
El resultado de la función lo asignamos al objeto que llamamos total.filas.
En la tercera instrucción incorporamos a la tabla inicial, mediante la función cbind(),
la columna de totales calculada en el paso anterior. Asignamos el nuevo objeto a una
tabla llamada tabla.intermedia que no nos interesará una vez terminado el proceso.
En la cuarta, calculamos el total por columnas de la tabla intermedia, que contiene ya
el total por filas. Lo hacemos con la función apply(), pero en este caso, como el cálculo
se efectúa por columnas y no por filas, en lugar de poner como argumento el número 1,
ponemos el 2. También, asignamos el resultado al objeto que llamamos total.columnas.
En el último paso, incorporamos el total por columnas a la tabla intermedia con cbind()
para obtener la tabla.final .
El resultado sería:
tabla.final
0
1
1994
27 11
1995
69 20
1996
104 37
1997
110 64
1998
415 160
1999
383 149
2000
323 144
2001
213 118
total.columnas1644 703
2
2
21
26
29
117
129
101
85
510
3
3
4
24
19
87
94
95
84
410
4
3
14
7
10
88
69
78
60
329
5
1
6
7
4
60
78
91
74
321
6 7
5 4
7 6
10 6
11 7
61 53
81 39
79 69
63 41
317 225
8
9
4
5
6
31
30
49
38
172
9
5
8
6
4
14
37
20
19
113
10
0
4
4
21
16
18
17
13
93
total.filas
70
163
263
285
1102
1107
1066
808
4837
Por supuesto, sería posible realizar la acción con una sola instrucción que reuniera las
anteriores, pero la creación de macroinstrucciones debería reservarse a los casos en los
que se tenga gran control de sus resultados.
Como este tipo de tablas es muy habitual, podría ser conveniente crear una función
que la generase con sólo indicar qué variables queremos tabular. Un ejemplo de función que llevaría a cabo ese cometido sería la siguiente.
crea.tabla<-function(x){
+TF<-margin.table(x,1)
+ TC<-margin.table(x,2)
rbind(cbind(x,TotalFilas=TF),TotalColumnas=c(TC,sum(TC)))
}
Como puede apreciarse, en este caso hemos utilizado la función margin(), que calcula
directamente la suma por filas o columnas de manera similar a como lo hace apply().
La función se guardaría en el espacio de trabajo con el nombre crea.tabla. Ahora sólo
habría que teclear
crea.tabla(table(IN,Año))
para obtener la tabla anterior.
5.2. CÓMO RESUMIR LA INFORMACIÓN CONTENIDA EN UN DATA.FRAME 49
Del mismo modo,
crea.tabla(table(Evaluacion,IN))
generaría una tabla de contingencia de las variables Evaluación e IN con totales de filas
y columnas.
Siempre que guardemos los objetos en el espacio de trabajo en el momento de
abandonar R, dispondremos de la función crea.tabla() al abrir de nuevo ese espacio de
trabajo.
Sin embargo, la función no estaría disponible al abrir cualquier otro espacio de trabajo.
Para que sí lo estuviera, podemos introducir la función en el paquete base tal y como
se explicó en el apartado Medidas características.
Tablas multidimensionales
En las tablas multidimensionales se resume la información de más de dos variables. Por supuesto, para visualizarlas en un plano bidimensional, es preciso agruparlas
en dos ejes.
Supongamos que queremos conocer el número de calificaciones contenidas en nuestra tabla de resultados académicos agrupadas por año,curso y evaluación. Podríamos
teclear
ftable(Año,Curso,Evaluacion)
saliendo por pantalla la siguiente tabla
Evaluacion 1
Año Curso
1994 1
0
2
0
3
0
4
0
1995 1
0
2
0
3
0
4
0
1996 1
0
2
0
3
0
4
0
1997 1
0
2
0
3
0
4
0
1998 1
99
2
96
3
95
4
72
2
F
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
100
102
97
76
0
0
70
0
0
0
111
52
0
27
119
90
9
66
107
103
102
106
84
73
CAPÍTULO 5. ESTADÍSTICA DESCRIPTIVA
50
1999 1
2
3
4
2000 1
2
3
4
2001 1
2
3
4
103
132
44
65
90
110
100
56
95
146
102
58
103
138
82
66
97
120
101
59
97
148
102
60
104
133
72
65
100
121
69
43
0
0
0
0
Por supuesto, es posible agrupar alguna de las variables en clases tal y como hicimos en las tablas bidimensionales. Así,
ftable(Año,Curso,cut(SB,3))
nos proporcionará una tabla con el número de sobresalientes agrupado en tres clases
(cut(SB,3)) en los diferentes cursos de los años incluidos en la base de datos.
Finalmente, indicar que podemos agrupar las variables mediante expresiones cuasialgebráicas que facilitarán la creación de tablas de dimensiones mayores. Si deseamos
agrupar, por un lado, Curso y Año y, por otro, Evaluacion y SB. Podríamos introducir
la siguiente instrucción
ftable(Año+Curso~Evaluacion+SB)3
lo que generaría una tabla de cuatro dimensiones agrupadas en dos entradas.
5.2.2. Tablas con otras medidas estadísticas
Además de las tablas de recuento de casos estudiadas en el apartado anterior, es
habitual elaborar otros tipos de tablas. Las más comunes son, tal vez, las tablas de
frecuencias relativas, pero también nos pueden interesar otras medidas estadísticas. En
este apartado veremos algunas de las solcuiones que proporciona R para elaborar tablas
de este tipo.
Tablas de frecuencias relativas
Para crear este tipo de tablas podemos utilizar, de nuevo, las posibilidades que ofrece R (y que son típicas de los sistemas UNIX) para llegar a un objetivo final mediante
pasos intermedios. Veamos el procedimiento con un ejemplo.
(1)tabla.inicial<-table(Año,Curso)
(2)total.filas<-apply(tabla.inicial,1,sum)
(3)str(tabla.inicial)
(4)tabla.frecuencias.rel<-tabla.inicial[1:8,1:4]/total.filas*100
(5)options(digits=4)
(6)tabla.frecuencias.rel
Con la primera instrucción creamos una tabla bidimensional.
3 La
tilde se introduce con la combinación de teclas AltGr + 4
5.2. CÓMO RESUMIR LA INFORMACIÓN CONTENIDA EN UN DATA.FRAME 51
Con la segunda, creamos el total por filas, tal y como se hizo en un apartado anterior,
con la función apply()
Con la tercera instrucción analizamos la estructura de la tabla inicial. En este caso
nos informa que tabla.inicial es el resultado de tabular la variable Año (que presenta
8 elementos [1:8]) y la variable Curso (que presenta 4 elementos [1:4]). Estos datos
son utilizados en la siguiente orden, que hace dividir de manera adecuada los elementos de tabla.inicial entre los elementos de total.filas para generar la nueva tabla tabla.frecuencias.rel. El resultado se multiplica por 100 para obtener porcentajes. Como
se puede apreciar, la estructura de la tabla inicial se incorpora a la operación algebráica
entre corchetes para efectuar la selección de los elementos de la tabla.
La quinta es una instrucción símplemente para reducir el número de decimales de la
salida (por defecto, digits=7).
La última orden imprime por pantalla la tabla de frecuencias relativas calculadas en
base al total por filas. La tabla es la siguiente
Año
1994
1995
1996
1997
1998
1999
2000
2001
1
0.000
0.000
0.000
3.158
27.314
28.004
26.923
23.762
Curso
2
0.00
0.00
11.44
23.16
27.59
36.40
32.93
36.39
3
4
100.00 0.00
68.10 31.90
50.42 38.14
37.54 36.14
25.05 20.05
17.89 17.71
25.33 14.82
25.25 14.60
Afortunadamente, R nos proporciona la función prop.table() que nos genera directamente tablas de frecuencias relativas por filas o columnas. En el caso anterior, sólo
deberíamos teclear
prop.table(tabla.inicial,1)*100
para obtener el mismo resultado. Obsérvese que hay que multiplicar por 100 si deseamos que la tabla muestre porcentajes ya que por defecto el resultado aparece en tantos
por uno.
Si hubiéramos introducido la siguiente orden
prop.table(tabla.inicial,2)*100
el resultado hubiera sido una tabla de frecuencias relativas por columnas (como manda
el 2 introducido como argumento de la función).
Otras tablas estadísticas
Conocemos ya la función summary() y la manera de obtener otras medidas estadísticas de las variables incluidas en un data.frame. Por otro lado, en el apartado anterior
hemos visto cómo utilizar la función apply() para calcular totales por filas y columnas.
En este apartado vamos a profundizar un poco más en las posibilidades de extracción
de información en forma de tablas.
CAPÍTULO 5. ESTADÍSTICA DESCRIPTIVA
52
Cuando nos interese obtener determinado estadístico de una serie de variables de
un data.frame o una tabla bidimensional, podemos aplicar la función apply(). Por ejemplo, para conocer el rango de las variables IN,SF,B,NT y SB, podemos teclear
apply(resultados[3:7],2,range,na.rm=T)
la orden es ya familiar. Los corchetes seleccionan las variables que queremos analizar,
el 2 ordena a la función que “trabaje” por columnas, range es la función que deseamos aplicar a las variables, y na.rm=T indica que se omitan los valores perdidos. El
resultado es
B
[1,] 0
[2,] 9
IN
0
10
NT SB SF
0
0
0
9
10 10
La función también puede aplicarse a una tabla. Por ejemplo, podemos pedir la desviación estandard para las diferentes modalidades de la variable IN en los diferentes
años del data.frame resultados. La tabla que hemos llamado tabla.final en un apartado
anterior será ahora el argumento de la función apply(). Este es el resultado:
apply(tabla.final,2,sd,na.rm=T)
0
1
2
3
4
5
6
7
8
9
10
total.filas
499.82 213.02155.81125.92101.66100.4997.8669.85 52.80 34.57 28.10 1474.60
Podemos incluso hacer tablas más complejas, en las que se presente el estadístico
de una variable en una relación cruzada de dos variables diferentes. Por ejemplo, podemos querer conocer la media de insuficientes en los diferentes cursos a lo largo de
los distintos años recogidos en nuestro data.frame. Como se ve, en este caso entran en
juego tres variables. Dos de ellas, Año y Curso, serán las entradas de la tabla y la tercera, IN, será el valor. Para obtener este tipo de tablas aplicaremos la función tapply()
de la siguiente manera
tapply(IN,list(Año,Curso),mean)
el resultado es
1994
1995
1996
1997
1998
1999
2000
2001
1
NA
NA
NA
1.89
2.11
2.26
2.26
2.83
2
NA
NA
1.15
0.71
2.68
3.02
3.04
2.89
3
3.09
3.00
2.32
3.64
2.90
3.05
3.64
3.99
4
NA
1.06
1.70
1.89
1.49
1.76
2.51
1.81
Este tipo de tablas va bastante más allá que las simples tablas de frecuencias y proporcionan información solicitada muy habitualmente en los estudios estadísticos. Esta
tabla nos dice, por ejemplo, que en 1996, la media de insuficientes en tercero fue de
2.32 y que en 2001 fue de 3.99.
5.2. CÓMO RESUMIR LA INFORMACIÓN CONTENIDA EN UN DATA.FRAME 53
5.2.3. Métodos gráficos para presentar la información contenida
en tablas
Además de las tablas, podemos utilizar diferentes gráficos para visualizar la información contenida en una base de datos. El tipo de representación dependerá del número
de variables que queramos analizar y la naturaleza de las mismas.
En apartados anteriores ya hemos presentado algunas de las funciones gráficas que
podremos aplicar con este fin (hist(), plot(), boxplot(). Por ese motivo nos centraremos
en la aplicación de la función plot() al caso concreto de tablas.
Anteriormente hemos creado una tabla unidimensional con el número de casos que
presentaban cada uno de los valores que adopta la variable IN. Podemos representar
gráficamente la información contenida en esa tabla con la instrucción
barplot(table(resultados$IN))
cuyo resultado es el gráfico de la Figura 5.10, un gráfico de barras, que resulta una
opción muy adecuada a una variable de este tipo.
Para el caso de tablas bidimensionales podemos utilizar la función plot(). Por ejemplo, si queremos representar el número de insuficientes a lo largo de los diferentes años,
podemos teclear
plot(table(IN,Año))
que proporciona el gráfico de la Figura 5.11. Este gráfico permite descubrir algunas
particularidades a primera vista, como el hecho de que durante los cuatro primeros
años haya bastantes menos registros que durante los cuatro segundos; la disminución
progresiva del alumnado con cero insuficientes; o la gran cantidad de alumnos que
tuvieron 10 insuficientes en el año 1997.
Cuando la representación que queremos hace es de carácter multidimensional, la
función plot() da lugar a un gráfico más complejo. Para ilustrarlo utilizaremos los datos
contenidos en la tabla Titanic que viene con R. Ejecutando las siguientes instrucciones
se obtiene la Figura 5.12.
El gráfico requiere mayor esfuerzo de interpretación pues se representa por un lado el
sexo de la persona y si sobrevivió o no y, por otro, la clase de pasaje y la edad. Puede
apreciarse como la mayor mortandad afectó a los varones adultos de clase inferior y
que la mayor tasa de supervivencia se dio entre las mujeres de primera clase. Lo hemos
obtenido del siguiente modo
data(Titanic)
plot(Titanic)
Logicamente, es posible representar parte de una tabla utilizando las técnicas de selección que ya conocemos. Por ejemplo, para analizar la evolución de la media de
insuficientes en tercero a lo largo de los años podemos seleccionar la columna correspondiente de la última tabla elaborada. Para ello no habría mas que teclear
plot(tapply(IN,list(Año,Curso),mean)[,3],type=“l”)
En esta instrucción, con [,3] se le indica a R que seleccione todos los elementos de la
tercera columna. Con type=“l” se le dice que el gráfico sea de líneas. El resultado es
el de la Figura 5.13. Como puede observarse, en el eje de las abcisas aparece un índice
en lugar del año. Como dijimos anteriormente, los retoques necesarios para hacer los
CAPÍTULO 5. ESTADÍSTICA DESCRIPTIVA
0
500
1000
1500
54
0
1
2
3
4
5
6
7
8
9
10
Figura 5.10: Gráfico de barras con barplot()
1998
1999
2000
2001
10
9
8
7
6
5
4
3
2
IN
1
0
1994
1995 1996 1997
Año
Figura 5.11: Un gráfico interesante para tablas bidimensionales
5.2. CÓMO RESUMIR LA INFORMACIÓN CONTENIDA EN UN DATA.FRAME 55
1st
Adult
2nd
Child Adult
Child
3rd
Adult
Child
Crew
Adult
Female
Yes
No
Sex
Male
Yes
No
Child
Class
Figura 5.12: Representación gráfica de una tabla multidimensional
gráficos más elegantes se verán en el capítulo final.
56
4.0
3.5
3.0
tapply(IN, list(Año, Curso), mean)[, 3]
1
2
3
Index
5
6
7
8
CAPÍTULO 5. ESTADÍSTICA DESCRIPTIVA
4
Figura 5.13: Representación de parte de una tabla multidimensional
2.5
Capítulo 6
Pruebas de significación
6.1. Pruebas no paramétricas
6.1.1. Pruebas basadas en la χ2
Vamos a considerar la aplicación de la χ2 en dos situaciones:
1. para evaluar el ajuste de unos datos unidimensionales a una distribución de probabilidad
2. para determinar la homegeneidad de una variable a partir de una tabla de contingencia
χ2 para analizar el ajuste a una distribución
La función que proporciona R para la aplicación de los test basados en la χ2 es
chisq.test(). Aplicada a un vector de datos sin más argumentos, evalua el ajuste de los
mismos a una función de distribución uniforme.
Por ejemplo, consideremos que en el centro escolar cuyos resultados estamos analizando el alumnado procede de cuatro barrios diferentes. En el Cuadro 6.1 se indican el
número de alumnos/as que escolariza de cada barrio así como el número de alumnos/as
con problemas educativos que aporta cada uno de los barrios.
Supongamos que estamos interesados en saber si la procedencia del alumnado por barrios es unidorme con un nivel de significación del 1 %. Para ello podríamos introducir
Número de alumnos/as
Alumnos/as con dificultades
A
195
84
B
90
54
C
28
11
D
23
11
Cuadro 6.1: Alumnado total y con problemas educativos
57
58
CAPÍTULO 6. PRUEBAS DE SIGNIFICACIÓN
la siguiente instrucción
chisq.test(c(195,90,28,23))
cuyo resultado es
Chi-squared test for given probabilities
data: c(195, 90, 28, 23)
X-squared = 228.7381, df = 3, p-value = < 2.2e-16
Como la probabilidad asociada al parámetro χ2 p-value = < 2.2e-16 es inferior al nivel
de significación (0.01), se rechaza la hipótesis de uniformidad en la procedencia del
alumnado (tal y como podíamos prever a la luz de los datos proporcionados).
Pasemos ahora al análisis del ajuste a una distribución de probabilidad no uniforme. En el ejemplo que estamos considerando, podríamos estudiar si el alumnado con
dificultades educativas se distribuye entre los barrios de procedencia en concordancia
con el número total de alumnos/as que viene de cada barrio. En este caso tendremos
que evaluar la χ2 incorporando como frecuencias teóricas la probabilidad de procedencia que le corresponde a cada barrio, que es el cociente entre el alumnado del barrio y
el alumnado total. Podríamos actuar del siguiente modo
alumnado<-c(195,90,28,23)
prob.alumnado<-alumnado/sum(alumnado)
alum.dificultades<-c(84,54,11,11)
chisq.test(alum.dificultades,p=prob.alumnado)
en la primera sentencia se asigna los datos de procedencia de los diferentes sectores a
alumnado. En la segunda se calcula la probabilidad asociada a cada barrio dividiendo
el número de alumnos/as de cada barrio entre el total (sum(alumnado)). En la tercera
se asigna a alum.dificultades el número de alumnos con dificultades educativas procedentes de cada barrio en el orden adecuado. En la cuarta se aplica el test de χ2 al
alumnado con dificultades tomando como probabilidades teóricas las incluidas en el
vector prob.alumnado. Hay que notar que la asignación de un nuevo vector de probabilidades se hace con el argumento p. El resultado
Chi-squared test for given probabilities
data: al.problemas
X-squared = 4.1505, df = 3, p-value = 0.2457
nos muestra que la distribución por barrios del alumnado con dificultades no se desvía
significativamente de la teórica pues la probabilidad de que los valores observados se
ajusten a los teóricos, 0.2457, es muy superior al 0.05 o 0.01 que suelen tomarse como
niveles de significación para rechazar la hipótesis nula.
Test de χ2 para tablas de contingencia
Este tipo de pruebas suele utilizarse para analizar la homogeneidad de una variable
respecto a otra. Consideremos el siguiente caso: en el centro escolar se han recogido
los datos de la Tabla 6.2 que representa el número de alumnos/as que supera/repite
el primer curso de bachillerato en relación al número de áreas que suspendió el curso
precedente (0,1,2 o más). Si analizamos la tabla, parece claro que no tienen las mismas
probabilidades de susperar el curso los alumnos que aprobaron todas las áreas que los
que promocionaron con alguna área suspensa, pero deseamos poner a prueba estadísti-
6.1. PRUEBAS NO PARAMÉTRICAS
59
camente esta suposición. Podríamos hacerlo mediante la χ2 de la siguiente manera
promocionan<-c(101,14,7)
repiten<-c(14,25,13)
tabla3<-data.frame(promocionan,repiten,row.names=c(“0”,”1”,”2+”))
Con las dos primeras instrucciones creamos los vectores que formarán las columnas
con valores de la tabla de contingencia. Con la tercera creamos un data.frame, llamado
tabla3, en el que introducimos como nombres de filas (row.names) los correspondientes a 0,1,2+ suspensos.
Una vez creada la tabla de contingencia, podemos aplicar el test mediante
chisq.test(tabla3)
cuya salida es
Pearson’s Chi-squared test
data: tabla3
X-squared = 50.777, df = 2, p-value = 9.417e-12
el valor de p = 9,417e − 1 permite rechazar claramente la hipótesis de homogeneidad
de la variable repetir/no repetir en relación con la variable número de suspensos en el
curso anterior lo que demuestra claramente que, a la hora de aprobar o repetir el primer
curso de bachillerato, no es lo mismo haber aprobado la ESO con 0, 1 o 2 o más áreas
suspensas.
6.1.2. Test de Wilcoxon, de Mann-Whitney y de Kolmogorov-Smirnov
La función wilcox.test(), permite aplicar varias pruebas de significación: el test de
rangos signados de Wilcoxon; el contraste de suma de rangos de Wilcoxon; y el test
de la U de Mann-Whitney. Las diferencias entre ellos radican en los argumentos que
se pasen a la función: si tenemos dos muestras y se incorpora la opción paired=T,
tendremos muestras emparejadas y el test aplicado será el de suma de rangos de Wilcoxon. Si dejamos la opción por defecto, que es paired=F, el test aplicado será el de
Mann-Whitney. Si sólo hay una muestra, podemos utilizar la función como contraste
de localización incorporando como argumento el valor(mu) de la mediana que queremos contrastar.
Nosotros nos centraremos en la aplicación de la función para contrastar la hipótesis
de que dos muestras provengan, o no, de la misma distribución.
Supongamos que en nuestra centro educativo se ha definido un índice algebráico para medir el rendimiento académico del alumnado y se quiere contrastar su adecuación
Suspensos curso anterior
0
1
2+
Promocionan
101
14
7
Repiten
14
25
13
Cuadro 6.2: Promoción con suspensos
60
CAPÍTULO 6. PRUEBAS DE SIGNIFICACIÓN
comparando los resultados obtenidos con el índice con las valoraciones realizadas por
el profesorado. En el Cuadro 6.3 se pueden ver los resultados obtenidos por los dos
medios.
Para llevar a cabo la prueba tecleamos:
profes<-c(1,4,1,1,2,2,3,4,5,3,2,5,4,3,2,3,2,4,4,4)
indice<-c(1,4,1,1,2,1,3,4,5,3,2,5,5,3,2,3,2,5,4,3)
wilcox.test(profes,indice,paired=T)
En las dos primeras instrucciones se asignan los valores de las muestras a contrastar,
y en la tercera se aplica la función a las mismas, indicando que se trata de muestras
emparejadas. El resultado es
Wilcoxon signed rank test with continuity correction
data: profes and indice
V = 5, p-value = 1
alternative hypothesis: true mu is not equal to 0
Warning messages:
1: Cannot compute exact p-value with ties in: wilcox.test.default(profes, indice, paired
= T)
2: Cannot compute exact p-value with zeroes in: wilcox.test.default(profes, indice, paired = T)
a pesar de los dos mensajes que da, informando de los problemas encontrados, queda
de manifiesto que la hipótesis nula, que establece el mismo origen de las dos muestras,
queda totalmente confirmada ya que la probabilidad de que así sea es máxima (p = 1).
A la misma conclusión llegamos aplicando el test de Kolmogorov-Smirnov para
dos muestras. La función de R encargada de esta prueba es ks.test(). En el ejemplo que
nos ocupa, deberíamos teclear
ks.test(profes,indice)
cuyo resultado es
Two-sample Kolmogorov-Smirnov test
data: profes and indice
D = 0.1, p-value = 1
alternative hypothesis: two.sided
6.1.3. Test de Kruskal-Wallis
Con esta prueba podemos contrastar la procedencia (o no) de la misma distribución
de tres o más muestras. Supongamos que queremos saber si el índice de resultados
académicos contenido en el data.frame resultados ha variado significativamente desde
el año 1994 a 1996. Aplicando la función kruskal.test() a los valores correspondientes
podremos contestar la pregunta. El procedimiento podría ser el siguiente:
a<-subset(resultados,resultados$Año==1994,select=10)
b<-subset(resultados,resultados$Año==1995,select=10)
c<-subset(resultados,resultados$Año==1996,select=10)
kruskal.test(list(a[,1],b[,1],c[,1]))
Con las tres primeras sentencias se selecciona el índice que queremos analizar (la columna 10) para los años que nos interesan y se asignan a tres data.frame llamados a,b,c.
En la cuarta sentencia se aplica el test de Kruskal-Wallis. Para ello tenemos que cons-
6.1. PRUEBAS NO PARAMÉTRICAS
Alumno/a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Valoración profesorado
1
4
1
1
2
2
3
4
5
3
2
5
4
3
2
3
2
4
4
4
61
Valoración índice
1
4
1
1
2
1
3
4
5
3
2
5
5
3
2
3
2
5
4
3
Cuadro 6.3: Valoraciones alumnado
62
CAPÍTULO 6. PRUEBAS DE SIGNIFICACIÓN
truir una lista encadenando las tres series de datos. Como están en sendos data.frames,
es preciso seleccionar la columna (en estos casos, única) que los almacena.
El resultado
Kruskal-Wallis rank sum test
data: list(a[, 1], b[, 1], c[, 1])
Kruskal-Wallis chi-squared = 2.1531, df = 2, p-value = 0.3408
nos indica que no podemos rechazar la hipótesis de que las tres muestras provengan
de la misma distribución, pues la probabilidad de que así sea, p − value = 0,3408, es
superior al nivel de significación del 5 %.
La función boxplot() nos proporciona una aproximación gráfica a este tipo de análisis como puede apreciarse si tecleamos
boxplot(a[,1],b[,1],c[,1], notch=T)
el resultado es la Figura 6.1 en la que se aprecia que el primer cuartil ha aumentado a
lo largo de los tres años y que el rango intercuartílico se ha ido reduciendo. A pesar de
ello, las medianas son similares y, como nos indican las cuñas laterales introducidas por
la opción notch=T, no difieren entre sí de manera significativa al nivel de significación
del 5 % puesto que las incisiones se solapan unas con otras.
6.2. Pruebas paramétricas
6.2.1. Test basados en la t de Student
Debemos abandonar el data.frame resultados para hacer una pequeña incursión
en las pruebas paramétricas. Este tipo de pruebas sólo pueden ser aplicadas bajo la
condición de normalidad y con variables medidas en escala de intervalo o de razón,
y ninguna de las contenidas en él cumple esas condiciones. Para ilustrar el uso de la
función t.test(), utilizaremos los datos contenidos en el data.frame survey del paquete
MASS. Para cargarlo tecleamos
library(MASS)
data(survey)
attach(survey)
para obtener una descripción de los datos teclearemos
?survey
En el data.frame tenemos varias variables. Supongamos que nos interesa estudiar
la estatura, que es una variable que se distribuye normalmente y se mide en una escala
de razón, y su relación con el sexo y el carácter zurdo o diestro de los estudiantes. Para
ver si hay diferencias por sexos, teclearíamos
t.test(Height~Sex)
que le dice a R que aplique el test a la variable altura diferenciando dos muestras en
función del sexo (es lo que indicamos con la tilde que enlaza ambas variables) De nuevo, como hemos puesto los datos en la ruta de búsqueda con attach(survey), podemos
hacer referencia directa al nombre de las variables. El resultado que sale por pantalla
es
6.2. PRUEBAS PARAMÉTRICAS
−20
−10
0
10
20
30
40
63
1
2
3
Figura 6.1: Notched boxplots
Welch Two Sample t-test
data: Height by Sex
t = -12.9243, df = 192.703, p-value = < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-15.14454 -11.13420
sample estimates:
mean in group Female mean in group Male
165.6867 178.8260
el valor de p =< 2,2e − 16 nos indica que la hipótesis alternativa, es decir, que las
medias de estatura de las dos muestras difieren significativamente, es perfectamente
aceptable. Por el contrario, las diferencias entre los zurdos y los diestros no son significativas, ya que
t.test(Height~ W.Hnd)
da un p − value = 0,2807.
64
CAPÍTULO 6. PRUEBAS DE SIGNIFICACIÓN
Capítulo 7
Correlación y regresión
Continuaremos con los datos del data.frame survey para explicar los procedimientos básicos de los análisis de correlación y de regresión. A lo largo del capítulo se presentarán procedimientos gráficos algo más sofisticados que los estudiados hasta ahora.
En este caso serán explicados en el momento de su aplicación ya que son inseparables
del contenido conceptual de la materia. Serán dejados para el capítulo final los procedimientos de carácter general válidos para todo tipo de gráficos.
7.1. Estudio de la correlación bivariada
7.1.1. Métodos gráficos
La primera aproximación al estudio de la relación entre variables es el análisis visual del diagrama de dispersión de ambas que, como ya se sabe, puede obtenerse con
la función plot().
En la Fig 7.1 se puede observar la relación entre el pulso y la estatura de los individuos
del data.frame survey, como puede apreciarse, la correlación es escasa. En la Fig 7.2,
por el contrario, se observa una elevada correlación positiva entre la estatura y el tamaño de la mano. En ocasiones, al estudiar la relación entre dos variables, nos interesa
agrupar los casos en función de una tercera variable, generalmente categórica (lo que
en R se llama una factor). Podemos optar por dos soluciones: representar en el mismo
gráfico todos los casos representando cada grupo con un símbolo y/o color distinto; o
representar por separado los dos grupos. Veamos qué podemos hacer en R.
Supongamos que deseamos estudiar la relación entre la estatura y el tamaño de la mano
pero queremos diferenciar en el diagrama de dispersión los puntos en función del sexo
de la persona. Una forma sencilla de conseguirlo sería tecleando
plot(Height,NW.Hnd,pch=as.integer(Sex))
obsérvese que hemos añadido a la función un argumento (pch) que gestiona el tipo de
símbolo que aparece en el gráfico. Cada símbolo tiene asociado un número, por ese
motivo se transforma el código del sexo, que en el data.frame está como factor, en un
65
CAPÍTULO 7. CORRELACIÓN Y REGRESIÓN
70
40
50
60
Pulse
80
90
100
66
150
160
170
180
190
200
Height
18
16
14
NW.Hnd
20
22
Figura 7.1: Un ejemplo de escasa correlación
150
160
170
180
190
200
Height
Figura 7.2: En este caso, la correlación es fuerte
7.1. ESTUDIO DE LA CORRELACIÓN BIVARIADA
67
número. En este caso asociará al sexo femenino el 1 y al masculino el 2. El resultado es
la Figura 7.3 en la que vemos que aparecen triángulos y circunferencias diferenciando
los sexos.
Sin embargo, este tipo de gráficos precisa una leyenda pues, de lo contrario, no
sabremos qué símbolo está asociado a cada grupo. Para crear un gráfico con leyenda
deberíamos teclear
plot(Height,NW.Hnd,pch=as.integer(Sex))
legend(locator(1),legend=c(“Chicas”,“Chicos”),pch=as.integer(Sex))
La primera instrucción es la que ya hemos utilizado anteriormente: crea el gráfico y
lo presenta en la pantalla gráfica. La segunda es la que añadirá la leyenda y debemos
analizarla en detalle.
La función utilizada es legend(), una de las funciones de tipo interactivo que encontramos en R y que permite realizar acciones con el ratón sobre la pantalla gráfica.
Con el argumento locator(1) se indica que haremos sobre la pantalla un solo clic con
el botón izquierdo del ratón allí donde queramos situar la leyenda. El argumento legend=c(“Chicas”,“Chicos”) indica los nombres de los grupos representados en el
gráfico. Es muy importante ponerlos en el mismo orden en el que se encuentran en
el diseño del data.frame, lo cual puede conocerse con la función str(). Hay que darse
cuenta de que R no puede adivinar, qué entendemos nosotros por Chico o Chica de
modo que tendremos que decírselo explícitamente. Por último, pch=as.integer(Sex)
define el símbolo que utilizaremos en la leyenda que debe ser, evidentemente, el mismo que hayamos utilizado al hacer el gráfico.
Tras teclear la instrucción, la linea de comandos pasa el control al ratón. Deberemos
hacer clic en el gráfico en la zona adecuada y veremos cómo, efectivamente, se inserta
la leyenda. El resultado es el que podemos ver en la Figura 7.4.
Este tipo de gráficos puede ser en ocasiones un poco lioso y tal vez nos interese
separar los dos grupos en gráficos separados pero en la misma figura. Para ello podemos
utilizar la función coplot(), diseñada para hacer gráficos condicionados. En este caso
queremos representar la relación entre dos variables controlando la salida gráfica en
función del sexo de los registros. Para obtener dicho gráfico podemos teclear
coplot(Height~NW.Hnd | Sex)
Obsérvese que la tilde indica qué variables queremos analizar, y la barra (|) nos indica
qué variable queremos controlar. El resultado es muy interesante y podemos verlo en
la Figura 7.5. Por supuesto, es posible introducir más de una variable de control. Por
ejemplo, si queremos condicionar los diagramas de dispersión no sólo por el sexo, sino
también por el carácter diestro o zurdo del individuo, deberíamos teclear
coplot(Height~NW.Hnd | Sex + W.Hnd)
como se vé en la expresión, los factores condicionantes se encadenan con el signo +.
El resultado será un gráfico 2x2 como el de la Figura 7.6.
Para acabar con el análisis gráfico de la correlación entre variables comentaremos
el gráfico que presenta diagramas de dispersión cruzados para varias variables. Podemos crearlos con la función pairs(). Así,
pairs(survey)
generaría un gráfico que permitiría apreciar las relaciones entre todas las variables del
CAPÍTULO 7. CORRELACIÓN Y REGRESIÓN
18
14
16
NW.Hnd
20
22
68
150
160
170
180
190
200
Height
18
16
Chicas
Chicos
14
NW.Hnd
20
22
Figura 7.3: Diagrama de dispersión con dos grupos de datos
150
160
170
180
190
200
Height
Figura 7.4: Diagrama mucho más elaborado
7.1. ESTUDIO DE LA CORRELACIÓN BIVARIADA
69
Given : Sex
Male
Female
16
18
20
22
180
170
150
160
Height
190
200
14
14
16
18
20
22
NW.Hnd
Figura 7.5: Diagrama de dispersión con dos grupos de datos obtenido con coplot()
Given : Sex
Male
Female
16
18
20
22
Given : W.Hnd
150
200
150
160
170
Left
180
190
Height
160
170
Right
180
190
200
14
14
16
18
20
22
NW.Hnd
Figura 7.6: Diagrama de dispersión controlando para dos variables
CAPÍTULO 7. CORRELACIÓN Y REGRESIÓN
70
data.frame. Muchas de ellas no son numericas y por lo tanto su interés es menor, pero
la representación, en general, facilita el análisis exploratorio de la correlación entre variables.
Para observar las correlaciones entre las variables numéricas podemos crear un data.frame con las mismas y pasarle la función pairs(). Así,
pairs(data.frame(Pulse,Height,NW.Hnd,Wr.Hnd)
crea la Figura 7.7, que permite apreciar las relaciones entre todas las variables numéricas de este data.frame como, por ejemplo, la clara relación entre el tamaño de ambas
manos o la menor que hay entre el tamaño de la mano y la estatura.
7.1.2. Matrices de correlaciones
La función cor() proporciona la matriz de coeficientes de correlación de Pearson
de las variables introducidas como argumento. Así,
cor(survey$Height,survey$Wr.Hnd, use=”complete.obs”)
nos da el coeficiente de correlación entre la estatura y el tamaño de la mano. El resultado
[1] 0.600991
es lo que deberemos interpretar. Hay que hacer notar que, cuando hay valores perdidos, a la función cor() hay que decirle a R qué hacer con los mismos. Para que haga el
cálculo del coeficiente sólo a partir de los casos completos para ambas variables introducimos la opción use=”complete.obs”.
Para calcular el coeficiente de determinación sólo deberíamos elevar al cuadrado el valor devuelto por la función. Por ejemplo tecleando
cor(survey$Height,survey$Wr.Hnd, use=”complete.obs”)^2
Adviértase que, como no hemos asignado el valor a ningún objeto, no quedará almacenado en el espacio de trabajo; tan sólo será presentado por pantalla.
Podemos aplicar la función cor() a un data.frame con variables numéricas. En este
caso obtendremos una matriz de correlaciones. Para obtener la matriz de correlaciones
de las cuatro variables numéricas contenidas en el data.frame survey podemos teclear
options(digits=3)
cor(data.frame(NW.Hnd,Wr.Hnd,Height,Pulse),use=”complete.obs”)
como se ve, se crea un data.frame interno que almacena las variables numéricas. Este
será el objeto que recibirá la acción de la función. Como antes, sólo se tendrán en
cuenta los casos completos. El resultado es
NW.Hnd
Wr.Hnd
Height
Pulse
NW.Hnd
1.0000
0.9664
0.6000
-0.0170
Wr.Hnd
0.96643
1.00000
0.61835
-0.00761
Height
0.6000
0.6184
1.0000
-0.0847
Pulse
-0.01698
-0.00761
-0.08468
1.00000
Como se explicó en un capítulo anterior, si nos interesase calcular estos valores con
asiduidad, sería conveniente definir sendas funciones.
7.1. ESTUDIO DE LA CORRELACIÓN BIVARIADA
18
22
150
170
190
22
14
71
22
14
18
Wr.Hnd
80 100
14
18
NW.Hnd
190
40
60
Pulse
150
170
Height
14
18
22
40
60
80 100
Figura 7.7: Diagrama de dispersión cruzada entre variables con pairs()
CAPÍTULO 7. CORRELACIÓN Y REGRESIÓN
72
Una cuestión importante es contrastar el grado de significación de los coeficientes
de la matriz de correlaciones. Para un α √
= 0,05, podemos considerar que son significativos los valores ri j que cumplen |ri j | · n > 1,96 siendo n el número de casos de la
serie de datos1 .
En el ejemplo que estamos utilizando, para obtener el valor de n debemos tener en
cuenta que en el cálculo de los coeficientes de correlación estamos considerando sólo
los casos completos para las cuatro variables numéricas. Para sabér cuántos son, podemos teclear
str(na.omit((data.frame(NW.Hnd,Wr.Hnd,Height,Pulse))))
que solicita la estructura del data.frame de variables numéricas omitiendo(cosa que
conseguimos con na.omit())los casos con algún valor perdido. El resultado
‘data.frame’: 170 obs. of 4 variables:
$ NW.Hnd: num 18 20.5 20 17.7 17.7 17.3 19.5 18.5 17.2 20.2 ...
$ Wr.Hnd: num 18.5 19.5 20 18 17.7 17 20 18.5 17 19.5 ...
$ Height: num 173 178 165 173 183 ...
$ Pulse : num 92 104 35 64 83 74 72 90 80 66 ...
- attr(*, "na.action")=Class ’omit’ Named int [1:67] 3 4 12 13 15 16 19 25 26 29 ...
.. ..- attr(*, "names")= chr [1:67] "341213"...
nos informa de que el data.frame consta de 170 observaciones.
En este momento podemos multiplicar los coeficientes de correlación por la raiz cuadrada del número de observaciones efectuando la siguiente operación
cor(data.frame(NW.Hnd,Wr.Hnd,Height,Pulse),
use=”complete.obs”)*sqrt(170)
cuyo resultado es
Pulse
-0.22136976
-0.09920578
-1.10414082
13.03840481
√
Puede apreciarse que la diagonal se ha transformado en la 170 y que son significativos al 5 % los coeficientes de correlación entre las variables tamaño de la mano
escritora/tamaño de la mano no escritora, r = 12,600 y altura frente a tamaño de
ambas manos (r = 7,823 y r = 8,062).
NW.Hnd
Wr.Hnd
Height
Pulse
NW.Hnd
13.0384048
12.6007250
7.8225652
-0.2213698
Wr.Hnd
12.60072500
13.03840481
8.06234371
-0.09920578
Height
7.822565
8.062344
13.038405
-1.104141
7.1.3. Coeficiente de correlación de Spearman
Veamos ahora cómo calcular el coeficiente de correlación de Spearman. Este está
basado en rangos y es aplicable, por lo tanto, a variables de tipo ordinal.
Como en nuestro data.frame no tenemos variables ordinales, crearemos dos con la
función cut(), que divide un vector en partes iguales. Así,
a<-na.omit(cut(NW.Hnd,5))
b<-na.omit(cut(Wr.Hnd,5))
reclasificará esas dos variables a sendas variables ordinales con cinco modalidades
1 En
el caso de α = 0,01, el valor que debería ser superado es 2,575
7.1. ESTUDIO DE LA CORRELACIÓN BIVARIADA
73
(1, 2, 3, 4, 5) y además eliminará los valores perdidos.
Para calcular el coeficiente de correlación de Spearman sólo habrá que teclear
cor(rank(a),rank(b))
dando como resultado
[1] 0.8834653
7.1.4. Coeficiente de correlación parcial
Finalmente, veremos cómo calcular el coeficiente de correlación parcial entre dos
variables controlando los efectos que ejerce una tercera variable sobre la relación entre ellas. Este coeficiente de correlación parcial se suele utilizar cuando se supone que
puedan existir relaciones espúreas entre variables.
Si definimos el coeficiente de correlación parcial entre las variables a, b controlado por
la variable c como
rab − rac · rbc
q
rab|c = p
2
2 ·
1 − rac
1 − rbc
y tenemos tres variables a,b,c, podremos calcular rab|c con la siguiente serie de instrucciones.
r.ab<-cor(a,b)
r.bc<-cor(b,c)
r.ac<-cor(a,c)
r.abc<-(r.ab-(r.ac*r.bc))/(sqrt(1-(r.ac^2))*sqrt(1-(r.bc^2)))
Con las tres primeras se calculan los coeficientes de correlación bivariada entre las tres
variables tomadas dos a dos. En la cuarta se introduce la expresión algebraica que permite obtener el coeficiente de correlación parcial.
La siguiente función, bautizada como cor.par() nos daría el coeficiente con sólo introducir las variables en orden consecutivo, siendo las dos primeras las variables a
estudiar, y la tercera la variable que queremos controlar.
cor.par<-function(a,b,c){
r.ab<-cor(a,b)
r.bc<-cor(b,c)
r.ac<-cor(a,c)
coef<-(r.ab-(r.ac*r.bc))/(sqrt(1-(r.ac^2))*sqrt(1-(r.bc^2)))
return(coef)
}
Para ilustrar el uso de los índices de correlación parcial consideraremos los datos
del Cuadro 7.1. En él aparecen una serie de variables (temperatura, albedo, flujo térmico, radio y distacia media al Sol) para los cuatro planetas gigantes del Sistema Solar.
En primer lugar deberemos introducir los datos de la tabla en un data.frame al que
podemos llamar, por ejemplo s.solar.
Ahora, supongamos que nos interesa conocer los factores que influyen en la temperatura de los planetas. En primer lugar, desearemos confirmar que exite relación entre
ésta y la distancia al Sol. Para ello podríamos teclear
CAPÍTULO 7. CORRELACIÓN Y REGRESIÓN
74
Planeta
Júpiter
Saturno
Urano
Neptuno
Distancia(u.a.)
5,203
9,539
19,18
30,06
Temperatura(K)
125
94
58
55
Radio(Km)
71714
60330
26200
25225
Albedo
0,42
0,36
0,37
0,33
Flujo térmico(erg/cm2sg)
7600
2800
175
285
Cuadro 7.1: Algunos datos de los planetas gigantes
cor(s.solar$dist,s.solar$temp)
que da
[1] -0.9085313
es decir, una elevada correlación negativa; a mayor alejamiento del Sol, menor temperatura planetaria.
Para analizar gráficamente esta relación podemos teclear
plot(s.solar$dist,s.solar$temp)
lo que genera la Figura 7.8 en la que se observa que hay un descenso de la temperatura
con la distancia claramente exponencial.
Si queremos conocer las relaciones entre todas las variables tomadas de dos en dos, deberemos solicitar la matriz de correlaciones, para lo cual sólo tenemos que cor(s.solar).
El resultado es
temp
albedo
flujo
dist
radio
temp
albedo
flujo
dist
radio
1.0000000 0.8361303 0.9774232 -0.9085313 0.9808471
0.8361303 1.0000000 0.8731807 -0.8367831 0.7406799
0.9774232 0.8731807 1.0000000 -0.8295449 0.9198315
-0.9085313 -0.8367831 -0.8295449 1.0000000 -0.9220161
0.9808471 0.7406799 0.9198315 -0.9220161 1.0000000
Puede observarse que los coeficientes son elevados para casi todos los pares de variables, llamando especialmente la atención la relación entre la temperatura y el radio
planetario y el flujo térmico. En la Figura 7.9 vemos gráficamente la relación entre la
temperatura y el flujo térmico.
Aparentemente, la distancia al Sol no es el factor que más afecta a la temperatura
de estos planetas. Para conocer cuál es la correlación entre temperatura y distancia,
“descontando” el efecto del flujo térmico, podemos utilizar nuestra función cor.par()
del siguiente modo
attach(s.solar)
cor.par(temp,dist,flujo)
el resultado
[1] -0.828139
refleja que, cuando controlamos el efecto del flujo térmico, la relación entre temperatura y distancia al Sol disminuye. Si lo analizamos en términos del coeficiente de
determinación (cuadrado del coeficiente de correlación), pasamos de que la distancia
explique el 83 % de la varianza a que explique sólo el 69 %.
Los astrónomos conocen bien este hecho. Los planetas gaseosos están tan lejos del Sol
7.1. ESTUDIO DE LA CORRELACIÓN BIVARIADA
90
60
70
80
temp
100
110
120
75
5
10
15
20
25
30
dist
4000
0
2000
flujo
6000
Figura 7.8: Relación entre temperatura y distancia
60
70
80
90
100
110
120
temp
Figura 7.9: Relación entre temperatura y flujo térmico
76
CAPÍTULO 7. CORRELACIÓN Y REGRESIÓN
que, incluso, emiten al espacio más energía de la que reciben del astro rey. Por ese
motivo, su temperatura depende en gran medida del aporte de calor interno. Esto queda
claramente de manifiesto al analizar la relación entre estas dos variables removiendo el
efecto de la distancia como vemos a continuación
cor.par(temp,flujo,dist)
[1] -0.9589847
Comparando este valor con el valor de la matriz de correlaciones, apreciamos que controlar para la distancia no conlleva una reducción muy grande del coeficiente de correlación entre temperatura y flujo térmico.
7.2. Regresión lineal simple
En esta sección trabajaremos con los datos contenidos en el data.frame trees. La
siguiente sucesión de órdenes nos permiten cargarlos, conocer su contenido y ponerlo
en ruta de búsqueda.
data(trees)
str(trees)
?trees
attach(trees)
Vemos que consiste en una serie de datos de altura, diámetro y volumen de 31 árboles.
Como en todo análisis de regresión simple, intentaremos analizar las relaciones existentes entre las variables con la intención de predecir valores de un de ellas en función
de otra. Antes de comenzar, haremos un análisis preliminar de las correlaciones bivariadas. Con
cor(trees)
obtendremos la siguiente matriz de correlaciones
Girth
Height
Volume
Girth 1.0000000 0.5192801 0.9671194
Height 0.5192801 1.0000000 0.5982497
Volume0.9671194 0.5982497 1.0000000
Con
pairs(trees)
obtendremos la Figura 7.10.
Tanto en la matriz como en la figura se puede apreciar que hay una relación lineal
muy fuerte entre el volumen del árbol y su diámetro. También se observa que la relación entre el volumen y la altura no lo es tanto. Finalmente, hay también relación entre
el diámetro y la altura.
En R, para efectuar el análisis de regresión linear se utiliza la función lm(). Esta
genera un tipo especial de objeto que puede ser argumento de muchas funciones que
podremos utilizar para obtener información sobre el modelo de regresión calculado.
Por ese motivo, es conveniente asignar el resultado de lm() a algún objeto con su correspondiente nombre. En nuestro caso, para hacer la regresión simple entre volumen y
diámetro teclearemos
7.2. REGRESIÓN LINEAL SIMPLE
70
75
80
85
18
65
77
80
85
8 10
14
Girth
50
70
65
70
75
Height
10
30
Volume
8 10
14
18
10
30
50
70
Figura 7.10: Relación entre las variables de trees
lm.vol.dia<-lm(Volume~Girth)
lo que almacena en el objeto lm.vol.dia todos los resultados del análisis de regresión.
Como puede observarse, lm() utiliza el sistema de fórmulas (con la tilde) para expresar
la variable dependiente y la independiente.
La función summary() aplicada al objeto de regresión, nos va a proporcionar la mayor
parte de la información que nos interesa en un principio como vemos a continuación
summary(lm.vol.dia)
Call:
lm(formula = Volume Girth)
Residuals:
Min 1Q Median 3Q Max
-8.0654 -3.1067 0.1520 3.4948 9.5868
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -36.9435 3.3651 -10.98 7.62e-12 ***
Girth 5.0659 0.2474 20.48 < 2e-16 ***
—
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 4.252 on 29 degrees of freedom
Multiple R-Squared: 0.9353, Adjusted R-squared: 0.9331
F-statistic: 419.4 on 1 and 29 DF, p-value: 0
Tanto el valor como el grado de significación los coeficientes de la recta de regresión
aparecen en el apartado coefficients. En la penúltima linea aparecen los valores de r y
r2 ; y, en la última, la probabilidad de que el modelo obtenido sea inadecuado.
CAPÍTULO 7. CORRELACIÓN Y REGRESIÓN
78
En este caso, el coeficiente de determinación (r2 ) nos indica que el 93 % de la variación
en el volumen del árbol puede explicarse por variaciones en el diámetro del mismo. Por
otro lado, el modelo de regresión obtenido es apropiado puesto que la probabilidad de
que no lo sea es cero.
Para hacer predicciones del volumen de una serie de árboles a partir de su diámetro debemos crear un data.frame con una columna que almacene los diámetros de los
mismos. Por ejemplo, si tenemos tres ejemplares, A,B,C con diámetros 11.5,10.6,18.7,
para obtener los volúmenes predichos habría que proceder como sigue.
muestra<-data.frame(Girth=c(11.5,10.6,18.7),
row.names=c(“A”;”B”;”C”))
predict(lm.vol.dia,muestra)
Con la primera instrucción creamos el data.frame muestra que contiene una columna con el nombre de la variable independiente (en este caso el diámetro) que alberga
los valores de la muestra. Además se indica la etiqueta de cada uno de los registros
(A,B,C).
Con la segunda instrucción pedimos que calcule los valores predichos según el modelo
guardado en lm.vol.dia. El resultado es
A
B
C
21.31389 16.75462 57.78806
Si, además del valor predicho, deseamos conocer el intervalo de confianza a un
nivel determinado (digamos del 95 %), deberemos teclear
predict(lm.vol.dia,muestra,level=.95,interval=“confidence”)
el resultado será
A
B
C
fit
lwr
upr
21.3138919.51889 23.10889
16.7546214.69672 18.81252
57.7880654.61832 60.95779
donde podemos conocer el valor inferior (lwr) y superior (upr) para ese nivel de confianza. Para modificar el nivel de confianza, sólo hay que introducir otro valor en el
argumento level de la función predict().
Finalmente, vamos a ver cómo incorporar al diagrama de dispersión algunos elementos importantes en análisis de regresión.
El primero es la recta de regresión. Para ello vamos a utilizar la función abline() que,
pasada por consola tras haber generado un gráfico, le incorpora una recta con los parámetros que se le indiquen como argumentos. Veamos cómo hacerlo si queremos estudiar la relación entre el volumen y la altura.
plot(Height,Volume)
abline(lm(Volume~Height))
El resultado se presenta en la Figura 7.11.
En muchas ocasiones sería conveniente identificar ciertos puntos del diagrama de
dispersión que destacan por alguna circunstancia (en general, valores anómalos). Para
hacer esto podemos utlizar la función identify() de la siguiente manera
plot(Height,Volume)
7.2. REGRESIÓN LINEAL SIMPLE
Volume
10
20
30
40
50
60
70
79
65
70
75
80
85
Height
Figura 7.11: Inclusión de la recta de regresión con abline()
identify(Height,Volume)
Tras haber realizado el gráfico con plot(), tecleamos la función identify() aplicada al
mismo. Esto es así porque la función interactúa con el dispositivo gráfico. Tras teclearla, deberemos utilizar el ratón para marcar con el botón izquierdo los puntos que
deseamos etiquetar. Por defecto se añadirá al gráfico un número índice, pero esto puede modificarse si existe alguna otra etiqueta. Cuando hayamos concluido, deberemos
hacer clic con el botón derecho sobre el gráfico para cerrar la función. En ese momento
aparacerán sobre la consola los índices de los puntos seleccionados. En la Figura 7.12
puede apreciarse cómo se ha seleccionado y etiquetado algunos de los casos.
CAPÍTULO 7. CORRELACIÓN Y REGRESIÓN
80
30
40
50
28
20
18
6
10
Volume
60
70
31
65
70
75
80
85
Height
Figura 7.12: Identificación de casos con identify()
Capítulo 8
Personalización de gráficos
R posee unas capacidades gráficas extraordinarias. En este (último) capítulo vamos
a estudiar las más básicas, las que nos van a permitir personalizar nuestros gráficos y
dotarlos de una mayor presencia. Para ello nos serviremos de los gráficos que hemos ido
presentando a lo largo del manual y cuya presentación no ha sido la que desearíamos
para presentar en una publicación.
8.1. Títulos
Consideremos la Figura 3.3 de la página 20. Lo primero que llama la atención es
que los títulos de los ejes están en inglés. Ello se debe a que el data.frame cars viene
con R. Posiblemente, con datos nuestros eso no ocurrirá, pero aún así es conveniente
saber cómo añadir/modificar los títulos de una figura. Consideraremos tanto el texto en
sí como su formato (fuente y color).
Para los títulos de ejes tenemos los argumentos x.lab e y.lab. Tras ellos sólo hay
que teclear entrecomillado el texto que queremos que vaya a cada uno de los ejes. Así
plot(speed,dist,x.lab=“Velocidad“,y.lab=”Distancia“)
cambiaría los nombres de las variables del inglés al castellano.
Si queremos, podemos cambiar la fuente del texto con el argumento font.lab, que acepta
cuatro valores que van del 1 al 4. Para que aparezcan en negrita habría que añadir a la
sentencia anterior font.lab=2.
También podemos cambiar el color. Posteriormente hablaremos de cómo conseguir
millones de colores diferentes, ahora nos conformaremos con las posibilidades que nos
dan los primeros diez números enteros. Para ello utilizaremos el argumento col.lab
seguido de un número del 0 al 9. Para el azul, el número es el 4. También podemos
modificar el tamaño de la fuente con cex.lab. Este argumento acepta valores numéricos,
resultando los menores a 1 en una reducción del tamaño y, los superiores a 1, en un
aumento. Así,
plot(speed,dist,x.lab=“Velocidad“,y.lab=”Distancia“,font.lab=2,
col.lab=4,cex.lab=1.5)
nos dejerá unos títulos en castellano, en negrita,de mayor tamaño, y de color azul.
81
82
CAPÍTULO 8. PERSONALIZACIÓN DE GRÁFICOS
Para añadir un título al gráfico utilizaremos el argumento main seguido del título
entrecomillado. Al igual que con los títulos de los ejes, podremos utilizar los argumentos col.main, cex.main y font.main para modificar el color, el tamaño y la fuente del
título principal.
El resultado final de la personalización de títulos puede apreciarse en la Figura 8.1,
y resulta de la siguiente instrucción
plot(cars$speed,cars$dist,xlab="Velocidad",ylab="Distancia",
font.lab=3,col.lab=4,cex.lab=1.5,main="Diagrama de
dispersión\nVelocidad/Distancia", cex.main=2,col.main=4)
Obsérvese que, para introducir un salto de linea en el título principal se ha tecleado \n
allí donde se desea que aparezca.
8.2. Ejes
El aspecto de los ejes puede modificarse de la misma manera que hemos comentado en los títulos con los argumentos font.axis, col.axis y cex.axis. También podemos
modificar el rango de los ejes con los argumentos xlim e ylim que, como puede adivinarse, establecen los límites para cada uno de los ejes. Así, xlim=c(0,40),ylim=c(20,45)
generáría un eje de abcsisas de 0 a 40 y un eje de ordenadas de 20 a 45.
Además de modificar el rango, se puede variar la escala de los ejes. Con el argumento log podemos transformar a escala logarítmica el eje x, el y o ambos. Con la
siguiente orden modificaríamos los dos ejes de la Figura 7.8 (página 75) para transformarlos a escala logarítmica y obtener la Figura 8.2.
plot(s.solar$dist,s.solar$temp,log="xy",xlab="log(distancia)",
ylab="log(temp)",col.axis=4,fg=2)
Para modificar sólo uno de los ejes lo único que hay que hacer es notificárselo al
argumento. Así, log=“x” sólo pasaría a logarítmico el eje de abcisas, y log“y” haría lo
propio sólo con el eje de ordenadas.
Hemos visto que en algunos casos (por ejemplo en la Figura 5.2, página 39) en el
eje de abcisas no nos aparece el nombre de la variable sino que aparece un númeroíndice. En este caso en concreto nos convendría que apareciera en lugar de 1, IN, en
lugar de 2, SF, ... Para conseguirlo podemos utilizar la función axis(), que modifica las
etiquetas de los ejes como vemos a continuación. Para obtener la Figura 8.3 deberíamos introducir la siguiente secuencia de instrucciones
attach(resultados)
boxplot(IN,SF,B,NT,SB,xaxt="n")
axis(1,at=1:5,lab=c("IN","SF","B","NT","SB"),col.axis=2)
La primera ya la conocemos bien; nos evitará hacer continuamente llamadas al data.frame en las siguientes instrucciones. Con la segunda obtenemos un boxplot múltiple en el que no visualizaremos las etiquetas del eje de abcisas porque hemos añadido
la opción xaxt=“n” (del inglés x axis text, no). Estas etiquetas las añadimos con la
tercera instrucción. A la función axis() se le indica con el 1 que va a trabajar con el eje
de abcisas. Con at=1:5 se le dice que debe colocar las primeras cinco etiquetas, que
son las cinco que indicamos con lab=c("IN","SF","B","NT","SB"). Finalmente le
indicamos que las coloree de rojo simplemente para destacar el efecto de la función
8.2. EJES
83
60
0
20
40
Distancia
80
100
120
Diagrama de dispersión
Velocidad/Distancia
5
10
15
20
25
Velocidad
80
70
60
log(temp)
90
100
110
120
Figura 8.1: Personalización de títulos
5
10
15
20
log(distancia)
Figura 8.2: Ejes logarítmicos
25
30
84
CAPÍTULO 8. PERSONALIZACIÓN DE GRÁFICOS
sobre el gráfico original.
8.3. Colores
Como hemos visto, podemos personalizar los colores de fuentes y ejes. Por supuesto, podemos establecer un color para el objeto principal de la representación (puntos,
líneas, polígonos) con el argumento col. Asímismo,podemos modificar el color de fondo (bg) y de los objetos situados en primer plano (fg).
Con las funciones rgb() y hsv() aplicadas a cualquier argumento que indique un color,
podemos conseguir millones de colores. Tan sólo hay que introducir como parámetros
de esas funciones tres valores decimales comprendidos entre el 0 y el 1. En la primera
(rgb()), será una mezcla de rojo, verde y azul. En la segunda (hsv()), son los valores de
matiz, saturación y valor.
En la Figura 8.4 podemos ver el resultado de la siguiente instrucción
hist(cars$dist,col=rgb(.3,.6,.2),fg=2,main="Histograma",
col.main=hsv(.2,.8,.9),xlab="velocidad",ylab="frecuencia",
col.lab=hsv(.2,.8,.6)).
Puede verse cómo han cambiado tanto el color del histograma como de los títulos.
También hay que hacer notar que el argumento fg=2 determina que el color de los ejes
sea rojo.
8.4. Añadir textos a un gráfico
Esta es una operación habitual en gráficos. Los textos nos permiten realizar comentarios o resaltar información. Veamos cómo utilizar la función text() para añadir un
pequeño comentario a la Figura 3.3. Podríamos hacer lo siguiente
plot(cars$speed,cars$dist)
text(5,100,"Se puede apreciar una\nbuena correlación\nentre ambas
variables,\nespecialmente para velocidades\nbajas y medias.",
adj=0,col=4)
Con la primera instrucción creamos la figura. La segunda es la que debemos analizar
en profundidad.
En primer lugar le decimos a R dónde debe colocar el texto. Para ello nos basamos
en las coordenadas utilizadas en el gráfico. Como vemos que en la zona de bajas velocidades y elevadas distancias hay bastante espacio en blanco, ponemos 5,100 (5 de
velocidad y 100 de distancia). A continuación introducimos el texto entrecomillado
(obsérvese la inserción de nuevas lineas con \n). Con adj=0 indicamos que queremos
un texto justificado a la izquierda (por defecto es centrado). Finalmente, le decimos que
queremos un texto en color azul con col=4. El resultado es el de la Figura 8.5.
Para establecer las coordenadas que definen la localización de los textos también
podemos utilizar funciones. Por ejemplo, si quisiéramos etiquetar los elementos principales del boxplot de la Figura 5.1 (página 39) podríamos proceder de la siguiente
manera
boxplot(cars$speed)
8.4. AÑADIR TEXTOS A UN GRÁFICO
85
Figura 8.3: Modificar etiquetas de ejes con axis()
10
5
0
frecuencia
15
Histograma
0
5
10
15
20
25
velocidad
Figura 8.4: Millones de colores con rgb() y hsv()
CAPÍTULO 8. PERSONALIZACIÓN DE GRÁFICOS
Se puede apreciar una
buena correlación
entre ambas variables,
especialmente para velocidades
bajas y medias.
60
0
20
40
cars$dist
80
100
120
86
5
10
15
20
25
cars$speed
Figura 8.5: Añadir textos con text()
axis(1,at=1,"Velocidad",cex.axis=1.5,col.axis=2)
text(1.3,fivenum(cars$speed)[1],"mínimo",col=4,adj=0)
text(1.3,fivenum(cars$speed)[2],"primer cuartil",col=4,adj=0)
text(1.3,median(cars$speed),"mediana",col=4,adj=0)
text(1.3,fivenum(cars$speed)[4],"tercer cuartil",col=4,adj=0)
text(1.3,fivenum(cars$speed)[5],"máximo",col=4,adj=0)
Como vemos, tras dibujar el gráfico y añadirle la etiqueta Velocidad al eje de abcisas, se procede a incorporar textos a los elementos del boxplot. Para que aparezca a
un lado de la caja y no encima de ella, la primera coordenada la establecemos en 1.3.
Para situar el texto mínimo a la altura exacta, no hace falta obtener previamente ese
valor mínimo, podemos establecer su coordenada y seleccionando el primer elemento
del vector proporcionado por la función fivenum(), que da el mínimo, primer cuartil,
mediana, tercer cuartil y máximo, de una variable. Para colocar los demás textos sólo
habrá que ir seleccionando los correspondientes elementos de ese vector como se hace
en las sentencias 4,5,6 y 7. El resultado es el que se aprecia en la Figura 8.6.
8.5. Tipos de puntos y lineas
Podemos modificar tanto el tipo de linea o punto, como su color y tamaño.
Por ejemplo, la Fig 5.7 representa una gráfica de tipo linea obtenida con la instrucción
plot(density(cars$speed)). Vamos a ver qué argumentos debemos utilizar para modificarla y obtener la Figura 8.7. La instrucción requerida es
plot(density(cars$speed),lty=6,lwd=4,col=4)
El argumento col establecerá el color. El tipo de línea lo definimos con lty, que acepta
8.5. TIPOS DE PUNTOS Y LINEAS
25
87
20
máximo
15
tercer cuartil
mediana
5
10
primer cuartil
mínimo
Velocidad
Figura 8.6: Utilizar funciones para establecer coordenadas de textos con text()
Density
0.00
0.01
0.02
0.03
0.04
0.05
0.06
density(x = cars$speed)
0
5
10
15
20
25
30
N = 50 Bandwidth = 2.15
Figura 8.7: Personalización de líneas con lty,lwd,col
CAPÍTULO 8. PERSONALIZACIÓN DE GRÁFICOS
88
varios valores numéricos. De la misma manera estableceremos la anchura de la linea
con lwd .
Para gráficos de puntos el procedimiento es muy similar. Para transformar la Figura 3.3 en la Figura 8.8 debemos teclear
plot(cars$speed,cars$dist,pch=3,cex=.5,col=2)
Podemos ver que volvemos a dar color con col. Con pch, que acepta valores numéricos, establecemos el tipo de símbolo, correspondiendo el 3 a la cruz. Finalmente, con
cex introducimos un factor de disminución o aumento del tamaño con respecto al que
está definido por defecto.
8.6. Añadir puntos y lineas a un gráfico
En R es posible superponer puntos y lineas a gráficos recien creados en la pantalla
gráfica. Por ejemplo, supongamos que queremos añadir al diagrama de dispersión de
la Figura 3.3 unos puntos que indiquen los cuartiles y la media de ambas variables. El
resultado (Figura 8.9), se obtiene de la siguiente manera
plot(cars$speed,cars$dist)
points(fivenum(cars$speed)[c(2,3,4)],fivenum(cars$dist)[c(2,3,4)],
pch=18,cex=2,col=2)
points(mean(cars$speed),mean(cars$dist),pch=15,cex=2,col=4)
Con la segunda instrucción añadimos el primer cuartil, la mediana y el tercer cuartil1 de
una variable frente a los de la otra, en forma de rombos rojos. Con la tercera, añadimos
la media de speed frente a la media de dist y la representamos como un cuadrado azul.
En la sección correspondiente a la regresión, hemos visto cómo añadir la linea de
ajuste por mínimos cuadrados a un diagrama de dispersión con la función abline(). En
este apartado veremos otras posibilidades en relación a la adición de curvas y líneas a
gráficos.
Volvamos de nuevo al gráfico de cars. Imaginemos que deseamos añadir dos lineas
que indiquen los valores medios de vada variable, de modo que el gráfico quede dividido en cuatro sectores (valores inferiores a las dos medias, inferiores a una pero superior
a la otra, y superiores a las dos medias). Podríamos hacerlo como sigue
plot(cars$speed,cars$dist)
abline(h=mean(cars$dist),lty=3,col=4)
abline(v=mean(cars$speed),lty=3,col=4)
Con la segunda orden, mandamos hacer una linea horizontal que pase por la media de
la variable dist. Con la tercera hacemos una horizontal que pase por la media de speed.
El resultado lo vemos en la Figura 8.10.
Veamos, finalmente, cómo añadir a un gráfico una función matemática. Como
ejemplo tomaremos la Figura 5.6 de la página 43.
En ella se puede observar un histograma al que se le ha superpuesto la función de distribución normal teórica para su contraste visual. Se ha obtenido mediante la siguiente
serie de instrucciones
hist(scale(cars$speed),prob=T)
1 Que
son el segundo, tercer y cuarto elemento, respectivamente, del vector devuelto por fivenum()
8.6. AÑADIR PUNTOS Y LINEAS A UN GRÁFICO
60
0
20
40
cars$dist
80
100
120
89
5
10
15
20
25
cars$speed
60
40
20
0
cars$dist
80
100
120
Figura 8.8: Personalización de puntos con pch,cex,col
5
10
15
20
cars$speed
Figura 8.9: Añadir puntos con points()
25
CAPÍTULO 8. PERSONALIZACIÓN DE GRÁFICOS
60
0
20
40
cars$dist
80
100
120
90
5
10
15
20
25
cars$speed
Figura 8.10: Añadir lineas con abline()
curve(dnorm(x),add=T)
Con la primera obtenemos el histograma de la variable estandarizada. Con la segunda
se le superpone la distribución teórica para lo cual se utiliza la función dnorm(). Para
una variable estandarizada, la gráfica se obtiene con dnorm(x). Hay que hacer notar el
add=T que se incorpora para que la función se superponga al gráfico preexistente.
También podemos utilizar estas herramientas para añadir a la función de densidad de
la Figura 5.7 (página 43) la función teórica y obtener la Figura 8.11.
Las instrucciones para ello serían
plot(density(scale(cars$speed)),col=4,lwd=2,ylim=c(0,0.5))
curve(dnorm(x),add=T,col=2,lwd=2)
Con la primera dibujaremos la función de densidad de la variable cars$speed estandarizada en color azul. Con la segunda le superpondremos la función de densidad teórica
en color rojo.
8.7. Plantillas gráficas
De las secciones anteriores se deduce que, si nuestra intención es utilizar con frecuencia determinada configuración gráfica (porque nos gusta un tipo determinado de
caracter, color, grosor de linea,...), sería muy conveniente almacenarlo de alguna manera para evitarnos teclear continuamente esa serie de parámetros. Eso es lo que vamos
a poder hacer con la función par().
Antes de crear una nueva configuración, puede ser conveniente guardar la configuración por defecto con un nombre concreto. Así,
8.7. PLANTILLAS GRÁFICAS
91
0.0
0.1
0.2
Density
0.3
0.4
0.5
density(x = scale(cars$speed))
−3
−2
−1
0
1
2
3
N = 50 Bandwidth = 0.4066
Figura 8.11: Añadir curvas con curve()
defecto<-par()
guardará todos esos parámetros en el objeto llamado defecto.
Ahora, podríamos querer definir una configuración nueva como la siguiente
col=3,pch=2,lwd=2,fg=2,bg=hsv(.4,.1,.8),cex=.7
cuyo significado conocemos ya.
La siguiente secuencia de órdenes generará la Figura 8.12, la Figura 8.13 y la Figura 8.14.
plantilla<-par(col=3,pch=2,lwd=4,fg=2,bg=hsv(.4,.1,.8),cex=.7)
hist(cars$speed)
hist(cars$speed,col=8)
plot(cars$speed,cars$dist,col=7)
par(defecto)
Con la primera instrucción definimos la nueva plantilla gráfica y se abre automáticamente un dispositivo gráfico si no estaba abierto ninguno. Con la segunda generamos
el primer gráfico sin pasar como argumento ningún parámetro gráfico. Con la tercera
mantenemos todos los parámetros de plantilla pero introducimos un color que rellenará
las barras del histograma. Con la cuarta generamos un diagrama de dispersión de las
dos variables. Como se ve, no se indica el tipo de punto ni su color porque estamos
bajo los efectos de plantilla. Finalmente, con la última (par(defecto)) lo que hacemos
es desactivar la plantilla y volver a los parámetros por defecto.
A partir de este momento los gráficos volverán a crearse con los parámetros normales.
Para cargar de nuevo los de nuestra plantilla deberemos teclear
par(plantilla)
CAPÍTULO 8. PERSONALIZACIÓN DE GRÁFICOS
92
0
5
Frequency
10
15
Histogram of cars$speed
0
5
10
15
20
25
cars$speed
Figura 8.12: Modificación de parámetros gráficos con par() (I)
0
5
Frequency
10
15
Histogram of cars$speed
0
5
10
15
20
25
cars$speed
Figura 8.13: Modificación de parámetros gráficos con par() (II)
8.8. GRÁFICOS MÚLTIPLES
60
0
20
40
cars$dist
80
100
120
93
5
10
15
20
25
cars$speed
Figura 8.14: Modificación de parámetros gráficos con par() (III)
8.8. Gráficos múltiples
Por lo general presentaremos sólo un gráfico por figura, pero en ocasiones nos puede interesar presentar varios gráficos agrupados en una misma figura (por ejemplo, dos
histogramas de sendas variables). Para hacer esto, R dispone de varias posibilidades.
Una de ellas es la función layout(). Esta función requiere como argumento una matriz
en la que se informe del número de ventanas en las que hay que dividir el dispositivo gráfico, su numeración y el número de columnas y filas que vamos a utilizar. Por
ejemplo, para dividir la figura en seis ventanas (cada una para un gráfico diferente)
agrupadas en dos filas de tres columnas, deberemos teclear
layout(matrix(1:6,2,3))
los que dividirá la pantalla tal y como vemos en la Figura 8.15.
La matriz que introducimos como argumento incluye en primer lugar el número de
ventanas que vamos a crear y su numeración (en este caso serán seis consecutivas,
1:6). En segundo lugar se indica el número de filas 2 y, finalmente el de columnas 3.
Puede apreciarse en la figura el orden en el que serán ocupadas las ventanas cuando
desde R se mande realizar un gráfico. Por defecto se numeran desde la esquina superior izquierda y siguiendo las columnas.
Las posibilidades de subdivisión son inmensas; en realidad, van más allá de lo que
necesitaremos en la práctica. Podemos. por ejemplo, hacer divisiones desiguales de la
pantalla sólo con asignar a ventanas consecutivas la misma numeración. Por ejemplo,
layout(matrix(c(1,1,2,3,4,4),2,3))
CAPÍTULO 8. PERSONALIZACIÓN DE GRÁFICOS
94
1
3
5
2
4
6
Figura 8.15: División de la pantalla gráfica con layout()
genera la división de la Figura 8.16.
Puede resultar una buena idea tener creadas unas cuantas matrices para las divisiones que utilicemos más habitualmente. Por ejemplo, crear las siguientes matrices
dos.hor<-matrix(1:2,1,2)
dos.ver<-matrix(1:2,2,1)
cuatro<-matrix(1:4,2,2)
normal<-matrix(1)
nos permitirá dividir las pantallas en dos ventanas horizontales, dos verticales, cuatro
ventanas, y volver a la pantalla única original con sólo teclear
layout(dos.hor)
layout(dos.ver)
layout(cuatro)
layout(normal)
Para crear la Figura 8.17, podríamos introducir las siguientes órdenes
X11() layout(dos.ver)
hist(cars$speed,main="Velocidad",col=2,xlab="V(mph)",
ylab="Frecuencia")
hist(cars$dist,main="Distancia",col=4,xlab="d(pies)",
ylab="Frecuencia")
Para crear layouts regulares (con todas las ventanas del mismo tamaño) también
podemos utilizar un parámetro de la función par(); se trata de mfrow. Este nos permite
establecer el número de ventanas en términos de filas y columnas. Así, para dividir el
8.8. GRÁFICOS MÚLTIPLES
95
2
1
4
3
Figura 8.16: División desigual de la pantalla gráfica con layout()
Distancia
15
10
0
5
Frecuencia
10
5
0
Frecuencia
15
Velocidad
0
5 10
V(mph)
20
0
40
80
d(pies)
Figura 8.17: Dos histogramas con layout()
120
96
CAPÍTULO 8. PERSONALIZACIÓN DE GRÁFICOS
dispositivo gráfico en seis ventanas organizadas en tres columnas de dos filas habría
que teclear
par(mfrow=c(2,3))
lo que, tras la siguiente serie de instrucciones, permite obtener la Figura 8.18.
plot(density(scale(cars$speed)),col=4,lwd=2,ylim=c(0,0.5),
main="Densidad(velocidad)",ylab="densidad",xlab=)
hist(cars$speed,col=3, main="Histograma(velocidad)",
ylab="frecuencia",xlab="velocidad")
plot(cars$speed,cars$dist,main="Dispersión(vel/dist)",
xlab="velocidad",ylab="distancia")
plot(density(scale(cars$dist)),col=2,lwd=2,ylim=c(0,0.5),
main="Densidad(distancia)",xlab=,ylab="densidad")
hist(cars$dist,col=6,main="Histograma(distancia)",
xlab="distancia",ylab="frecuencia")
plot(cars$dist,cars$speed,main="Dispersión(dist/vel)",
xlab="distancia",ylab="velocidad")
8.8. GRÁFICOS MÚLTIPLES
97
Histograma(velocidad)
Dispersión(vel/dist)
−1
0
1
2
3
0
5
10
15
20
25
5
10
15
20
25
velocidad
velocidad
Histograma(distancia)
Dispersión(dist/vel)
15
velocidad
10
10
0
0.0
5
0.1
5
0.2
frecuencia
0.3
20
0.4
15
25
0.5
Densidad(distancia)
densidad
60
80
−3
0
0
0.0
20
0.1
5
40
distancia
10
frecuencia
0.3
0.2
densidad
0.4
100
15
0.5
120
Densidad(velocidad)
−2
0
1
2
3
4
0
20 40 60 80
120
0
distancia
Figura 8.18: Figuras múltiples par(mfrow)
20
40
60
80
distancia
120
Descargar