Sunteți pe pagina 1din 432

07

5-
Análisis de datos con R aplicado a la

-0
economía, la empresa y la industria
19
Emilio López Cano – con contribuciones de: Javier M. Moguerza, Miguel
Ángel Tarancón Morán, Matías Gámez Martínez
20
2019-05-07
or
ad
rr
Bo
2

Bo
rr
ad
or
20
19
-0
5-
07
Índice general

07
Prefacio 7
Agradecimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

5-
I Análisis de datos básico 11

-0
1. Introducción al análisis de datos con R 13
1.1. R y su ecosistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

19
1.2. Componentes de R y RStudio . . . . .
1.3. Estructuras de datos y su tratamiento
1.4. Importación y exportación de datos . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
19
37
53
20
1.5. Informes reproducibles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
1.6. Programación básica en R . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
1.7. Prácticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
or

2. Análisis exploratorio de datos con R 103


2.1. Estructuras de datos y tipos de variables . . . . . . . . . . . . . . . . . . . . 103
2.2. Análisis univariante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
ad

2.3. Análisis multivariante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134


2.4. Técnicas de análisis multivariante . . . . . . . . . . . . . . . . . . . . . . . . 150
2.5. Prácticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
rr

II Técnicas multivariantes 179


Bo

3. Análisis de la varianza con R 181


3.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
3.2. Análisis de la varianza de un factor . . . . . . . . . . . . . . . . . . . . . . . 181
3.3. Análisis de la varianza de varios factores . . . . . . . . . . . . . . . . . . . . 194
3.4. Introducción a los modelos mixtos: efectos fijos y efectos aleatorios . . . . . 198
3.5. Análisis multivariante de la varianza . . . . . . . . . . . . . . . . . . . . . . 200
3.6. Introducción al diseño de experimentos . . . . . . . . . . . . . . . . . . . . . 201
3.7. Prácticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222

4. Análisis de componentes principales con R 241

3
4 ÍNDICE GENERAL

4.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241


4.2. Obtención de las componentes principales . . . . . . . . . . . . . . . . . . . 242
4.3. Selección e interpretación de componentes . . . . . . . . . . . . . . . . . . . 247
4.4. Análisis gráfico de los componentes principales . . . . . . . . . . . . . . . . . 251
4.5. Análisis de componentes principales con R . . . . . . . . . . . . . . . . . . . 255
4.6. Aplicación del Análisis de Componentes Principales a la regresión múltiple . 268
4.7. Prácticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271

5. Análisis Cluster con R 305


5.1. Introducción al análisis cluster . . . . . . . . . . . . . . . . . . . . . . . . . . 305

07
5.2. Cálculo de distancias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
5.3. Métodos jerárquicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
5.4. Métodos no jerárquicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318

5-
5.5. Caracterización de grupos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
5.6. Más análisis cluster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326

-0
5.7. Prácticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331

6. Análisis de correspondencias con R 377

19
6.1. Introducción al análisis de correspondencias . . . . . . . . . . . . . . . . .
6.2. Asociación entre atributos . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.3. Análisis de correspondencias simples . . . . . . . . . . . . . . . . . . . . .
.
.
.
377
378
381
20
6.4. Análisis de correspondencias múltiple . . . . . . . . . . . . . . . . . . . . . . 397
6.5. Prácticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
Práctica 6.1: Ejemplo de color de ojos y pelo . . . . . . . . . . . . . . . . . . . . . 407
Práctica 6.2: Análisis de correspondencias simple con los datos de la encuesta . . . 411
or

Práctica 6.3: Ejemplo de Análisis de Correspondencias Múltiple . . . . . . . . . . 411


Práctica 6.4: Análisis de correspondencias múltiple con los datos de la encuesta . 415
ad

III Extensiones del modelo lineal 417


7. Modelos lineales mixtos 421
rr

7.1. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421


7.2. Modelo de efectos fijos y aleatorios . . . . . . . . . . . . . . . . . . . . . . . 421
Bo

7.3. Modelo de medidas repetidas . . . . . . . . . . . . . . . . . . . . . . . . . . 421


7.4. Modelos de panel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
7.5. Modelo de efectos aleatorios . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
7.6. Algunas consideraciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422

8. Capítulos en preparación 423


8.1. Visualización de datos avanzada . . . . . . . . . . . . . . . . . . . . . . . . . 424
8.2. Probabilidad e inferencia básicas . . . . . . . . . . . . . . . . . . . . . . . . 424
8.3. Modelos lineales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
8.4. Series temporales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
8.5. Extensiones del modelo lineal . . . . . . . . . . . . . . . . . . . . . . . . . . 424
ÍNDICE GENERAL 5

8.6. Técnicas avanzadas de predicción . . . . . . . . . . . . . . . . . . . . . . . . 424


8.7. Técnicas de clasificación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
8.8. Diseño y análisis de experimentos . . . . . . . . . . . . . . . . . . . . . . . . 424
8.9. Análisis de encuestas con R . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
8.10. Control estadístico de procesos . . . . . . . . . . . . . . . . . . . . . . . . . 424
8.11. Análisis y visualización de datos espaciales . . . . . . . . . . . . . . . . . . . 424
8.12. Análisis de datos Bayesiano . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
8.13. Técnicas de Investigación Operativa con R . . . . . . . . . . . . . . . . . . . 424
8.14. Análisis matemático y álgebra con R . . . . . . . . . . . . . . . . . . . . . . 424

07
A. Símbolos 425
A.1. Letras griegas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425
A.2. Símbolos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425

5-
B. Créditos 427

-0
19
20
or
ad
rr
Bo
6

Bo
rr
ad
or
20
19
-0
5-
07
ÍNDICE GENERAL
Prefacio

07
Este libro es el resultado de la experiencia del autor con el software estadístico y lenguaje
de programación R en los ámbitos de la docencia, la investigación y la transferencia. Trata

5-
de compilar los distintos materiales que se han ido utilizando en publicaciones, cursos en
empresas y docencia oficial. Un poco por poner orden en el caos de materiales dispersos
que se van acumulando en el propio proceso de (auto-)aprendizaje-enseñanza. También me

-0
mueve el hecho de que, si bien hay mucho material sobre R en inglés, no hay obras en español
que traten el análisis de datos con R en una extensión amplia.

19
Los primeros capítulos son muy introductorios, casi divulgativos. A medida que avance el
libro, se tratarán temas más complejos tanto desde el punto de vista de los métodos estadís-
ticos como desde el punto de vista del uso y programación de R. En todo caso, el espíritu de
20
esta obra es eminentemente práctico, por lo que profundidad matemático-teórica se limitará
en la mayoría de los casos a lo mínimo imprescindible para aplicar los métodos con cier-
ta solvencia, proporcionando referencias donde corresponda pare consultar los fundamentos
teóricos, detalles y demostraciones.
or

Los contenidos de este libro se basan en dos paradigmas que están presentes en los intereses
de investigación y docencia del autor: los estándares y el software libre. En lo que se
refiere a estándares, la notación utilizada, definiciones y fórmulas se ajustarán el máximo
ad

posible a la utilizada en normas nacionales e internacionales sobre metodología estadística.


Estas normas se citarán pertinentemente a lo largo del texto. En cuanto al software libre, es
un libro sobre R1 (R Core Team, 2019), sofware estadístico y lenguaje de programación libre
rr

y gratuito con el que se realizan todos los análisis. El primer capítulo del libro está dedicado
a su aprendizaje y comprensión.
Bo

Las normas son clave para el desarrollo económico de un país. Estudios en diversos países,
incluido España, han demostrado que la aportación de la normalización a su economía es del
1 % del PIB2 . La Asociación Española de Normalización (UNE) es el organismo legalmente
responsable del desarrollo y difusión de las normas técnicas en España. Además, representa
a España en los organismos internacionales de normalización como ISO3 y CEN4 .
Las normas sobre estadística que surgen de ISO las elabora el Technical Committee ISO TC
1
http://www.r-project.org
2
http://www.aenor.es/DescargasWeb/normas/como-beneficia-es.pdf
3
https://www.iso.org/
4
https://www.cen.eu/

7
8 ÍNDICE GENERAL

695 Statistical Methods. Por su parte, el subcomité técnico de normalización CTN 66/SC 36 ,
Métodos Estadísticos, participa como miembro nacional en ese comité ISO. Las normas que
son de interés en España, se ratifican en inglés o se traducen al español como normas UNE.
Para una descripción más completa de la elaboración de normas, véase Cano et al. (2015).

Este libro se ha elaborado utilizando el lenguaje Markdown con el propio software R y el


paquete rmarkdown (Allaire et al., 2019). Incluye una gran cantidad de ejemplos de código
de R, que aparecen en el texto sombreados y con la sintaxis coloreada, como el fragmento a
continuación donde se puede comprobar la sesión de R en la que ha sido generado.

07
sessionInfo()

## R version 3.6.0 (2019-04-26)


## Platform: x86_64-apple-darwin15.6.0 (64-bit)

5-
## Running under: macOS Mojave 10.14.4
##

-0
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib
##
##
##
locale: 19
[1] es_ES.UTF-8/es_ES.UTF-8/es_ES.UTF-8/C/es_ES.UTF-8/es_ES.UTF-8
20
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
or

## loaded via a namespace (and not attached):


## [1] compiler_3.6.0 magrittr_1.5 bookdown_0.9 tools_3.6.0
## [5] htmltools_0.3.6 rstudioapi_0.10 yaml_2.2.0 Rcpp_1.0.1
ad

## [9] stringi_1.4.3 rmarkdown_1.12 knitr_1.22 stringr_1.4.0


## [13] xfun_0.6 digest_0.6.18 evaluate_0.13

Normalmente, antes del código de ejemplo se incluye un bloque con el siguiente aspecto
rr

explicando el ejemplo:
Bo

Esto es un ejemplo. A continuación puede mostrarse código o no.

El texto incluye otros bloques con información de distinto tipo.

Este contenido se considera avanzado. El lector principiante puede saltarse estos


apartados y volver sobre ellos en una segunda lectura.

5
http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_tc_browse.htm?commid=49742
6
http://www.aenor.es/aenor/normas/ctn/fichactn.asp?codigonorm=AEN/CTN%2066/SC%203
ÍNDICE GENERAL 9

Estos bloques están pensados para incluir información curiosa o complementaria para
poner en contexto las explicaciones.

El material se proporciona bajo licencia CC-BY-ND-NC. Todos los logotipos y marcas co-
merciales que puedan aparecer en este texto son propiedad de sus respectivos dueños y se
incluyen en este texto únicamente con fines didácticos. Se ha puesto especial cuidado en la
adecuada atribución del material no elaborado por el autor, véase el Apéndice B. Aún así,
si detecta algún uso indebido de material protegido póngase en contacto con el autor y será

07
retirado.
Sobre el autor: http://blog.uclm.es/emiliolcano

5-
-0
Análisis de datos con R aplicado a la economía, la empresa y la industria de Emilio López
Cano está licenciado bajo Creative Commons Attribution-NonCommercial-ShareAlike 4.0
International License.

Agradecimientos
19
20
Aunque gran parte del material lo he elaborado con anterioridad con diversos propósitos, la
decisión de abordar este nuevo formato la ha provocado la preparación del primer seminario
de análisis de datos con R organizado en la Facultad de Derecho y Ciencias Sociales de la
or

Universidad de Castilla-La Mancha en el campus de Ciudad Real. La expectación que generó


aquél seminario entre los compañeros y el éxito de inscripciones me animó, como entusiasta
de R, a preparar un material que fuera más allá del mismo. A todos ellos mi agradecimiento,
ad

y en especial a Miguel Ángel Tarancón Morán, María Jesús Ruiz Fuensanta y Juan José
Rubio por su confianza.
Agradezco también a Víctor Casero Alonso, compañero y amigo del departamento de Ma-
rr

temáticas (área de Estadística e Investigacion Operativa) de la UCLM por los comentarios


sobre el texto y detección de erratas que me han permitido mejorarlo mucho.
Bo
10

Bo
rr
ad
or
20
19
-0
5-
07
ÍNDICE GENERAL
07
5-
Parte I

-0
19
Análisis de datos básico
20
or
ad
rr
Bo

11
Bo
rr
ad
or
20
19
-0
5-
07
Capítulo 1

07
Introducción al análisis de datos con
R

5-
-0
1.1. R y su ecosistema
1.1.1. Introducción 19
20
El análisis estadístico de datos es una tarea fundamental en la economía aplicada. Siempre
lo ha sido, pero en la actualidad la disponibilidad de datos, la cantidad de los mismos, y
la velocidad con la que se requieren resultados, está haciendo necesario el capacitar a los
investigadores y profesionales para el análisis de datos avanzado con nuevas herramientas.
Nuevas tendencias (muchas veces malinterpretadas) como Big Data, Industria 4.0, Internet
or

of Things (IoT), o Data Science, aumentan el interés por parte de las empresas, los profesio-
nales y los investigadores en estas técnicas. El análisis estadístico de datos requiere el uso
ad

de software avanzado. Aunque algunas tareas se pueden realizar eficazmente con programas
de hoja de cálculo como Excel1 , se debería utilizar software especializado para el análisis de
datos. Existen distintos paquetes estadísticos comerciales, como SPSS, Statgraphics, Stata
(muy popular en el análisis económico), o Minitab (líder en análisis de datos para metodolo-
rr

gías de calidad). En los últimos años se ha abierto camino el software estadístico y lenguaje
de programación R2 (R Core Team, 2019). R es software libre, pero su gratuidad solo es
Bo

una de sus ventajas3 , como se verá a lo largo del libro. El gran inconveniente es la curva de
aprendizaje: no es tan fácil de aprender y usar como un software de ventanas, ya que el uso
de R se basa en expresiones que hay que ejecutar desde scripts. No obstante, una vez que se
tienen las nociones básicas es fácil ir aplicando nuevos métodos.
En este capítulo nos centraremos en los primeros pasos para empezar a utilizar R, y en
perderle el miedo a una aplicación con la cual no se interactúa mediante ventanitas y menús,
sino mediante una consola y scripts de código.
1
Por ejemplo, son una buena herramienta para mecanizar y almacenar datos.
2
http://www.r-project.org
3
R is FOSS (Free and Open Source Software). Free as in free beer, and free as in free speech.

13
14 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

En el análisis económico, empresarial o industrial, siempre o casi siempre tenemos que tra-
bajar con datos. Tras leer este capítulo, el lector será capaz de crear, acceder y modificar
datos con R, y realizar un tratamiento básico con ellos. Esto sentará las bases para una pos-
terior profundización en el uso de R para usos específicos, tales como estimación, predicción,
visualización, etc.
Respecto a los datos, veremos en este capítulo cómo crear estructuras de datos desde R.
También trabajaremos con ficheros de datos de ejemplo. La estructura y formato de estos
ficheros tiene una importancia crucial al trabajar con R o con cualquier software de análisis
de datos.

07
En resumen, R es una de las alternativas4 al software comercial para el análisis de datos. R
es:

5-
Un sistema para computación estadística: software de análisis de datos, gráficos
y lenguaje de programación

-0
Ampliamente utilizado en investigación y docencia, grandes empresas lo usan: Google,
Pfizer, …

19
La evolución del trabajo de los laboratorios Bell con el lenguaje S (Venables and Ripley,
2002), llevado al mundo del software libre por Ross Ihaka y Robert Gentleman.
La web del proyecto R (http://www.r-project.org/, véase la figura 1.1), aunque austera,
20
contiene una gran cantidad de recursos para el uso de R. El apartado de documentación
y la revista de R (The R Journal) contienen gran cantidad de documentos generales y
específicos para ciertas tareas. Los recursos oficiales se encuentran en el repositorio CRAN
(The Comprehensive R Archive Network, véase la figura 1.2). Aquí es donde se descarga la
or

aplicación para instalar, pero también dispone de otros recursos.

1.1.2. Paquetes y librerías


ad

Uno de los aspectos más espectaculares de R es la cantidad de paquetes disponibles. Un


paquete de R es un componente adicional que se puede instalar en el sistema para ser
rr

utilizado por R. En el momento de compilar este libro el número de paquetes disponibles en


el repositorio oficial es de 14178. Los paquetes se almacenan en librerías. Podemos tener
varias librerías, aunque lo habitual es trabajar con las que configura por defecto R: una
Bo

librería del sistema, con los paquetes base, y una librería de usuario, con los paquetes que
se van instalando. Las librerías por defecto5 se encuentran en la carpeta de usuario, en el
directorio R.
Para poner un poco de orden en esta ingente cantidad de recursos, tenemos las task views
(véase la figura 1.3), que son una especie de recopilaciones de recursos sobre un tema concreto6 .
4
Hay otras alternativas, pero en la mayoría de los casos, o son parciales referidas a un ámbito concreto,
o son más lenguajes de programación que software estadístico, como Python.
5
R crea una para cada versión intermedia de R, por ejemplo, para R.4.x y R.5.x
6
Según CRAN “provide some guidance which packages on CRAN are relevant for tasks related to a certain
topic.”
1.1. R Y SU ECOSISTEMA 15

07
5-
-0
19
Figura 1.1: Captura de pantalla de la web del proyecto R: http://www.r-project.org
20
or
ad
rr
Bo

Figura 1.2: Captura de pantalla de CRAN: http://cran.r-project.org


16 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
5-
-0
19
Figura 1.3: Captura de pantalla de las tasks views en CRAN

Por ejemplo, si vamos a la task view Econometrics (figura 1.4), encontramos recursos
20
agrupados por subtemas (series temporales, modelos de panel, etc.) relacionados con los
métodos cuantitativos para la economía: libros, paquetes, funciones, bases de datos, enlaces,
etc.
CRAN no es el único repositorio de paquetes de R. Los siguientes son algunos de los más
or

importantes7 :
Bioconductor: (http://www.bioconductor.org/packages/).
ad

Github: (https://github.com/trending/r).
R-Forge: (https://r-forge.r-project.org/).
Omegahat: (http://www.omegahat.net/).
rr

Buscador global: (http://www.rdocumentation.org/).


Bioconductor8 , es otro repositorio oficial, especializado en bioinformática, bioestadística, bio-
Bo

metría, etc. Para poder publicar una librería en estos repositorios oficiales los autores deben
seguir unas reglas estrictas en cuanto a programación y documentación, por lo que estos
paquetes cumplen unos estándares mínimos de calidad. Algunos autores no publican los pa-
quetes en los repositorios oficiales, sino que los hacen públicos en sus propias webs o en
repositorios genéricos. Uno de los más prolíficos es github9 , con la ventaja de que se pue-
den instalar directamente en R gracias al paquete devtools. Además, es habitual que los
autores suban a github las versiones en desarrollo de los paquetes, aunque aún no los hayan
7
Para el alcance de este libro trabajaremos solo con CRAN, el lector puede visitar los enlaces a los
repositorios para aprender más.
8
http://www.bioconductor.org
9
http://www.github.com
1.1. R Y SU ECOSISTEMA 17

07
5-
-0
19
Figura 1.4: Captura de pantalla de la task view de econometría

publicado en CRAN.
20
1.1.3. Comunidad
El mundo del software libre genera recelos en las empresas (algunas veces con motivos funda-
or

dos). La primera pregunta es ¿quién mantiene todo esto? Los principales pilares que sustentan
el proyecto R son los siguientes:
ad

R Foundation.
R Core Team.
R Contributors.
Institute for Statistics and Mathematics of WU (Wirtschaftsuniversität Wien, Vienna
rr

University of Economics and Business).


R Consortium.
Bo

La fundación de R está establecida en Viena (Austria). Obtiene recursos de su propia ac-


tividad mediante la organización de un congreso anual, pero sobre todo de sus donantes.
Podemos ver algunos específicos del mundo de R, como RStudio, pero también algunos muy
importantes como AT&T o Google. En el año 2015 se constituyó el R Consortium10 para
apoyar a la comunidad de R, la fundación de R y a las organizaciones que desarollan, man-
tienen y distribuyen software R. Actualmente importantes compañías como IBM, Microsoft
o Google son miembros del consorcio.
La comunidad de usuarios de R proporciona recursos adicionales a los del propio proyecto
10
https://www.r-consortium.org/
18 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
5-
-0
19
Figura 1.5: Captura de pantalla de la web de la comunidad R Hispano: http://r-es.org/

R. Una simple búsqueda en Internet sobre algún tema concreto de análisis de datos añadien-
20
do “R” a la búsqueda, nos proporcionará provechosos enlaces. De especial interés son los
siguientes:
Documentación.
or

Listas de correo.
Stackoverflow.
ad

The R Journal.
R Pubs.
rr

Libros (e.g., Springer use R! series).


Bo

En España existe una asociación de usuarios de R (Comunidad R-Hispano). Asociarse es


gratuito. En la web de la asociación11 (figura 1.5) se pueden encontrar recursos en español. Por
ejemplo, los grupos de interés local comparten presentaciones y material de diversos temas
relacionados con R. También se puede encontrar información y material de las Jornadas de
Usuarios de R, que se celebran anualmente. La asociación también dispone de cuenta de
Twitter: @R_Hisp y una lista de correo.
Una vez conocemos el mundo de R nos podemos hacer la pregunta, ¿y por qué utilizar R?
Es imposible dar un único motivo, a continuación se enumeran algunas de las ventajas que
tiene R:
11
http://r-es.org/
1.2. COMPONENTES DE R Y RSTUDIO 19

Es gratis. En inglés se suele decir free as in free beer, and free as in free speech.
Amplia comunidad de usuarios que proporciona recursos.
Es multiplataforma.
Se usa cada vez en más empresas e instituciones.
Es posible obtener soporte comercial (TIBCO, R Studio, …).
Se ha alcanzado una masa crítica de usuarios que lo hace confiable.

07
Es extensible (desde pequeñas funciones, hasta paquetes).
Se puede implementar la innovación inmediatamente. En software comercial hay que
esperar a nuevas versiones, en el mejor de los casos.

5-
Posee características de Investigación reproducible. Veremos más adelante qué implica
este enfoque.

-0
Una característica que hace R universal es el hecho de que cada usuario puede decidir hasta
dónde quiere llegar. Las funciones de R están diseñadas para que, con muy poco esfuerzo,

19
se consigan resultados básicos. A partir de ahí, a medida que necesitamos más complejidad,
podemos añadir opciones, por medio de argumentos a las funciones, uso de otras funciones,
etc. Se puede llegar a resultados muy elaborados, como libros, aplicaciones web, widgets, etc.
20
Como nada es perfecto, R también tiene sus inconvenientes. El más importante es la llamada
curva de aprendizaje. Como muestra la figura 1.6, cuesta mucho aprender a utilizar R al
principio, especialmente para analistas que no están acostumbrados a programar o a utilizar
software que se basen en el uso de scripts, como por ejemplo MATLAB. Pero una vez se
or

aprenden los principios básicos, la productividad aumenta. Aunque parezca que no se avanza
porque se le dedica más tiempo, en realidad lo que está pasando es que cada vez se quieren
hacer cosas más elaboradas. Llega un momento en que se aprende muy rápido hasta que
ad

se consigue un buen nivel de conocimiento. Siguen apareciendo errores, pero se identifican


rápidamente las causas y se solucionan. Al final, llega a ser adictivo, y uno quiere hacerlo
todo con R. Otros inconvenientes de las etapas iniciales de R, como el hecho de trabajar con
rr

datos en memoria y no en disco, lo que a priori dificulta trabajar con grandes cantidades de
datos, han sido superados con las últimas versiones y paquetes especializados.
Bo

1.2. Componentes de R y RStudio


1.2.1. Las bases
R es una aplicación de análisis estadístico y representación gráfica de datos, y además un
lenguaje de programación. R es interactivo, en el sentido de que responde a través de un
intérprete a las entradas que recibe a través de la consola. Estas entradas son expresiones
que pueden ser de diversos tipos, principalmente:
Una expresión aritmética.
20 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

Soy un experto

Conocimiento de R
Sé un montón

Sé algo

No sé nada

07
0 5 10 15

Tiempo

5-
Figura 1.6: La curva de aprendizaje de R. La escala de tiempo dependerá de cada usuario.

-0
Una expresión lógica.
Una llamada a una función12 .
Una asignación.
19
20
Si la expresión está incompleta, el intérprete de R queda a la espera hasta que la expresión
se complete. Si la expresión está completa, el intérprete la evalúa, produciendo un resultado.
Este resultado puede mostrar algunas salidas al usuario, que puede ser texto o gráficos.
Algunas expresiones no producen ninguna salida visible, y su resultado puede ser, entre
or

otros, almacenar datos en variables o escribir datos en disco.


R trabaja con datos en memoria, es decir, necesita tener los objetos almacenados en su es-
ad

pacio de trabajo. Veremos más adelante estos detalles. Pero aunque R trabaje con los datos
en memoria, necesitaremos usar archivos en disco de diversas formas, principalmente para
importar datos y escribir código. Los ficheros estarán siempre referenciados al directorio
de trabajo.
rr

1.2.2. Componentes
Bo

La infraestructura de R se compone de una serie de elementos que principalmente son los


siguientes:
La Consola.
Editor de código (scripts).
Salida gráfica.
El historial.
12
En realidad, todo lo que sucede en R es la respuesta a una función
1.2. COMPONENTES DE R Y RSTUDIO 21

07
5-
Figura 1.7: Interfaz de usuario de R por defecto para Windows

-0
El espacio de trabajo.
El directorio de trabajo.
19
La figura 1.7 muestra el interfaz gráfico de usuario (GUI) por defecto de R. Podemos ver la
consola, la salida gráfica y el editor de código, pero el resto de los componentes mencionados
20
no están visibles.

1.2.3. RStudio
or

El interfaz de usuario de R (R GUI, Graphical User Interface) cumple las funciones bási-
cas para interactuar con R, pero es muy pobre a la hora de trabajar con él. En su lugar,
utilizaremos el interfaz de usuario RStudio13 , que es como un envoltorio del sistema R con
ad

más funcionalidades y ayudas, pero manteniendo el mismo nivel de interacción: consola y


scripts (código). Al igual que R, RStudio es una aplicación de software libre, pero en este
caso desarrollada y mantenida por una compañía privada. Existen versiones de pago para
rr

las cuales esta compañía ofrece soporte y otros servicios. La ventana del programa RStudio
se divide en cuatro partes o paneles (panes), véase la figura 1.8:
Bo

En la parte superior izquierda, tenemos el editor. Aquí podemos editar scripts de R y


cualquier otro tipo de archivo de texto, por ejemplo R Markdown para realizar informes.
También es en este cuadrante donde se visualizan las tablas de datos que tengamos en
el espacio de trabajo.
En la parte inferior izquierda, tenemos la consola de R. Podemos interactuar con R
como se describe a continuación. Las versiones más recientes incluyen también una
terminal del sistema, y otras pestañas para tareas avanzadas.
En la parte superior derecha tenemos los entornos (environment), entre los que se
13
http://www.rstudio.org
22 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
5-
-0
19
Figura 1.8: interfaz de usuario de RStudio
20
encuentra el espacio de trabajo de la sesión actual, y el historial. Las versiones más
recientes incluyen también pestañas para conectar con bases de datos y otras tareas
avanzadas.
or

En la parte inferior derecha tenemos organizadas en pestañas los siguientes elementos:


• Un explorador de archivos.
ad

• La salida gráfica de R.
• Los paquetes disponibles.
rr

• La ayuda.
• Un visualizador de aplicaciones y documentos web.
Bo

Esta es la distribución por defecto, se puede cambiar la disposición de los distintos paneles
de RStudio en la configuración global mediante el menú Tools/Global Options.
Existen otros interfaces para usar R, tanto del tipo de RStudio, es decir, entornos de desa-
rrollo (IDE, Integrated development Environment) como interfaces gráficos de usuario (GUI).
Estas otras opciones quedan fuera del alcance de este libro, pero se recomienda probarlos
para elegir el que mejor se adapte a las necesidades de cada uno. Algunos de estos interfaces
son:
Con menús y ventanas:
• Rcommander: http://www.rcommander.com/
1.2. COMPONENTES DE R Y RSTUDIO 23

• Deducer: http://www.deducer.org
• RKWard: https://rkward.kde.org/
De desarrollo
• Eclipse + statET: http://www.walware.de/goto/statet
• Microsoft Visual Studio: https://www.visualstudio.com/vs/rtvs/
• EMACS: https://ess.r-project.org/
El enfoque de este libro es el de utilizar entornos de desarrollo como RStudio. En opinión
del autor, el analista debe tener control total sobre todo el proceso de análisis de datos, y el
enfoque IDE es el más adecuado. Para usuarios no cualificados que sólo necesiten interpretar

07
resultados, se pueden desarrollar interfaces a medida de forma relativamente fácil con Shiny14
o RStudio Addins15 . El uso de menús y ventanas al estilo tradicional del software estadístico
es un punto intermedio que por una parte no evita tener que formar al usuario, pero por

5-
otra el usuario no sabrá lo que está haciendo realmente. No obstante en algunos entornos de
investigación o docencia puede ser adecuado utilizarlos.

-0
Realice la práctica 1.1 cuyo guión se encuentra en el apartado 1.7 para instalar R y
RStudio.

La sesión de R
19
20
Cuando abrimos R (directamente o con RStudio), iniciamos una Sesión de R. La sesión de
R se inicia en un directorio de trabajo (working directory). Las expresiones introducidas
en la consola se van guardando en el Historial, véase la figura 1.9. Se puede acceder al
historial desde la consola simplemente utilizando las flechas arriba y abajo del teclado. En
or

RStudio, además, podemos ver todo el historial en la pestaña History del panel superior
derecho, y realizar otras operaciones como buscar, limpiar, guardar, abrir, o pasar líneas a la
consola o al editor de código. Por defecto, RStudio guarda siempre el historial de la sesión en
ad

el directorio de trabajo al cerrar16 , y lo carga al iniciar una sesión de R en ese directorio de


trabajo. También se pueden utilizar las funciones savehistory y loadhistory para guardar
y recuperar el historial respectivamente.
rr

La consola de R
Bo

La consola de R en RStudio (figura 1.10) se encuentra en el panel inferior izquierdo de la


ventana del programa. Funciona exactamente igual que en R GUI, aunque los colores pueden
ser diferentes. Algunos detalles sobre la consola en RStudio:
Podemos situar el cursor en el símbolo de la consola > desde cualquier lugar del pro-
grama pulsando CTRL + 2.
En la barra de título de la consola, a continuación de Console se indica el directorio
de trabajo (working directory). El símbolo ~ indica la carpeta de usuario, por ejemplo
14
https://shiny.rstudio.com
15
https://rstudio.github.io/rstudioaddins/
16
Se puede cambiar este comportamiento en las opciones de RStudio.
24 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
5-
-0
Figura 1.9: El historial de R en RStudio

“Documentos” en Windows, o “/home/usuario” en Linux.


19
La flecha a la derecha del directorio de trabajo sirve para que el explorador de ficheros
muestre el directorio de trabajo.
20
Si empezamos a escribir y pulsamos la tecla TAB o CTRL + ESPACIO aparece una lis-
ta para seleccionar elementos disponibles en el espacio de trabajo, como variables o
funciones. Aparece también un mensaje emergente con la ayuda básica de ese objeto,
especialmente útil para funciones.
or

CTRL + ESPACIO dentro de una función muestra los argumentos posibles y su signifi-
cado como un mensaje emergente al movernos a través de ellos.
ad

CTRL + ESPACIO dentro de comillas muestra los ficheros del directorio de trabajo.
La tecla ESC cancela la expresión actual.
rr

CTRL + L limpia la consola.


Bo

La combinación CTRL + ESPACIO y el TAB permite también insertar snippets, que son
una especie de plantillas de fragmentos de código para tareas repetitivas, como crear bucles
o condiciones.

En la consola podemos introducir expresiones que son evaluadas una a una. Una expresión
de R puede ser una llamada a una función, de hecho es la expresión que más utilizamos.
La llamada a una función es siempre igual: el nombre de la función más (obligatoriamente)
paréntesis de apertura y cierre, y, dentro de los paréntesis, los argumentos de la función
separados por comas. Los argumentos de las funciones se pueden declarar de varias formas:
Por el orden en el que están definidos en la propia función.
1.2. COMPONENTES DE R Y RSTUDIO 25

07
5-
-0
Figura 1.10: La Consola de R en RStudio

19
Por el nombre con el que están definidos en la propia función. R tiene una caracte-
rística llamada partial matching que permite escribir sólo los primeros caracteres del
20
nombre.

Utilizar su valor predeterminado. Algunos parámetros de funciones tienen un valor


or

predeterminado. Si no proporcionamos uno distinto, es el que se utiliza. Podemos ver


los argumentos de una función mediante la función str o el atajo de teclado en RStudio
mencionado anteriormente, CTRL + ESPACIO. Es obligatorio usar paréntesis aunque la
ad

función no requiera argumentos.

La función mean calcula la media del vector de números y acepta un argumento na.rm
rr

(veremos más adelante estos conceptos). En el siguiente fragmento de código se genera un


vector aleatorio de 10 valores y se calcula su media. Las llamadas a la función mean devuelven
Bo

el mismo resultado, aunque la especificación de los argumentos sea distinta. Vea la ayuda de
la función mean y averigüe por qué.

set.seed(1)
unvector <- rnorm(10)
mean(unvector)
mean(x = unvector)
mean(x = unvector, na.rm = FALSE)
mean(na.rm = FALSE, x = unvector)
mean(unvector, na.rm = FALSE)
mean(unvector, na = FALSE)
26 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
5-
-0
Figura 1.11: El entorno de trabajo (workspace) en RStudio

El espacio de trabajo de R
19
Una de las características de R es que todos los datos con los que trabaja se encuentran en
memoria. Cuando hay grandes volúmenes de datos (realmente grandes) es necesario utilizar
20
tecnologías Big Data, como por ejemplo Spark 17 , que este libro no cubre. No obstante, la
mayoría de los problemas de análisis de datos a los que nos enfrentamos en el día a día no
son realmente Big Data.

Los objetos que creemos con R se guardan en el espacio de trabajo (workspace), véase la
or

figura 1.11. Para crear un objeto en el espacio de trabajo utilizamos el operador de asignación
<-. Nótese que es como una flecha hacia la izquierda, con la que asignamos al símbolo que
ad

pongamos a la izquierda, el resultado de la expresión que pongamos a la derecha18 . En reali-


dad, hay varios workspaces, uno para cada environment. El Global Environment es el entorno
de trabajo del usuario. El resto de environments tienen que ver con aspectos programáticos
de R que no se tratan en este libro. Podemos acceder a los distintos environments mediante la
rr

pestaña Environment en el panel superior derecho desde donde también es posible importar
un fichero de datos19 mediante el cuadro de diálogo Import Dataset.
Bo

En la barra superior del espacio de trabajo tenemos iconos para guardar, abrir y limpiar
el espacio de trabajo. Los espacios de trabajo se guardan con extensión .RData. También
se pueden utilizar las funciones save.image, save y load para guardar todo el espacio de
trabajo, algunos objetos del espacio de trabajo, o recuperar un espacio de trabajo respecti-
vamente. Podemos mostrar los objetos que hay en el espacio de trabajo con la función ls,
eliminarlos con la función rm, o ver su estructura con la función str.
17
https://spark.apache.org/
18
Se puede utilizar el símbolo = en R para la asignación. Algunos usuarios prefieren utilizar este símbolo,
pero en este texto utilizamos el símbolo específico de R <-.
19
Formatos CSV, Excel, Stata, SPSS, SAS.
1.2. COMPONENTES DE R Y RSTUDIO 27

07
5-
-0
Figura 1.12: Salida gráfica de RStudio

La salida gráfica
19
Cuando el resultado de una expresión de R es una salida gráfica, se muestra en la pestaña
Plots del panel inferior derecho, véase la figura 1.12. Desde este pastaña se pueden exportar los
20
gráficos en varios formatos (pdf, imagen, portapapeles) eligiendo opciones como la resolución.
Los gráficos se van guardando en un histórico por el que se puede navegar y limpiar. También
podemos sacar el gráfico a otra ventana con el icono zoom.
or

La ayuda
ad

Ya hemos visto una de las formas de obtener ayuda contextual con RStudio, a través del
atajo CTRL + ESPACIO dentro de una función. De esta forma podemos ver la descripción
de la función y el significado de los argumentos que acepta. Para ver la documentación
rr

completa de la función podemos pulsar la tecla F1 con el cursor situado sobre el nombre de
una función o cualquier otro objeto de R que tenga documentación, por ejemplo un conjunto
Bo

de datos. La documentación se abre en la pestaña Help del panel inferior derecho (véase la
figura 1.13). Podemos ir directamente a este panel con el atajo CTRL + 3. En esta pestaña,
tenemos opciones para buscar dentro de la documentación abierta, o buscar documentación
de otros temas, además de poder imprimir y navegar por la documentación. Un tipo de
documento especial son las llamadas Vignettes, que pueden incluir ejemplos y explicaciones
más extensas, incluidos gráficos. También podemos buscar ayuda interactivamente con las
funciones apropos, help, vignette, example y demo.

Realice la práctica 1.2 cuyo guión se encuentra en el apartado 1.7 para interactuar
con la consola de R en RStudio.
28 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
5-
-0
Figura 1.13: Ayuda de RStudio

Paquetes
19
La funcionalidad de R se organiza en librerías que contienen paquetes (packages). R puede
tener varias librerías y dentro de estas librerías se instalan los paquetes, que después se
20
pueden cargar. Al abrir R, los paquetes base se cargan automáticamente y están disponibles.
Para utilizar funciones de otros paquetes es necesario cargar antes el paquete en la sesión.
Los paquetes se cargan con la función library20 con el nombre del paquete como argumento,
no son necesarias comillas.
or

El paquete nortest (Gross and Ligges, 2015) sirve para realizar contrastes de nor-
malidad sobre conjuntos de datos. Contiene una función llamada ad.test para realizar el
ad

contraste de Anderson-Darling. El siguiente código genera un conjunto de datos aleatorios,


carga el paquete y realiza dicho contraste.
rr

set.seed(1)
x <- rpois(50, 4)
Bo

library(nortest)
ad.test(x)

##
## Anderson-Darling normality test
##
## data: x
## A = 0.77845, p-value = 0.04038
20
La función require también se utiliza para cargar paquetes, aunque su comportamiento es ligeramente
diferente y más adecuado para utilizar dentro de otras funciones, véase la ayuda ?require.
1.2. COMPONENTES DE R Y RSTUDIO 29

07
5-
-0
Figura 1.14: Gestión de paquetes en RStudio

19
Nötese que el paquete debe estar instalado previamente como se explica más abajo.

Una alternativa a cargar el paquete con la función library sería llamar a la función
20
con la sintaxis paquete::funcion(). Esto es útil en muchas ocasiones, por ejemplo si solo
necesitamos llamar a la función una vez y no necesitaremos más funciones del paquete.
Además, sirve para asegurarnos de que la función corresponde al paquete que queremos usar,
ya que podría haber una función con el mismo nombre en otro paquete cargado que haga
or

otra cosa completamente distinta.

nortest::ad.test(x)
ad

##
## Anderson-Darling normality test
rr

##
## data: x
## A = 0.77845, p-value = 0.04038
Bo

Por otra parte, para poder cargar un paquete tiene que estar instalado en el sistema. Podemos
realizar estas opciones con el interfaz gráfico de RStudio que tenemos en la pestaña Packages
del panel inferior derecho como se refleja en la figura 1.14. La instalación, actualización y
eliminación de paquetes es más cómoda desde RStudio, aunque también se puede hacer in-
teractivamente con las funciones intsall.packages, update.packages y remove.packages
respectivamente. Sin embargo, para cargar paquetes, una vez establecemos la rutina, lo nor-
mal es cargarlas al principio del script mediante la función library, o bien justo antes de
utilizar funciones del paquete. En resumen, para utilizar una función de un paquete, este
tiene que estar cargado, y para cargar el paquete, tiene que estar instalado. La instalación
solo hay que realizarla una vez, pero es necesario cargar el paquete en cada sesión de R.
30 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

El directorio de trabajo
Una sesión de R tiene asignado un directorio de trabajo para aquellas tareas relacionadas
con ficheros en disco. Por ejemplo, para trabajar con datos, trabajar con código, o exportar
gráficos. Cuando en alguna expresión de R intervienen ficheros, se puede proporcionar la
ubicación del fichero de dos formas distintas:
Mediante la ruta absoluta. Es decir, la ubicación en el disco duro del ordenador con la
ruta completa.
Mediante la ruta relativa. Es decir, la ubicación en el disco duro del ordenador a partir

07
del directorio de trabajo.
Una ayuda importante con RStudio es que podemos acceder a los ficheros y carpetas del

5-
directorio de trabajo desde la consola o desde el editor de código pulsando la combinación
de teclas CTRL + ESPACIO estando el cursor dentro de comillas.

-0
IMPORTANTE: En R, el carácter \ no se puede utilizar tal cual. Por lo tanto, para indicar
las rutas de ficheros en Windows, tenemos que utilizar la barra normal (/), o bien poner doble
barra invertida (\\) para separar directorios. Esto es importante cuando copiamos y pegamos

19
una ruta del explorador de archivos de Windows.

La función setwd establece el directorio de trabajo. En el siguiente fragmento de


20
código se muestran dos formas de referirse correctamente a la carpeta “micodigo” que se
encuentra en el disco “C:” de Windows, y la forma incorrecta para R correspondiente a la
sintaxis típica de Windows.
or

## Correcto:
setwd("C:/micodigo")
setwd("C:\\micodigo")
ad

## Incorrecto:
setwd("C:\micodigo")
rr

Además, en la pestaña Files del panel inferior derecho (véase la figura 1.15) disponemos de un
explorador de archivos que podemos vincular al directorio de trabajo mediante la flecha en la
Bo

barra de título de la consola. La operación inversa también es posible: buscamos una carpeta
mediante el icono ... arriba a la derecha, y a continuación seleccionamos Set as working
directory en el icono More. Otras opciones son crear carpetas, copiar, mover, cambiar nombre,
o abrir la carpeta con el explorador de archivos en una nueva ventana. Por último, también es
posible establecer como directorio de trabajo el que contiene un script abierto en el editor de
código, mediante el menú Session. En las opciones globales de RStudio se puede configurar el
directorio de trabajo al abrir la aplicación, por defecto “Mis Documentos”, que se representa
con el símbolo21 ~. Aunque el interfaz de usuario es útil para trabajar con ficheros y con
21
Este símbolo se obtiene en el teclado con la combinación de teclas Alt Gr + 4. Es posible que tenga
que pulsar la barra espaciadora después de la combinación de teclas.
1.2. COMPONENTES DE R Y RSTUDIO 31

07
5-
-0
Figura 1.15: Explorador de ficheros de RStudio

el directorio de trabajo puntualmente, una práctica muy extendida es fijar el directorio de


19
trabajo en las primeras expresiones de los scripts que se utilizan. No obstante, si se trabaja
con proyectos de RStudio esto no tiene mucho sentido, como veremos más adelante.
20
Hay también funciones para eliminar ficheros, copiar, etc. No obstante para los objetivos de
este libro, es mejor utilizar el explorador del sistema operativo para copiar y borrar ficheros.
Es importante recordar que la eliminación de ficheros en R y RStudio es irreversible ya que
los ficheros o carpetas no pasan por la papelera de reciclaje al ser eliminados.
or

El editor de RStudio
ad

Interactuar con la consola de R es conveniente en muchas situaciones, por ejemplo cuando


estamos probando cosas, aprendiendo, o queremos obtener un resultado momentáneamente.
Pero la forma natural de trabajar con R es mediante scripts o ficheros de código. Un script
rr

es un fichero de texto con expresiones de R. Trabajar con scripts permite, entre otras cosas,
reutilizar código, automatizar tareas de análisis de datos, o registrar los análisis realizados.
Un script de R es “texto plano” y por tanto se puede utilizar cualquier editor de texto para
Bo

crearlos o verlos. El GUI de R incluye un editor de código simple desde el que se pueden
crear scripts. No obstante, el editor de código de RStudio (véase la figura 1.16) proporciona
mucha más funcionalidad. Por ejemplo, dispone de sintaxis coloreada, es decir, los distintintos
elementos de una expresión (números, cadenas de texto, nombres de funciones, …) aparecen
en distintos colores22 . Además, todas las ayudas explicadas anterioremente para la consola,
funcionan en el editor de RStudio (TAB o CTRL + ESPACIO). El atajo de teclado CTRL +
1 sitúa el cursor en el editor de RStudio. Otras características útiles son la búsqueda, la
posibilidad de crear secciones y visualizar un índice (outline) o de “desacoplar” ventanas del
panel para trabajar más cómodamene.
22
En las opciones de RStudio se puede elegir el tema.
32 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
5-
-0
Figura 1.16: Editor de código de RStudio

Los scripts de R tienen extensión .R. Para crear un script, utilizamos el menú File o el
19
icono justo debajo de este menú. Vemos que hay más tipos de archivos que se pueden crear
en el editor, pero de momento nos fijamos solo en el R Script. El código de un script se
puede ejecutar de diversas formas, aunque en definitiva se trata de enviar al intérprete, bien
20
expresión a expresión a través de la consola, bien como bloque a través de la función source.
Las expresiones pueden ocupar una o varias líneas. De hecho cuando las expresiones son
muy largas es preferible usar varias líneas para que se lean mejor. El editor de RStudio las
or

autoindenta. Se puede escribir más de una expresión en la misma línea si las separamos con
punto y coma (;). Se pueden incluir también comentarios en el código mediante el carácter
#. Lo importante es seguir un estilo consistente en cuanto a nombres de objetos, espacios en
ad

blanco y distribución del código en el script, véase por ejemplo la guía de estilo de Hadley
Wickam23 (Wickham, 2015).
Como se ha dicho anteriormente, existen diversas formas de ejecutar código de un script:
rr

Para ejecutar una línea del script que está abierto, situamos el cursor en cualquier
posición de la línea y pulsamos CTRL + INTRO o hacemos clic en el icono Run de la
Bo

barra del editor.


Para ejecutar un bloque de código, seleccionamos el bloque y pulsamos CTRL + INTRO
o hacemos clic en el icono Run de la barra del editor..
Para ejecutar el script actual completo, hacemos clic en el icono Source. Con la función
source podemos ejecutar cualquier script almacenado en el disco duro que le pasemos
como argumento. En este caso, el output no se muestra por defecto en la consola, pero
podemos modificar este comportamiento con los argumentos de la función, véase la
ayuda.
23
http://adv-r.had.co.nz/Style.html
1.2. COMPONENTES DE R Y RSTUDIO 33

07
Figura 1.17: Esquema de un script

5-
En el menú Code hay varias opciones y atajos de teclado para ejecutar porciones del
script, por ejemplo para ejecutar un script completo sin tener que seleccionar todas las

-0
líneas, podemos utilizar el atajo CTRL + S.
Para ejecutar un script completo desde el sistema operativo (sin abrir R ni RStudio),

operativo. 19
se utiliza la llamada al programa RScript desde la línea de comandos del sistema

Para moverse de forma ágil dentro de los scripts y de los informes se puede usar el índice (1)
20
que se va creando automáticamente o el selector de apartados (2), véase la figura 1.17. Las
entradas de índice se pueden crear con el menú Code/Insert section…, o bien directamente
escribiendo una línea de comentario que termine en cuatro o más guiones medios, por ejemplo:
or

# Apartado 1 ----
ad

Realice la práctica 1.3 cuyo guión se encuentra en el apartado 1.7 para trabajar con
scripts.
rr

1.2.4. Proyectos en RStudio


En este apartado se proporcionan unas pautas para utilizar de forma eficiente RStudio. La
Bo

principal ventaja de utilizar R Studio es el ahorro de tiempo para el analista, por lo que
si se está dedicando más tiempo a tareas sin valor como corregir errores, leer datos, haciendo
muchos clics con el ratón, etc. que a tareas que sí aportan valor como pensar en el problema
y su aplicación, es que las cosas se deberían hacer de otra forma. En los proyectos de análisis
de datos lo importante son los métodos y su comprensión, no la herramienta. En los primeros
días de uso de R uno de los principales obstáculos que surgen es la estructura y localización
de los ficheros. También se propone una estructura eficiente de ficheros, que obviamente se
debe adaptar al estilo de trabajo del analista y al propio proyecto, pero lo importante es
sobre todo que se puedan cargar los datos a la primera.
Trabajar con proyectos en R Studio tiene varias ventajas. Una de ellas es que, una vez que
34 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
5-
Figura 1.18: Inicio de RStudio sin abrir proyecto

-0
entendemos cómo funcionan los proyectos, no tenemos que preocuparnos del directorio de
trabajo. Cuando abrimos R Studio desde el icono del escritorio, pueden pasar dos cosas: que

19
se abra directamente un proyecto, o que se abra R Studio sin ningún proyecto. En este último
caso veríamos en la parte superior derecha “Project: (None)”, véase la figura 1.18.
En el triángulo de la derecha podemos abrir un menú para gestionar los proyectos. Para crear
20
un proyecto, hay que elegir una carpeta en la que se va a crear (del equipo o de una memoria
extraíble si se utiliza, por ejemplo, el ordenador de un aula de informática). Dentro de esa
carpeta, se va a crear otra con el nombre que se le pongas al proyecto, y dentro de esa nueva
carpeta se creará un archivo con el mismo nombre y extensión “.RProj”. Muy importante:
or

no se le debe cambiar el nombre a la carpeta una vez creado el proyecto ya que debe tener
el mismo nombre que el archivo .RProj24 . Por otra parte, se recomienda utilizar nombres de
proyecto (incluida su ruta de carpetas) que no contengan espacios ni caracteres no ASCII
ad

(por ejemplo acentos y eñes), ya que podrían provocar algún errore en algunas funciones de
importación de datos.
rr

Cuando tenemos un proyecto de RStudio abierto (figura 1.19) nuestro directorio de trabajo
aparece siempre en la barra de título de la consola (1), que se muestra por defecto en el panel
de archivos (2) por el que podemos desplazarnos arriba (3) por la ruta (4) o buscando una
Bo

carpeta (5). También entrando en las carpetas, una vez se hayan creado. Siempre podemos
volver a nuestro directorio de trabajo utilizando la flecha de la barra de título de la consola
(6).
Es importante organizar bien los ficheros de un proyecto de análisis de datos, especialmente
cuando el proyecto gana complejidad. Una estructura de carpetas comúnmente aceptada
como buenas prácticas en análisis de datos incluiría las siguientes carpetas:
datos: Aquí se guardan todos los ficheros de datos.
informes: Para los archivos que incluyan análisis, como ficheros .Rmd, R Markdown.
24
Y si se hace, cambiar también el nombre del archivo .Rproj para que sean iguales.
1.2. COMPONENTES DE R Y RSTUDIO 35

07
5-
-0
Figura 1.19: Poner nombre al proyecto

19
scripts: para los scripts, ficheros .R.
Estas tres carpetas serían lo mínimo que habría que tener para tener organizado el proyecto.
Otras carpetas útiles según la naturaleza del proyecto serían:
20
img: Para imágenes.
ref: Para referencias.
subcarpetas dentro de las anteriores.
or

Y en definitiva, cualesquiera que sean útiles para el proyecto. En general, se deben evitar
en los nombres de carpetas y ficheros caracteres no ASCII y espacios en blanco. Aunque el
ad

sistema operativo pueda trabajar con ellos, es posible que el software de análisis de datos dé
algún problema inesperado.
Las carpetas se crean desde el panel de ficheros de R Studio mediante el icono “New Folder”
rr

(figura 1.20).
El flujo de trabajo a partir de aquí será a través de un proyecto. Antes de empezar a trabajar,
Bo

hay que asegurarse de que estamos en el proyecto deseado. El proyecto cargado aparece en
la parte superior derecha como en la figura 1.21.
Si al abrir R Studio al retomar el trabajo no se abre el proyecto automáticamente, hay que
buscarlo con la opción “Open Project” de ese mismo menú, o directamente abrirlo haciendo
doble clic en el archivo del proyecto (extensión .RProject) dentro de la carpeta desde el
explorador de archivos del sistema operativo, figura 1.22.
Una vez está el proyecto abierto realizaremos tareas como:
1. Copiar ficheros de datos en la carpeta “datos”.
2. Crear scripts en la carpeta “scripts”. Importante: aunque estén en otra carpeta, el
36 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
5-
Figura 1.20: Crear nueva carpeta

-0
19
20
or

Figura 1.21: Menú proyectos


ad
rr
Bo

Figura 1.22: Archivo de proyecto de RStudio


1.3. ESTRUCTURAS DE DATOS Y SU TRATAMIENTO 37

directorio de trabajo sigue siendo el del proyecto.


3. Crea informes en la carpeta “informes”. Al generar los informes, el resultado se guardará
en la misma carpeta25 .
4. Ejecutar los scripts e informes a conveniencia.
En este apartado sobre RStudio hemos revisado la funcionalidad más importante para análsis
de datos. RStudio tiene otras características que se pueden explorar para sacarle todo el jugo,
como por ejemplo:
Control de versiones (git, svn). Útil no sólo para desarrollar paquetes sino también
para trabajar en proyectos de análisis de datos de forma colaborativa.

07
htmlwidgets: permite crear informes dinámicos, por ejemplo con mapas o tablas nave-
gables.
Aplicaciones shiny: para crear interfaces de usuario que funcionan en el navegador.

5-
Addins: para crear menús personalizables dentro de RStudio.
Se recomienda visitar el sitio web de RStudio para aprender más sobre cualquiera de estos

-0
aspectos.

19
Realice la práctica 1.4 cuyo guión se encuentra en el apartado 1.7 para crear un
proyecto de RStudio.
20
1.3. Estructuras de datos y su tratamiento
En R, los datos de una variable26 pueden ser de un tipo determinado, por ejemplo números
or

o texto. Estas variables pueden a su vez estar integradas en otras estructuras. La forma más
simple es en forma de vector para una sola variable. Las matrices son vectores con más de
una dimensión. Las listas pueden contener objetos de distinto tipo y longitud. Los objetos de
ad

tipo data frame contienen variables de distinto tipo con el mismo número de observaciones,
y es el formato más adecuado para el análisis de datos.
rr

1.3.1. Clases y tipos


En R, las estructuras de datos se almacenan con un tipo, que puede ser principalmente; logi-
Bo

cal (Verdadero/Falso), integer (Número entero), double (Número real) o character (Cadena
de texto). Hay otros tipos como complex, raw, NULL, o closure que son menos habituales
en análisis de datos. El modo de almacenamiento es básicamente igual, aunque los tipos
integer y double tienen el modo numeric.

En el siguiente fragmento de código creamos un vector con la secuencia de números


del 1 al 10, y después comprobamos su tipo y su modo.
25
Más adelante aprenderemos más sobre informes.
26
El lector puede encontrar útil en este punto revisar antes los tipos de variables en el apartado 2.1
38 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

un_vector <- 1:10


typeof(un_vector)

## [1] "integer"
mode(un_vector)

## [1] "numeric"
Por otra parte, todos los objetos de R tienen una clase (class). En el caso de vectores de datos,
la clase será cualquiera de los modos indicados antes, u otros más complejos como: factor

07
(vector categórico, es decir, niveles + etiquetas); table (tabla de frecuencias); Date (fecha);
POSIXct (fecha y hora); ts, xts o zoo (series temporales); S3 o S4 (clases personalizadas,
definidas en un paquete, función, etc, por ejemplo lm, spatial).

5-
La clase del vector creado anteriormente coincide con su tipo. Examinemos también

-0
el objeto AirPassengers, conjunto de datos de ejemplo de los proporcionados en el paque-
te datasets. Vemos que la clase es ts (time series), pero el modo de almacenamiento es
numeric.
class(un_vector) 19
20
## [1] "integer"
class(AirPassengers)

## [1] "ts"
or

mode(AirPassengers)

## [1] "numeric"
ad

1.3.2. Vectores y matrices


rr

Podemos crear vectores introduciendo todos sus elementos, o generando secuencias. La fun-
ción c crea un vector cuyos elementos serán los que pasemos como argumentos. El intérprete
Bo

de R asigna al objeto la clase más conveniente. El operador : (dos puntos) entre dos números
enteros genera una secuencia de números enteros entre ambos. La función seq, de la que
ya hemos visto algún ejemplo, genera secuencias a intervalos regulares. La función rep crea
repeticiones de valores o vectores. Con la función scan podemos crear vectores a partir de
un fichero, texto dentro de la propia función, o interactivamente en la consola.

Con las siguientes expresiones creamos en el espacio de trabajo vectores. La primera


expresión crea el vector v1 con los valores 2, 4, 6, 8; la segunda crea el vector v2 con los 10
primeros números naturales; la tercera crea el vecto v3 con una secuencia de ceros y unos
repitiendo dos veces cada valor hasta tener 10. La última crea un vector cuyos componentes
1.3. ESTRUCTURAS DE DATOS Y SU TRATAMIENTO 39

son cadenas de caracteres


v1 <- c(2, 4, 6, 8)
v2 <- 1:10
v3 <- rep(0:1, each = 2, length.out = 10)
v4 <- scan(text = "Mallorca Menorca Ibiza Formentera Cabrera",
what = "chr")

Además de vectores numéricos y de texto, podemos crear vectores con valores lógicos o con
factores (variables categóricas). Un valor lógico resulta de una comparación, que se puede

07
hacer entre dos valores o como resultado de una función. Para comparar si dos valores27 son
iguales utilizamos el doble símbolo de igualdad ==. Para comparar si dos valores son distintos,
utilizamos el símbolo !=. Utilizamos los símbolos >, <, >= y <= para las comparaciones “ma-

5-
yor que”, “menor que”, “mayor o igual que” y “menor o igual que” respectivamente. Estas
expresiones devuelven un valor lógico, TRUE o FALSE. Podemos combinar múltiples compara-
ciones lógicas con los símobolos &, && (‘AND’, se tienen que cumplir las dos condiciones a

-0
ambos lados del símbolo para que la expresión sea TRUE) y |, || (‘OR’, se tiene que cumplir
una de las dos condiciones, o las dos a la vez, para que la expresión sea TRUE). La diferencia

19
entre el operador simple y doble es que el operador sencillo realiza la comparación “elemen-
to a elemento”, mientras que el operador doble realiza la comparación únicamente entre el
primer elemento de los dos vectores a comparar.
20
Los siguientes ejemplos evalúan expresiones lógicas con los vectores creados en el ejem-
plo anterior. Vea las diferencias y comprenda los resultados obtenidos. La última expresión
crea un vector lógico v5.
or

v1 > 5
ad

## [1] FALSE FALSE TRUE TRUE


v1 == 5
rr

## [1] FALSE FALSE FALSE FALSE


v1 != 4
Bo

## [1] TRUE FALSE TRUE TRUE


v3 == 1 & v3 > 5

## [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
v3 == 1 && v3 > 5

## [1] FALSE

27
Nos referimos en general a dos valores pero puede ser cualquier objeto de R.
40 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

v3 == 0 | v4 != "Menorca"

## [1] TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE

Los factores se crean con las funciónes factor y gl, y se pueden generar todas las combina-
ciones de varios factores con la función expand.grid.

El vector v4 creado anteriormente es de tipo carácter. Vamos a crear un factor


repitiendo estos valores dos veces. Las dos primeras expresiones producen el mismo resultado,

07
pero en la función gl se pueden especificar más argumentos. Nótese que es el primer vector
que vemos ocupando más de una línea de la salida de la consola. Aquí podemos ver el sentido
del número entre corchetes al principio de cada línea: indica el índice del primer elemento de

5-
la línea. La última expresión genera una tabla con las combinaciones posibles de dos factores
(máquina y tratamiento) con dos niveles cada uno.

-0
f1 <- factor(rep(v4, 2))
gl(n = 5, k = 2, labels = v4)

## [1] Mallorca Mallorca Menorca


## [7] Formentera Formentera Cabrera
19
Menorca
Cabrera
Ibiza Ibiza
20
## Levels: Mallorca Menorca Ibiza Formentera Cabrera
expand.grid(máquina = c("a", "b"), tratamiento = 0:1)

## máquina tratamiento
or

## 1 a 0
## 2 b 0
## 3 a 1
ad

## 4 b 1

Los vectores siempre tienen longitud, y sus elementos pueden tener o no nombres. La longitud
rr

del vector se puede obtener con la función length, aunque con RStudio lo más cómodo es
examinar el Environment. Los vectores aparecen en el grupo Values y se muestra la misma
información que proporciona la función str: junto al símbolo del vector, el tipo de datos,
Bo

entre corchetes los índices del primer y último elemento28 , y una muestra de los primeros
elementos del vector. Podemos asignar nombres a cada elemento del vector con la función
names. Los vectores están indexados, y podemos acceder a ellos mediante su índice o su
nombre. El acceso a objetos indexados se realiza mediante los corchetes ‘[ ]’. Esta selección
puede ser de múltiples elementos. En R es de especial importancia la selección de elementos
de un vector (o una lista) mediante vectores lógicos. Si dentro de los corchetes incluimos un
vector lógico, el resultado será un vector con los elementos cuyo índice es verdadero en el
vector lógico.

28
por tanto, la longitud del vector es el segundo de estos números
1.3. ESTRUCTURAS DE DATOS Y SU TRATAMIENTO 41

Compruebe en las siguientes expresiones cómo obtenemos información de los vectores.

length(v1)

## [1] 4
str(v1)

## num [1:4] 2 4 6 8

07
names(v1) <- c("a", "b", "c", "d")
v1

5-
## a b c d
## 2 4 6 8

-0
v4[2]

## [1] "Menorca"
v4[2:3] 19
20
## [1] "Menorca" "Ibiza"
v1[v1 > 5]

## c d
or

## 6 8

Los elementos de un vector tienen un orden. Hay dos funciones relacionadas con el orden
ad

de los elementos de un vector, con la función sort obtenemos el vector ordenado, y con la
función order obtenemos los índices que ocupan los valores ordenados, es decir, el primer
elemento del vector es el índice del mínimo valor, y así sucesivamente. Se puede invertir el
orden con la función rev.
rr
Bo

v4 sort(v4) order(v4) rev(v4)

Se pueden realizar dos tipos de operaciones con vectores: operaciones sobre todo el vector
que devuelven un solo valor, y operaciones sobre cada elemento del vector que devuelven
otro vector de la misma longitud. Las operaciones aritméticas sobre un vector realmente son
operaciones entre dos vectores. Si no tienen la misma longitud, R recicla los valores del más
pequeño hasta completar la longitud del más grande. Si la longitud del más grande no es
múltiplo de la longitud del más corto, se realiza la operación pero lanza un mensaje de ad-
vertencia (warning). Además de operaciones aritméticas, cuando un vector es argumento de
una función, el resultado puede ser un solo valor u otro vector, dependiendo de la naturaleza
de la función.
42 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

En las siguientes expresiones se ilustran las operaciones con vectores y el concepto de


reciclaje. Las tres primeras operan con vectores. La cuarta calcula la media de los valores
del vector 1. La última calcula la raíz cuadrada de cada uno de los elementos.
v1 + 2

## a b c d
## 4 6 8 10

07
v2 + v3

## [1] 1 2 4 5 5 6 8 9 9 10

5-
v1 + v2

## Warning in v1 + v2: longitud de objeto mayor no es múltiplo de la longitud

-0
## de uno menor

## [1] 3 6 9 12 7 10 13 16 11 14
mean(v1)

## [1] 5
19
20
sqrt(v1)

## a b c d
## 1.414214 2.000000 2.449490 2.828427
or

Una matriz es una estructura de datos bidimensional, organizada en filas y columnas. Pode-
mos ver la matriz como un vector que colocamos en columnas de una determinada longitud.
ad

Así, cada fila y cada columna de la matriz es también un vector. Las matrices se crean con la
función matrix, a partir de un vector con todos los datos e indicando el número de filas y/o
columnas. Por defecto, se crea la matriz por columnas, pero esto se puede cambiar con el
rr

argumento byrow = TRUE. La selección de elementos se realiza también con los corchetes, en
este caso indicando los índices de cada una de las dimensiones, filas y columnas, separados
por una coma. Si no indicamos índices en una de las dimensiones, quiere decir que queremos
Bo

todos los elementos de esa dimensión.

En la pestaña Environment de RStudio, las matrices aparecen en el grupo Data. Esto permite
abrir la matriz en el visualizador si hacemos clic en el icono de la cuadrícula a la derecha.

En el código a continuación creamos una matriz de dos filas con los datos que hay en
el vector v2, y seleccionamos algunos elementos.

m1 <- matrix(data = v2, nrow = 2)


m1
1.3. ESTRUCTURAS DE DATOS Y SU TRATAMIENTO 43

## [,1] [,2] [,3] [,4] [,5]


## [1,] 1 3 5 7 9
## [2,] 2 4 6 8 10
m1[1, ]

## [1] 1 3 5 7 9
m1[, 1]

## [1] 1 2

07
m1[1, 2:3]

## [1] 3 5

5-
Podemos asignar nombres a las filas y columnas de una matriz, y realizar cálculos sobre filas
o columnas, como veremos en la práctica más adelante.

-0
colnames, rownames, dimnames: Obtiene o establece nombres de filas y/o columnas de
una matriz.

matriz. 19
rowSums, colSums: Obtiene un vector con la suma por filas o por columnas de una

rowMeans, colMeans: Obtiene un vector con las medias por filas o por columnas de
20
una matriz.
Podemos tener datos organizados en más de dos dimensiones. Por ejemplo para tres dimen-
siones la primera dimensión sería la fila de una matriz, la segunda la columna, y la tercera
estaría compuesta por matrices con filas y columnas, y así sucesivamente. En los contenidos
or

de esta obra trabajaremos solo con dos dimensiones.


ad

1.3.3. Listas y data frames


Una lista es un conjunto de estructuras de datos que puede ser heterogénea (vectores, ma-
trices, otras listas, …). Las listas se pueden crear introduciendo sus elementos, que pueden
rr

ser otros objetos ya creados. Las listas también están indexadas y se puede acceder a sus
elementos por índice o por nombre. En este último caso, el acceso por nombre se puede hacer
Bo

mediante el operador $. La importancia de las listas radica en que muchos objetos creados
como resultado de operaciones estadísticas son del tipo lista, con varios elementos a los que
se accede posteriormente. El acceso a los elementos de la lista, a diferencia de los vectores,
se realiza con dobles corchetes. También se puede utilizar el corchete simple, pero en este
caso no obtendríamos el elemento de la lista, sino una lista con los elementos indicados (algo
poco habitual para el alcance de este libro).

En el siguiente ejemplo creamos una lista con tres elementos. La selección con corchete
doble es equivalente a la selección con nombre. la selección con corchete simple nos da una
lista.
44 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

l1 <- list(pares = v1, islas = v4, matriz = m1)


l1

## $pares
## a b c d
## 2 4 6 8
##
## $islas
## [1] "Mallorca" "Menorca" "Ibiza" "Formentera" "Cabrera"

07
##
## $matriz
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 3 5 7 9

5-
## [2,] 2 4 6 8 10
l1$pares

-0
## a b c d
## 2 4 6 8
l1[[1]] 19
20
## a b c d
## 2 4 6 8
l1[1:2]
or

## $pares
## a b c d
## 2 4 6 8
ad

##
## $islas
## [1] "Mallorca" "Menorca" "Ibiza" "Formentera" "Cabrera"
rr

En la pestaña Environment de RStudio, las listas aparecen en el grupo Data. Podemos


expandir la lista para ver sus elementos haciendo clic en el icono azul de la izquierda, lo que
Bo

nos mostraría la misma información que la función str. Además, podemos explorar la lista
haciendo clic en el icono de la lupa a la derecha, en cuyo caso se abre en el visualizador la
lista de elementos y podemos explorarlos por separado, por ejemplo si hay un data frame, se
abre en otra pestaña del panel superior izquierdo.

La organización más adecuada para análisis de datos es en forma de tabla o data frame,
en la cual cada columna se corresponde con una variable, y cada fila se corresponde con una
observación (individuo, fecha, etc.). Para esta organización R tiene la clase data.frame. Lo
normal será que importemos los datos de archivos en disco como veremos en el siguiente
apartado, si bien podemos crear nuestras propias tablas de datos con la función data.frame.
Un data frame es una mezcla de las estructuras que hemos visto hasta ahora:
1.3. ESTRUCTURAS DE DATOS Y SU TRATAMIENTO 45

Es como una matriz en el sentido de que tiene dos dimensiones. Podemos acceder a
sus elementos con corchetes, tenemos nombres de filas y columnas, y podemos operar
con ellas. Se diferencian en que las matrices tienen un único tipo de datos, mientras
que en el data frame cada columna puede ser de un tipo distinto.

Es como una lista porque cada columna tiene un nombre y podemos acceder a ellas con
el símbolo $. Se diferencian en que todas las columnas de un data frame son vectores
con la misma longitud.

Cada columna del data frame es un vector29 , que puede ser numérico, factor, carácter

07
o lógico.

Por tanto, todo lo que hemos visto hasta ahora se aplica al data frame o a sus columnas.

5-
El conjunto de OrchardSprays del paquete datasets contiene datos sobre un expe-
rimento en agricultura (véase ?OrchardSprays). A continuación se muestran ejemplos de

-0
acceso a datos y características del data frame.

str(OrchardSprays)

## 'data.frame': 64 obs. of 4 variables:


19
## $ decrease : num 57 95 8 69 92 90 15 2 84 6 ...
20
## $ rowpos : num 1 2 3 4 5 6 7 8 1 2 ...
## $ colpos : num 1 1 1 1 1 1 1 1 2 2 ...
## $ treatment: Factor w/ 8 levels "A","B","C","D",..: 4 5 2 8 7 6 3 1 3 2 ...
or

OrchardSprays[5:10, 1]

## [1] 92 90 15 2 84 6
ad

OrchardSprays$decrease[5:10]

## [1] 92 90 15 2 84 6
rr

OrchardSprays[OrchardSprays$decrease > 100, ]


Bo

## decrease rowpos colpos treatment


## 11 127 3 2 H
## 25 130 1 4 H
## 27 114 3 4 E
## 58 114 2 8 F
colnames(OrchardSprays)

## [1] "decrease" "rowpos" "colpos" "treatment"

29
En realidad pueden ser objetos de otra clase, pero para los efectos de este libro no nos interesan.
46 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

nrow(OrchardSprays)

## [1] 64
En la pestaña Environment de RStudio, los data frames aparecen en el grupo Data. Podemos
expandir el data frame para ver las columnas que lo componen igual que hacíamos con las
listas, o abrirlos en el visualizador igual que hicimos con las matrices.
Es importante destacar que las variables (columnas) sólo existen en el environment del data
frame. Por eso tenemos que usar el símbolo $ para acceder a ellas. Existen dos formas de

07
escribir sólo el nombre de la variable. Una es utilizando las funciónes attach y detach
con el data frame como argumento. Esto puede tener efectos secundarios en otros objetos y
funciones, por lo que en general se recomienda usarla con cautela. La otra es utilizando la

5-
función with, con el data frame como primer argumento y el conjunto de expresiones entre
corchetes como segundo. En este libro preferimos usar nombres cortos para los conjuntos de
datos y el nombre completo (df$var) para las variables.

-0
En el código a continuación se muestran tres ejemplos para obtener la media de la

19
variable decrease del data frame OrchardSpays. Las tres producen el mismo resultado, el
analista debe elegir uno de los estilos y ser consistente con él.
20
mean(OrchardSprays$decrease)

## [1] 45.42188
attach(OrchardSprays)
or

mean(decrease)

## [1] 45.42188
ad

## Otras expresiones
detach(OrchardSprays)
rr

with(OrchardSprays, {
mean(decrease)
## otras expresiones
Bo

})

## [1] 45.42188
Podemos obtener subtotales del data frame con la función aggregate. El primer argumento
de la función aggregate es una fórmula, una clase de objetos muy importante en R que es la
primera vez que aparece en este texto. Las fórmulas en R consisten en dos expresiones una
a cada lado del símbolo ~, y en general y ~ x se puede interpretar como “y depende de x”.
En el contexto de la función aggregate, realizaremos subtotales de la variable y agrupando
por los valores de x. Los subtotales no se limitan a sumas, sino que puede ser el resultado
de aplicar cualquier función que realice un cálculo de agregación (media, máximo, etc.)
1.3. ESTRUCTURAS DE DATOS Y SU TRATAMIENTO 47

La siguiente expresión obtiene la media de la variable decrease para cada valor del
factor treatment en el conjunto de datos OrchardSprays.

aggregate(decrease ~ treatment, OrchardSprays, mean)

## treatment decrease
## 1 A 4.625
## 2 B 7.625

07
## 3 C 25.250
## 4 D 35.000
## 5 E 63.125

5-
## 6 F 69.000
## 7 G 68.500
## 8 H 90.250

-0
Otras operaciones muy comunes con los data frames son filtrar y ordenar datos. Ya hemos
visto algunos ejemplos de cómo filtrar utilizando los corchetes de selección, pero la función

19
subset proporciona una forma más intuitiva de hacerlo.
20
Las dos primeras expresiones a continuación realizan filtrado de datos con la función
subset y expresiones lógicas sobre el conjunto de datos OrchardSprays. La tercera ordena
los datos de uno de estos subconjuntos en orden descendente de la variable decrease.

A <- subset(OrchardSprays, treatment == "A")


or

## decrease rowpos colpos treatment


ad

## 8 2 8 1 A
## 14 2 6 2 A
## 19 5 3 3 A
rr

## 26 4 2 4 A
## 36 5 4 5 A
Bo

## 41 12 1 6 A
## 53 4 5 7 A
## 63 3 7 8 A
B <- subset(OrchardSprays, decrease >= 100)
B

## decrease rowpos colpos treatment


## 11 127 3 2 H
## 25 130 1 4 H
## 27 114 3 4 E
## 58 114 2 8 F
48 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

B[order(B$decrease, decreasing = TRUE), ]

## decrease rowpos colpos treatment


## 25 130 1 4 H
## 11 127 3 2 H
## 27 114 3 4 E
## 58 114 2 8 F

A veces lo que nos interesa es unir varios data frames. Las funciones rbind y cbind unen
por filas o por columnas, respectivamente, dos o más data frames o matrices.

07
En el ejemplo anterior, unimos los dataframes A y B con la siguiente expresión.

5-
rbind(A, B)

-0
## decrease rowpos colpos treatment
## 8 2 8 1 A
##
##
##
##
14
19
26
36
2
5
4
5
6
3
2
4
2
3
4
5
19
A
A
A
A
20
## 41 12 1 6 A
## 53 4 5 7 A
## 63 3 7 8 A
## 11 127 3 2 H
or

## 25 130 1 4 H
## 27 114 3 4 E
## 58 114 2 8 F
ad

Para modificar un conjunto de datos, utilizamos el operador de asignación de R, <-. Por


ejemplo, para añadir una nueva columna, simplemente asignamos un vector a un nuevo
rr

nombre de columna. De igual forma podemos sustituir una columna por nuevos valores, o
eliminarla asignando el valor NULL. Estas nuevas columnas, pueden ser calculadas a partir
de las ya existentes en el data frame. La modificación de un valor individual o de un rango
Bo

de valores, se realiza igualmente con el símbolo de asignación apuntando a la celda o rango


que queremos cambiar.

En el siguiente ejemplo, en el data frame B creado anteriormente añadimos primero


una columna con ceros (recuérdese el reciclaje), eliminamos la columna treatment y creamos
una nueva columna calculada30 .
B$indicador <- 1
B$treatment <- NULL
B$z <- scale(B$decrease)
1.3. ESTRUCTURAS DE DATOS Y SU TRATAMIENTO 49

## decrease rowpos colpos indicador z


## 11 127 3 2 1 0.6796133
## 25 130 1 4 1 1.0341942
## 27 114 3 4 1 -0.8569038
## 58 114 2 8 1 -0.8569038
Los objetos de clase data.frame tienen automáticamente nombres de columnas y nombres
de filas. Los nombres de columnas son los nombres de las variables al crear o importar el

07
conjunto de datos. Los nombres de filas por defecto son los índices que identifican cada fila.
Se pueden asignar nuevos nombres tanto a las columnas, es decir, renombrar variables, como
a las filas, utilizando las funciones colnames y rownames, respectivamente.

5-
1.3.4. Valores especiales

-0
Los valores perdidos o missing values son un problema frecuente en el análisis de datos. Su
consideración y tratamiento es muy importante en algunas técnicas, y especialmente en la

19
fase de limpieza de datos. Los valores faltantes o perdidos se representan en R mediante el
símbolo NA (not available). Si intentamos hacer cálculos sobre vectores que contienen NAs,
por ejemplo la media, obtendremos NA a menos que incluyamos el argumento na.rm = TRUE.
En algunas ocasiones querremos imputar a los valores NA otro valor, por ejemplo porque si no
20
está el valor significa que es cero. La función is.na sirve para identificar los valores faltantes
en un vector.
En R disponemos además de algunos valores especiales y constantes. Ya hemos visto NULL
or

utilizándolo para eliminar una columna de un data.frame. Este valor puede aparecer también
cuando un objeto no existe. Los valores Inf y -Inf son devueltos en expresiones como
por ejemplo 1/0, y algunas funciones los aceptan como argumentos. Se puede √ trabajar con
ad

números complejos en R, teniendo en cuenta que la constante imaginaria i = −1 se expresa


como 1i. Si intentamos obtenerla como sqrt(-1) obtenemos otro valore especial en R, NaN,
Not a Number. Por otra parte, R dispone de algunas constantes, escalares o en forma de
rr

vector, como el número π, pi, las letras del alfabeto inglés, letters y LETTERS y los nombres
y abreviaturas de los meses, month.name y month.abb31 .
Bo

1.3.5. Textos y fechas


Los vectores de clase character en R contienen cadenas de caracteres. La mayoría de las
veces las utilizaremos como variables cualitativas o de atributo en data frames. En ocasiones
es útil extraer información de las cadenas de caracteres o combinarlas entre sí. Para unir
cadenas de caracteres utilizamos las funciones paste y paste0. La diferencia entre ambas
es que paste une los textos con separación, por defecto un espacio. Actúan sobre vectores,
de forma que une los elementos de los distintos vectores según los índices (el primero de un
vector con el primero de otro, y así sucesivamente). Si queremos unir los elementos de un
31
En inglés
50 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

vector entre sí, entonces tenemos que utilizar el argumento collapse indicando la cadena
que separará los elementos.

a <- letters[1:5]
b <- 1:5
paste(a, b)

07
## [1] "a 1" "b 2" "c 3" "d 4" "e 5"
paste0(a,b)

5-
## [1] "a1" "b2" "c3" "d4" "e5"
paste0(a,b, collapse = "-")

-0
## [1] "a1-b2-c3-d4-e5"
paste(a, b, sep = ".")

## [1] "a.1" "b.2" "c.3" "d.4" "e.5" 19


20
Si lo que queremos es obtener fragmentos de una cadena, podemos utilizar la función substr.
La longitud de una cadena nos la da la función nchar. Podemos dividir una cadena de texto en
base a un separador con la función strsplit. La función grep encuentra aquellos elementos
de un vector de tipo carácter que contengan cierto patrón, mientras que la función gsub
sustituye fragmentos que cumplen un patrón por otros.
or

Las expresiones en el siguiente fragmento de código ilustran las funciones expuestas


ad

anterioremente.
h <- "Universidad de Castilla-La Mancha"
nchar(h)
rr

## [1] 33
Bo

substr(h, 16, 23)

## [1] "Castilla"
strsplit(h, " ")

## [[1]]
## [1] "Universidad" "de" "Castilla-La" "Mancha"
grep("ember", month.name)

## [1] 9 11 12
1.3. ESTRUCTURAS DE DATOS Y SU TRATAMIENTO 51

gsub("uary", ".", month.name)

## [1] "Jan." "Febr." "March" "April" "May"


## [6] "June" "July" "August" "September" "October"
## [11] "November" "December"

Los ficheros de texto almacenan números y cadenas de texto. El software, por su parte, al-
macena las fechas como números, generalmente como número de días transcurridos desde
una fecha determinada. Las fechas por tanto son consideradas como cadenas de texto o como
factores, y para que R entienda que es una fecha, hay que transformar la variable. Utilizamos

07
para ello la función as.Date. En general, es una buena idea trabajar con fechas en formato
ISO, es decir, año-dia-mes, por ejemplo “2000-01-01”. El software suele entender este for-
mato sin necesidad de más explicaciones, y la ordenación será correcta aunque se guarden

5-
como tipo carácter. Siempre se puede especificar el formato indicando una especificación
de conversión, véase ?strptime. Cuando tenemos datos con fechas, además, puede ser útil

-0
tener columnas con el año, el mes, el año-mes y la semana para realizar análisis de datos
secuenciales y por grupos de fechas. Es decir, hacer la transformación inversa con la función
format. Es importante que las columnas de tipo fecha en un data frame sean de la clase
correcta ya que en otro caso
19
20
En el código a continuación, creamos dos objetos de tipo carácter con un solo elemento
que representa una fecha. Nótese que podríamos trabajar igual con vectores de mayor tamaño.
La primera fecha está en formato ISO y por tanto la función as.Date interpreta sin más la
fecha. A la segunda fecha le tenemos que especificar dónde está cada componente para que
la convierta correctamente.
or

fecha1 <- "2000-01-01"


class(fecha1)
ad

## [1] "character"
fecha1b <- as.Date(fecha1)
rr

class(fecha1b)

## [1] "Date"
Bo

fecha2 <- "01/01/2000"


as.Date(fecha2, format = "%d/%m/%Y")

## [1] "2000-01-01"
format(fecha1b, "%Y-%m")

## [1] "2000-01"

Los datos de tipo tiempo (fecha + hora exacta) hay que guardarlos como tipo de datos
POSIXct, de forma similar a las fechas.
52 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

En el siguiente ejemplo guardamos la fecha y hora actuales y formateamos la hora.

ahora <- Sys.time()


class(ahora)

## [1] "POSIXct" "POSIXt"


format(ahora, "Son las %H:%M")

07
## [1] "Son las 10:23"

5-
Los paquetes stringr (Wickham, 2019) y lubridate (Spinu et al., 2018), pertene-
cientes al tidyverse, contienen funciones específicas para realizar operaciones más complejas
con cadenas de caracteres y fechas de forma sencilla.

-0
1.3.6.
19
Conversión entre tipos de datos
Al crear objetos, R intentará deducir el tipo de datos que contiene (numérico, texto, …)
20
y su clase (data.frame, factor, …). Se pueden convertir estructuras de datos de un tipo a
otro. Si existiera algún problema, R lo intenta solucionar. Por ejemplo, si tenemos un vector
de cadenas de texto donde hay números pero también alguna cadena extraña, los textos
correspondientes a números los convierte en números y las cadenas que no puede convertir
las convierte en valores faltantes. Podemos consultar la clase de un determinado objeto con la
or

función class, comprobar si es de un determinado tipo con las funciones is.x (por ejemplo
is.matrix) o forzar a ser de un determinado tipo con las funciones as.x (por ejemplo
ad

as.data.frame).

Un caso especial de conversión de tipos es cuando queremos transformar una variable numé-
rica en un factor según ciertos intervalos. Para ello utilizamos la función cut, que divide los
rr

datos según alguno de los siguientes criterios:

Número de cortes. Entonces hace los intervalos equiespaciados.


Bo

Posición de los cortes, dentro del rango de los datos.

En ambos caso mediante el argumento breaks.

En este libro vamos a utilizar el estilo y las funciones clásicas de R. Actualmente se está
convirtiendo en una tendencia utilizar los paquetes del llamado tidyverse para trabajar con
estructuras de datos, especialmente dplyr (Wickham et al., 2019b) y tidyr (Wickham and
Henry, 2019). Una vez dominados los aspectos básicos de R-base, recomendamos profundizar
en este estilo más productivo con el libro de Wickham and Grolemund (2016).
1.4. IMPORTACIÓN Y EXPORTACIÓN DE DATOS 53

Realice la práctica 1.5 cuyo guión se encuentra en el apartado 1.7 para trabajar con
estructuras de datos.

1.4. Importación y exportación de datos


Vamos a considerar en este apartado que los datos que vamos a analizar se encuentran

07
almacenados en ficheros. Recordemos aquí la importancia de referenciar a ficheros en la ruta
adecuada a partir del directorio e trabajo. En los sucesivos ejemplos, asumimos que tenemos
una carpeta “datos” dentro del directorio de trabajo donde se encuentran los ficheros. Si el

5-
fichero de datos está en Internet, podemos descargarlo a nuestro ordenador con la función
download.file.

-0
El siguiente código descarga los ficheros de ejemplo a la carpeta “datos” del directorio
de trabajo desde la web del libro.

19
download.file(url = "http://emilio.lcano.com/b/adr/p/datos/RRHH.xlsx",
destfile = "datos/RRHH.xlsx",
20
mode = "wb")
download.file(url = "http://emilio.lcano.com/b/adr/p/datos/ejDatos.csv",
destfile = "datos/ejDatos.csv")
download.file(url = "http://emilio.lcano.com/b/adr/p/datos/merma.RData",
destfile = "datos/merma.RData",
or

mode = "wb")
download.file(url = "http://emilio.lcano.com/b/adr/p/datos/merma.rds"
ad

destfile = "datos/merma.rds",
mode = "wb")

Con el argumento mode nos aseguramos de que los ficheros binarios se descargan correcta-
rr

mente en todos los sistemas.


Bo

1.4.1. Importación de ficheros de datos de R


Existen básicamente dos formatos de ficheros de datos de R. Los ficheros “Rdata” pueden
contener varios objetos de R, de cualquier tipo. Al importarlos, se cargan en el espacio de
trabajo todos los objetos con el mismo nombre con el que se guardaron. Los ficheros “rds”
pueden contener un único objeto de R. Si disponemos de los datos en formato “RData”,
podemos importarlos a R con la función load. Como vimos anteriormente, los ficheros de
datos de R son workspaces, que pueden contener cualquier objeto de R (no solo tablas de
datos). Si tenemos un fichero “rds”, hay que asignar el resultado de la importación con la
función readRDS a un nuevo objeto del espacio de trabajo.
54 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

El siguiente código carga en el espacio de trabajo todos los objetos existentes en el


workspace contenido en el fichero merma.RData que se encuentra en la carpeta datos. Los
objetos se añaden al espacio de trabajo, sustituyendo en su caso a los que existan con el
mismo nombre.
load("datos/merma.RData")

07
Si el data frame se guardó en un archivo “rds”, con el siguiente código asignamos al
objeto “mermards” dicho data frame.

mermards <- readRDS("datos/merma.rds")

5-
1.4.2. Importación de datos en ficheros de texto

-0
La forma más segura de trabajar con datos externos es hacerlo en formato de texto plano.

19
Los ficheros de texto plano pueden tener cualquier extensión, pero las más habituales son
“.txt” y “.csv”. Los datos dentro del fichero estarán organizados según una estructura, de la
que hay que tener en cuenta los siguientes valores:
20
Separador de columnas. Los valores más habituales suelen ser:
• El “tabulador”, representado en R por \t
• La coma, que se utiliza en los ficheros CSV (Comma Separated Values) que utili-
zan el punto como símbolo decimal.
or

• El punto y coma, que se utiliza en los ficheros CSV (Comma Separated Values)
que utilizan la coma como punto decimal.
Separador decimal. Suele ser el punto. En sistemas cuyo lenguaje no es el inglés,
ad

normalmente se utiliza la coma.


Encabezados. Si la primera fila del fichero contiene los nombres de las variables.
En los ficheros de texto también pueden venir los datos con formato de columna de ancho
rr

fijo, aunque no es lo más habitual32 .


El formato CSV suele ser el más conveniente ya que normalmente cualquier programa es
Bo

capaz de exportar datos en formato CSV. Por ejemplo, la hoja de cálculo Microsoft Excel
exporta en formato CSV separado por punto y coma, utilizando la coma como símbolo
decimal, y con encabezados. Si Excel está configurado para idioma inglés, entonces genera el
CSV separado por comas y utilizando el punto como símbolo decimal. A R le es indiferente,
ya que puede trabajar con cualquier tipo de ficheros, siempre y cuando se utilicen las opciones
adecuadas a cada caso.
Una consideración importante cuando se trabaja con ficheros de texto es la codificación.
Si el fichero de datos contiene caracteres “no ASCII”, por ejemplo acentos o eñes, podemos
32
De hecho, tiene su origen en las antiguas tarjetas perforadas.
1.4. IMPORTACIÓN Y EXPORTACIÓN DE DATOS 55

07
5-
Figura 1.23: Asistente de importación de texto de RStudio

-0
obtener resultados no esperados si la codificación de texto del sistema es diferente a la codifi-

19
cación de texto del fichero. Sin entrar en mayores consideraciones, digamos que los sistemas
Unix como Linux o Mac utilizan la codificación UTF-8, mientras que los sistemas Windows
utilizan la codificación ISO-8859-1, abreviados respectivamente como utf8 y latin1. Por
20
tanto, si el fichero que queremos importar tiene una codificación distinta a la de nuestro
sistema, tendremos que indicárselo a la función que importa el texto, normalmente con el
argumento fileEncoding = 'utf8' o fileEncoding = 'latin1', según proceda.
La importación de datos mediante código se realiza con la función read.table o sus méto-
or

dos abreviados read.csv (separados por comas) o read.csv2 (separados por punto y coma).
Desde RStudio se pueden importar ficheros CSV con el cuadro de diálogo “Import Dataset”
disponible en la pestaña Environment del panel superior derecho, véase la figura 1.23. Aquí,
ad

escribimos el nombre del objeto donde se importarán los datos (Name). Se pueden configurar
fácilmente las opciones si no se detectan automáticamente. Por ejemplo, si las primeras líneas
del fichero no se corresponden con datos propiamente dichas, podemos “saltárnoslas” (Skip);
rr

si el fichero contiene encabezados o no (First Row as Names); cuáles son los caracteres sepa-
rador (Delimiter, para CSV en español, el punto y coma es semicolon). El símbolo decimal y
Bo

el separador de miles se configuran en la opción Locale. Se muestra una previsualización de


los datos a importar con las opciones seleccionadas y el código utilizado para la importación
(Code Preview), que se puede copiar al portapapeles. El tipo de datos de cada columna se
selecciona automáticamente, aunque se puede cambiar en los encabezados.
Una vez importados los datos, RStudio muestra el conjunto de datos en el visualizador de
datos si se ha marcado la opción Open Data Viewer, véase la figura 1.24.
El uso del asistente está bien al principio y para probar ficheros de los que no estamos seguros
de su estructura. Una vez tenemos una pauta fijada, lo normal será incluir en nuestro script el
código para importar y exportar ficheros. Podemos ver que realmente el asistente de RStudio
ha creado un par de expresiones en la consola al usar el asistente.
56 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
5-
Figura 1.24: Visor de datos de RStudio

-0
library(readr)

19
ejDatos <- read_delim("datos/ejDatos.csv",
";", escape_double = FALSE, locale = locale(decimal_mark = ",",
grouping_mark = "."), trim_ws = TRUE)
View(ejDatos)
20
La primera expresión carga el paquete readr, la segunda importa el fichero y asigna los
datos a un objeto data frame con el nombre asignado en el asistente, mientras que la tercera
visualiza los datos.
or

El asistente de RStudio utiliza el paquete readr (Wickham et al., 2018), pero, como se ha
ad

indicado anteriormente, la instalación base de R incluye algunas funciones para importar


datos. La función básica para importar cualquier fichero de texto con datos en forma de
tabla es read.table. Las funciones read.csv y read.csv2 son versiones simplificadas para
importar ficheros csv (comma separated values, valores separados por comas). Por defecto,
rr

read.csv2 utiliza las opciones para importar utilizando la coma como símbolo decimal y el
punto y coma como separador, utilizado en sistemas con idioma español (entre otros).
Bo

Podemos usar simplemente la siguiente expresión para obtener el mismo resultado


que antes.

ejDatos <- read.csv2("datos/ejDatos.csv")

La elección de unos paquetes u otros dependerá en definitiva del gusto del analista. Las
funciones del paquete readr serán más rápidas para ficheros grandes, y presentan la ventaja
de contar con el asistente y una gestión fácil de los tipos de datos. Además, el data.frame
importado tiene estructura tibble, que se utiliza en otros paquetes de RStudio y del conocido
1.4. IMPORTACIÓN Y EXPORTACIÓN DE DATOS 57

como tidyverse33 .

Para ficheros con datos separados por tabuladores, el argumento sep de la función
read.table o delim de la función read_delim se indicará como \t. Si el fichero contiene
caracteres no ASCII (acentos, eñes, etc.) es posible que sea necesario indicar la codificación
del fichero tal y como se ha comentado anteriormente.

Una vez importados los datos, ya están en el espacio de trabajo y podemos trabajar directa-
mente con ellos.

07
Una vez tenemos el data frame en el workspace podemos obtener un resumen de la
variable merma1 con la función summary.

5-
summary(ejDatos$merma1)

-0
## Length Class Mode
## 0 NULL NULL

19
Para concluir, se pueden incluir los datos a importar en la propia llamada a la función.
Esto puede ser útil para crear ejemplos reproducibles sin necesidad de más ficheros, cuando
20
tenemos pocos datos, o porque convenga tener los datos dentro del propio script.

En el siguiente script se asigna al objeto datos_en_script un data frame creado con


or

el argumento text de la función read.table.

datos_en_script <- read.table(


ad

sep = ";", dec = ",", header = TRUE,


text =
"fecha;muestra;peso
2017-09-25;1;753,5
rr

2017-09-25;2;755,3
2017-09-26;1;749,9
Bo

2017-09-25;2;751,2")
datos_en_script

## fecha muestra peso


## 1 2017-09-25 1 753.5
## 2 2017-09-25 2 755.3
## 3 2017-09-26 1 749.9
## 4 2017-09-25 2 751.2

33
https://www.tidyverse.org/
58 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

1.4.3. Importación de ficheros de otros programas


Si bien el formato más adecuado de datos es el descrito en el apartado anterior, es muy
habitual introducir los datos en ficheros de hojas de cálculo como Microsoft Excel. También
podemos querer importar datos desde otros programas de análisis de datos como Stata, SPSS
o SAS.
El asistente de importación de RStudio permite importar no solo ficheros de texto, sino
también ficheros de Excel y de los programas estadísticos SAS, SPSS y Stata. Para los ficheros
Excel hace uso del paquete readxl (Wickham and Bryan, 2019), función read_excel. Para
los otros formatos utiliza el paquete haven (Wickham and Miller, 2019), funciones read_dta

07
y read_stata para ficheros de Stata, read_spssy read_sav para ficheros de SPSS. De nuevo,
podemos utilizar el asistente como hemos hecho antes, o importarlo directamente en el script
con la función read_excel.

5-
La siguiente expresión importa el fichero RRHH.xlsx al data frame datos_excel.

-0
library(readxl)
datos_excel <- read_excel("datos/RRHH.xlsx")
19
Existen varios paquetes más para leer y escribir ficheros Excel que no describimos aquí por
cuestión de espacio34 .
20
Cabe destacar que las funciones de los paquetes readr, readxl y haven aceptan como ruta
del fichero tanto una ruta local del ordenador como una URL para descargar el fichero de
Internet antes de importarlo. Además, si el archivo es un fichero comprimido, la propia
or

función se encarga de descomprimirlo antes de importarlo.


La instalación base de R también dispone de funciones para importar ficheros en otros for-
matos35 a través del paquete foreign (R Core Team, 2018). El paquete RODBC (Ripley and
ad

Lapsley, 2017) permite importar datos de fuentes ODBC (Open Database Connectivity).
Otro tipo de formatos estructurados como XML o json también se pueden tratar fácilmente
en R. Existe un manual en la documentación incluida con R dedicado íntegramente a este
rr

tema (‘R Data Import/Export Manual’).


Por último, R puede conectar con servidores de bases de datos de los que obtener datos. Se
Bo

utiliza el paquete DBI (R Special Interest Group on Databases (R-SIG-DB) et al., 2018) y
el paquete correspondiente al servidor utilizado, por ejemplo para un servidor de bases de
datos MySQL, el paquete RMySQL (Ooms et al., 2018).

El siguiente sería un ejemplo de aplicación, en el que primero se define la conexión, a


continuación la consulta a la base de datos, y por último se guarda el resultado en un data
frame (véase la ayuda de los respectivos paquetes para los detalles).

34
Véase, por ejemplo A million ways to connect R and Excel
35
incluidos Minitab, SAS, SPSS y Stata.
1.4. IMPORTACIÓN Y EXPORTACIÓN DE DATOS 59

## No ejecutar, solo a modo ilustrativo


library(RMySQL)
on.exit(dbDisconnect(con))

## Crear conexión
con <- dbConnect(MySQL(), user = "profesor",
password = "****", dbname = "curso",
host = "127.0.0.1")

07
## Definición de la consulta a la base de datos
sqlstr <- "SELECT * FROM curso.datos1"
res <- dbSendQuery(con, sqlstr)

5-
## Creación del data frame
wdata <- fetch(res, n = -1)

-0
dbClearResult(res)

1.4.4. Exportación de datos


19
Para la exportación de datos tenemos básicamente las mismas opciones que para la importa-
ción. El formato de fichero más compatible con el que podemos guardar los datos existentes
20
en R es el formato de texto, ya sea en forma de fichero csv o txt. La función write.table
puede guardar cualquier estructura de datos de R (vector, matriz o data frame) en un fichero
de texto. Las funciones write.csv y write.csv2 son un atajo a la función write.table
con las opciones adecuadas para ficheros csv con valores separados por comas y por punto
or

y coma respectivamente. Por defecto, R guarda también los nombres de fila, casi siempre
los identificadores de fila, lo que normalmente no es aconsejable. El argumento row.names
indica si se guardan los nombres de fila como primera columna sin nombre. En general, es
ad

aconsejable guardar nombres de columna, pero no de fila. Si el fichero ya existe y lo que


queremos es añadir los nuevos datos, podemos utilizar el argumento append = TRUE.
rr

Las siguientes expresiones son equivalentes para generar un fichero csv que se abrirá
correctamente en Excel36 :
Bo

write.table(x = ejDatos,
file = "datos/miFichero.csv",
sep = ";", dec = ",",
col.names = TRUE,
row.names = FALSE)

write.csv2(ejDatos, "datos/mifichero.csv",
row.names = FALSE)

También podemos guardar los datos en forma de workspace de R (.RData). En este caso
60 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

utilizamos la función save. Al ser un workspace, podemos guardar más de un objeto en el


mismo fichero.

El siguiente código guarda los objetos datos_excel y ejDatos en el fichero “misda-


tos.RData” dentro de la carpeta “datos”, que luego podemos cargar con la función load:

save(datos_excel, ejDatos, file = "datos/misdatos.RData")

07
Para exportar un único objeto en formato .rds, utilizamos la función saveRDS.

El siguiente código guarda el objeto datos_excel en el fichero “datos_excel.rds”

5-
dentro de la carpeta “datos”, que luego podemos cargar con la función readRDS:

saveRDS(datos_excel, file = "datos/datos_excel.rds")

-0
19
Si lo que queremos es exportar los datos a una hoja de cálculo, debemos utilizar alguno
de los paquetes disponibles para ello. El paquete XLConnect (?) contiene gran cantidad de
funciones para crear sofisticados ficheros Excel (véase la documentación del paquete). El
20
paquete openxlsx (Walker, 2018) es otra opción sencilla

El siguiente código guarda el conjunto de datos ejDatos en la hoja “datos” del libro
Exel “miLibro.xlsx” dentro de la carpeta “datos”:
or

library(openxlsx)
write.xlsx(x = ejDatos,
ad

file = "datos/miLibro.xlsx",
sheetName = "datos",
row.names = FALSE)
rr

## Note: zip::zip() is deprecated, please use zip::zipr() instead


Bo

Para exportar datos a ficheros de otros programas estadísticos podemos utlizar las funciones
del paquete haven (Wickham and Miller, 2019), de igual forma que se vio anteriormente para
la importación. Así, las funciones write_dta, write_sas y write_sav guardan los datos en
formatos de Stata, SAS y SPSS respectivamente. Por su parte, los interfaces de bases de
datos permiten escribir en los distintos servidores mediante sentencias SQL.

Realice la práctica 1.6 cuyo guión se encuentra en el apartado 1.7 para importar y
exportar ficheros de datos.
1.5. INFORMES REPRODUCIBLES 61

07
5-
-0
Figura 1.25: Esquema del proceso de información de análisis de datos

1.5.
1.5.1.
Informes reproducibles
Problema y enfoques
19
20
El resultado final de nuestro proyecto de análisis de datos terminará comunicándose a dis-
tintos niveles, tanto aguas arriba como aguas abajo. Esta comunicación, digamos en general
informes que pueden tener distintos formatos de destino, estará compuesta de múltiples ele-
mentos como texto, gráficos, resultados numéricos, tablas, etc. Además, es posible que haya
or

que generarlos en distintos formatos como la web, documentos imprimibles o presentacio-


nes. Finalmente, con una alta probabilidad varias personas intervendrán en el proceso. Esta
ad

situación se esquematiza en la figura 1.25.


La forma de abordar el problema es típicamente con un enfoque corta-pega, en el que primero
se realiza todo el análisis de datos con el software estadístico y después se utilizan los resul-
rr

tados del análisis como base de un informe escrito, posiblemente con algunas iteraciones del
proceso si el proyecto tiene cierta envergadura. El software estadístico suele incluir formas
de generar resultados listos para integrar en un informe, pero siempre bajo este paradigma
Bo

de incluir el resultado a posteriori (Leisch, 2002).


Este enfoque provoca inconsistencias (por ejemplo entre unos grupos y otros, entre diferentes
analistas, etc.), errores, contenidos desactualizados o no reproducibles, especialmente en la
ejecución de software, simulaciones, etc. Además, cada vez que hay que hacer un cambio,
hay que hacerlo en muchos sitios, con la consiguiente pérdida de tiempo y posibles errores.
El enfoque de la investigación reproducible37 supera muchos de los obstáculos a la hora
de preparar informes de análisis de datos. El objetivo es unir instrucciones para análisis
37
The goal of reproducible research is to tie specific instructions to data analysis and experimental data
so that reports can be recreated, better understood and verified (Kuhn, 2019).
62 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
Figura 1.26: Flujo de trabajo reproducible

5-
de datos con datos experimentales de forma que los resultados se puedan volver a obtener,
entender mejor y verificar.

-0
Un concepto muy relacionado que utilizamos en R es la programación “literaria”38 , mediante
la cual combinamos un lenguaje de programación como R con documentación de todo tipo
(por ejemplo comentarios en el código).

19
Con el enfoque de la investigación reproducible, lo que hacemos es darle la vuelta al enfoque
corta-pega, de forma que se escribe el informe a la vez que se realiza el análisis, incrustando
20
el código dentro del propio informe. Obviamente es necesario un sistema que consolide el
informe con los resultados del código, y esto es lo que nos permite R y RStudio mediante
archivos R Markdown.
El flujo de trabajo sería el siguiente (véase la figura 1.26): los contenidos se encuentran
or

en ficheros de código. Estos ficheros fuente, se compilan y producen los materiales en los
formatos necesarios. Los cambios se hacen una vez, y todos los materiales son actualizados
adecuadamente.
ad

Las ventajas de utlizar un enfoque reproducible se pueden resumir en:


Si el mismo analista tiene que volver al análisis en el futuro, los resultados se pueden
rr

volver a obtener de nuevo fácil y comprensiblemente.


En el caso de que en el proyecto participen más analistas, toda la explicación está a
Bo

mano.
Cualquier cambio en un punto del análisis (por ejemplo, añadir una variable a un
modelo) se puede realizar de una sola vez y los cambios en los resultados y gráficos se
actualizarán automáticamente.
Los resultados se pueden verificar por terceros en caso necesario. Un caso paradigmático
fue el escándalo de los ensayos de cáncer en Duke en 201139 . No obstante es un tema
38
Literate programming is a methodology that combines a programming language with a documentation
language (Knuth, 1984).
39
http://www.nytimes.com/2011/07/08/health/research/08genes.html
1.5. INFORMES REPRODUCIBLES 63

que cada vez se demanda más en otros campos fuera de la investigación clínica (por
ejemplo en publicaciones de cualquier tipo).
A continuación nos centraremos en el enfoque reproducible. Para el otro enfoque, simplemente
copie los resultados de la consola y los gráficos de la pestaña Plots en del panel inferior derecho
en su editor de textos favorito.

1.5.2. Enfoque reproducible: R Markdown


Markdown es un tipo de ficheros de texto pensado para que se pueda leer bajo cualquier

07
circunstancia, con una sintaxis muy simple que permite leerlo directamente por las personas,
o ser convertido por un ordenador en otro formato más elaborado como HTML (página
web). En RStudio, se pueden crear ficheros Rmarkdown utilizando esta sintaxis para las

5-
explicaciones de nuestro análisis, e incluir dentro “trozos” (chunks) de código de forma que
al generar el informe, el resultado de ese código queda incluido en el informe. Así, si una vez
terminado el informe se nos ha olvidado, por ejemplo, incluir un gráfico, sólo tenemos que

-0
añadir las líneas de código que lo crean y volver a generar el informe.
Al crear un nuevo documento R Markdown, se crea una plantilla automáticamente (véase

19
la figura 1.27) donde podemos ver lo fácil que es crear el informe. Hay una guía rápida
de markdown disponible en la ayuda de RStudio, así como enlaces a la Cheatsheet. Incluir
títulos, énfasis en el texto y listas es muy sencillo, y a menudo no necesitamos nada más
20
para realizar un informe. El código de R se inserta mediante el icono insert del editor40 . Un
chunk consta de unos marcadores de inicio y final del chunk, entre los cuales se insertan
expresiones de R que se ejecutarán al generar el documento de salida. El marcador de inicio
son cuatro símbolos de acento grave (backticks, “‘ ) seguidos de unas llaves con la letra r
or

dentro. Opcionalmente, en el marcador de incio se puede añadir un identificador del chunk


y algunas opciones separadas por comas. El marcador de cierre del chunk son de nuevo tres
acentos graves, sin más.
ad

El chunk que se muestra a continuación tiene como identificador “ejemplo”, y como


opciones “echo=FALSE, fig.align=‘center’ ”, lo que indica que el código no se mostrará en
rr

el informe final y que el gráfico producido se alineará en el centro del texto.


Bo

```{r ejemplo, echo=FALSE, fig.align='center'}


plot(cars)
```
Con RStudio, además de ficheros html es posible crear ficheros pdf y Word. Para este cometi-
do RStudio integra la aplicación pandoc. Al crear un fichero R Markdown aparece un cuadro
de diálogo donde podemos seleccionar si queremos hacer un documento, una presentación,
un documento interactivo (shiny), o utilizar una plantilla, véase la figura 1.28. Si seleccio-
namos Documento, podemos elegir el formato (html, pdf o Word), aunque posteriormente
40
Se pueden insertar fragmentos de código de otros lenguajes de programación, pero para el objeto de este
libro solo nos interesan los de R
64 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
5-
-0
19
Figura 1.27: Archivo R Markdown en RStudio
20
se puede generar cualquiera de los formatos independientemente del que se haya elegido al
crear el fichero. Para generar el documento, utilizamos el icono de “bordado” (knit). Si en
vez de pulsarlo directamente hacemos clic en el triángulo de la derecha, podemos selccionar
el formato de salida (hrml, pdf o Word). El formato PDF requieren tener instalada una
or

distribución del sistema de edición libre LaTeX41 .

Podemos compilar el informe cuantas veces queramos con el icono knit (bordado). Para
ad

trabajo en curso, se recomienda ir previsualizando en formato HTML, y una vez sea definitivo
generar el archivo Word. El formato HTML se puede publicar, bien internamente, bien
públicamente, por ejemplo en el servicio RPubs^{http://rpubs.com/}.
rr

A continuación se muestra el contenido de un posible informe R Markdown.


Bo

---
title: "Ejemplo informe de análisis de datos"
author: "Emilio L. Cano"
date: "31/01/2019"
output: word_document
---

41
Se puede instalar una distribución ligera de LaTeX con el paquete tinytex, ejecutando
tinytex::install_tinytex() habiendo instalado el paquete.
1.5. INFORMES REPRODUCIBLES 65

07
5-
Figura 1.28: Nuevo documento R Markdown

-0
Este es mi primer ejemplo de informe generado con RStudio. Voy a crear un
conjunto de datos:

```{r} 19
pdensity <- c(10.6817, 10.6040, 10.5709, 10.7858,
20
10.7668, 10.8101, 10.6905, 10.6079,
10.5724, 10.7736, 11.0921, 11.1023,
11.0934, 10.8530, 10.6774, 10.6712,
10.6935, 10.5669, 10.8002, 10.7607,
or

10.5470, 10.5555, 10.5705, 10.7723)


```
ad

Y este es su histograma:

```{r, echo=FALSE}
rr

hist(data = pdensity)
```
Bo

¡Funcionó! Usar R para análisis de datos es genial.

Un aspecto muy importante al trabajar con ficheros R Markdown es que al generar los
documentos, es que los chunks no se evalúan en el directorio de trabajo, sino en el directorio
donde se encuentra el archivo R Markdown. Por tanto, si vamos a utilizar ficheros, por
ejemplo para importar datos, y el fichero R Markdown no está en el directorio raíz del
proyecto sino en una carpeta, tenemos dos opciones:

1. Hacer referencia a los ficheros desde la ubicación del fichero R Markdown. Por ejemplo,
si el fichero R Markdown está en la carpeta ‘informes’ y los datos en la carpeta ‘datos’,
la ruta al fichero sería “../datos/[fichero de datos]”
66 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
Ejemplo informe de análisis de datos
Emilio L. Cano
2019-01-27

5-
Este es mi primer ejemplo de informe generado con RStudio. Voy a crear un conjunto
de datos:
pdensity <- c(10.6817, 10.6040, 10.5709, 10.7858,
10.7668, 10.8101, 10.6905, 10.6079,

-0
10.5724, 10.7736, 11.0921, 11.1023,
11.0934, 10.8530, 10.6774, 10.6712,
10.6935, 10.5669, 10.8002, 10.7607,
10.5470, 10.5555, 10.5705, 10.7723)

Y este es su histograma:

19
20
or
ad
rr


¡Funcionó! Usar R para análisis de datos es genial.
Bo

Figura 1.29: Resultado final en Word del informe RMarkdown


1.5. INFORMES REPRODUCIBLES 67

2. Cambiar el comportamiento por defecto del paquete knitr para que los chunks se
evalúen en el directorio de trabajo del proyecto, como en el ejemplo que se verá más
adelante. En este caso, la ruta al fichero sería igual que en un script normal: “da-
tos/[fichero de datos]”

1.5.3. Control del código


Dentro de los ficheros R Markdown, Sweave, o cualquier otro que incluya chunks (pedazos)
de código, podemos controlar cómo se verá el código y el output (tanto textual como gráfico)
en el documento final. Estas son algunas de las opciones más útiles.

07
echo Mostrar código en informe
error Mostrar mensajes de error

5-
warning Mostrar mensajes de advertencia
message Mostrar mensajes
eval Evaluar el chunk

-0
fig.align Alineación de los gráficos
fig.width Ancho del gráfico generado (en pulgadas, por defecto 7)

19
fig.height Alto del gráfico generado (en pulgadas, por defecto 7)
out.width Ancho del espacio que ocupa el gráfico en el informe
out.height Alto del espacio que ocupa el gráfico en el informe
fig.keep Mantener los gráficos en el informe
20
include Mostrar salida de texto al ejecutar el código
results Forma de mostrar los resultados
Podemos manejar el aspecto que tendrá finalmente el resultado de los chunks en el informe
or

mediante un gran número de opciones. Las más habituales se pueden configurar en el cuadro
que aparece al hacer clic en el icono Modify chunk options (la ruedecita) arriba a la derecha
de cada chunk. Las opciones se pueden fijar para todos los chunks de un archivo R Markdown
ad

en el primer chunk del fichero, como se muestra en el ejemplo a continuación. Además de las
opciones de los chunks, también se pueden fijar opciones de configuración del paquete. La
lista completa de opciones tanto de chunks como del paquete se encuentra en https://yihui.
rr

name/knitr/options/, y también en la guía de referencia de Rmarkdown, accesible desde el


menú Help/Cheatsheets o en el enlace: https://www.rstudio.com/wp-content/uploads/2015/
03/rmarkdown-reference.pdf.
Bo

Como en cualquier script, dentro de un chunk podemos ejecutar otros scripts mediante la
función source, por ejemplo para la importación de datos u otras acciones rutinarias, y dejar
el código en el informe lo más limpio posible.

En el siguiente chunk, que no muestra ninguna salida (include=FALSE), se fija para


todos los chunks que no se muestre el código (echo=FALSE), y a nivel del paquete, que el
directorio de trabajo sea el anterior al que contiene el informe (por ejemplo, porque nuestro
archivo R Markdown está dentro de la carpeta ‘informes’ del proyecto). Además, se ejecuta
el script ‘utiles.R’ que se encuentra en la carpeta ‘scripts’ del proyecto y carga el paquete
68 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

corrplot

```{r config, include=FALSE}


knitr::opts_chunk$set(echo=FALSE)
knitr::opts_knit$set(root.dir = "..")
source("scripts/utiles.R")
library(corrplot)
```

07
En el siguiente chunk, que no muestra ninguna salida (include=FALSE), se fija para
todos los chunks que no se muestre el código (echo=FALSE), y a nivel del paquete, que el
directorio de trabajo sea el anterior al que contiene el informe (por ejemplo, porque nuestro

5-
archivo R Markdown está dentro de la carpeta ‘informes’ del proyecto). Además, se ejecuta
el script ‘utiles.R’ que se encuentra en la carpeta ‘scripts’ del proyecto y carga el paquete
corrplot

-0
```{r config, include=FALSE}
knitr::opts_chunk$set(echo=FALSE)
knitr::opts_knit$set(root.dir = "..")
source("scripts/utiles.R")
19
20
library(corrplot)
```
Otra opción muy interesante para personalizar los informes con R Markdown, es el uso de
parámetros. Los parámetros se pueden incluir en el encabezado del documento R Markdown
or

y utilizar en los chunks como valores almacenados en el espacio de trabajo. Por ejemplo, pode-
mos tener un parámetro llamado “fichero” y acceder a él en un chunk como params$fichero,
por ejemplo para cargar distintos conjuntos de datos42 .
ad

1.5.4. Presentaciones
rr

Al crear un archivo R Markdown, podemos seleccionar que el tipo de documento sea una
presentación, véase la figura 1.30. Al igual que con los informes, podemos hacer presentaciones
tres formatos: html, pdf o PowerPoint43 . Para html tenemos dos opciones distintas, mientras
Bo

que para pdf se utiliza la clase Beamer de LaTeX. Igual que antes, no es necesario tener
conocimientos de LaTeX, aunque si se quieren incluir diseños elaborados es recomendable.
Las presentaciones en formato HTML incluyen las imágenes embebidas, y se podrá visualizar
en cualquier navegador moderno, por ejemplo Google Chrome, o “imprimir” en PDF. Igual
que para los documentos, las presentaciones en pdf requieren tener instalada una distribución
del sistema de edición libre LaTeX.
42
Véase otro ejemplo en https://rmarkdown.rstudio.com/lesson-6.html
43
Las presentaciones en Power Point están disponibles en la versión 1.2 de RStudio, que en el momento
de escribir este documento se puede obtener en versión “preview” aquí: https://www.rstudio.com/products/
rstudio/download/preview/
1.5. INFORMES REPRODUCIBLES 69

07
5-
-0
Figura 1.30: Nueva presentación R Markdown

Markdown son: 19
Al igual que para los documentos, las principales ventajas de realizar presentaciones con R

Podemos incluir código y resultados de R.


20
Añadimos características de investigación reproducible también a la comunicación de
resultados.
Podemos introducir cambios y rehacer los resultados sin tener que recurrir al “corta-
or

pega”.
La sintaxis es muy sencilla para las tareas más habituales, y también se pueden per-
feccionar incluyendo diseños más impactantes.
ad

Una opción más para crear presentaciones impactantes presentando resultados de análisis de
datos es utilizar el paquete xaringan (Xie, 2019c). Una vez instalado el paquete, creamos el
rr

documento R Markdown desde una plantilla.

1.5.5. Más opciones para informes


Bo

Utilizar markdown para realizar informes de análisis de datos es la opción más sencilla tanto
por su uso como porque no se requieren otras aplicaciones instaladas. A continuación se
incluyen a modo de referencia otras opciones muy interesantes para comunicar resultados de
análisis de datos.

1.5.5.1. Otros formatos


En el menú File/New File (o el priner icono de la barra de herramientas) de RStudio en-
contramos algunos tipos de archivos adicionales, reseñamos los que sirven para comunicar
resultados:
70 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

R Notebook: Es un archivo R Markdown que presenta pequeñas diferencias de com-


portamiento con un R Markdown “normal”. El archivo html se va generando a medida
que se guarda el archivo, pero el código solo se ejecuta si se ha hecho explícitamente
desde el editor (no al generar el fichero)
Shiny Web App: Las aplicaciones shiny permiten diseñar websites interactivos que
ejecutan código en función de las acciones del usuario (como seleccionar opciones,
introducir valores, etc.). Es una forma muy efectiva de presentar resultados con unas
cuantas líneas de código a través del paquete shiny (Chang et al., 2019). Se pueden
ver ejemplos aquí: https://shiny.rstudio.com/gallery/.

07
R Sweave: Permitir escribir documentos con sintaxis LaTeX y chunks de código R.
R HTML: Permite incrustar chunks de código en documentos html “puros”.

5-
R Presentation: Es un tipo de presentación nativa de RStudio similar a las creadas
con un nuevo R Markdown44 .

-0
1.5.5.2. Proyectos con múltiples documentos

19
R y RStudio ofrecen varias posibilidades para crear estructuras más complejas de documentos
con propósitos de comunicar resultados de análisis de datos. Los más importantes son:
R Markdown websites: Permite crear varios documentos relacionados con menús y
20
enlaces con una mínima estructura (véase el apartado 10.5 de (Xie et al., 2018a)).
blogdown: Permite una mayor complejidad para construir websites con estructura
de carpetas, posts y páginas con el paquete blogdown (Xie, 2019a), véase (Xie et al.,
2017).
or

bookdown: Permite crear documentación en forma de libro, incluyendo referencias


cruzadas, capítulos y partes, etc con el paquete bookdown (Xie, 2018), véase (Xie,
ad

2016).

1.5.5.3. Control de versiones


rr

A medida que se avanza en el análisis de datos con R, se van adquiriendo capacidades de


programación para análisis de datos. Los proyectos de análisis de datos que adquieren cierta
Bo

coplejidad requieren, al igual que los proyectos de desarrollo de software, una adecuada
gestión y control de las versiones. El control de versiones en un proyecto de análisis de datos
permite registrar qué cambios se han hecho en el código (o en los informes) quién los hizo, y
(si está bien documentado) por qué.
Aunque hay varios sistemas de control de versiones, el más popular en el mundo del análisis de
datos es el repositorio GitHub (https://github.com) que, además, se integra perfectamente
en RStudio y permite enviar y recibir los cambios desde la propia aplicación. En Bryan (2019)
se puede encontrar un extraordinario recurso para utilizar GitHub y RStudio.
44
Véase una descripción más completa en https://support.rstudio.com/hc/en-us/articles/
200486468-Authoring-R-Presentations
1.6. PROGRAMACIÓN BÁSICA EN R 71

1.5.5.4. Otras funciones útiles


La Función kable del paquete knitr (Xie, 2019b) crea fácilmente tablas en los infor-
mes.
gtable (Wickham and Pedersen, 2019): Este paquete vuelca tablas de datos al dispo-
sitivo gráfico.
htmlwidgets (Vaidyanathan et al., 2018): Elementos web para crear visualizaciones
interactivas. Incluye plotly (Sievert et al., 2019) (gráficos), leaflet (Cheng et al.,
2018) (mapas), DT (Xie et al., 2018b) (tablas de datos interactivas), y hasta 104 en el
momento de escribir estas líneas (véase http://gallery.htmlwidgets.org).

07
Una característica muy útil de R Markdown es que permite introducir ecuaciones y fórmulas
en formato LaTeX, que al generar el informe se incrustan también en el informe o presentación
de salida. Así, podemos incluir la especificación de un modelo o cualquier otra expresión

5-
matemática con esta sintaxis.
Por último, señalar que se pueden utilizar reference docs a modo de plantillas para crear

-0
documentos Word y Power Point con archivos R Markdown45 .

19
Realice la práctica 1.7 cuyo guión se encuentra en el apartado 1.7 para crear un
informe RMarkdown.
20
1.6. Programación básica en R
Al ser R un lenguaje de programación, los scripts pueden contener estructuras de control
or

como bucles y condiciones. Por otra parte, podemos crear nuestras propias funciones. A
continuación se muestran algunos ejemplos a modo ilustrativo, aunque no es el objetivo de
esta obra. Para profundizar más, véase la ayuda con help("function") y help(Çontrol").
ad

Existen snippets con plantillas para muchas estructuras de programación, véase Tools/Global
options -> Code -> snippets. Por ejemplo si en un script escribimos fun y pulsamos el
tabulador, se crea el esqueleto de una función. Aunque en algunos ejemplos del resto del libro
rr

se puedan utilizar puntualmente estructuras simples de programación, no se profundizará en


el tema. Para aprender más, véase el libro de (Wickham, 2015).
Bo

En el primero de los siguientes fragmentos de código creamos una función que suma

los elementos de un vector elevados al cuadrado ( x2i ). En el segundo, si un vector tiene
más de 10 elementos, asignamos al objeto grande el valor TRUE, y en otro caso le asignamos
FALSE. En el tercero, para cada elemento del vector, mostramos en la salida de la consola
(función cat) su valor al cuadrado.

unvector <- 1:10


a2 <- function(x){
45
Véase, por ejemplo, https://rmarkdown.rstudio.com/articles_docx.html
72 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

sum(x^2)/length(x)
}
a2(unvector)

## [1] 38.5
if (length(unvector) > 10){
grande = TRUE
} else {
grande = FALSE

07
}
for (i in 1:10){
cat(un_vector[i]^2, sep="\n")

5-
}

-0
## 1
## 4
## 9
##
##
##
16
25
36
19
20
## 49
## 64
## 81
## 100
or

Un tipo de funciones especiales son las funciones anónimas: no se almacenan con un nombre,
sólo se utilizan temporalmente en el entorno en el que se crean (normalmente dentro de otra
función). Son especialmente útiles en las funciones “vectorizadas”.
ad

El siguiente código devuelve las diferencias de los valores de un vector con su media,
rr

elevadas al cuadrado.
sapply(unvector,
Bo

function(x) {
(x - mean(unvector))^2
})

## [1] 20.25 12.25 6.25 2.25 0.25 0.25 2.25 6.25 12.25 20.25
Las funciones vectorizadas aplican una función a los elementos de una lista o vector de n
elementos. En el ejemplo anterior, sapply devuelve el resultado en el formato más compacto
que puede. Otras funciones vectorizadas son:
lapply: Devuelve una lista de tamaño n
vapply: Especifica el tipo de salida
1.7. PRÁCTICAS 73

mapply: versión multivariante de sapply


Otras funciones de la familia *apply cuyo comportamiento es ligeramente diferente son:
apply: Aplica una función a las filas (argumento margin = 1) o columnas (argumento
margin = 2) de una matriz
tapply: Aplica una función a una variable (primer argumento) para cada nivel de un
factor (segundo argumento)
by: Igual que tapply pero aplicado a data frames.
Estas funciones llegan a ser muy útiles, pero requieren de mucha práctica para dominarlas.

07
1.7. Prácticas

5-
En este apartado se presentan las prácticas a las que se han hecho referencia durante el
capítulo. La reproducibilidad del código ha sido comprobada con la sesión de R que se

-0
detalla en el Prefacio. El lector puede teclear el código o copiarlo y pegarlo en la consola o
el editor. También se puede descargar el script con el código de todas las prácticas con la
siguiente expresión:

19
download.file("http://emilio.lcano.com/b/adr/practicas/01-intro.R",
destfile = "01-intro.R")
20
Algunas expresiones pueden aparece comentadas (empezando por ##). Para ejecutarlas, selec-
cione la expresión sin los comentarios, o elimínelos. En cada práctica se proporciona código
para descargar los ficheros de datos de ejemplo, en caso de ser necesarios.
or

Práctica 1.1: Instalar R y RStudio


Objetivo
ad

En esta primera práctica revisaremos el proceso de instalación del software necesario para
seguir el libro. Se describe el proceso para Windows, véase la documentación en la web de
R para otros sistemas. Los programas se deben instalar en el mismo orden en que aparecen.
rr

Descarga de R
Bo

Ve a http://www.r-project.org;
Haz click en el enlace Download R;
Selecciona un mirror próximo a tu localización;
Haz click en el enlace Download R for Windows;
Haz click en el enlace base;
Haz click en el enlace Download R 3.x.x for Windows;
Guarda el fichero .exe en una carpeta de tu ordenador.
74 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

Instala R

Instalación de R
Abre la carpeta donde guardaste el fichero .exe;
Haz doble click en el fichero R-3.x.x-win.exe;
Acepta las opciones por defecto en el asistente de instalación.

Descarga de RStudio

07
Ve a http://www.rstudio.com;
Haz click en el enlace Download bajo RStudio;
Haz click en el botón Download de la primera columna (“Open Source License”);

5-
Haz click en el enlace RStudio x.xx.xxx - Windows Vista/7/8/10;
Guarda el fichero .exe en una carpeta de tu elección.

-0
Instalación de RStudio
Abre la carpeta donde guardaste el fichero .exe;
19
Haz doble click en el fichero RStudio-x.xx.xxx.exe;
Acepta las opciones por defecto del asistente de instalación.
20
Iniciar programas
Abre el interfaz por defecto de R
Interactúa con la consola, prueba las siguientes expresiones:
or

1/6
ad

## [1] 0.1666667
set.seed(1)
x <- rnorm(30, 10, 2)
rr

summary(x)

## Min. 1st Qu. Median Mean 3rd Qu. Max.


Bo

## 5.571 9.130 10.513 10.165 11.417 13.191


boxplot(x)

Abre el interfaz de usuario RStudio y familiarízate con sus componentes

Práctica 1.2: Interactuar con la consola


Antes de iniciar esta práctica, asegúrate de que tu espacio de trabajo está vacío, para cen-
trarnos solo en lo que hace esta práctica. Si no lo está, vacíalo con el icono de la escoba en
la pestaña Environment.
1.7. PRÁCTICAS 75

Expresiones
La principal forma de interactuar con R es a través de la consola. La consola es un intérprete
de expresiones que espera a que introduzcamos una expresión cada vez, después la evalúa,
y produce un resultado (con salida visible o no). La consola espera que escribamos una
expresión tras el símbolo > Una vez escrita la expresión, pulsamos la tecla de retorno de
línea, si está completa la evalúa. Por ejemplo, la expresión más sencilla posible es escribir un
número (practica tú mismo todas las expresiones en la consola):
1

07
## [1] 1
Vemos que el resultado de esta expresión es una línea de texto con el número 1 entre corchetes
y a continuación el número 1. El número 1 entre corchetes es un identificador que se explicará

5-
más adelante. El resultado es el mismo número que hemos escrito. Un paso más sería hacer
un cálculo numérico, por ejemplo:

-0
1 + 1

## [1] 2

19
Podemos hacer operaciones aritméticas con números en la consola. ¿Qué pasa si la expresión
está incompleta?
20
1 +

Como podemos comprobar, el símbolo > cambia a +, indicando que la expresión no está
completa. El sistema queda así hasta que completamos la expresión, o pulsamos la tecla ESC,
que cancela la instrucción.
or

Las expresiones aritméticas devuelven el resultado de la operación. Otro tipo de expresiones


en R son las expresiones lógicas, que devuelven el valor verdadero (TRUE) o falso (FALSE):
ad

5 > 6

## [1] FALSE
rr

Por último, habíamos dicho que una llamada a una función es también una expresión. La
siguiente expresión es un ejemplo sencillo de una llamada a una función:
Bo

log(pi)

## [1] 1.14473
donde pi es a su vez una expresión que obtiene el valor del objeto interno que contiene el
valor de π = 3,14159 . . ..
pi

## [1] 3.141593
La función log obtiene el logaritmo de un número. La llamada a una función es siempre igual:
76 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

el nombre de la función más (obligatoriamente) paréntesis de apertura y cierre, y dentro de


los paréntesis, los argumentos de la función separados por comas. Los argumentos de las
funciones se pueden declarar de varias formas:
Por el orden en el que están definidos en la propia función;
Por el nombre con el que están definidos en la propia función. R tiene una característica
llamada partial matching que permite escribir sólo el principio del nombre;
Utilizar su valor predeterminado. Algunos parámetros de funciones tienen un valor
predeterminado. Si no proporcionamos uno distinto, es el que se utiliza.

07
Siguiendo con el ejemplo del logaritmo, podemos ver los argumentos que puede recibir me-
diante la función str46 , o pulsando CTRL + ESPACIO después del paréntesis de apertura:

5-
str(log)

## function (x, base = exp(1))

-0
Por tanto, log es una función que admite dos argumentos: x, que no tiene ningún valor
predeterminado, y base, cuyo valor predeterminado es la expresión:
exp(1)

## [1] 2.718282
19
20
es decir, el número e. Por tanto el valor que obtenemos con la función log es el logaritmo
natural (con base e) del número que le pasemos como primer argumento, o con otra base si
se la pasamos como argumento base. Por ejemplo el logaritmo decimal sería:
or

log(1000, base = 10)

## [1] 3
ad

¿Qué pasa si no le pasamos tampoco el primer argumento a la función?


log()
rr

## Error in eval(expr, envir, enclos): el argumento "x" está ausente, sin valor por omis
Lo que pasa es que como no hay un valor predeterminado para el argumento x, la función
Bo

devuelve un error indicando que se necesita un argumento. El mensaje suele tener indicaciones
para resolver el problema. Algunas funciones pueden devolver el resultado sin necesidad de
ningún argumento. Por ejemplo, la función seq genera secuencias de números:
str(seq)

## function (...)
Los tres puntos (…) indican que la función acepta un número indeterminado de argumentos.
¿Qué pasa si la ejecutamos sin argumentos?
46
Esta función devuelve la estructura (structure) de cualquier objeto de R
1.7. PRÁCTICAS 77

seq()

## [1] 1
Obtenemos una secuencia de números desde el 1 hasta el 1 por intervalos de 1. Es decir,
simplemente un 1. Veremos más adelante cómo obtener ayuda sobre los argumentos de una
función.
Como la función no necesita ningún argumento para funcionar, ¿la podríamos usar sin los
paréntesis?

07
seq

## function (...)

5-
## UseMethod("seq")
## <bytecode: 0x7ff9a3f42880>
## <environment: namespace:base>

-0
La respuesta es no, porque para R, todos los símbolos son objetos. La expresión seq sin parén-
tesis es el símbolo de la función seq, y lo que devuelve el intérprete de R es el “contenido””de
la función, es decir, su código47 .
19
Podemos averiguar más sobre los argumentos que espera una función pulsando la tecla F1
con el cursor sobre la función, o llamando a la ayuda de R con cualquiera de las siguientes
20
expresiones:
help("seq")
?seq
or

O también con la ayuda contextual pulsando CTRL + ESPACIO tras escribir su nombre y
dentro de los paréntesis.
ad

Creación de objetos
Hasta ahora hemos utilizado expresiones pero no tenenos ningún objeto guardado en el
rr

espacio de trabajo. Como hemos dicho anteriormente, vamos a utiliza el operador de


asignación <-. Por ejemplo, la siguiente expresión:
Bo

x <- log(pi)

asigna al objeto cuyo símbolo es x el resultado de la expresión log(pi). Vemos que en este
caso no tenemos ninguna salida. Ahora bien, R ha almacenado en el objeto llamado x el valor
de esa expresión, como podemos comprobar en la pestaña Environment del panel superior
derecho. Los símbolos de objetos que vamos creando son expresiones en sí, y podemos mostrar
su valor simplemente escribiéndolos:
x

## [1] 1.14473
47
En este caso no se muestra todo el código porque es una función compilada.
78 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

A partir del momento en que lo hayamos creado, podemos utilizarlo para cualquier cálculo
posterior. Vamos a crear más objetos:
r <- 5
y <- x * r

Ahora tenemos tres objetos en nuestro espacio de trabajo. Podemos ver cómo los objetos van
apareciendo en la pestaña Environment del panel superior derecho. También podemos ver
una lista de los objetos desde la consola:
ls()

07
## [1] "r" "x" "y"
Mediante expresiones también podemos borrar objetos e incluso todo el directorio de trabajo.

5-
Guardo lo que llevo hecho:
save.image("~/tmp.RData")

-0
Limpio el espacio de trabajo:
rm(list = ls())

Compruebo que no hay nada:


19
20
ls()

## character(0)
Creo un nuevo objeto llamado “mivariable” al que asigno 50 valores aleatorios de una distri-
or

bución normal estandarizada48 .


mivariable <- rnorm(50)
ad

Miro su estructura:
str(mivariable)
rr

## num [1:50] 1.3587 -0.1028 0.3877 -0.0538 -1.3771 ...


Nótese que, al ser aleatorios, el resultado obtenido será distinto al que se muestra aquí y
Bo

distinto cada vez que se ejecute la función rnorm.


Cargo el espacio de trabajo anterior:
load("~/tmp.RData")

Vemos que los objetos guardados se han añadido al espacio de trabajo actual, manteniendo
el objeto existente “mivariable”. No obstante, téngase en cuenta que si el espacio de trabajo
cargado contiene un objeto con el mismo nombre que otro existente en el Global Environment,
este último será sustituido por el que se importa.
48
función rnorm
1.7. PRÁCTICAS 79

ls()

## [1] "mivariable" "r" "x" "y"

Salida gráfica
Vamos a hacer un par de sencillos gráficos para ver cómo se producen y exploran las salidas
gráficas:
boxplot(mivariable)

07
plot(mivariable, type = "l")

Examina los gráficos en la pestaña Plots del panel inferior derecho. Utiliza las flechas de

5-
navegación de la barra superior.

-0
1.7.0.1. Ayuda
Por último, vamos a explorar la ayuda que proporciona RStudio. Podemos buscar nombres

19
de funciones con un texto determinado, por ejemplo “lm”:
apropos("lm")
20
## [1] ".colMeans" ".lm.fit" "colMeans"
## [4] "confint.lm" "contr.helmert" "dummy.coef.lm"
## [7] "getAllMethods" "glm" "glm.control"
## [10] "glm.fit" "KalmanForecast" "KalmanLike"
or

## [13] "KalmanRun" "KalmanSmooth" "kappa.lm"


## [16] "lm" "lm.fit" "lm.influence"
## [19] "lm.wfit" "model.matrix.lm" "nlm"
ad

## [22] "nlminb" "predict.glm" "predict.lm"


## [25] "removeCellMerge" "residuals.glm" "residuals.lm"
## [28] "summary.glm" "summary.lm"
rr

Nótese que el número de funciones disponibles dependerá de los paquetes instalados en cada
versión de R, por lo que puede no coincidir con los que se muestran aquí.
Bo

Las siguientes expresiones llevan a la ayud de una función en la pestaña “Help”:


?lm
help("lm")

La función help.search hace una búsqueda por toda la documentación de R:


help.search("matrix")

Acceso a las viñetas de los paquetes:


vignette("grid", "grid")
80 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

Y a los ejemplos:
example(boxplot)

Las demos son colecciones de ejemplos de un paquete:


demo(graphics)
demo() ## Lista de demos disponibles

Práctica 1.3: Trabajar con código

07
Antes de iniciar la práctica, asegúrate de que tu espacio de trabajo está vacío, para centrarnos
solo en lo que hace esta práctica. Si no lo está, vacíalo con el icono de la escoba en la pestaña

5-
Environment.

Aunque es más cómodo gestionar los paquetes en la pestaña Packages de RStudio, vamos a

-0
instalar el paquete micEcon (Henningsen, 2017) desde la consola. Nótese que el nombre del
paquete para la instalación debe ir entre comillas.
## Instalar paquete
install.packages("micEcon")
19
Para cargar un paquete, utilizamos la función library. En este caso, el nombre del paquete
20
puede ir o no ir entre comillas:
library(micEcon)
or

##
## If you have questions, suggestions, or comments regarding one of the 'micEcon' packag
## https://r-forge.r-project.org/projects/micecon/
ad

También podemos “descargarlo” o desconectarlo, aunque rara vez es necesario:


detach("package:micEcon", unload = TRUE)
rr

Los paquetes se instalan en librerías. Podemos consultar las librerías disponibles en nuestra
instalación de R:
Bo

En RStudio vemos el directorio de trabajo en la pestaña de la consola, pero también podemos


obtener su ruta completa mediante código:

El directorio de trabajo se podría cambiar, como en el siguiente ejemplo, aunque al trabajar


con proyectos no lo utilizaremos:
## No ejecutar, solo a modo de ejemplo
setwd("./curso")

Mediante código se pueden realizar operaciones con ficheros, por ejemplo la siguiente expre-
sión devuelve una lista de ficheros en el directorio de trabajo:
1.7. PRÁCTICAS 81

dir()

No obstante, a menos que sea con propósitos de programación, casi siempre es suficiente con
utilizar la pestaña Files para trabajar con ficheros, siempre teniendo en cuenta que el botón
Delete elimina de forma permanente los ficheros y carpetas seleccionados, sin pasar por la
papelera. En una práctica posterior importaremos ficheros de datos al espacio de trabajo.
Vamos ahora a crear un script. Utiliza el menú File/New File/R Script o el icono que hay
debajo de este menú. Escribe las siguientes expresiones en el mismo:

07
## Esto es un comentario explicativo
## El siguiente es un comentario temporal, para no ejecutar la expresión
# mean(x)
set.seed(1)

5-
unvector <- round(rnorm(10, 10, 2), 2)
mean(unvector)

-0
unvector^2
cat("fin del fichero")
Guarda el script con el nombre “rutina.R”49 . Ejecuta las expresiones una a una desde el
19
editor, bien con CTRL + INTRO o con el icono Run.
Cierra el script y ejecútalo desde la consola con la función source:
20
source("rutina.R", print.eval = TRUE)

El argumento print.eval es necesario para que el output se muestre en la consola.


or

Práctica 1.4: Crear un proyecto en RStudio


Vamos a crear el proyecto con el nombre, por ejemplo, “ADR”. En primer lugar, abrimos el
ad

menú de nuevo proyecto (figura 1.31). Elegimos “New Directory” (figura 1.32) y, a continua-
ción, “Empty Project” (figura 1.33)50 .
En la última ventana (figura 1.34):
rr

1. Escribe el nombre del directorio (que va a ser también el nombre del proyecto y no se
debe cambiar después).
Bo

2. Explora (Browse…) la carpeta donde quieres crear el proyecto.


3. Haz click en “Create project”.
Ya tenemos un proyecto vacío, y siempre que lo abramos se iniciará una sesión de R en esa car-
peta, por lo que será automáticamente nuestro directorio de trabajo y no nos preocuparemos
más de ese tema.
49
Es posible que RStudio pregunte por la codificación del fichero de texto. Se recomienda utilizar la
opción que se ofrece por defecto. Véase el siguiente artículo de soporte: https://support.rstudio.com/hc/
en-us/articles/200532197-Character-Encoding
50
Nótese que las capturas de pantalla pueden variar ligeramente según la versión de RStudio instalada
82 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

07
5-
-0
19
20
Figura 1.31: Crear un nuevo proyecto en RStudio
or
ad
rr
Bo

Figura 1.32: Nuevo proyecto en nuevo directorio


1.7. PRÁCTICAS 83

07
5-
-0
19
Figura 1.33: Nuevo proyecto vacío
20
or
ad
rr
Bo

Figura 1.34: Poner nombre al proyecto


84 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

Crea las siguientes carpetas dentro del proyecto con el icono New Folder de la pestaña Files:
datos: Aquí guardaremos todos los ficheros de datos.
practicas: guardaremos los archivos fuente de las prácticas, que contienen el código
(generalmente ficheros .R, scripts).
scripts: aquí podemos guardar los scripts que queramos hacer de pruebas, por ejemplo
(ficheros .R).
informes: aquí guardaremos los informes que hagamos.
A partir de este momento, asegúrate siempre de que estás trabajando en un proyecto de
RStudio para seguir correctamente los ejemplos y prácticas del libro.

07
Práctica 1.5: Estructuras de datos

5-
Objetivo
En esta práctica vamos a trabajar con estructuras de datos en gran medida creándolos de

-0
cero desde el código. Lo practicado aquí servirá también para aplicar a datos importados de
ficheros.

Limpiar el espacio de trabajo 19


20
Crea un script para esta práctica (o abre el script descargado de la web del libro). Antes
de empezar a crear estructuras de datos, vamos a limpiar el espacio de trabajo para que
podamos ir viendo cómo se van añadiendo los objetos de forma clara. Puedes utilizar el
icono de la escoba en la pestaña Environment, o ejecutar la siguiente expresión:
or

rm(list = ls())

Vectores
ad

La estructura de datos básica es el vector. Es sobre vectores sobre los que vamos a realizar
análisis de datos. Crea los siguientes vectores desde el script. Observa cómo se van añadiendo
rr

al espacio de trabajo enla pestaña Environment y familiarízate con la información que se


proporciona de cada uno.
Bo

x1 <- c(10, 20, 30); x1

## [1] 10 20 30
x2 <- 1:10; x2

## [1] 1 2 3 4 5 6 7 8 9 10
x3 <- seq(0, 1, 0.1); x3

## [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
x4 <- c(rep("IBERICO", 3), rep("SERRANO", 2)); x4
1.7. PRÁCTICAS 85

## [1] "IBERICO" "IBERICO" "IBERICO" "SERRANO" "SERRANO"


x5 <- seq_along(x4); x5

## [1] 1 2 3 4 5
Crea un vector introduciendo datos directamente en la consola con la función scan. Introduce
unos cuantos valores numéricos y para terminar, pulsa INTRO sin introducir ningún dato.
x <- scan() # Ejecutar en la consola

Crea los siguientes vectores lógicos y categóricos (factores).

07
miFactor <- factor(1:5, labels = letters[1:5]); miFactor

## [1] a b c d e

5-
## Levels: a b c d e
factorNiveles <- gl(5, 3, labels = letters[1:5]); factorNiveles

-0
## [1] a a a b b b c c c d d d e e e
## Levels: a b c d e
vectorLogico <- 1:10 > 5; vectorLogico 19
20
## [1] FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE
Asigna nombres al vector x1 y comprueba el número de elementos que tiene.
names(x1) <- c("semana1", "semana2", "semana3")
x1
or

## semana1 semana2 semana3


## 10 20 30
ad

length(x1)

## [1] 3
rr

1:length(x1)
Bo

## [1] 1 2 3
Selección en vectores
x1[1]

## semana1
## 10
x1["semana1"]

## semana1
## 10
86 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

x1[c(1,3)]

## semana1 semana3
## 10 30
x1[-c(1)]

## semana2 semana3
## 20 30
Selección lógica

07
x1 >= 15

## semana1 semana2 semana3

5-
## FALSE TRUE TRUE
x1[x1 >= 15] # Equivale a x1[c(2, 3)

-0
## semana2 semana3
## 20 30
x4[x4 != "IBERICO"]

## [1] "SERRANO" "SERRANO"


19
20
x4[x4 == "IBERICO"]

## [1] "IBERICO" "IBERICO" "IBERICO"


or

Ordenación. Hay dos funciones relacionadas con el orden de los elementos de un vector,
con una obtenemos el vector ordenado, y con la otra obtenemos los índices que ocupan los
valores ordenados, es decir, el primer elemento del vector es el índice del mínimo valor, y así
ad

sucesivamente. Se puede invertir el orden con la función rev.


set.seed(1234)
x6 <- sample(0:9, 10, replace = TRUE)
rr

x6
Bo

## [1] 9 5 4 8 4 5 3 1 6 5
sort(x6)

## [1] 1 3 4 4 5 5 5 6 8 9
rev(sort(x6))

## [1] 9 8 6 5 5 5 4 4 3 1
order(x6)

## [1] 8 7 3 5 2 6 10 9 4 1
1.7. PRÁCTICAS 87

Operaciones con vectores


Realiza las siguientes operaciones con vectores y observa los resultados. Fíjate especialmente
en cómo funciona el reciclado de valores.
Reciclado:
x1

## semana1 semana2 semana3


## 10 20 30

07
x1 + 2

## semana1 semana2 semana3


## 12 22 32

5-
x2

-0
## [1] 1 2 3 4 5 6 7 8 9 10
x5

## [1] 1 2 3 4 5
x2 + x5 19
20
## [1] 2 4 6 8 10 7 9 11 13 15
x1 + x3

## Warning in x1 + x3: longitud de objeto mayor no es múltiplo de la longitud


or

## de uno menor
## [1] 10.0 20.1 30.2 10.3 20.4 30.5 10.6 20.7 30.8 10.9 21.0
ad

mean(x1)

## [1] 20
sqrt(x1)
rr

## semana1 semana2 semana3


Bo

## 3.162278 4.472136 5.477226

Matrices
Creación y acceso a matrices
miMatriz <- matrix(c(10, 20, 30, 40, 12, 26, 34, 39),
nrow = 4, ncol = 2); miMatriz

## [,1] [,2]
## [1,] 10 12
## [2,] 20 26
88 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

## [3,] 30 34
## [4,] 40 39
miMatriz[1, ]

## [1] 10 12
miMatriz[, 1]

## [1] 10 20 30 40
miMatriz[3, 2]

07
## [1] 34

5-
Podemos asignar nombres a las filas y columnas de una matriz, y realizar cálculos sobre filas
o columnas
colnames(miMatriz) <- c("variable1", "variable2")

-0
rownames(miMatriz) <- c("caso1", "caso2", "caso3", "caso4")
miMatriz

##
##
##
caso1
caso2
variable1 variable2
10
20
12
26
19
20
## caso3 30 34
## caso4 40 39
rowSums(miMatriz)
or

## caso1 caso2 caso3 caso4


## 22 46 64 79
ad

colMeans(miMatriz)

## variable1 variable2
## 25.00 27.75
rr

Arrays
Bo

array(letters, dim = c(3, 4, 2))

## , , 1
##
## [,1] [,2] [,3] [,4]
## [1,] "a" "d" "g" "j"
## [2,] "b" "e" "h" "k"
## [3,] "c" "f" "i" "l"
##
## , , 2
##
1.7. PRÁCTICAS 89

## [,1] [,2] [,3] [,4]


## [1,] "m" "p" "s" "v"
## [2,] "n" "q" "t" "w"
## [3,] "o" "r" "u" "x"

Listas

Las listas se pueden crear introduciendo sus elementos, que pueden ser otros objetos ya
creados. Las listas también están indexadas y se puede acceder a sus elementos por índice o

07
por nombre. En este caso, el acceso por nombre se puede hacer mediante el operador $.
miLista <- list(matriz = miMatriz, vector1 = x1, x2); miLista

5-
## $matriz
## variable1 variable2
## caso1 10 12

-0
## caso2 20 26
## caso3 30 34
##
##
##
caso4

$vector1
40 39
19
20
## semana1 semana2 semana3
## 10 20 30
##
## [[3]]
## [1] 1 2 3 4 5 6 7 8 9 10
or

Acceso a listas
ad

miLista$vector1

## semana1 semana2 semana3


## 10 20 30
rr

miLista[[1]]
Bo

## variable1 variable2
## caso1 10 12
## caso2 20 26
## caso3 30 34
## caso4 40 39
miLista["vector1"]

## $vector1
## semana1 semana2 semana3
## 10 20 30
90 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

miLista[3]

## [[1]]
## [1] 1 2 3 4 5 6 7 8 9 10
miLista$matriz[, 2]

## caso1 caso2 caso3 caso4


## 12 26 34 39
La mayoría de clases compuestas son listas Los objetos obtenidos con las funciones más

07
habituales para análisis estadístico, son listas a las que se acceden como hemos visto atrás.
modelo <- lm(Ozone ~ Temp, airquality)
class(modelo); typeof(modelo)

5-
## [1] "lm"

-0
## [1] "list"
names(modelo)

## [1]
## [5]
## [9]
"coefficients" "residuals"
"fitted.values" "assign"
"na.action" "xlevels"
19 "effects"
"qr"
"call"
"rank"
"df.residual"
"terms"
20
## [13] "model"
var(modelo$residuals)

## [1] 557.4773
or

La diferencia entre los corchetes simples y dobles es que los dobles devuelven el objeto original
dentro de la lista (por ejemplo, un vector), mientras que el corchete simple devuelve una lista
ad

que contiene los elementos de la selección. Vemos que también podemos acceder directamente
a un elemento del objeto que hay dentro de la lista, por ejemplo una fila de la matriz en el
primer elemento de la lista.
rr

Conjuntos de datos (data frames)


Bo

Aunque lo normal será que importemos los datos de ficheros csv como veremos en el siguien-
te apartado, algunas veces necesitaremos crear nuestras propias tablas de datos. Podemos
obtener la estructura del conjunto de datos y el número de filas.
Crear data.frames:
misDatos <- data.frame(tipo = c("A", "A", "B", "C", "C", "C"),
peso = c(10, 20, 15, 13, 23, 8)); misDatos

## tipo peso
## 1 A 10
## 2 A 20
1.7. PRÁCTICAS 91

## 3 B 15
## 4 C 13
## 5 C 23
## 6 C 8
str(misDatos)

## 'data.frame': 6 obs. of 2 variables:


## $ tipo: Factor w/ 3 levels "A","B","C": 1 1 2 3 3 3
## $ peso: num 10 20 15 13 23 8

07
nrow(misDatos)

## [1] 6

5-
Una vez tenemos un objeto de clase data.frame, podemos acceder a sus filas y columnas de
la misma forma que una matriz, y a las columnas (variables) de la misma manera que a las
listas. Aquí vemos la aplicación de la selección mediante vectores lógicos.

-0
misDatos$peso

## [1] 10 20 15 13 23
misDatos[3, ]
8
19
20
## tipo peso
## 3 B 15
misDatos$peso < 15
or

## [1] TRUE FALSE FALSE TRUE FALSE TRUE


misDatos[misDatos$peso < 15, ]
ad

## tipo peso
## 1 A 10
## 4 C 13
rr

## 6 C 8
Para no tener que usar el símbolo $, probamos las dos alternativas. La no recomendada:
Bo

attach(misDatos)
peso <- peso * 2.20462
# más instrucciones
detach(misDatos)

Buenas prácticas:
with(misDatos, {
peso <- peso * 2.20462
# más instrucciones
})
92 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

Filtra, agrega y ordena el data frame y observa los resultados:


subset(misDatos, peso < 15)

## tipo peso
## 1 A 10
## 4 C 13
## 6 C 8

07
aggregate(peso ~ tipo, data = misDatos, mean)

## tipo peso
## 1 A 15.00000

5-
## 2 B 15.00000
## 3 C 14.66667

-0
misDatos[order(misDatos$peso), ]

## tipo peso
##
##
##
6
1
4
C
A
C
8
10
13
19
20
## 3 B 15
## 2 A 20
## 5 C 23
or

Modificar conjuntos de datos


Añadir y eliminar una columna:
ad

misDatos$prueba <- NA; misDatos

## tipo peso prueba


rr

## 1 A 10 NA
## 2 A 20 NA
Bo

## 3 B 15 NA
## 4 C 13 NA
## 5 C 23 NA
## 6 C 8 NA
misDatos$prueba <- NULL; misDatos

## tipo peso
## 1 A 10
## 2 A 20
## 3 B 15
## 4 C 13
1.7. PRÁCTICAS 93

## 5 C 23
## 6 C 8
Columnas calculadas:
misDatos$proporcion <- misDatos$peso/sum(misDatos$peso)
misDatos$suma <- misDatos$peso + misDatos$proporcion
misDatos

## tipo peso proporcion suma


## 1 A 10 0.11235955 10.112360

07
## 2 A 20 0.22471910 20.224719
## 3 B 15 0.16853933 15.168539
## 4 C 13 0.14606742 13.146067

5-
## 5 C 23 0.25842697 23.258427
## 6 C 8 0.08988764 8.089888

-0
Accede y modifica los nombres de filas y columnas del data frame y explora los resultados
en el Environment y el visualizador de datos.
colnames(misDatos)

## [1] "tipo" "peso"


colnames(misDatos)[4] <- "miSuma"
19
"proporcion" "suma"
20
rownames(misDatos)

## [1] "1" "2" "3" "4" "5" "6"


rownames(misDatos) <- paste("caso", rownames(misDatos), sep = "_")
or

misDatos

## tipo peso proporcion miSuma


ad

## caso_1 A 10 0.11235955 10.112360


## caso_2 A 20 0.22471910 20.224719
## caso_3 B 15 0.16853933 15.168539
rr

## caso_4 C 13 0.14606742 13.146067


## caso_5 C 23 0.25842697 23.258427
## caso_6 C 8 0.08988764 8.089888
Bo

Valores especiales
Creamos un vector con valores perdidos y vemos qué pasa si intentamos calcular la media:
x <- c(1, 3, NA, 5, 6)
mean(x)

## [1] NA
Tenemos que especificar en la función que ignore los valores perdidos, o bien imputarles algún
valor.
94 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

mean(x, na.rm = TRUE)

## [1] 3.75
x[is.na(x)] <- 0; x

## [1] 1 3 0 5 6
mean(x)

## [1] 3

07
Otros valores especiales:
NULL

5-
## NULL
1/0

-0
## [1] Inf
sqrt(-1)
19
## Warning in sqrt(-1): Se han producido NaNs
20
## [1] NaN
1i

## [1] 0+1i
or

pi

## [1] 3.141593
ad

letters

## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q"
rr

## [18] "r" "s" "t" "u" "v" "w" "x" "y" "z"
LETTERS
Bo

## [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q"
## [18] "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
month.name

## [1] "January" "February" "March" "April" "May"


## [6] "June" "July" "August" "September" "October"
## [11] "November" "December"
month.abb

## [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov"
1.7. PRÁCTICAS 95

## [12] "Dec"

Conversión entre tipos de datos


Convierte un vector carácter a numérico y observa el resultado donde no hay números.
x <- c("1", "2", "tres")
str(x)

## chr [1:3] "1" "2" "tres"

07
y <- as.numeric(x)

## Warning: NAs introducidos por coerción

5-
y

## [1] 1 2 NA

-0
str(y)

## num [1:3] 1 2 NA
class(y) 19
20
## [1] "numeric"
is.numeric(y)

## [1] TRUE
or

Trabajar con fechas


ad

Vamos a importar un fichero de texto que contiene fechas51 :


download.file("http://emilio.lcano.com/b/adr/p/datos/datospeso.csv",
"datos/datospeso.csv")
rr

datosfechas <- read.csv2("datos/datospeso.csv", stringsAsFactors = FALSE)


Bo

vectorfechas <- datosfechas$fechaparto[1:20]

Las fechas en formato texto se importan como vectores. Nótese que hemos incluido el argu-
mento stringsAsFactors = FALSE para evitar que los cree como factores. Hay que trans-
formarlas en fechas, nótese cómo afecta el tipo de datos a la ordenación.
str(vectorfechas)

## chr [1:20] "30/09/2011" "28/09/2011" "28/09/2011" "29/09/2011" ...


sort(vectorfechas)
51
En la siguiente práctica trataremos esto con más detalle.
96 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

## [1] "03/10/2011" "04/10/2011" "04/10/2011" "04/10/2011" "04/10/2011"


## [6] "04/10/2011" "05/10/2011" "28/09/2011" "28/09/2011" "28/09/2011"
## [11] "28/09/2011" "29/09/2011" "29/09/2011" "29/09/2011" "29/09/2011"
## [16] "29/09/2011" "30/09/2011" "30/09/2011" "30/09/2011" "30/09/2011"
vectorfechas <- as.Date(vectorfechas, format("%d/%m/%Y"))
sort(vectorfechas)

## [1] "2011-09-28" "2011-09-28" "2011-09-28" "2011-09-28" "2011-09-29"


## [6] "2011-09-29" "2011-09-29" "2011-09-29" "2011-09-29" "2011-09-30"

07
## [11] "2011-09-30" "2011-09-30" "2011-09-30" "2011-10-03" "2011-10-04"
## [16] "2011-10-04" "2011-10-04" "2011-10-04" "2011-10-04" "2011-10-05"
Vamos a dar formato a las fechas y por ejemplo obtener una tabla de frecuencias por día de

5-
la semana.
vectornumeromes <- format(vectorfechas, "%m")

-0
vectormes <- format(vectorfechas, "%Y-%m")
vectordiasemana <- format(vectorfechas,"%A")
table(vectordiasemana)

## vectordiasemana
## jueves lunes
19
martes miércoles viernes
20
## 5 1 5 5 4
Consulta la ayuda ?strptime y explora más opciones de formato, por ejemplo para obtener
el número de semana del año.
or

Recodificación - discretización
Vamos a usar un nuevo conjunto de datos, se puede descargar así:
ad

download.file("http://emilio.lcano.com/b/adr/p/datos/ejdatos.csv",
"datos/ejdatos.csv")
rr

Lo leemos y creamos una variable nueva disc que divida la variable merma en 4 cortes
(breaks), poniendo unas etiquetas personalizadas.
Bo

ejDatos <- read.csv2("datos/ejdatos.csv"); head(ejDatos, 4)

## maquina merma manchas defecto defecto2 temp


## 1 maquina1 5.376656 4 Sí 1 14.68176
## 2 maquina1 6.007177 8 Sí 1 18.59629
## 3 maquina1 4.822433 8 No 0 13.44364
## 4 maquina1 6.014084 8 Sí 1 18.02711
ejDatos$disc <- cut(x = ejDatos$merma,
breaks = 4,
labels = paste0("A", 1:4),
1.7. PRÁCTICAS 97

include.lowest = TRUE)
summary(ejDatos$disc)

## A1 A2 A3 A4
## 30 50 19 1

Recodificar factores. Veamos qué niveles tenemos (levels).


ejDatos$disc

07
## [1] A2 A3 A2 A3 A1 A2 A1 A2 A1 A2 A3 A1 A2 A1 A2 A2 A2 A2 A2 A2 A2 A1 A3
## [24] A2 A2 A1 A1 A1 A1 A1 A2 A2 A3 A2 A2 A2 A2 A1 A2 A3 A2 A2 A2 A3 A2 A1
## [47] A2 A2 A2 A2 A2 A3 A1 A1 A1 A2 A3 A3 A1 A3 A2 A4 A2 A2 A3 A2 A1 A3 A2

5-
## [70] A1 A2 A2 A1 A3 A2 A1 A3 A2 A3 A2 A1 A1 A2 A2 A1 A2 A1 A2 A2 A1 A2 A3
## [93] A1 A2 A3 A1 A1 A2 A3 A1
## Levels: A1 A2 A3 A4

-0
levels(ejDatos$disc)

## [1] "A1" "A2" "A3" "A4"

Ahora vamos a renombrar los niveles:


19
20
levels(ejDatos$disc) <- c( "bajo", "medio-bajo", "medio-alto", "alto")
levels(ejDatos$disc)

## [1] "bajo" "medio-bajo" "medio-alto" "alto"


or

Los factores pueden estar ordenados si los niveles tienen una relación de orden. Para ilustrar
la creación de un factor ordenado, vamos a invertir el orden del que ya tenemos. Observa en
ad

el Environment la diferencia.
ejDatos$disc2 <- ordered(ejDatos$disc,
levels = c("alto", "medio-alto", "medio-bajo", "bajo"))
rr

levels(ejDatos$disc2)

## [1] "alto" "medio-alto" "medio-bajo" "bajo"


Bo

str(ejDatos$disc2)

## Ord.factor w/ 4 levels "alto"<"medio-alto"<..: 3 2 3 2 4 3 4 3 4 3 ...

Práctica 1.6: Importación y exportación de datos


Objetivo
En esta práctica vamos a importar ficheros de datos en distintos formatos para trabajar con
ellos en R.
98 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

Limpiar el espacio de trabajo


Abre tu proyecto de RStudio y crea un script para esta práctica. Antes de empezar a importar
datos, vamos a limpiar el espacio de trabajo para que podamos ir viendo cómo se van
añadiendo los datos de forma clara. Puedes utilizar el icono de la escoba en la pestaña
Environment, o ejecutar la siguiente expresión:
rm(list = ls())

Importar datos CSV

07
El primer fichero con el que vamos a trabajar es uno llamado “ejDatos.csv”, que contiene da-
tos sobre la producción de un determinado producto de alimentación. La siguiente expresión
descarga el fichero a la carpeta “datos” de nuestro proyecto.

5-
download.file("http://emilio.lcano.com/b/adr/p/datos/ejDatos.csv",
"datos/ejDatos.csv")

-0
Abre el fichero de texto en el editor (clic en el fichero y View file) y observa cómo son los
valores. Claramente tiene encabezados, el separador es el punto y coma y el símbolo decimal

19
la coma. Si al importarlo con Import Dataset en la pestaña Environment no detectara estos
parámetros habría que especificarlos. Es importante asignar el resultado de la importación
a un objeto, si no lo hacemos los datos se mostrarán en el output, pero no se guardarán en el
20
espacio de trabajo. Este fichero en particular lo podemos importar también mediante código
utilizando cualquiera de las siguientes expresiones:
ejDatos <- read.csv2("datos/ejDatos.csv")
ejDatos <- read.table("datos/ejDatos.csv",
or

sep = ";", dec = ",", header = TRUE)

Al hacerlo con el paquete readr (que es lo que realmente utiliza el Import Dataset), hay que
ad

configurar los parámetros “locales”. Tras ejecutar el asistente tenemos en la consola:


library(readr)
ejDatos <- read_delim("datos/ejDatos.csv",
rr

";", escape_double = FALSE, locale = locale(decimal_mark = ",",


grouping_mark = "."), trim_ws = TRUE)
Bo

## Parsed with column specification:


## cols(
## maquina = col_character(),
## merma1 = col_double(),
## merma2 = col_double(),
## manchas = col_double(),
## defecto = col_character(),
## defecto2 = col_double(),
## temp = col_double()
## )
1.7. PRÁCTICAS 99

que produce el mismo resultado que los anteriores, informando en el output del tipo de datos
que ha asignado a cada columna.

Importación desde Excel


Aunque hay otras opciones, vamos a utilizar en este caso el Import Dataset de RStudio para
cargar un fichero de muestra de datos, que contiene las respuestas a una encuesta de Recursos
Humanos en una empresa ficticia. Lo descargamos del sitio web del libro:
download.file("http://emilio.lcano.com/b/adr/p/datos/RRHH.xlsx",

07
destfile = "datos/RRHH.xlsx",
mode = "wb")

Y a continuación lo buscamos con Import Dataset/From Excel… No es necesario cambiar

5-
ninguna opción ya que es un fichero bien estructurado de Excel. Tras la importación debemos
tener el siguiente código:

-0
library(readxl)
RRHH <- read_excel("datos/RRHH.xlsx")

Importanción desde Stata, SAS y SPSS 19


Descarga e importa los siguientes ficheros de datos en estos formatos:
20
download.file("http://emilio.lcano.com/b/adr/p/datos/anscombe.dta",
"datos/anscombe.dta", mode = "wb")
download.file("http://emilio.lcano.com/b/adr/p/datos/lung.sas7bdat",
or

"datos/lung.sas7bdat", mode = "wb")


download.file("http://emilio.lcano.com/b/adr/p/datos/p004.sav",
"datos/p004.sav", mode = "wb")
ad

¿Notas alguna diferencia? Observa cómo se importan también algunos metadatos del formato
original:
rr

El fichero Stata, la clase del objeto creado y una muestra de los datos:
library(haven)
Bo

anscombe <- read_dta("datos/anscombe.dta")


class(anscombe)

## [1] "tbl_df" "tbl" "data.frame"


head(anscombe)

## # A tibble: 6 x 5
## state educspnd income prop18 propurb
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 ME 189 2824 351. 508
## 2 NH 169 3259 346. 564
100 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

## 3 VT 230 3072 348. 322


## 4 MA 168 3835 335. 846
## 5 RI 180 3549 327. 871
## 6 CT 193 4256 341 774
El fichero SPSS y un resumen:
p004 <- read_sav("datos/p004.sav")
summary(p004)

## CURRENTM PREVIOUS FAT PROTEIN

07
## Min. : 14.00 Min. : 17.0 Min. :1.800 Min. :1.300
## 1st Qu.: 54.00 1st Qu.: 53.0 1st Qu.:3.150 1st Qu.:2.900
## Median : 64.00 Median : 62.0 Median :3.600 Median :3.200

5-
## Mean : 64.82 Mean : 62.6 Mean :3.723 Mean :3.185
## 3rd Qu.: 77.00 3rd Qu.: 73.0 3rd Qu.:4.100 3rd Qu.:3.400
## Max. :113.00 Max. :104.0 Max. :7.400 Max. :8.900

-0
## DAYS LACTATIO I79
## Min. : 21.0 Min. :1.000 Min. :0.0000
##
##
##
1st Qu.:105.0
Median :149.0
Mean :155.1 Mean
19
1st Qu.:1.000
Median :2.000
:2.236
1st Qu.:1.0000
Median :1.0000
Mean :0.8492
20
## 3rd Qu.:208.5 3rd Qu.:3.000 3rd Qu.:1.0000
## Max. :301.0 Max. :8.000 Max. :1.0000
El fichero SAS y sus variables:
pulmon <- read_sas("datos/lung.sas7bdat")
or

names(pulmon)
ad

## [1] "ID" "AREA" "FSEX" "FAGE" "FHEIGHT" "FWEIGHT"


## [7] "FFVC" "FFEV1" "MSEX" "MAGE" "MHEIGHT" "MWEIGHT"
## [13] "FMVC" "MFEV1" "OCSEX" "OCAGE" "OCHEIGHT" "OCWEIGHT"
## [19] "OCFVC" "OCFEV1" "MCSEX" "MCAGE" "MCHEIGHT" "MCWEIGHT"
rr

## [25] "MCFVC" "MCFEV1" "YCSEX" "YCAGE" "YCHEIGHT" "YCWEIGHT"


## [31] "YCFVC" "YCFEV1"
Bo

Ficheros RData
Vamos a exportar algunos datos al formato de datos de R:
merma <- ejDatos[, 2:3]
save(merma, file = "datos/merma.RData")

Lo borramos del espacio de trabajo:


rm(merma)
ls()
1.7. PRÁCTICAS 101

## [1] "anscombe" "ejDatos" "p004" "pulmon"


Para recuperarlo en posteriores sesiones, lo haríamos así:
load(file = "datos/merma.RData")
ls()

## [1] "anscombe" "ejDatos" "merma" "p004" "pulmon"


Los ficheros RData también se cargan directamente en el espacio de trabajo haciendo clic
en el fichero desde el panel Files, o abriéndolo desde el explorador de archivos del sistema
operativo.

07
Exportación

5-
Vamos ahora a exportar los datos que importamos desde Excel a formato csv. Ya deberiamos
tener el objeto RRHH en el espacio de trabajo, si no es así, lo volvemos a importar:

-0
library(readxl)
RRHH <- read_excel("datos/RRHH.xlsx")

Y ahora exportamos a un fichero CSV:


19
write.csv2(x = RRHH, file = "datos/RRHH.csv", row.names = FALSE)
20
Esto lo podríamos hacer con cualquier conjunto de datos. Si no modificamos el argumen-
to row.names, se crea una columna en el fichero de texto con los nombres de fila, lo que
habitualmente no es buena idea para usar el fichero fuera de R.
or

Práctica 1.7: Informes reproducibles


Objetivo
ad

En esta práctica vamos a generar un informe reproducible.

Crear un informe reproducible


rr

Crea un nuevo documento RMarkdown, de tipo Document y con formato de salida


HTML. Introduce un título y autor. El fichero se crea con texto de ejemplo a modo de
Bo

plantilla.
Examina el texto y el código del fichero creado.
Genera el informe en formato HTML con el botón Knit.

Cambiar opciones en el informe


Descarga el fichero de ejemplo de esta práctica, la siguiente expresión lo hace directa-
mente si tienes una carpeta practicas dentro de tu proyecto de RStudio:
download.file("http://emilio.lcano.com/b/adr/practicas/01-ejemplo-rmd.Rmd",
"practicas/01-ejemplo-rmd.Rmd")
102 CAPÍTULO 1. INTRODUCCIÓN AL ANÁLISIS DE DATOS CON R

Abre el fichero de ejemplo de esta práctica. Observa qué se hace en cada chunk.
Genera el informe en HTML sin hacer ningún cambio
Cambia opciones de los chunks y vuelve a generarlo, observa los diferentes resultados.
Realiza algún análisis con esos datos, ve cambiando cosas para ver cómo se actualiza
el informe automáticamente.

Resultado final en Word


Es preferible generar el informe en Word una vez tenemos el informe como queremos en

07
HTML, porque si lo hacemos siempre en Word hay que estar cerrando el fichero y abriéndolo.
Genera el informe en Word.

5-
-0
19
20
or
ad
rr
Bo
Capítulo 2

07
Análisis exploratorio de datos con R

5-
Independientemente de los datos que tengamos y de las técnicas estadísticas que sean más

-0
apropiadas para el análisis, siempre empezaremos por un análisis descriptivo que nos permita
conocer los datos e identificar posibles problemas. Con el análisis exploratorio de datos
podremos identificar cuáles van a ser esas técnicas más apropiadas, limpiar los datos, y

19
organizarlos de una forma estructurada para aplicar las técnicas.
20
2.1. Estructuras de datos y tipos de variables
Para realizar análisis de datos, necesitamos que estos estén estructurados de forma adecua-
da. Algunas fuentes de información contienen datos no estructurados, como por ejemplo la
or

información de texto, imágenes y videos disponible en Internet (vídeos, imágenes, redes so-
ciales, contenidos, etc.). Otro tipo de datos no estructurados (aunque lo parezcan) son las
hojas de cálculo que de forma más o menos anárquica se van elaborando en las empresas con
ad

los datos que se producen en distintos departamentos o áreas. Este tipo de información no
estructurada se debe tratar convenientemente de forma que tenga el formato adecuado para
el análisis de datos.
rr

2.1.1. Estructuras de datos


Bo

La estructura de datos adecuada para el análisis estadístico es mediante variables. Una


variable contiene información de una característica medida u observada en un determinado
número de elementos. El tipo de datos de una variable debe ser el mismo y en la misma escala
para todos los elementos observados. Podemos ver una variable como un vector de datos cuyos
componentes pueden ser números o atributos, con una estructura homogénea y referida a
una serie de elementos. Llamaremos observaciones a las mediciones o clasificaciones de
cada uno de esos elementos.
Por otra parte, en una serie de elementos podemos observar más de una característica. En
este caso, tendremos en cada observación más de un dato, cada uno de ellos referido a
una de las características. Estos datos con varias variables con un número determinado

103
104 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

de observaciones, son datos multivariantes, frente a los datos univariantes cuando tenemos
una sola característica. Generalmente tenemos datos multivariantes con los que podremos
hacer análisis estadístico univariante de cada una de las características observadas y análisis
estadístico multivariante utilizando conjuntamente varias variables.

La forma adecuada de disponer los datos multivariantes para el análisis estadístico, es en


forma de matriz donde las filas representan las observaciones, y las columnas representan
las variables. Nótese que, de esta forma, las variables son vectores columna y las observacio-
nes son vectores fila. Esta estructura nos va a permitir trabajar matemáticamente con los
conjuntos de datos de forma eficiente, de forma que:

07
En el análisis univariante, trabajaremos con vectores de datos con los que podemos
hacer cálculos con todos los elementos, o con cada uno de ellos.

5-
En al análisis multivariante será igual, pero trabajando con cálculo matricial.

Nótese que cuando estamos observando características no numéricas (por ejemplo, la ocupa-

-0
ción en una serie de individuos), el vector que representa la variable no contiene números,
sino atributos. Esto difiere del concepto matemático de vector y matriz, donde los componen-

19
tes son siempre números. Estas variables tendrán un tratamiento distinto según los objetivos
del análisis, que a lo largo del texto se irán describiendo, así como su posible tratamiento en
el análisis de datos.
20
2.1.2. Tipos de variables y escalas
Las características a observar pueden dar lugar a diferentes tipos de datos o variables. Antes
or

de realizar ningún tipo de análisis, lo primero que tenemos que tener en cuenta es qué
tipos de variables tenemos. Dependiendo del tipo de variable, tanto el tratamiento de esos
datos como los modelos a aplicar para la toma de decisiones puede ser distinto. Veamos
ad

los distintos tipos de variables que nos podemos encontrar. La primera clasificación posible
es si las variables son numéricas o nominales. Una variable numérica o cuantitativa es
aquella cuya característica a observar se puede expresar como un número. Las variables
rr

categóricas o cualitativas son aquellas que no se pueden expresar como un número (con
sentido numérico), sino que indican una cualidad o atributo que tiene el elemento. A su
vez, las variables cuantitativas puden ser de dos tipos: variables continuas cuando pueden
Bo

tomar cualquier valor en un intervalo dado (es decir, infinitos), y variables discretas,
cuando podemos contar el número de valores que puede tomar la variable (pueden ser finitos
o infinito numerable). Por su parte las variables cualitativas pueden tener varios niveles o solo
dos (dicotómicas). Si en una variable categórica podemos ordenar las categorías, entonces
tenemos variables ordinales, a las que podremos asignar un número de orden y aplicar
algunos cálculos de las variables numéricas1 .

Relacionado con estos tipos de variables, a menudo se habla de Escalas de medida. Cada
variable está referida e una escala de medida, que puede ser:
1
Pero con cuidado, porque realmente no son variables cuantitativas.
2.1. ESTRUCTURAS DE DATOS Y TIPOS DE VARIABLES 105

Escala nominal. Los valores que toma la variable son etiquetas que diferencian a los
individuos en grupos.

Escala ordinal: Los valores que toma el atributo indican un orden de precedencia entre
los individuos, pero no la distancia entre ellos.

Escala métrica: Permiten medir diferencias entre individuos, puesto que cuantifica el
grado en que se da la característica en el individuo.

Nótese que a nivel de estructura de datos, podemos almacenar los atributos como números

07
(por ejemplo, 1=hombre, 2=mujer), pero lo importante es la naturaleza de la característica
que estamos midiendo y su escala.

En el apartado 2.3 volveremos sobre estos conceptos cuando hablemos de conjuntos de datos

5-
multivariantes.

-0
La variable tiempo cuando se refiere al momento en que se realiza la medición, por ejemplo la
fecha y hora, es un tipo especial de datos que algunas veces tratamos como variable nominal
para estudiar datos en distintos momentos del tiempo, realizando las agrupaciones oportunas.

19
Agrupados o sin agrupar, uno de los principales usos de la variable tiempo es el de ordenar los
datos y comparar en periodos de tiempo distintos, o estudiar la evolución. En otras técnicas
puede ser tratada como una variable en escala métrica.
20
Téngase en cuenta que las variables continuas se pueden discretizar, simplemente creando
intervalos que representen un atributo creado de forma arbitraria. Por ejemplo, si tenemos
una variable que sea el sueldo de los empleados de una empresa (numérica continua), podemos
crear una variable cualitativa que sea nivel de ingresos con las categorías bajo, medio, y alto
or

dividiendo el rango de salarios en tres intervalos.


ad

Ejemplos de variables cuantitativas continuas son las mediciones de características


como el peso de un producto o la longitud de una pieza. La variable tiempo también es
continua, por ejemplo el tiempo de duración de un artículo hasta que se estropea, o el
rr

tiempo que un cliente hace cola en la caja de un supermercado.


Ejemplos de variables cuantitativas discretas son los recuentos de cualquier tipo, por ejemplo
Bo

el número de clientes que visitan una página web hasta que se materializa una compra,
el número de piezas producidas de un determinado artículo, el número de pasas en una
cucharada de cereales, etc.
Ejemplos de variables categóricas es cualquier atributo que se pueda observar en un deter-
minado elemento. Por ejemplo, si una pieza es defectuosa o no, la especie de los animales
en una granja, el tipo de música o cine preferido, el tipo de queso en una fábrica de quesos,
etc. La estación del año, el día de la semana, o el mes, son ejemplos de variables categóricas
relacionadas con la variable tiempo (que por naturaleza es continua). Las mediciones en una
escala de preferencias como por ejemplo del 1 al 5 donde 1 es nada satisfecho y 5 es muy
satisfecho, son del tipo nominal ordinal.
106 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

Probabilidad
Población Estadística
Descriptiva

Muestra

07
5-
Inferencia Estadística
Figura 2.1: Relación entre la Estadística Descriptiva, el Cálculo de Probabilidades y la Es-

-0
tadística Inferencial

2.1.3. Población y muestra


19
La figura 2.1 representa una especie de dogma de la Estadística, esto es, su relación con la
probabilidad y la inferencia, a través de la población y la muestra.
20
En general, los datos que vamos a analizar serán datos de una muestra, que debe ser
representativa de la población que estamos estudiando. Algunas técnicas estadísticas nos
servirán para describir la población a través de la muestra mediante la Estadística Descriptiva.
or

Otras técnicas nos servirán para realizar inferencia sobre la población, es decir, obtener
estimaciones, predicciones, extraer conclusiones o tomar decisiones para toda la población a
partir de la evidencia que muestran los datos de la muestra.
ad

El muestreo y sus técnicas no se trata en este texto, pero debe tenerse en cuenta que la
adecuada selección de la muestra es un tema de vital importancia para el análisis de datos
en general.
rr
Bo

2.1.4. Calidad de datos


Una vez hemos identificado los tipos de variables del problema de análisis de datos que
queremos abordar, es necesario que tengamos los datos correctamente en el software que
vamos a utilizar, es decir, es muy importante comprobar continuamente la calidad en los
datos. La importación de datos siempre puede dar problemas (y por Murphy, los dará).
Por eso siempre deberíamos comprobar la estructura de los datos después de importar un
conjunto de datos (al menos la primera vez). Uno de los errores más comunes es que el tipo
de datos importado no se corresponda con el que conceptualmente debe tener la variable.
Esto no produce ningún error al importar, pero sí al analizar los datos. Otros problemas de
calidad tienen que ver con valores atípicos (outliers) y con valores perdidos (missing).
2.1. ESTRUCTURAS DE DATOS Y TIPOS DE VARIABLES 107

2.1.4.1. Datos atípicos


A medida que llevamos el análisis de datos a aplicaciones reales, es más fácil que aparezcan
observaciones que estropean el análisis porque se salen de lo esperado en relación con el
resto de datos. La parte 4 de norma UNE-ISO 16269 (ISO, 2010), un valor atípico es
un “Miembro de un pequeño subconjunto de observaciones que parece ser inconsistente con
el resto de una muestra dada”. La identificación de valores candidatos a ser considerados
como atípicos es una labor muy importante para el analista, ya que pueden influir tanto
en los resultados del análisis como en la técnica a utilizar. Estos valores identificados como
posibles valores atípicos deben ser investigados y determinar cuál es la causa de esta posible

07
desviación. Se suele atribuir a una de las siguientes causas:
1. Error de medida o de registro. Esto puede ser debido a la observación del dato o al
propio registro.

5-
2. Contaminación. Los datos provienen de más de una distribución. Por ejemplo, por
estar mezclando datos de grupos que tienen distintas medias. Entonces, los valores

-0
de la distribución contaninante aparecerán como valores atípicos en la distribución de
interés.

19
3. Suposición incorrecta sobre la distribución. La característica en estudio de la pobla-
ción se supone que sigue una determinada distribución (por ejemplo normal) pero en
realidad sigue otra (por ejemnplo exponencial). Entonces los valores que parecen atí-
20
picos para la distribución normal, son perfectamente compatibles con la distribución
verdadera.
4. Observaciones excepcionales. Estos no son verdaderos valores atípicos, simplemente
or

han ocurrido por azar, aunque sea muy improbable su ocurrencia.


En el primer caso, hay que encontrar el valor correcto y si esto no es posible, dar el valor
por perdido (missing). En el segundo, hay que estratificar los datos y realizar el análisis
ad

por grupos, separando las distribuciones. Si son solo unos pocos datos los que por error
han contaminado la muestra, se pueden eliminar o dar por perdidos. En el tercer caso, se
modifican las asunciones sobre el modelo de distribución subyacente en la población. En el
rr

último caso los valores deberían permanecer en la muestra, aunque generalmente se etiquetan
erróneamente como valores atípicos por su excepcionalidad.
Bo

El análisis de los valores atípicos es importante por varios motivos. Por una parte, puede dar
lugar a descubrimientos interesantes al investigar por qué han ocurrido (por ejemplo, se ha
hecho algo diferente y un proceso ha mejorado). Por otra parte, muchas medidas y métodos
estadísticos son muy sensibles a observaciones atípicas, y entonces es posible que haya que
usar alternativas robustas. Y en todo caso, nos ayuda a determinar la adecuada distribución
de probabilidad.
La observación de los datos con métodos gráficos a menudo proporciona suficiente informa-
ción para identificar valores candidatos a ser atípicos. En contreto, el gráfico de cajas diseñado
por John W. Tukey (Tukey, 1977) y recogido en la norma UNE-ISO 16269 (ISO, 2010) marca
estos valores de forma clara (véase el apartado 2.2.2 para una completa explicación de su
108 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

construcción e interpretación).
Aparte de los métodos gráficos, existen diversos contrastes de hipótesis para determinar si
existen valores atípicos en una muestra de datos dada una distribución de probabilidad. La
norma UNE-ISO 16269 (ISO, 2010) recoge métodos para la distribución normal y también
para otros modelos de distribución, así como un método general para distribuciones descono-
cidas y el test de Cochran para varianza atípica. El paquete outliers de R contiene varias
funciones para realizar contrastes de hipótesis sobre valores atípicos a un conjunto de datos,
incluidos el test de Grubbs y el test de Cochran.
En cuanto al tratamiento de datos que contienen valores candidatos a ser atípicos pero de

07
los que no se ha podido identificar una causa válida para eliminarlos, deberíamos recurrir al
análisis de datos robusto, de forma que las observaciones atípicas no influyan demasiado
en los resultados, pero sin eliminarlas. Otra alternativa es realizar el análisis con y sin valores

5-
candidatos a ser atípicos y comprobar cómo varía ese resultado.
Entre las medidas de centralización robustas se encuentran la mediana y la media recortada

-0
(véase 2.2.1.2), aunque hay otras. También para la estimación de la dispersión se encuentran
estimadores robustos como la Mediana de las medianas de las desviaciones absolutas de los
pares (ISO, 2010).
19
Lo dicho hasta ahora sirve para detectar atípicos para una característica. En conjuntos
multivariantes, se pueden observar valores atípicos con respecto a más de una variable. En
20
particular, en modelos de regresión puede haber observaciones influyentes (que posiblemente
no son atípicas en la variable aislada) que influyen en la estimación de los parámetros de forma
que el resultado no es representativo del conjunto de datos. Los gráficos de diagnóstico de
R para los modelos lineales proporcionan un gráfico señalando las observaciones influyentes
or

según la distancia de Cook. También el paquete car contiene una función (outlierTest)
con la que podemos obtener la observación más extrema para la regresión.
Por último, podemos detectar observaciones atípicas con respecto a todo un conjunto multi-
ad

variante de datos en escala métrica. Para ello, lo que se hace es reducir este conjunto multiva-
riate en univariante, obteniendo unas distancias de las observaciones a la media muestral del
conjunto de datos, estandarizada mediante la matriz de varianzas-covarianzas de la muestra.
rr

Entonces aquellas observaciones muy alejadas de esos valores centrales pueden estudiarse
como candidatos a ser valores atípicos multivariantes. En ISO (2010) se proporciona un con-
traste de hipótesis y un método gráfico para identificar estos valores atípicos. En el apartado
Bo

2.3.3 se proporcionan las funciones necesarias para calcular la distancia de Mahalanobis.

2.1.4.2. Valores perdidos (missing values)


La ausencia de valores para determinadas observaciones de nuestra muestra es otro de los
problemas habituales que surgen con los datos. Al igual que con los valores atípicos, un valor
perdido puede ser fruto de un error en la recogida o registro de los datos. Si ese error es
recuperable, bastará con añadir el verdadero valor a nuestro conjunto de datos. Si el valor
se da definitivamente por perdido, entonces podemos seguir dos caminos:
1. Realizar el análisis sin considerar las observaciones con valores perdidos.
2.1. ESTRUCTURAS DE DATOS Y TIPOS DE VARIABLES 109

2. Imputar un valor a las observaciones perdidas.


El primer caso merece la siguiente consideración. Cuando estamos analizando una sola ca-
racterística, este camino es único. Por ejemplo, en un conjunto de 100 observaciones donde
faltan 2, se calcula la media con las 98 restantes. O en un gráfico, se representan solo los va-
lores existentes. Pero cuando estamos analizando un conjunto multivariante, podemos tener
valores perdidos en todas las variables, o solo en algunas. Entonces podemos tomar diferen-
tes decisiones a este respecto. Por ejemplo, si queremos calcular una matriz de correlaciones,
podemos considerar solo las observaciones en las que hay valores para todas las variables, o
eliminar solo los pares de observaciones relevantes para cada coeficiente de correlación entre

07
dos variables2 .
El segundo camino es más complicado y requiere a su vez elegir el método de imputación
del valor perdido. La imputación más sencilla es simplemente asignar la media o la mediana

5-
como valor representativo de toda la variable. Pero cuando tenemos conjuntos multivariantes,
puede ser más adecuado hacer una imputación en función de la información disponible en
otras variables. Por ejemplo, si tenemos una variable de tipo atributo, la media del grupo al

-0
que pertenece la observación será generalmente más adecuada que la media global.
En R tenemos varias alternativas para la imputación de valores perdidos. La función impute
19
del paquete Hmisc realiza imputaciones sencillas (por defecto la mediana). El paquete mice
realiza imputaciones utilizando datos multivariantes con un buen número de opciones.
20
La investigación de los valores perdidos y su tratamiento adecuado debe ser siempre una
fase importante del proyecto de análisis de datos. Además, este análisis se puede solapar con
el análisis de los valores atípicos, por ejemplo cuando un valor atípico se determina que es
un dato erróneo pero no podemos asegurar cuál es el valor verdadero, entonces tenemos que
considerarlo como perdido y aplicar lo aquí visto.
or

2.1.4.3. Errores comunes


ad

Aparte de los errores en los datos que ya se han tratado, hay que evitar algunos errores
demasiado comunes a la hora de abordar el análisis de datos, y especialmente la interpretación
de resultados. En este apartado se mencionan algunos de los más importantes.
rr

1. Confundir correlación con causalidad.


Cuando realizamos una regresión de una variable respuesta Y sobre una o varias variables
Bo

explicativas X, tendemos a pensar que X es la causa de la variación de Y . Esto no siempre es


así, y deberíamos tenerlo presente incluso en aplicaciones en las que conocemos los procesos y
“estamos seguro” de que es así. Para confirmar que una relación es de causa-efecto, deberíamos
recurrir al Diseño de Experimentos, donde además podremos estudiar las interacciones.
2. Falta de parsimonia.
La parsimoniosidad es un principio científico (véase Wikipedia (2018))3 que, aplicado a la
Estadística, significa seleccionar el modelo más reducido y simple posible que consiga explicar
2
En R, la función cor controla este comportamiento mediante el argumento use.
3
En igualdad de condiciones, la explicación más sencilla suele ser la más probable.
110 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

el fenómeno a estudiar, frente a modelos más complejos (con muchas variables) con una
mínima o nula ganancia de poder predictivo. En modelos de regresión múltiple, por ejemplo,
ninguna variable cuyo coeficiente no sea significativo se debería incluir en el modelo final al
que llega la investigación.

2. Interpretación de porcentajes sin fijarse en el tamaño.

Este error común viene explicado por la paradoja de Simpson (Wikipedia, 2019). Esta
paradoja aparece cuando hay un atributo oculto que no se tiene en cuenta a la hora de
interpretar porcentajes, pudiendo darse el caso de que otro atributo presenta un porcentaje

07
mayor en una categoría, pero si se analizan por separado los porcentajes para las categorías
del atributo oculto, resulta que el porcentaje de la categoría que era mayor globalmente, es
menor en TODOS los grupos del atributo oculto.

5-
3. Informar los valores medios pero no la dispersión.

La media por sí sola no debería llevar a conclusión alguna. Siempre se debe analizar conjun-

-0
tamente la centralidad y dispersión de los datos, ya que un valor medio puede estar calculado
con valores muy extremos y ocultar mucha información.

19
4. Pasar por alto las hipótesis del modelo.

Muchos modelos estadísticos requieren, para ser válidos, que se cumplan ciertas condiciones.
20
Si utilizamos un método que requiere normalidad, debemos comprobar que los datos pro-
vienen de una distribución normal. Ante la duda, debemos comprobar que un método no
paramétrico conduce a resultados similares.

5. Sobreajuste (overfitting).
or

El sobreajuste aparece cuando en un modelo predictivo conseguimos estimar perfectamente


los valores de la muestra, pero el modelo utilizado no sirve para generalizar a nuevos casos.
ad

En Machine Learning es muy fácil conseguir un modelo perfecto para los datos utilizados,
pero pésimo para nuevos casos. El paradigma de entrenamiento y validación consigue evitar
el sobreajuste.
rr

6. Utilizar muestras sesgadas como si fueran aleatorias


Bo

Los métodos probabilísticos de uno u otro modo se basan en que los datos provienen de
muestras aleatorias. A pesar de que en muchas situaciones de análisis de datos esto no lo
podamos ni siquiera soñar, es importante tenerlo en mente para, a la hora de interpretar re-
sultados y llegar a conclusiones, hacer una reflexión sobre cuánto nos estamos alejando de esa
aleatoriedad. Por ejemplo, si estoy haciendo un estudio de los clientes de una empresa y solo
analizo las transacciones de la primera semana del mes, tengo una muestra sesgada porque
no tengo representado el resto del mes (posiblemente con un comportamiento diferente).

Realice la práctica 2.1 cuyo guión se encuentra en el apartado 2.5 para identificar
problemas y limpiar un conjunto de datos.
2.2. ANÁLISIS UNIVARIANTE 111

Tabla 2.1: Ejemplos de variables


maquina merma1 merma2 manchas defecto defecto2 temp
maquina1 5.377 4.007 11 No 0 15.7
maquina1 6.007 4.598 7 Sí 1 18.8
maquina1 4.822 5.742 9 No 0 13.9
maquina1 6.014 3.960 6 Sí 1 18.5
maquina1 3.892 5.268 6 No 0 12.0
maquina1 5.379 5.913 9 No 0 17.3

07
2.2. Análisis univariante
En un conjunto de datos, podemos analizar una única variable de forma independiente,

5-
ya sea de un tipo u otro. Tenemos un vector de datos con los valores de la variable. En
el siguiente apartado hablaremos del análisis multivariante, pero tengamos en cuenta que

-0
siempre podemos extraer una variable del conjunto de datos multivariante para analizarla
por separado. De hecho, esto será parte del análisis exploratorio de datos multivariantes.

19
Ejemplo numérico. La tabla 2.1 muestra las primeras filas de un conjunto de datos
de 100 observaciones. Cada una contiene la medición de una característica en un producto,
20
supongamos que está relacionada con la merma en gramos. Las variables merma1y merma2son
numéricas continuas, ya que puede tomar cualquier valor en un intervalo. La variable maquina
es cualitativa, ya que no se puede cuantificar. La variable manchas representa el número de
manchas detectadas en cada unidad en una inspección visual. Esta es una variable numé-
rica discreta. La variable defecto inicialmente la podemos considerar categórica (toma los
or

valores sí/no), pero también la podemos considerar ordinal (defecto2), y asignando un va-
lor numérico ordenado podemos hacer cálculos. Comprobamos que los tipos de datos en el
espacio de trabajo se corresponden con los tipos de variables que tenemos.
ad

str(ejDatos)
rr

## 'data.frame': 100 obs. of 7 variables:


## $ maquina : Factor w/ 2 levels "maquina1","maquina2": 1 1 1 1 1 1 1 1 1 1 ...
## $ merma1 : num 5.38 6.01 4.82 6.01 3.89 ...
Bo

## $ merma2 : num 4.01 4.6 5.74 3.96 5.27 ...


## $ manchas : int 11 7 9 6 6 9 6 9 3 8 ...
## $ defecto : Factor w/ 2 levels "No","Sí": 1 2 1 2 1 1 1 1 1 1 ...
## $ defecto2: int 0 1 0 1 0 0 0 0 0 0 ...
## $ temp : num 15.7 18.8 13.9 18.5 12 17.3 13.8 13.1 12.1 14.2 ...

2.2.1. Resúmenes numéricos


Trabajar directamente con los conjuntos de datos completos en la mayoría de las ocasiones es
una labor imposible. Incluso cuando los conjuntos de datos son pequeños, es más conveniente
112 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

Tabla 2.2: Tabla de frecuencias de la variable ’defectuoso’


No Sí
94 6

Tabla 2.3: Tabla de frecuencias de la variable número de manchas


3 4 5 6 7 8 9 10 11
6 12 14 16 18 12 14 4 4

estudiar los datos en su conjunto mediante tablas, medidas y representaciones gráficas que

07
resumen la información.

5-
2.2.1.1. Tablas de frecuencias
Los datos se pueden resumir en forma de tablas. Esta información nos aportará más infor-
mación que un solo número de resumen, y es útil para incluir en informes o análisis previos.

-0
Las tablas más utilizadas son las tablas de frecuencias, que contienen el número de ob-
servaciones para cada posible valor de la variables. Para variables discretas y categóricas,

19
la tabla de frecuencias representa el número de observaciones para el cual la variable toma
cada uno de los valores o atributos.
20
La tabla 2.2 muestra la tabla de frecuencias de la variable defecto en el conjunto de
datos de ejemplo, y la tabla 2.3 muestra la tabla de frecuencias de la variable manchas.

En el caso de las variables continuas, las observaciones se cuentan por intervalos. Estos
or

intervalos se pueden calcular utilizando diferentes métodos. Una posible regla sería el método
de Sturges, que es el que utiliza por defecto R. Esta regla establece que el número de intervalos
k en el que se deben dividir los datos es:
ad

log n
k = 1 + log2 n = 1 +
log 2
rr

redondeado por arriba, es decir, el menor entero mayor que el cálculo anterior. Una vez
Bo

decidido el número de intervalos, la amplitud de los mismos será el rango (máximo menos
mínimo) dividido por el número de intervalos, que normalmente se redondea o trunca para
facilitar la presentación e interpretación. Al valor central de cada intervalo se le denomina
marca de clase.

En el ejemplo que estamos utilizando el número de divisiones que haríamos para


la variable merma2 utilizando esta regla es 8. Este valor estrictamente nos llevaría a tener
intervalos de amplitud 0,584, calculado como el recorrido dividido por el número de grupos.
Para facilitar la interpretación de estas tablas, lo normal es redondear o truncar esta amplitud,
y entonces el número de intervalos puede variar ligeramente. En este ejemplo la tabla de
2.2. ANÁLISIS UNIVARIANTE 113

Tabla 2.4: Tabla de frecuencias por intervalos


Merma Frecuencia
3.00 - 3.50 2
3.50 - 4.00 9
4.00 - 4.50 9
4.50 - 5.00 19
5.00 - 5.50 20
5.50 - 6.00 20
6.00 - 6.50 9

07
6.50 - 7.00 5
7.00 - 7.50 1
7.50 - 8.00 6

5-
frecuencias así calculada sería la que se muestra en la tabla 2.4, con 10 intervalos de amplitud

-0
0,5.

19
La importancia de esta tabla de frecuencias radica en que es la base para dibujar histogramas,
que es una de las herramientas gráficas más importantes en el análisis exploratorio de datos.
20
2.2.1.2. Medidas de centralización
La información en tablas de frecuencias está bien, pero para realizar cálculos necesitamos me-
didas numéricas que resuman alguna característica de los datos mediante un número. Cuando
or

estas medidas resumen se calculan sobre los datos de una muestra, se llaman estadísticos.
El valor teórico de una medida resumen referido al conjunto de la población, generalmente
desconocido, se llama parámetro. Las principales medidas numéricas se agrupan en dos
ad

grandes bloques:

Medidas de centralización. Recogen valores entorno a los cuales varían los datos.
Medidas de dispersión. Describen cómo es esa variación.
rr

Además, podemos utilizar medidas de posición y medidas de forma.


Bo

Llegados a este punto, se hace necesario recordar algunos símbolos y nomenclatura que
aparecen durante el texto.

X, Y, Xj , . . .: Variables
i: Identificador o índice para cada observación
xi : Valor que toma la variable X en la observación i4 .
n: Número total de observaciones en la muestra. Si hay muestras de distinto tamaño,
pueden representarse como nj
N : Número total de observaciones en la población

4
En datos agrupados, xi representa la marca de clase de los intervalos.
114 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R


n
: Representa la suma de los elementos que contiene en su interior para cada obser-
i=1
vación
x̄: Media muestral de la variable X
s2 : Varianza muestral de la variable X
s: Desviación típica muestral de la variable X
µ: Media poblacional
σ 2 : Varianza poblacional
σ: Desviación típica poblacional
ˆ Simboliza un estimador de [·]. Por ejemplo, s = σ̂ quiere decir que la desviación
[·]:

07
típica muestral s es un estimador de la desviación típica poblacional σ.
Las medidas de centralización resumen los datos mediante valores medios, entorno a los cuales
varían los datos. Las más importantes son la media aritmética, la mediana y la moda. Hay

5-
otras medias como la media geométrica, la armónica y la cuadrática. La media aritmética
es la suma de todos los valores de la variable dividido por el número de observaciones.

-0

n
xi

19 x̄ = i=1
n

Una variante de la media es la media recortada. Por ejemplo, en la media recortada al 5 % no


20
tendríamos en cuenta el 5 % de los valores más grandes ni el 5 % de los valores más pequeños.
Por otra parte, si tenemos los datos en forma de tabla de frecuencias, podemos calcular la
media como una media ponderada5 . La media se calcularía como:
or


n
x̄ = xi · f i ,
i=1
ad

donde ni es la frecuencia absoluta, es decir, número de observaciones que toman el valor xi ,


y fi = nni es la frecuencia relativa.
rr

La función mean calcula la media de un vector numérico. Con el argumento trim


Bo

podemos calcular medias recortadas. A continuación se muestran algunos ejemplos. La tabla


2.3 mostraba la tabla de frecuencias para la variable manchas del ejemplo. Supongamos que
no tenemos todos los datos en R, sino la tabla de frecuencias almacenada en un data frame
llamado df cuya primera columna son los valores de la variable y la segunda columna son las
frecuencias absolutas. Entonces, utilizaríamos la función weighted.mean como en el ejemplo.

mean(ejDatos$merma1)

## [1] 5.06671
5
En realidad, podemos utilizar otras ponderaciones por conveniencia, por ejemplo en estadística espacial
es habitual ponderar por la distancia inversa al cuadrado.
2.2. ANÁLISIS UNIVARIANTE 115

mean(ejDatos$merma1, trim = 0.05)

## [1] 5.071167
weighted.mean(x = df[, 1], w = df[, 2])

## [1] 4.64

La media representa el centro de gravedad de los datos. Es una buena medida resumen para
distribuciones simétricas y que no tengan valores muy extremos. Sus buenas propiedades

07
matemáticas la hacen imprescindible para realizar otros cálculos. Una propiedad importante
de la media es que la suma de las diferencias de la variable a su media es cero:

5-

n
(xi − x̄) = 0 (2.1)
i=1

-0
La mediana es el valor central de los datos, es decir, aquél que divide los datos en dos mitades:
uno con las observaciones cuyo valor es inferior a la mediana, y otro con las observaciones
19
cuyo valor es mayor que la mediana. Esta medida de centralización no se ve afectada por
valores atípicos, ya que es una medida de orden. Para calcularla, ordenamos las observaciones.
Si el número de observaciones es impar, la mediana es exactamente el valor que queda en
20
medio. Por ejemplo, si tenemos 25 mediciones, la número 13 en orden ascendente deja por
debajo y por arriba 12 observaciones, por lo tanto el valor que tome en la decimotercera
observación ordenada, es la mediana. Si el número de observaciones es par, se toman los dos
valores centrales y la mediana se calcula como la media aritmética de esos dos valores.
or

La función median de R calcula la mediana de un vector de datos, por ejemplo para


ad

la variable merma1:
median(ejDatos$merma1)
rr

## [1] 5.0745

La moda es el valor central de los datos en el sentido de ser el más frecuente. En variables
Bo

categóricas, será la clase que más observaciones tiene. En variables numéricas discretas,
contamos el número de observaciones para cada posible valor, y la moda será aquél valor
que se produce en mayor número de observaciones. En variables continuas, tendremos un
intervalo modal que es el que más observaciones contiene (ver más adelante el histograma).

Mientras que la mediana y la media son únicas, es posible que un conjunto de datos tenga
dos modas. Esto, muy probablemente, nos estará indicando que estamos analizando datos
mezclados de dos grupos distintos y quizás deberíamos separarlos (análisis estratificado).

No hay una función en R para calcular la moda, aunque podemos obtenerla buscando en la
tabla de frecuencias cuál es el valor más frecuente.
116 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

Por ejemplo para la variable manchas del ejemplo se calcularía con el siguiente código,
siendo 7 manchas el valor más frecuente, y por tanto la moda.

frecuencias <- table(ejDatos$manchas)


as.numeric(names(frecuencias)[which(frecuencias == max(frecuencias))])

## [1] 7

07
2.2.1.3. Medidas de posición
Del mismo modo que definimos la mediana para separar los datos en dos mitades, definimos el

5-
percentil Xp como el valor tal que el p % de las observaciones tienen un valor de la variable
menor o igual que Xp . Podemos calcular cualquier percentil, siendo los más importantes,
además de la mediana, el primer y tercer cuartil (Q1 y Q3 respectivamente), que dejan entre

-0
ambos el 50 % de las observaciones entorno a la mediana.
Los percentiles se suelen expresar como porcentajes (por ejemplo, percentil 10). A menudo

19
se les nombra también como cuantiles, pero en este caso se expresan en forma de tanto por
uno, por ejemplo, cuantil 0,1.
20
La figura 2.2 muestra gráficamente la distribución de las observaciones con relación a
la mediana y los cuartiles de la variable merma1 del conjunto de datos de ejemplo. Podemos
ver fácilmente cómo la mediana es robusta a los valores atípicos. Por ejemplo, si el mayor
valor se hubiera almacenado sin el punto decimal, la media sería un valor muy alto y no
or

representativa de los datos, mientras que la mediana seguiría teniendo el mismo valor y
representaría mucho mejor los datos. En R podemos utilizar la función quantile para obtener
cualquier percentil. La función summary sobre un vector numérico nos proporciona el mínimo,
ad

el máximo, el primer cuartil, la mediana, el tercer cuartil y el máximo. Además, esta función
nos informa de si existen valores perdidos. Véase el siguiente código.
rr

quantile(ejDatos$merma1, c(0.1, 0.9))

## 10% 90%
Bo

## 4.4019 5.7959
summary(ejDatos$merma1)

## Min. 1st Qu. Median Mean 3rd Qu. Max.


## 3.728 4.737 5.074 5.067 5.383 6.167

2.2.1.4. Medidas de dispersión


En cuanto a las medidas de dispersión, la medida más sencilla que podemos tomar es el
rango, es decir, la diferencia entre el mayor y el menor valor:
2.2. ANÁLISIS UNIVARIANTE 117

Q1 Mediana Q3

07
5-
3.728 4.728 5.0745 5.386 6.167

Figura 2.2: Representación gráfica de la mediana y los cuartiles

-0
R = máx xi − mı́n xi .

19 i i

En R, la función range devuelve dos números, el mínimo y el máximo. Si queremos calcular


el rango, no tenemos más que obtener la diferencia, por ejemplo con la función diff que
20
devuelve las diferencias entre los sucesivos valores de un vector de cualquier tamaño.
Esta medida es muy pobre porque solo tiene en cuenta dos valores. Lo ideal sería utilizar una
medida que resumiera la variabilidad utilizando todos los datos. Por ejemplo, podemos medir
la distancia de cada valor hasta la media, y resumir todas esas distancias con su promedio
or

(véase la figura 2.3). Pero por la propiedad vista en la ecuación (2.1), ese promedio es cero.
La medida más utilizada para medir la dispersión de los datos es la desviación típica,
ad

que es la raíz cuadrada de la varianza. La varianza es el promedio de las desviaciones al


cuadrado con respecto de la media.
rr


N
(xi − µ)2
2 i=1
σ =
Bo

N
La mayoría de las veces trabajamos con muestras, y por tanto no podemos calcular σ 2 , sino
su estimador s2 :


n
(xi − x̄)2
2 i=1
s =
n−1
Se utiliza n − 1 en el denominador en vez de n debido a que es el mejor estimador de la
varianza al trabajar con muestras. Nótese que las unidades de la varianza no son las mismas
que las de la variable, y es por eso que se utiliza la desviación típica s:
118 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

07
Merma máquina proceso 1
x11 = 6.075

5-
6.0

-0
5.5

19
Peso

5.0 x = 4.97
20
4.5
or

4.0
ad

0 10 20 30 40 50
rr

Pieza

Figura 2.3: Distancias de cada valor a la media


Bo
2.2. ANÁLISIS UNIVARIANTE 119


s= s2 .

Al igual que la media, la desviación típica es muy sensible a observaciones atípicas. Una
propiedad interesante de la desviación típica es que, sea cual sea la distribución de los
datos,
( entre
) la media y un número de desviaciones típicas k se encuentran, al menos, el
1 − k12 × 100 %. Por ejemplo, para cualquier distribución de datos, entre la media y dos
desviaciones típicas (k = 2) se encuentran al menos el 75 % de las observaciones, y entre
la media y tres desviaciones típicas (k = 3), al menos el 89 % de las observaciones. Estos

07
límites aumentan dependiendo de la distribución específica que siguen los datos (el modelo).
Las funciones var y sd de R calculan la varianza y la desviación típica respectivamente de
un vector de datos.

5-
A veces se utiliza una medida relativa de la variabilidad, como es el coeficiente de variación.
Es especialmente útil para comparar variables que están en distintas unidades:

-0
s
CV = .
x

19
La instalación base de R no tienen una función para calcular el coeficiente de variación,
aunque es trivial calcularlo como sd(x)/mean(x).
20
En general, un coeficiente de variación inferior a 0,1 indicará que la media es representativa
de los datos, mientras que con valores mayores debemos cuestionarnos esa representatividad.
Para evitar los problemas que plantea la desviación típica, se puede utilizar como medida
de la variabilidad el rango intercuartílico, que es la diferencia entre el tercer y el primer
or

cuartil, que al igual que la mediana no está afectada excesivamente por los valores atípicos.
Representa la diferencia entre los valores centrales que incluyen el 50 % de los datos, es decir,
entre el primer y el tercer cuartil. La dispersión se puede medir también entorno a la mediana,
ad

por ejemplo con la desviación absoluta a la mediana, que es la mediana de las desviaciones
absolutas a la mediana. Las funciones IQR y mad de R realizan estos cálculos.
rr

A continuación se calculan todas las medidas de dispersión descritas para la variable


merma1 del conjunto de datos de ejemplo.
Bo

range(ejDatos$merma1)

## [1] 3.728 6.167


diff(range(ejDatos$merma1))

## [1] 2.439
var(ejDatos$merma1)

## [1] 0.2748028
120 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

sd(ejDatos$merma1)

## [1] 0.5242164
sd(ejDatos$merma1)/mean(ejDatos$merma1)

## [1] 0.1034629
IQR(ejDatos$merma1)

## [1] 0.645

07
mad(ejDatos$merma1)

## [1] 0.4766559

5-
Recordemos que si hay valores faltantes en los datos no podemos hacer cálculos a menos que
indiquemos que no se tengan en cuenta esas observaciones con el argumento na.rm = TRUE

-0
en las funciones utilizadas.

2.2.1.5. Otras medidas univariantes


19
Existen infinidad de medidas que podemos utilizar para describir los datos que no se tratan
en este texto por cuestión de espacio, como por ejemplo:
20
Momentos
Apuntamiento y curtosis
Asimetría
or

Estas medidas son útiles cuando los métodos gráficos no son suficientemente claros acerca
de la forma de la distribución, para establecer los modelos que tenemos que aplicar. Así,
los histogramas de los datos recogidos en dos líneas de producción pueden ser muy pare-
ad

cidos visualmente, pero puede haber cálculos numéricos que nos aporten más información.
Los paquetes moments (Komsta and Novomestky, 2015) y psych (Revelle, 2019) contienen
funciones para obtener estas y otras medidas.
rr

Otro tipo de análisis univariante que se puede realizar y que no se trata en este texto es
el análisis de series temporales. Cuando cada observación de una variable se refiere a un
Bo

instante en el tiempo y existe autocorrelación entre las observaciones, se puede analizar la


serie temporal tanto de forma descriptiva como predictiva. El paquete forecast (Hyndman
et al., 2019) es uno de los más utilizados para trabajar con series temporales.

2.2.2. Resúmenes gráficos


Aunque en este texto se presenten en apartados separados, normalmente el análisis explora-
torio de datos se realiza simultáneamente de forma numérica y gráfica. Veamos qué represen-
taciones gráficas para una variable son más adecuadas según el tipo de datos. En los ejemplos
de código que se incluyen a continuación se utilizan diversos métodos gráficos que van desde
la extrema sencillez a cierta sofisticación, pasando por opciones sencillas que mejoran los
2.2. ANÁLISIS UNIVARIANTE 121

Piezas defectuosas

No

07

5-
Figura 2.4: Gráfico de sectores de las piezas defectuosas. Se debe acompañar siempre de los

-0
datos (en el propio gráfico o fuera de él)

19
gráficos. En un capítulo posterior se trata en detalle la elaboración de gráficos, por lo que
estas opciones no se explican aquí. El lector puede consultar la ayuda de cada función para
saber más sobre sus opciones.
20
Para variables cualitativas, resumidas en tablas de frecuencias, podemos utilizar gráficos de
sectores y gráficos de barras. Los primeros no son en general recomendables6 , a menos que
se incluyan los valores numéricos claramente. Los gráficos de barras son ideales para tablas
de frecuencias, tanto de variables cualitativas como cuantitativas discretas.
or

Las figuras 2.4 y 2.5 son ejemplos de visualizaciones de las tablas de frecuencias 2.2
ad

y 2.3 respectivamente, obtenidas con las siguientes expresiones.

pie(table(ejDatos$defecto), main = "Piezas defectuosas")


rr

barplot(table(ejDatos$manchas))
Bo

En cuanto a las variables cuantitativas continuas, la representación más simple que podemos
obtener es un gráfico de puntos en el que el eje vertical representa el valor de la variable, y el
eje horizontal un identificador del dato, secuencialmente a como se han obtenidos los datos.
Cuando el orden de las observaciones tiene un sentido, por ejemplo una serie temporal, es
adecuado unir los puntos con líneas.

La figura 2.6 muestra un gráfico secuencial de la variable merma1 del conjunto de


datos de ejemplo. en la figura 2.7 se han añadido líneas que conectan los puntos y algunas

6
Véase la nota en la ayuda de la función con ?pie.
122 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

15
10
5

07
5-
0

3 4 5 6 7 8 9 10 11

-0
Figura 2.5: Gráfico de barras del número de manchas

19
opciones gráficas. Nótese cómo una expresión muy sencilla, con un único argumento, produce
un resultado, y cómo se puede mejorar añadiendo algunas opciones. Para saber más sobre
20
las opciones gráficas, véase la ayuda de ?gpar.

plot(ejDatos$merma2)

plot(ejDatos$merma2, las = 1, main = "Valores de una variable numérica",


or

xlab = "Identificador", ylab = "Peso",


pch = 16, col = "steelblue", type = "b")
ad

El histograma es el gráfico que representa la tabla de frecuencias por intervalos. Es im-


portante diferenciar entre el gráfico de barras de una variable discreta (por ejemplo el de la
figura 2.5) y el histograma, en el que las barras son contiguas. Si hay un hueco entre una
rr

barra y otra, significa que en ese intervalo hay cero observaciones. Con el histograma vemos
de un vistazo la distribución de los datos, por ejemplo si hay valores extremos, si es simétrica,
o cuáles son los valores más frecuentes. El histograma, como resumen gráfico que es, oculta
Bo

parte de la información. Los gráficos se pueden enriquecer añadiendo anotaciones y opciones,


como en el siguiente ejemplo.

La función hist de R crea histogramas fácilmente, por ejemplo la primera de las


siguientes expresiones crea el histograma de la figura 2.8. Podemos visualizar todos los datos
añadiendo puntos que representen cada valor, como en la figura 2.9 que se genera con la
segunda de las siguientes expresiones y añade más opciones gráficas.

hist(ejDatos$merma2)
2.2. ANÁLISIS UNIVARIANTE 123

8
7
ejDatos$merma2

6
5

07
4

5-
-0
0 20 40 60 80 100

Index

19
Figura 2.6: Gráfico de puntos básico de una variable numérica
20
Valores de una variable numérica

8
or

7
ad

6
Peso

rr

5
Bo

0 20 40 60 80 100

Identificador

Figura 2.7: Gráfico de puntos y líneas de una variable numérica, con algunas opciones gráficas
124 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

Histogram of ejDatos$merma2

20
15
Frequency

10

07
5

5-
0

-0
3 4 5 6 7 8

19 ejDatos$merma2

Figura 2.8: Histograma de una variable continua


20
hist(ejDatos$merma2, las = 1,
main = "Histograma de la merma del proceso 2",
or

xlab = "Peso", ylab = "Frecuencias",


col = "steelblue", border = "white")
points(ejDatos$merma2, abs(jitter(rep(1, 100), factor = 50)),
ad

col = scales::alpha("tomato", 0.5), pch = 20, cex = 2)

Otra visualización para datos continuos unidimensionales es el gráfico de cajas, también


rr

conocido como “de cajas y bigotes” (box-and-whisker plot). Consiste en la representación del
conocido como “Resumen de cinco números”, que son el mínimo, el máximo, la mediana y
las bisagras (hinges) de Tukey. Estas bisagras son una versión del primer y tercer cuartil,
Bo

aunque calculados de forma ligeramente diferente7 . La función fivenum nos devuelve estos
números.

Las siguientes expresiones muestran los cuartiles y las bisagras de la variable merma2
del conjunto de datos de ejemplo. Nótese cómo la bisagra superior no es exactamente el
tercer cuartil, aunque están muy próximos.

7
Véase la ayuda de ?boxplot.stats en R. El cálculo también está especificado en la norma UNE-ISO
16269:4.
2.2. ANÁLISIS UNIVARIANTE 125

Histograma de la merma del proceso 2

20

15
Frecuencias

10

07
5

5-
0

-0
3 4 5 6 7 8

19 Peso

Figura 2.9: Histograma con información superpuesta


20
summary(ejDatos$merma2)
or

## Min. 1st Qu. Median Mean 3rd Qu. Max.


## 3.200 4.598 5.269 5.310 5.846 7.869
fivenum(ejDatos$merma2)
ad

## [1] 3.2000 4.5975 5.2690 5.8620 7.8690


Los bordes inferior y superior de la caja son las bisagras (aproximadamente el primer y tercer
rr

cuartil) respectivamente. Los extremos de las líneas que salen de los bordes superior (inferior)
de la caja llegan hasta el valor más cercano a la caja de entre los siguientes:
Bo

El máximo (mínimo)
Una distancia k veces el rango intercuartílico desde el borde superior (inferior) de la
caja. Por defecto se toma k = 1,5 Todos los valores que van más allá de los bigotes se
representan como puntos, y se consideran candidatos a ser valores atípicos (outiliers).
Valores fuera de los límites calculado con k = 3 deben ser seriamente considerados como
atípicos e investigar su causa.

La figura 2.10 muestra el gráfico de cajas de la variable merma2 de nuestro conjunto


de datos de ejemplo, realizado con la función boxplot. Nótese cómo el valor máximo es
126 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

8
7
6
5

07
4

5-
Figura 2.10: Ejemplo de gráfico de cajas con un valor atípico

-0
candidato a ser un valor atípico ya que es mayor que el límite marcado por la bisagra

los cálculos de los límites. 19


superior más 1,5 veces el rango intercuartílico. La figura 2.11 muestra el mismo gráfico con

fivenum(ejDatos$merma2)[4] + 1.5*IQR(ejDatos$merma2)
20
## [1] 7.735125
max(ejDatos$merma2)
or

## [1] 7.869
boxplot(ejDatos$merma2)
ad

2.2.3. Distribución de probabilidad


rr

Volviendo al paradigma población-muestra subyacente a los métodos estadísticos represen-


tado en la figura 2.1, vamos a ponerlo en relación con los datos que vamos a analizar, re-
presentados en la figura 2.12. La característica objeto de estudio en nuestra población es
Bo

una variable aleatoria que sigue un modelo teórico representado por la función de densidad
de probabilidad (línea suave superpuesta al histograma), generalmente desconocido y con
el que queremos realizar inferencia estadística para tomar decisiones. Para ello necesitamos
datos, y obtenemos muestras. Los datos que obtenemos, representados en el histograma, nos
sirven para describir la población a través de la muestra y caracterizar el modelo teórico
(distribución de probabilidad, parámetros, etc.)
A los efectos de esta obra, simplemente vamos a recordar la definición de probabilidad como
frecuencia relativa en el límite. Si pudiéramos obtener muestras indefinidamente de nuestra
variable, el histograma se parecería cada vez más al modelo teórico. La probabilidad de que
la variable aleatoria tome valores en cada un intervalo cualquiera es igual al área debajo de
2.2. ANÁLISIS UNIVARIANTE 127

Gráfico de caja variable 'merma2'

8
7.869
Límite superior: 7.735
Máximo no atípico: 7.716

07
7

5-
-0
6 19 Hinge: 5.847
20
Peso

Mediana: 5.269
or

5
ad

Hinge: 4.598
rr

4
Bo

Mínimo: 3.2
3

Límite Inferior: 2.724


Figura 2.11: Construcción del gráfico de cajas
128 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

Frecuencia relativa/función de densidad

0.75

0.50

07
5-
0.25

-0
0.00

4.0 4.5
19 5.0
Volumen (cl)
5.5 6.0
20
Figura 2.12: Histograma y densidad de probabilidad

la curva, y se puede aproximar sumando las frecuencias relativas de los intervalos correspon-
dientes en la muestra. La explicación dada aquí se extiende fácilmente a variables discretas
or

tomando valores exactos de las variables en vez de intervalos.


## Registered S3 methods overwritten by 'ggplot2':
ad

## method from
## [.quosures rlang
## c.quosures rlang
rr

## print.quosures rlang
La variable aleatoria que describe la característica en estudio en la población puede estar ca-
Bo

racterizada por cualquier función de densidad que cumpla ciertos requisitos (véase el capítulo
8 de López Cano (2018). En la práctica, se utilizan un subconjunto reducido de modelos de
distribución de probabilidad que quedan caracterizadas por unos pocos parámetros. El más
importante de estos modelos es la llamada distribución normal, que queda caracterizada
por la media µ y varianza σ 2 , siendo la expresión de su función de densidad:

1 (x−µ)2
f (x) = √ e− 2σ2 .
2πσ 2

Denotamos que una variable aleatoria sigue una distribución normal como:
2.2. ANÁLISIS UNIVARIANTE 129

07
5-
µ − 3σ µ − 2σ µ−σ µ µ+σ µ + 2σ µ + 3σ

-0
Figura 2.13: Distribución normal estandarizada

19
X ∼ N (µ, σ).
20
La distribución normal es simétrica, toma valores −∞ < x < ∞, y se cumple que:
Entre la media y tres desviaciones típicas tenemos una probabilidad de 0.997
Entre la media y dos desviaciones típicas tenemos una probabilidad de 0.955
or

Entre la media y una desviación típica tenemos una probabilidad de 0.683


La figura 2.13 muestra la función de densidad de la distribución normal estandarizada con
su típica forma de campana.
ad

En el análisis exploratorio de datos, es importante intentar averiguar el modelo de distri-


bución de probabilidad que sigue la variable aleatoria de la que provienen los datos de la
rr

muestra. O al menos, identificar si los datos provienen de una distribución normal o no, ya
que muchos métodos estadísticos se basan en la hipótesis de que los datos provienen de una
distribución normal. Un simple examen visual del histograma de la variable nos puede dar
Bo

una idea para aceptar este hecho o no. Otra herramienta gráfica para este cometido es el
gráfico cuantil-cuantil, que representa los cuantiles teóricos de la distribución frente a los ob-
servados en la muestra. Los puntos así representados deberían caer aproximadamente sobre
una línea recta si los datos provienen de una distribución normal8 . La función qqnorm de
R produce este gráfico para un vector de datos. Si los métodos gráficos no fueran suficien-
tes, podemos comprobar numéricamente si los datos nos proporcionan evidencias suficientes
para rechazar que los datos provienen de una distribución normal, mediante un contraste
de hipótesis. La función shapiro.test contrasta la hipótesis nula de que los datos provie-
nen de una distribución normal frente a la alternativa de que no mediante el estadístico de
8
Se puede utilizar el método para otras distribuciones de probabilidad
130 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

Normal Q−Q Plot

8
7
Sample Quantiles

07
5

5-
4

-0
−2 −1 0 1 2

19 Theoretical Quantiles

Figura 2.14: Gráfico cuantil-cuantil de la variable merma2


20
Shapiro-Wilk.
or

El histograma de la variable merma2 en la figura 2.8 tenía forma aproximada de cam-


pana, pero nos pueden surgir dudas debido a algunas barras en la parte derecha. Realizamos
el análisis con el código que se muestra a continuación. La figura 2.14 muestra el gráfico
ad

cuantil-cuantil de los datos, donde vemos que los puntos caen aproximadamente sobre una
línea recta. En la prueba de Shapiro-Wilk, obtenemos un p-valor de 0,09911, suficientemente
grande como para no rechazar la hipótesis de normalidad a un nivel de significación del 5 %.
rr

Por tanto, podríamos utilizar los métodos que requieran normalidad.

qqnorm(ejDatos$merma2)
Bo

shapiro.test(ejDatos$merma2)

##
## Shapiro-Wilk normality test
##
## data: ejDatos$merma2
## W = 0.97837, p-value = 0.09911
Una vez determinada la distribución de probabilidad de una variable aleatoria, podemos
calcular probabilidades de que dicha variable tome ciertos valores (intervalos en el caso de
2.2. ANÁLISIS UNIVARIANTE 131

variables continuas). En R hay disponibles un buen número de distribuciones de probabilidad


(véase la ayuda de ?Distributions). Para cada distribución de probabilidad, hay cuatro
funciones relacionadas:

p*: Estas funciones calculan probabilidades utilizando la función de distribución de


probabilidad asociada a la variable aleatoria, es decir, dado x, P [X ≤ x].
d*: Estas funciones calculan densidades de probabilidad. En el caso de variables discre-
tas, se corresponde con P [X = x] dado x. En variables continuas no tiene más utilidad
que representar gráficamente la función.
q*: Es la función inversa a la función de distribución, es decir, dada una probabilidad

07
p, el cuantil q para el cual P [X < q] = p.
r*: Estas funciones generan números aleatorios para una distribución de probabilidad,
dados sus parámetros.

5-
A continuación de cada una de estas letras, vendría el nombre de la distribución, por ejemplo
para la distribución normal, pnorm, y como argumentos hay que añadir los parámetros de la

-0
distribución. Las funciones p* y q* hacen referencia a la cola inferior, por lo que si queremos
la probabilidad o el cuantil referidos a la cola superior, tenemos que añadir el argumento
lower.tail = FALSE.
19
Supongamos que sabemos que la variable merma1 del conjunto de datos de ejemplo
20
proviene de una distribución normal con media 5 y desviación típica 0,5. Con las dos primeras
expresiones a continuación respondemos a las siguiente preguntas:
¿Cuál es la probabilidad de que la variable valga menos de 6?
¿Cuál el es valor por encima del cuál solo queda el 5 % de probabilidad?
or

La cuarta expresión genera 10 números aleatorios de esta distribución normal. La función


set.seed sirve para obtener los mismos resultados a efectos de reproducibilidad del ejemplo.
ad

La última de las expresiones devuelve la probabilidad de que una variable aleatoria de Poisson
de parámetro λ = 5 sea igual a 2.

pnorm(6, mean = 5, sd = 0.5)


rr

## [1] 0.9772499
Bo

qnorm(0.05, mean = 5, sd = 0.5, lower.tail = FALSE)

## [1] 5.822427
set.seed(1)
rnorm(10, mean = 5, sd = 0.5)

## [1] 4.686773 5.091822 4.582186 5.797640 5.164754 4.589766 5.243715


## [8] 5.369162 5.287891 4.847306
dpois(2, lambda = 5)
132 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

## [1] 0.08422434

2.2.4. Transformaciones de datos


En ocasiones es conveniente, o incluso necesario, realizar transformaciones a los datos. Vamos
a ver dos tipos de transformaciones que es habitual realizar.

2.2.4.1. Tipificación
La tipificación o escalado de datos consiste en convertir cualquier conjunto de datos en otro

07
cuya media es igual a cero y desviación típica es igual a 1. Por las propiedades de la media
y la varianza, cualquier conjunto de datos X se tipifica restando su media y dividiendo por
su desviación típica:

5-
x − x̄

-0
Z=
s

19
La siguiente expresión tipifica la variable merma1 del conjunto de datos de ejemplo.
Podemos comprobar la media y desviación típica del nuevo conjunto de datos. Nótese cómo
por efectos de precisión de los cálculos con ordenador, no obtenemos exactamente cero, sino
20
un número infinitesimal (que es prácticamente cero).

z <- scale(ejDatos$merma1)
mean(z)
or

## [1] 7.917289e-16
sd(z)
ad

## [1] 1
Se puede transformar un conjunto de datos solamente centrándolo, fijando el argumento
rr

scale = FALSE dentro de la función scale. La tipificación de datos tiene muchas aplicacio-
nes. En el siguiente apartado veremos su utilidad en el análisis multivariante.
Bo

2.2.4.2. Transformación para conseguir normalidad


Se ha indicado anteriormente que algunos métodos requieren de normalidad en los datos
para poder aplicarlos. ¿Qué hacemos entonces, si no se da esta normalidad? En general, se
pueden tomar dos caminos:
1. Utilizar métodos no paramétricos, que no requieren normalidad.
2. Transformar los datos para conseguir que se aproximen a una normal.
Existen varios métodos de transformación de datos para conseguir normalidad. El más habi-
tual es la transformación de Box-Cox, que es del tipo:
2.2. ANÁLISIS UNIVARIANTE 133


 xλ −1 λ ̸= 0
x(λ) = λ
.
log(X) λ=0

Para algún valor de λ, los datos transformados suelen ser normales. Si la variable toma
valores iguales o menores que cero, entonces se transforma previamente x añadiendo una
constante α y se hace la transformación a los datos x + α. El paquete car contiene funciones
para encontrar el mejor valor de λ y transformar la variable.

07
La variable Volume del conjunto de datos trees que se encuentra en el paquete
datasets de R es claramente no normal, como demuestra la prueba de Shapiro-Wilk reali-
zada en la primera expresión del siguiente código de ejemplo. La función powerTransform

5-
del paquete car obtiene el valor óptimo de λ para acercarse a la distribución normal. La
función summary sobre el objeto creado con esta función nos da más información: además
del valor óptimo (Est Power), nos da un valor redondeado y un intervalo de confianza. Tam-

-0
bién proporciona dos pruebas muy útiles: la primera para comprobar si λ = 0, en cuyo caso
la transformación logarítmica es la adecuada y facilita la interpretación; la segunda com-

19
prueba si no es necesaria transformación. En este ejemplo concreto, la mejor transformación
es λ = 0. En general, se prefieren valores redondeados para facilitar la interpretación. Por
ejemplo, λ = −1 se corresponde con la inversa, λ = 0,5 con la raíz cuadrada, etc. Una vez
20
elegido λ, la variable transformada se puede obtener directamente con la función bcPower,
y comprobar la normalidad de los datos transformados, véase la figura 2.15.

shapiro.test(trees$Volume)
or

##
## Shapiro-Wilk normality test
##
ad

## data: trees$Volume
## W = 0.88757, p-value = 0.003579
library(car)
rr

## Loading required package: carData


Bo

bctrees <- powerTransform(trees$Volume)


summary(bctrees)

## bcPower Transformation to Normality


## Est Power Rounded Pwr Wald Lwr Bnd Wald Upr Bnd
## trees$Volume -0.0748 0 -0.7049 0.5554
##
## Likelihood ratio test that transformation parameter is equal to 0
## (log transformation)
## LRT df pval
## LR test, lambda = (0) 0.05395085 1 0.81633
134 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

Histogram of trees$Volume Histogram of xt


Frequency

Frequency
8

8
4

4
0

07
10 30 50 70 2.0 2.5 3.0 3.5 4.0 4.5

trees$Volume xt

5-
Figura 2.15: Histogramas de la variable Volume original (izquierda) y transformada (derecha)

-0
##
## Likelihood ratio test that no transformation is needed
## LRT df pval
## LR test, lambda = (1) 10.5197 1 0.0011811
xt <- bcPower(trees$Volume, bctrees$roundlam)
19
20
shapiro.test(xt)

##
## Shapiro-Wilk normality test
##
or

## data: xt
## W = 0.96427, p-value = 0.3766
ad

par(mfrow=c(1,2))
hist(trees$Volume)
hist(xt)
rr

Realice la práctica 2.2 cuyo guión se encuentra en el apartado 2.5 para realizar análisis
Bo

exploratorio univariante.

2.3. Análisis multivariante


En los conjuntos de datos multivariantes, tendremos más de una variable referidas a una
serie de observaciones o individuos9 . Los datos pueden estar organizados (o no) en forma de
tablas (data frames en R), matrices o vectores. Cada variable será un vector o una columna
de la matriz o data frame. Por tanto, podemos hacer análisis univariante de cualquiera de
9
Pueden ser personas, países, objetos, y en general cualquier entidad distinguible de los demás.
2.3. ANÁLISIS MULTIVARIANTE 135

Tabla 2.5: Tabla de contingencia de las variables defecto y manchas


3 4 5 6 7 8 9 10 11
No 5 11 14 14 17 12 14 3 4
Sí 1 1 0 2 1 0 0 1 0

ellas como se ha visto anteriormente. Además, podemos estudiar las variables conjuntamente.
Dependiendo de la pregunta que queramos responder con la técnica estadística y del tipo
de variables de que disponemos y sus escalas, se utilizarán unas técnicas u otras. Antes de
pasar a las técnicas, vamos a ver algunas medidas conjuntas para varias variables.

07
2.3.1. Frecuencias conjuntas

5-
Cuando tenemos variables de tipo cualitativo o discreto, podemos construir tablas de contin-
gencia con las frecuencias conjuntas de dos o más variables. El caso más común es la tabla de

-0
doble entrada para dos variables, en la que tenemos los niveles o valores de una variable en
filas, y los valores o niveles de la otra en columnas. Las celdas de la tabla son las frecuencias
absolutas conjuntas. Si lo queremos hacer para más de dos variables, entonces obtendremos

19
una tabla de doble entrada para cada valor de la tercera y sucesivas variables.
20
De forma similar a una variable, la función table de R produce tablas de contingencia
cuando se le pasa más de una variable. La función xtabs es otra opción utilizando un interfaz
de fórmula. Las siguientes expresiones producen la tabla de contingencias representada en la
tabla 2.5.
or

table(ejDatos$defecto, ejDatos$manchas)
xtabs(~ defecto + manchas, ejDatos)
ad

2.3.2. Medidas conjuntas


Además de los resúmenes numéricos y gráficos de las variables individualmente, podemos
rr

realizar cálculo de las variables dos a dos. Vamos a revisar las más importantes en análisis
multivariante.
Bo

Para cada par de variables, podemos obtener la covarianza sxy y el coeficiente de corre-
lación lineal rxy .


(xi − x)(yi − y)
sxy = ,
n−1
sxy
rxy = .
sx sy

En las técnicas multivariantes en las que intervienen variables en escala métrica, podemos
tener variables de magnitudes muy distintas. En algunas técnicas una práctica habitual es
136 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

tipificar o estandarizar todas las variables como se vio en el apartado anterior. Una propiedad
importante de la tipificación es que, aunque cambiemos la escala, no se mofifica la estructura
de correlación entre las variables. Esto implica que la covarianza de dos variables tipificadas
es igual a su coeficiente de correlación, que es el mismo que para las variables originales:

x − x̄ y − ȳ
zx = ; zy = =⇒ Cov(zx ; zy ) = rzx ,zy = rx,y .
sx sy

Cuando tenemos más de dos variables, representamos la estructura de correlación del con-

07
junto de datos multivariantes con la matriz de varianzas-covarianzas S. La posición central
del conjunto de datos se resume con la matriz de medias x. Así, para un conjunto de xk
variables k = 1, . . . , m, tendríamos:

5-
 
x̄1
 
 x̄2 

-0
 
 ... 
x=  
 x̄k 
 
 
 


s21
19 ...
x̄m

20
s12 . . . s1k . . . s1m
 


s21 s22 . . . s2k . . . s2m 

 .. .. .. .. .. .. 
 . . . . . . 
S=  
 sk1 sk2 . . . s2k . . . skm 
 
 .. .. .. .. .. .. 
or

 . 
 . . . . . 
sm1 sm2 . . . smk . . . s2m
ad

La matriz de varianzas-covarianzas es simétrica m × m, con las varianzas en la diagonal y las


covarianzas para cada par de variables fuera de la diagonal. De forma análoga construimos
la matriz de correlaciones, en la cual tendremos unos en la diagonal, y los coeficientes de
rr

correlación dos a dos fuera de la diagonal.

 
Bo

1 r12 . . . r1k . . . r1m


 
 r21 1 . . . r2k . . . r2m 
 
 .. .. .. .. .. .. 
 . . . . . . 
r=  
 rk1 rk2 ... 1 . . . rkm 
 
 .. .. .. .. .. .. 
 . 
 . . . . . 
rm1 rm2 . . . rmk . . . 1

El conjunto de datos que estamos utilizando de ejemplo tiene cuatro variables en


escala métrica. Guardamos primero un data frame con esas tres variables y después obtene-
2.3. ANÁLISIS MULTIVARIANTE 137

mos las matrices y medidas explicadas. El argumento select de la función subset permite
seleccionar columnas por nombre.

ejMetricas <- subset(ejDatos, select = c(merma1, merma2, manchas, temp))


M <- colMeans(ejMetricas); M

## merma1 merma2 manchas temp


## 5.06671 5.30990 6.64000 15.26400
S <- cov(ejMetricas); S

07
## merma1 merma2 manchas temp
## merma1 0.27480279 -0.08238823 0.07961172 0.85817228
## merma2 -0.08238823 1.06823134 0.17175152 -0.24638949

5-
## manchas 0.07961172 0.17175152 4.35393939 0.04145455
## temp 0.85817228 -0.24638949 0.04145455 3.47828687

-0
r <- cor(ejMetricas); r

## merma1 merma2 manchas temp


##
##
##
merma1 1.00000000 -0.15206244
merma2 -0.15206244 1.00000000
manchas 0.07278221 0.07963917
19 0.07278221 0.87777097
0.07963917 -0.12782236
1.00000000 0.01065242
20
## temp 0.87777097 -0.12782236 0.01065242 1.00000000

2.3.3. Distancias y atípicos multivariantes


or

En datos univariantes, podemos calcular la distancia de una observación a otra, simplemente


por la diferencia entre los valores de la variable. Análogamente, podemos obtener una medida
resumen de la distancia entre una observación y otra teniendo en cuenta todas las variables
ad

de forma conjunta. Hay varias formas de calcular esta distancia entre observaciones, siendo
las más importantes:
Distancia euclídea
rr

v
u∑
um
Bo

dii′ = t (xij − xi′ j )2 .


j=1

En ocasiones se utiliza la distancia euclídea al cuadrado, para quitar la raíz y reducir el coste
computacional.
Distancia de Manhattan


m
d ii′ = |xij − xi′ j |.
j=1

Distancia máxima (o de Chebyshev)


138 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

m
dii′ = máx |xij − xi′ j |.
j=1

Distancia Mínima

m
dii′ = mı́n |xij − xi′ j |.
j=1

Distancia de Minkowski

07
 1

m p

d2ii′ =  p
|xij − xi′ j | .
j=1

5-
Los valores más habituales de p son 1 y 2, que se corresponden con la distancia de Manhattan
y la distancia euclidea respectivamente. Además, cuando p tiende a infinito o a menos infinito,

-0
la distancia de Minkowski se corresponde, respectivamente, con la distancia máxima (o de
Chebyshev) y mínima.
Distancia de Mahalanobis
19
Las medidas anteriores no tienen en cuenta la estructura de correlación del conjunto de datos
multivariante. Una medida más completa es la distancia de Mahalanobis (D):
20

Dii′ = xi − x i′ )T S −1 (x
(x xi − x i′ ),

donde x i y x i′ son los vectores fila de las observaciones i e i′ respectivamente, y S es la matriz


or

de varianzas-covarianzas de todas las variables.


Sea cual sea la forma de calcular las distancias, podemos obtener una matriz de distancias
ad

para todas las observaciones del conjunto de datos dos a dos. Será una matriz simétrica con
ceros en la diagonal, normalmente muy grande para ser mostrada en su totalidad, pero que
se utilizará en algunas técnicas multivariantes. La función dist de R calcula distancias en
matrices de datos10 .
rr
Bo

El subconjunto creado anteriormente ha quedado con 100 observaciones de 4 variables


en escala métrica. La siguiente expresión obtiene la matriz de distancias euclídeas, que tendrá
una dimensión de 100×100. Se muestran las distancias entre las cinco primeras observaciones
a modo de ejemplo. De esas cinco primeras piezas, las más alejadas son la 2 y la 5.

distancias <- dist(ejMetricas)


as.matrix(distancias)[1:5, 1:5]

## 1 2 3 4 5
## 1 0.000000 5.133827 3.249346 5.766106 6.518078
10
Por defecto la distancia euclídea, pero se pueden seleccionar otros métodos.
2.3. ANÁLISIS MULTIVARIANTE 139

## 2 5.133827 0.000000 5.542830 1.223558 7.222335


## 3 3.249346 5.542830 0.000000 5.895455 3.701294
## 4 5.766106 1.223558 5.895455 0.000000 6.961591
## 5 6.518078 7.222335 3.701294 6.961591 0.000000

Recordemos la forma que teníamos en conjuntos de datos univariantes para detectar valores
extremos, candidatos a ser valores atípicos o outliers. Mirábamos el gráfico de cajas, y los
valores que aparecían demasiado alejados del resto se representaban como valores atípicos.
Pues bien, en conjuntos de datos multivariantes vamos a utilizar la distancia entre obser-
vaciones definida anteriormente para detectar aquellas observaciones que estén demasiado

07
alejadas del resto como para ser considerada atípica en relación al conjunto de datos y su
estructura de correlación. En particular, el método más comúnmente aceptado es el de la
distancia de Mahalanobis. La idea es calcular esta distancia con respecto al vector de medias

5-
del conjunto de datos. Así, aquellas observaciones que más se alejen de este vector de medias
deberían ser investigadas. Un simple gráfico de estas distancias etiquetando las observaciones
más alejadas puede ser suficiente en análisis exploratorio de datos. Existen métodos más so-

-0
fisticados aprovechando que la distancia de Mahalanobis sigue una distribución chi-cuadrado
pero no los tratamos aquí.

19
La función mahalanobis calcula la distancia de Mahalanobis de un conjunto de datos
a un determinado vector. Aprovechando que ya teníamos guardadas la matriz de varianzas-
20
covarianzas y el vector de medias para proporcionárselo a la función. El resultado es un
vector con las 100 distancias al centro. la figura 2.16 identifica los números de fila de todas
las distancias, parece que las observaciones 53 y 64 están más alejadas del resto, aunque no
demasiado.
or

dm <- mahalanobis(ejMetricas, M, S)
plot(dm, type = "n")
ad

text(dm)

Realice la práctica 2.3 cuyo guión se encuentra en el apartado 2.5 para realizar cálculos
rr

matriciales con conjuntos de datos multivariantes.


Bo

2.3.4. Gráficos multivariantes


Vamos a ver algunas herramientas para visualizar múltiples variables de forma conjunta.
La visualización de datos multivariantes es importante en etapas iniciales del análisis. Los
gráficos a menudo nos develan relaciones y patrones que nos pueden dar pistas sobre la
técnica más apropiada para el problema que se quiere abordar. Se presentan los gráficos
más habituales y genéricos, si bien en los capítulos en los que se trata cada técnica se
explicarán gráficos más específicos, aunque basados casi siempre en alguno de los que se
presentan aquí. Aunque trabajemos con datos multivariantes, tenemos que pensar siempre
en representaciones en dos dimensiones, y tener presente qué representa el eje horizontal
140 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

12
53
64

10
8 37 66
42
33 40 70 78
1 1114 26 32 51 56 90
dm

79 74
72
6

5 12 30 38 55 59 71 83
97
23 28 54 61 95
4 8 15 2225 76 88 93
65 69 73 81 96
4

2 6 52

07
18 2427 34 77
16 44 48
43 5860 848689
21 35 46 68 75 91
3 17 29 92 98
2

13 39 50 63 99
100
10 20 36 49 57 82 85
19 31 41 47 67 80
79 87 94

5-
45 62

0 20 40 60 80 100

-0
Index

19
Figura 2.16: Distancias de Mahalanobis del conjunto de datos de ejemplo

X y el eje vertical Y. Estos dos ejes generalmente pueden representar dos variables. Para
20
visualizar más variables, se añaden características gráficas que identifiquen otras variables,
como colores, tamaño de punto, grosor de linea, tipo de línea o símbolo, o etiqueta de texto.
Los distintos gráficos que podemos realizar, se pueden organizar a su vez en facetas (facets) o
rejillas (grids, lattice). En definitiva, matrices de gráficos que organizamos en filas y columnas,
or

donde a su vez estas filas y columnas pueden representar alguna variable cualitativa.
Los gráficos de mosaico son especialmente útiles para explorar muchas variables cualitativas
ad

y estudiar comparativamente los tamaños de las distintas categorías.

La figura 2.17 que se genera con el código a continuación representa las frecuencias
rr

de los distintos grupos de las variables maquina y defecto del conjunto de datos de ejemplo.
Bo

mosaicplot(table(ejDatos$maquina, ejDatos$defecto),
main = "Frecuencias por niveles de factores",
xlab = "Máquina", ylab = "Defectuoso")

Para visualizar dos variables en escala métrica, la visualización más adecuada es el gráfico de
dispersión, en el que los ejes representan la escala de las variables y los datos se representan
como puntos. Se puede añadir una línea de regresión para comprobar de un vistazo el tipo
de relación.

Vamos a comprobar gráficamente si hay algún tipo de relación entre las variables
2.3. ANÁLISIS MULTIVARIANTE 141

Frecuencias por niveles de factores

maquina1 maquina2
Defectuoso

No

07
5-

-0
Máquina

19
Figura 2.17: Gráfico de mosaico para dos variables con dos categorías cada una
20
merma1 y temp del conjunto de datos de ejemplo. La primera de las siguientes expresiones crea
el gráfico sencillo de puntos de la figura 2.18. La siguiente expresión que aparece comentada
produciría al mismo resultado, utilizando los vectores de datos como argumentos en vez de
un objeto fórmula. La tercera expresión produce un gráfico más elaborado (figura 2.19), con
or

el ajuste de una recta de regresión e intervalos de confianza.

plot(merma1 ~ temp, data = ejDatos)


ad

# plot(ejDatos$temp, ejDatos$merma1)

library(ggplot2)
rr

ggplot(ejDatos, aes(temp, merma1)) +


geom_point(col = "steelblue") +
geom_smooth(method = "lm") +
Bo

labs(title = "Gráfico de dispersión con ggplot2",


x = "Temperatura", y = "Merma")

Cuando una de las variables está en escala métrica y la otra en escala de atributo, la re-
presentación más efectiva son los gráficos en los cuales en el eje horizontal se presentan los
niveles del atributo y en el eje vertical la escala de la variable métrica. Bajo esta idea general,
lo que cambia es la representación que se hace dentro del gráfico. Para identificar diferencias
entre grupos, podemos representar gráficos de cajas para cada grupo. Si hay pocos datos de
cada grupo, puede ser más adecuado representar cada dato como un punto y las medias de
cada grupo, posiblemente unidas con líneas.
142 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

6.0
5.5
merma1

5.0

07
4.5

5-
4.0

-0
12 14 16 18

19 temp

Figura 2.18: Gráfico de dispersión sencillo


20
or

En el conjunto de datos de ejemplo la variable maquina es de tipo atributo. Vamos


a ver gráficamente si se aprecian diferencias entre las máquinas para la variable merma1. La
figura 2.20 muestra los gráficos de caja para cada una de las máquinas. Se aprecia cómo,
ad

aunque el valor más alto está en la máquina 2, los valores centrales están menos dispersos.
La máquina 1 presenta mucha más variabilidad, aunque la mediana es más baja. La máquina
2 además presenta un posible valor atípico por debajo. Nótese cómo la expresión utlizada
para producir este gráfico (la primera de las siguientes) es idéntica que la utilizada para el
rr

gráfico de dispersión. R decide en función del tipo de datos almacenado qué gráfico debe
generar. Para ilustrar el gráfico de puntos, creamos un subconjunto solo con las filas que
Bo

toman el valor “Sí” en la variable defecto. Las siguientes expresiones crean un gráfico de
puntos con las medias unidas con líneas de este subconjunto de datos como el que se ve en
la figura 2.21.

plot(merma1 ~ maquina, ejDatos)

errorSi <- subset(ejDatos, defecto == "Sí")


medias <- aggregate(merma1 ~ maquina, errorSi, mean)
ggplot(errorSi, aes(maquina, merma1)) +
geom_point() +
geom_point(data = medias, col = "red") +
2.3. ANÁLISIS MULTIVARIANTE 143

07
Gráfico de dispersión con ggplot2

5-
6.0

-0
5.5

19
Merma

5.0
20
4.5
or
ad

4.0
rr

12 14 16 18
Temperatura
Bo

Figura 2.19: Gráfico de dispersión con el paquete ggplot2


144 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

6.0
5.5
merma1

5.0

07
4.5

5-
4.0

-0
maquina1 maquina2

19 maquina

Figura 2.20: Gráficos de cajas por grupos


20
geom_line(data = medias, group = "maquina", col = "red")
or

Para representar más variables, como se ha indicado anteriormente se puede dotar a los
puntos, líneas, etc. de características gráficas distintas para diferenciar unos grupos de otros,
escalas de color para variables en escala métrica, o crear matrices de gráficos. Estas matri-
ad

ces de gráficos se pueden realizar con los paquetes lattice y ggplot. En este último, se
organizan los gráficos en “facetas”, indicando por qué grupos se hace cada gráfico.
rr

La siguiente expresión crea un gráfico representando todas las variables mediante una
matriz de gráficos con el atributo maquina en columnas y el atributo defecto en filas. Se ha
Bo

añadido una escala de color para los valores de la variable merma2. El resultado se muestra
en la figura 2.22.

ggplot(ejDatos, aes(merma1, temp, col = merma2)) +


geom_point() + facet_grid(defecto ~ maquina)

Por último, es habitual representar todos los pares de variables en una matriz de gráficos en
los que filas y columnas son las distintas variables. La función ggpairs del paquete GGally
(Schloerke et al., 2018) realiza gráficos adecuados para cada par de variables de forma que
se tiene una visión de conjunto de todos los datos.
2.3. ANÁLISIS MULTIVARIANTE 145

07
6.15

5-
-0
6.10
19
merma1

20
6.05
or
ad

6.00
rr

maquina1 maquina2
maquina
Bo

Figura 2.21: Gráfico de medias con medias por grupos


146 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

07
maquina1 maquina2

5-
18

-0
16

No
merma2
14

12
19 7
temp

6
20
5
18 4

16
or


14
ad

12

4.0 4.5 5.0 5.5 6.0 4.0 4.5 5.0 5.5 6.0
rr

merma1

Figura 2.22: Visualización de múltiples variables


Bo
2.3. ANÁLISIS MULTIVARIANTE 147

maquina merma1 merma2 manchas defecto defecto2 temp


50

maquina
40
30
20
10
0
6.0 Cor : −0.152Cor : 0.0728 Cor : 0.478 Cor : 0.878

merma1
5.5
5.0 maquina1: −0.0786
maquina1: 0.26 maquina1: maquina1:
0.56 0.905
4.5
4.0 maquina2: −0.258
maquina2: −0.152 maquina2: 0.414
maquina2: 0.847
8
Cor : 0.0796 Cor : −0.227Cor : −0.128

merma2
7
6 maquina1: 0.155 maquina1: −0.281
maquina1: 0.0232
5

07
4 maquina2: 0.0165 maquina2: −0.173
maquina2: −0.28
3
Cor : −0.0779Cor : 0.0107

manchas
10.0
7.5 maquina1: 0.0156
maquina1: 0.266

5-
5.0 maquina2: maquina2:
−0.21 −0.266
2.5
50
40
30

defecto
20
10
0

-0
50
40
30
20
10
0
1.00 Cor : 0.413

defecto2
0.75
0.50
0.25
0.00
20
18
19 maquina1: 0.463
maquina2: 0.379
20

temp
16
14
12
012345012345 4.04.55.05.56.0 3 4 5 6 7 8 5.0 7.510.0 0 2 4 6 0 2 4 6 0.00
0.25
0.50
0.75
1.0012 14 16 18

Figura 2.23: Gráficos de dispersión por pares


or
ad

El siguiente código realiza un análisis gráfico completo de las variables por pares del
conjunto de datos de ejemplo. Además de los gráficos, se muestran las correlaciones, y se
rr

identifican los grupos según se indica, en este caso por la variable máquina. El resultado es
el que se muestra en la figura 2.23.
Bo

library(GGally)
ggpairs(ejDatos, aes(col = maquina, pch = defecto), progress = FALSE)

Para variables ordinales en escala Likert, una representación visual muy completa es la
que proporciona el paquete likert (Bryer and Speerschneider, 2016) de R, en el que se
representan los porcentajes para cada item en forma de barras como el de la figura 2.24 que
se crea con el siguiente código utilizando datos de ejemplo del propio paquete likert. Véase
la ayuda de la función (?plot.likert) para ver más opciones de visualización.
library(likert)
data(pisaitems)
148 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

Revistas 30% 21% 48%

Periódicos 37% 16% 47%

Ficción 42% 20% 39%

Comics 62% 16% 22%

07
No ficción 61% 20% 19%

100 50 0 50 100

5-
Percentage

Response Never or almost never A few times a year About once a month Several times a month Several times a week

-0
Figura 2.24: Ejemplo de visualización de variable categórica ordinal

19
items29 <- pisaitems[,substr(names(pisaitems), 1,5) == 'ST25Q']
names(items29) <- c("Revistas", "Comics", "Ficción",
20
"No ficción", "Periódicos")
l29 <- likert(items29)
plot(l29)
or

2.3.5. Distribución de probabilidad multivariante


ad

De forma similar a lo expuesto en el apartado 2.2.3 para una característica univariante,


nuestro conjunto de datos multivariante es una muestra de nuestra población que sigue una
distribución de probabilidad multivariante. Así, en vez de tener una variable aleatoria X,
rr

tenemos un vector aleatorio X con m variables aleatorias X1 , . . . , Xm . Cada una de estas va-
riables aleatorias sigue una distribución de probabilidad, y la variable aleatoria multivariante
queda determinada por la de sus componentes.
Bo

La distribución normal multivariante es aquella cuyos componentes siguen una distribución


normal. Tiene especial importancia, ya que algunas técnicas de análisis multivariante re-
quieren que las variables sigan una distribución normal. Denotamos la distribución normal
multivariante como:

X ∼ Np (µ
µ, Σ)
Σ),

donde p es la dimensión de la variable X , µ es el vector de medias y Σ la matriz de varianzas-


covarianzas. La función de densidad tiene la siguiente expresión:
2.3. ANÁLISIS MULTIVARIANTE 149

1.0
0.8
0.02

0.06

0.6
0.1

0.16

07
Z

14
0.
0.12

0.4
0.08
0.04

5-
Y

ou
t 0.2

-0
0.0

19 0.0 0.2 0.4

Figura 2.25: Representación de la distribución normal bivariante


0.6 0.8 1.0
20
( )
−p/2 −1/2 (x − µ )T Σ−1 (x − µ )
X ) = 2π
f (X |Σ
Σ| exp − ,
or

2
con −∞ < Xj < ∞ para todo j.
ad

La distribución normal multivariante tiene algunas propiedades importantes, entre las que
destacamos:
Las combinaciones lineales de sus componentes son también normales.
rr

Los subconjuntos de componentes son también normales


Si dos componentes tienen covarianza cero son independientes, y viceversa
Bo

Las distribuciones condicionales de las componentes son también normales


La representación gráfica de vectores aleatorios se complica al aumentar la dimensión. Para
variables bidimensionales es posible representarlas en tres dimensiones o mediante gráficos
de contorno, como la normal bivariante representada en la figura 2.25.
Para verificar si un conjunto multivariante de datos sigue una distribución normal multiva-
riante, se comprueba que cada uno de sus componentes sigue una distribución normal, como
vimos en el apartado 2.2.3.

Realice la práctica 2.4 cuyo guión se encuentra en el apartado 2.5 para realizar análisis
150 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

exploratorio multivariante.

2.4. Técnicas de análisis multivariante


El análisis multivariante es un conjunto de técnicas estadísticas implementadas para analizar
grandes cantidades de información agrupada en múltiples variables (características) que son
medidas en un determinado grupo de individuos (personas, cosas o entidades sobre las que
se realiza el análisis). La profusión del empleo de estas técnicas se debe a dos motivos

07
fundamentales:
Los fenómenos que caracterizan a una sociedad cada vez más compleja son, por tanto,
más complejos, integrando múltiples relaciones entre variables.

5-
Al incremento en la capacidad del hardware y el software, que hacen posible el proce-
samiento de grandes masas de información.

-0
Las técnicas a aplicar dependerán de cómo se midan las características (variables o atributos)
que componen los conjuntos de datos multivariantes, según se vio en el apartado anterior.

2.4.1. Clasificación de técnicas 19


20
Una primera clasificación de las técnicas multivariantes es diferenciar entre técnicas de de-
pendencia y técnicas de interdependencia. Las técnicas de dependencia buscan explicar
y/o predecir un conjunto de variables respuesta a través de un conjunto de variables predic-
tivas. El ejemplo más sencillo de este tipo de técnicas es el modelo de regresión lineal simple,
or

en el que tenemos una variable respuesta (dependiente) continua y una variable predictiva
(independiente) continua:
ad

Y = β0 + β1 X.

Las técnicas de interdependencia buscan encontrar cómo se relacionan las variables entre
rr

sí, pero sin que necesariamente unas expliquen a otras. Podríamos decir que, en cierto sentido,
las primeras son técnicas predictivas, y las segundas son técnicas descriptivas.
Bo

Una vez sabemos el tipo de técnica a aplicar, la técnica concreta a utilizar va a depender
del tipo de datos de las variables y, en el caso de las técnicas de dependencia, el número
de variables independientes. Así, una clasificación de las técnicas multivariantes tratadas en
este texto sería la siguiente:
Técnicas de interdependencia
• Variables cuantitativas
◦ Análisis de Componentes Principales (PCA, Principal Component Analysis)
◦ Análisis de Conglomerados (Cluster Analysis)
• Variables cualitativas
◦ Análisis de Correspondencias
2.4. TÉCNICAS DE ANÁLISIS MULTIVARIANTE 151

Técnicas de dependencia
• Una variable respuesta cuantitativa
◦ Análisis de la varianza (ANOVA)
• Varias variables respuesta cuantitativas
◦ Análisis de la varianza múltiple (MANOVA)
A continuación se incluye una breve descripción de la pregunta a la que da respuesta cada
técnica, así como un breve ejemplo.

2.4.2. Descripción de las técnicas

07
Análisis de la varianza
El objetivo de esta técnica es determinar cómo influyen una serie de atributos o variables

5-
cualitativas independientes no métricos (factores) sobre variables dependientes métricas.
Ejemplo: ¿afecta de distinta manera a la productividad de una plantación agrícola el

-0
uso de fertilizantes químicos o biológicos? La Variable dependiente sería la productividad
(EUR/m2 ), y la variable independiente (o factor) el tipo de fertilizante (químico o biológico).

19
Cada posible valor del factor es un nivel de éste.

Análisis de Componentes Principales


20
Objetivo: reducir el número de variables que afectan a una serie de individuos perdiendo la
mínima información posible sobre éstos. Para ello se construyen combinaciones lineales de las
variables originales que recojan la mayor parte de la información contenida en éstas. Cada
combinación lineal extraída está incorrelacionada con las anteriores. Las variables originales
or

son métricas.
Ejemplo: agrupar items de una encuesta.
ad

Análisis Cluster
Objetivo: agrupar observaciones o individuos de manera que cada grupo esté constituido por
rr

individuos con valores para ciertas variables muy parecidos; y que los individuos de distintos
grupos presenten valores observados para dichas variables muy diferentes entre sí. Es decir,
Bo

se busca la homogeneidad dentro de los grupos, y la heterogeneidad entre los grupos.


Ejemplo: segmentación de clientes en base a datos disponibles.

Análisis de Correspondencias
Objetivo: es una técnica que permite representar en un espacio multidimensional reducido
(usualmente bidimensional) la relación existente entre las categorías o niveles de dos atributos
o variables no-métricas.
Este análisis mostrará las distancias entre los diferentes niveles de dos atributos, por lo que
sirve para visualizar tablas de contingencia.
152 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

2.4.3. Proceso de aplicación de técnicas


Paso 1. Definir el problema que se quiere resolver.
Tener claro los objetivos ¿qué quiero obtener? ¿a dónde quiero llegar? En función de lo
anterior, ¿qué técnica es más apropiado aplicar?
Paso 2. Preparación de los datos.
Hay que asegurarse de que se dispone de la información muestral (datos) apropiada. La
muestra debe ser suficientemente amplia. Los datos deben ser de calidad: procedimientos de

07
recogida de datos correctos. Las escalas deben ser las adecuadas para la Técnica de Análisis
Multivariante (TAM) elegida.
Paso 3. Cumplimiento de hipótesis básicas.

5-
La aplicación de ciertas TAM está sujeta al cumplimiento de una serie de hipótesis básicas,
tales como cumplimiento de normalidad, homoscedasticidad en los errores de los modelos,

-0
linealidad, etc. Para ello conviene someter a los datos a un análisis exploratorio previo, así
como efectuar una serie de contrastes o test sobre el cumplimiento de las hipótesis.
Paso 4. Aplicación de la TAM
19
Tras aplicarse la TAM, debe comprobarse que la bondad del ajuste del modelo es suficiente
como para garantizar que las conclusiones son sólidas. Además, en los resultados suelen
20
incluirse test y contrastes para verificar que la aplicación de la técnica ha sido correcta.
Paso 5. Análisis de los resultados.
Interpretación de éstos desde el punto de vista económico, y con la óptica de los objetivos
or

que se plantearon en el paso 1. Esta es la fase más importante del proceso: extracción de
conclusiones. Debe valorarse más este paso que el simple procedimiento técnico de utilización
de una TAM determinada.
ad

2.4.4. Ajuste de modelos con R


rr

En este apartado se proporciona una breve descripción de cómo ajustar modelos multivarian-
tes con R.
Bo

2.4.4.1. El modelo de fórmulas


En R tenemos una clase de especial de objetos llamada formula. Una formula consiste en
una expresión con dos términos, a la izquierda y a la derecha del símbolo ~. El término de la
izquierda es una expresión con las variables dependientes. El término de la derecha es una
expresión con las variables independientes. La nomenclatura que se utiliza es simplemente
los nombres de las variables, y cuando se ajuste el modelo, los coeficientes que afecten a
cada variable se mostrarán con el nombre de la variable. Las variables independientes se
pueden conectar con algunos operadores para indicar los términos que se quieren incluir en
el modelo:
2.4. TÉCNICAS DE ANÁLISIS MULTIVARIANTE 153

+ aditivo
: Interacción
* aditivo + interacción
| (Alt Gr + 1) para modelos mixtos
1 Término independiente
. Puede indicar “todas”
… Otros, depende de las funciones
En el lado de las variables dependientes, se pueden incluir con operadores, o en forma de
matriz. En técnicas donde no hay una variable dependiente, puede estar vacío.

07
En la mayoría de técnicas, se especifican los nombres de las variables en el argumento formula
y el conjunto de datos en el argumento data. Los objetos de clase formula se utilizan también
en gráficos, como ya se ha visto.

5-
2.4.4.2. Ajuste de un modelo lineal

-0
A modo de ejemplo, la función lm ajusta modelos lineales, y su estructura es la siguiente:
str(lm)

##
19
## function (formula, data, subset, weights, na.action, method = "qr",
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE,
20
## contrasts = NULL, offset, ...)
A continuación se presenta un ejemplo para entender la mecánica, aunque no se explican los
resultados. En los siguientes capítulos se darán más detalles.
or

El conjunto de datos cars disponible en la instalación base de R tiene dos variables


medidas en una serie de pruebas: velocidad (speed) y distancia de frenado (dist). En el
ad

siguiente código se ajusta un modelo de regresión lineal simple de la distancia de frenado


frente a la velocidad. El objeto que se crea es una lista con los elementos que se muestran
con la función names. El resumen producido con la función summary es otra lista de la que
rr

se pueden extraer datos, como el R2 .

modelo <- lm(dist ~ speed, data = cars)


Bo

names(modelo)

## [1] "coefficients" "residuals" "effects" "rank"


## [5] "fitted.values" "assign" "qr" "df.residual"
## [9] "xlevels" "call" "terms" "model"
resumen.modelo <- summary(modelo)
names(resumen.modelo)

## [1] "call" "terms" "residuals" "coefficients"


## [5] "aliased" "sigma" "df" "r.squared"
## [9] "adj.r.squared" "fstatistic" "cov.unscaled"
154 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

resumen.modelo

##
## Call:
## lm(formula = dist ~ speed, data = cars)
##
## Residuals:
## Min 1Q Median 3Q Max
## -29.069 -9.525 -2.272 9.215 43.201

07
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)

5-
## (Intercept) -17.5791 6.7584 -2.601 0.0123 *
## speed 3.9324 0.4155 9.464 1.49e-12 ***

-0
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
##
##
##
19
Residual standard error: 15.38 on 48 degrees of freedom
Multiple R-squared: 0.6511, Adjusted R-squared: 0.6438
F-statistic: 89.57 on 1 and 48 DF, p-value: 1.49e-12
20
resumen.modelo$r.squared

## [1] 0.6510794
or

Realice la práctica 2.5 cuyo guión se encuentra en el apartado 2.5 para ajustar un
ad

modelo de regresión lineal sencillo.


rr

2.5. Prácticas
Bo

En este apartado se presentan las prácticas a las que se han hecho referencia durante el
capítulo. La reproducibilidad del código ha sido comprobada con la sesión de R que se
detalla en el Prefacio. El lector puede teclear el código o copiarlo y pegarlo en la consola
o el editor. También se puede descargar el script con el código de todas las prácticas con
la siguiente expresión (asumiendo que tenemos una carpeta llamada “practicas” en nuestro
directorio de trabajo):
download.file("http://emilio.lcano.com/b/adr/practicas/02-aed.R",
destfile = "practicas/02-aed.R")
2.5. PRÁCTICAS 155

Práctica 2.1: Diagnóstico y limpieza de datos


Objetivo
En esta práctica vamos a limpiar un conjunto de datos que contiene errores.

Limpiar el espacio de trabajo


Crea un script para esta práctica (o abre el script descargado de la web de material del
curso). En primer lugar, vamos a limpiar el espacio de trabajo para que podamos ir viendo
cómo se van añadiendo los datos de forma clara. Puedes utilizar el icono de la escoba en la

07
pestaña Environment, o ejecutar la siguiente expresión:
rm(list = ls())

5-
Datos

-0
El siguiente fichero contiene datos con varios problemas que debemos identificar y resolver.
Debemos tener una carpeta llamada “datos” en el directorio de trabajo actual (se recomienda
trabajar en un proyecto de RStudio).

19
download.file("http://emilio.lcano.com/b/adr/datos/ejdatos_sucios.csv",
"datos/ejdatos_sucios.csv")
20
Lo importamos al espacio de trabajo. Para los efectos de esta práctica, nos interesa importar
las variables de texto como carácter, y no como factores. El argumento fileEncoding es
necesario en este caso para que la expresión importe bien el texto en cualquier sistema
operativo.
or

ejDatosSucios <- read.csv("datos/ejdatos_sucios.csv",


stringsAsFactors = FALSE,
ad

fileEncoding = "utf8")

Tenemos un data frame con 100 observaciones de 6 variables.


rr

Exploración de datos
Bo

Una vez importados los datos, ya están en el espacio de trabajo y podemos trabajar directa-
mente con ellos. Vamos a obtener un resumen de todas las variables.
summary(ejDatosSucios)

## maquina merma manchas defecto


## Length:100 Min. :3.429 Min. : 2.00 Length:100
## Class :character 1st Qu.:4.378 1st Qu.: 5.00 Class :character
## Mode :character Median :5.037 Median : 7.00 Mode :character
## Mean :4.943 Mean : 7.03
## 3rd Qu.:5.377 3rd Qu.: 8.00
## Max. :7.775 Max. :30.00
156 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

## NA's :1
## defecto2 temp
## Min. :0.00 Length:100
## 1st Qu.:0.00 Class :character
## Median :1.00 Mode :character
## Mean :0.52
## 3rd Qu.:1.00
## Max. :1.00
##

07
y un gráfico de las variables por pares de las variables numéricas:
ejDatosSuciosNum <- subset(ejDatosSucios, select = c(merma, manchas, defecto2, temp))
lattice::splom(ejDatosSuciosNum)

5-
23.88
23.88

-0
temp
10.16

10.16

1.0
19
0.8 0.6 1.0
0.6
defecto2
20
0.4
0.0 0.4 0.2
0.0
30
25 20 30
or

20
manchas
15
10
5 10 5
ad

7 6 7
6
merma
5
rr

4 5 4

Scatter Plot Matrix


Bo

Se identifican tres problemas:


1. La variable temp la ha importado como character, cuando debería ser numérica. Esto
además ha provacado mensajes de advertencia (warning) al intentar hacer el gráfico
de dispersión, que espera variables numéricas.
2. La variable merma tiene un valor perdido (NA).
3. En la variable manchas hay un punto que está muy alejado del resto.
Veamos cómo tratar cada uno de estos problemas. Cuando se trata de un error en los datos,
2.5. PRÁCTICAS 157

tenemos dos opciones: ir al fichero original, modificar el dato erróneo y volver a importarlo;
o modificar el conjunto de datos en R, y guardar el fichero CSV corregido. De esta forma
queda registrado todo lo que se ha hecho. Debemos documentar el código con lo que hacemos
para futura referencia. En primer lugar hacemos una copia en el espacio de trabajo para ir
arreglando los errores y no tocar los datos originales.
## Crear una copia de los datos a modificar
ejDatosLimpios <- ejDatosSucios

Tipo de datos

07
La variable temp debería ser numérica, pero es de tipo carácter. Esto nos va a impedir aplicar
técnicas que requieran hacer cálculos, por ejemplo si intentamos hacer una media:

5-
mean(ejDatosLimpios$temp)

## Warning in mean.default(ejDatosLimpios$temp): argument is not numeric or

-0
## logical: returning NA
## [1] NA
19
Obtenemos NA y un warning indicando que los datos no son del tipo que se esperaba para
hacer una media. Aquí podemos pensar que obtenemos NA porque hay valores perdidos,
20
pero si añadimos el argumento para no tener en cuenta dichos valores, obtenemos el mismo
resultado:
mean(ejDatosLimpios$temp, na.rm = TRUE)
or

## Warning in mean.default(ejDatosLimpios$temp, na.rm = TRUE): argument is not


## numeric or logical: returning NA
ad

## [1] NA
¿Qué puede haber pasado? ¡Porque aparentemente son números!:
ejDatosLimpios$temp
rr

## [1] "14.68" "18.6" "13.44" "18.03" "10.74" "17.24" "12.57" "13.09"


Bo

## [9] "11.81" "13.31" "17.06" "10.16" "14.96" "12.13" "14.74" "16,34"


## [17] "15.22" "14.66" "13.85" "15.18" "12.99" "12.12" "15.65" "14.01"
## [25] "14.55" "10.97" "12.73" "11.25" "12.39" "12.82" "16.7" "15.69"
## [33] "16.37" "15.67" "14.19" "16.05" "18.19" "12.74" "14.6" "18.08"
## [41] "17.87" "13.13" "15.64" "19.1" "16.11" "13.33" "14.08" "14.77"
## [49] "16.61" "17.63" "15.14" "17.03" "11.97" "12.81" "12.05" "13.86"
## [57] "16.75" "17.37" "11.72" "19.05" "16.47" "23.88" "14.85" "15.72"
## [65] "18.79" "14.46" "10.54" "18.57" "16.28" "10.78" "13.98" "15.27"
## [73] "11.47" "18.43" "15.86" "13.66" "17.36" "15.99" "18.76" "14.28"
## [81] "11.15" "10.25" "15.84" "16" "11.72" "15.58" "10.18" "14.12"
## [89] "15.68" "12.04" "14.62" "15.98" "12.05" "16.48" "17.71" "10.84"
158 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

## [97] "11.9" "17.47" "17.86" "13.51"


Podemos convertir todo el vector en numérico y ver qué pasa:
as.numeric(ejDatosLimpios$temp)

## Warning: NAs introducidos por coerción


## [1] 14.68 18.60 13.44 18.03 10.74 17.24 12.57 13.09 11.81 13.31 17.06
## [12] 10.16 14.96 12.13 14.74 NA 15.22 14.66 13.85 15.18 12.99 12.12
## [23] 15.65 14.01 14.55 10.97 12.73 11.25 12.39 12.82 16.70 15.69 16.37

07
## [34] 15.67 14.19 16.05 18.19 12.74 14.60 18.08 17.87 13.13 15.64 19.10
## [45] 16.11 13.33 14.08 14.77 16.61 17.63 15.14 17.03 11.97 12.81 12.05
## [56] 13.86 16.75 17.37 11.72 19.05 16.47 23.88 14.85 15.72 18.79 14.46
## [67] 10.54 18.57 16.28 10.78 13.98 15.27 11.47 18.43 15.86 13.66 17.36

5-
## [78] 15.99 18.76 14.28 11.15 10.25 15.84 16.00 11.72 15.58 10.18 14.12
## [89] 15.68 12.04 14.62 15.98 12.05 16.48 17.71 10.84 11.90 17.47 17.86

-0
## [100] 13.51
Nótese la diferencia con el output anterior: antes estaban entre comillas porque el vector era

19
de tipo carácter. Ahora no salen comillas porque es de tipo numérico.
Y vemos que ha devuelto un valor NA porque no era un número. En particular, el elemento
número 16 del vector es “16,34”, con la coma decimal. El resto de números usa el punto
20
decimal, como tiene que ser para la función read.csv. Por tanto, para corregir este error
podemos sustituir todas las comas por puntos (podría haber más de un valor) y después
convertir a numérico11 :
ejDatosLimpios$temp <- gsub(",", ".", ejDatosLimpios$temp)
or

ejDatosLimpios$temp <- as.numeric(ejDatosLimpios$temp)

Y vemos que ya podemos trabajar con el vector numérico:


ad

summary(ejDatosLimpios$temp)

## Min. 1st Qu. Median Mean 3rd Qu. Max.


rr

## 10.16 12.79 14.76 14.78 16.47 23.88


Bo

Valores atípicos
La variable manchas parece que tiene un punto muy alejado del resto. En el resumen también
se ve que el máximo está lejos de los valores centrales. Lo podemos comprobar numérica y
gráficamente con el gráfico de cajas:
summary(ejDatosLimpios$manchas)

## Min. 1st Qu. Median Mean 3rd Qu. Max.


## 2.00 5.00 7.00 7.03 8.00 30.00
11
La función gsub sustituye unas cadenas de caracteres por otras en vectores de tipo carácter, véase la
ayuda en ?gsub.
2.5. PRÁCTICAS 159

boxplot(ejDatosLimpios$manchas)
30
25
20
15

07
10

5-
5

-0
En ete caso hay que actuar con mucha cautela, efectivamente el máximo de 30 es un candidato

19
a ser un valor atípico. Habría que investigar si ha sido un error y ver si hay que cambiar
por otro, o eliminar la observación para los futuros análisis. Podemos utilizar el resultado
del gráfico de cajas para examinar y filtrar los datos atípicos. Al guardar el resultado de la
20
función boxplot en un objeto:
bp <- boxplot(ejDatosLimpios$manchas)

podemos acceder a los valores de las observaciones atípicas, que se guardan en el elemento
or

out de la lista que se crea:


bp$out
ad

## [1] 14 30 14
rr

y filtrar el conjunto de datos para ver cuáles son esas observaciones. Con la función which
podemos averiguar los índices de las observaciones candidatas a ser valores atípicos:
Bo

atipicos <- which(ejDatosLimpios$manchas %in% bp$out)


ejDatosLimpios[atipicos, ]

## maquina merma manchas defecto defecto2 temp


## 39 maquina1 5.090 14 Sí 1 14.60
## 50 maquina1 5.187 30 Sí 1 17.63
## 89 maquina2 4.943 14 No 0 15.68

Si quisiéramos eliminarlos del conjunto de datos, podríamos hacer:


ejDatosLimpisimos <- ejDatosLimpios[-atipicos, ]
160 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

Valores perdidos
Según vimos en el resumen, tenemos un valor perdido (NA) en la variable merma.
summary(ejDatosLimpios$merma)

## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's


## 3.429 4.378 5.037 4.943 5.377 7.775 1
Esto provoca, entre otras cosas, que los cálculos devuelvan también valores perdidos:
mean(ejDatosLimpios$merma)

07
## [1] NA
A menos que indiquemos expresamente que los obvie:

5-
mean(ejDatosLimpios$merma, na.rm = TRUE)

-0
## [1] 4.943303
Supongamos que el dato perdido en cuestión existe, pero por alguna razón no ha llegado al

19
fichero de datos. Primero querremos ver a qué observación se refiere ese valor perdido. Lo
podemos hacer seleccionando las filas del data frame para las que la variable merma es NA:
ejDatosLimpios[is.na(ejDatosLimpios$merma), ]
20
## maquina merma manchas defecto defecto2 temp
## 4 maquina1 NA 8 Sí 1 18.03
or

Es la observación 4. Imaginemos que al investigar qué paso encontramos que nos saltamos
el dato de la observación número 4 al meterlo en la hoja de cálculo (supongamos que el dato
es 0.188).
ad

## corregir el dato faltante


## Incluir comentarios sobre lo que se ha hecho
ejDatosLimpios$merma[4] <- 0.188
rr

Ahora ya podemos trabajar normalmente con la variable:


Bo

summary(ejDatosLimpios$merma)

## Min. 1st Qu. Median Mean 3rd Qu. Max.


## 0.188 4.343 5.026 4.896 5.377 7.775
mean(ejDatosLimpios$merma)

## [1] 4.89575

Exportación final
Por último, guardamos el fichero arreglado, que es el que se debe utilizar en sucesivos análisis.
2.5. PRÁCTICAS 161

## Guardar el fichero limpio con el que trabajaremos


write.csv2(ejDatosLimpios, "datos/ejdatos_limpio.csv", row.names = FALSE)

Práctica 2.2: Análisis exploratorio univariante


Objetivo
En esta práctica vamos a obtener resúmenes sencillos de datos y gráficos sencillos.

07
Limpiar el espacio de trabajo
Crea un script para esta práctica (o abre el script descargado de la web de material del
curso). Antes de empezar a explorar datos, vamos a limpiar el espacio de trabajo para que

5-
podamos ir viendo cómo se van añadiendo los datos de forma clara. Puedes utilizar el icono
de la escoba en la pestaña Environment, o ejecutar la siguiente expresión:

-0
rm(list = ls())

Datos
19
Vamos a trabajar con el conjunto de datos ejdatos. Lo podemos descargar con la siguiente
expresión. Debemos tener una carpeta llamada “datos” en el directorio de trabajo actual (se
20
recomienda trabajar en un proyecto de RStudio).
download.file("http://emilio.lcano.com/b/adr/p/datos/ejdatos.csv", "datos/ejdatos.csv")

ejDatos <- read.csv2("datos/ejdatos.csv",


or

fileEncoding = "utf8")

Exploremos el conjunto de datos:


ad

str(ejDatos)

## 'data.frame': 100 obs. of 6 variables:


rr

## $ maquina : Factor w/ 2 levels "maquina1","maquina2": 1 1 1 1 1 1 1 1 1 1 ...


## $ merma : num 5.38 6.01 4.82 6.01 3.89 ...
Bo

## $ manchas : int 4 8 8 8 10 8 2 5 8 7 ...


## $ defecto : Factor w/ 2 levels "No","Sí": 2 2 1 2 1 2 1 1 1 1 ...
## $ defecto2: int 1 1 0 1 0 1 0 0 0 0 ...
## $ temp : num 14.7 18.6 13.4 18 10.7 ...
head(ejDatos)

## maquina merma manchas defecto defecto2 temp


## 1 maquina1 5.376656 4 Sí 1 14.68176
## 2 maquina1 6.007177 8 Sí 1 18.59629
## 3 maquina1 4.822433 8 No 0 13.44364
## 4 maquina1 6.014084 8 Sí 1 18.02711
162 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

## 5 maquina1 3.891563 10 No 0 10.73874


## 6 maquina1 5.379198 8 Sí 1 17.23989
tail(ejDatos)

## maquina merma manchas defecto defecto2 temp


## 95 maquina2 5.912731 6 Sí 1 17.71192
## 96 maquina2 3.676500 7 No 0 10.83811
## 97 maquina2 4.227713 8 No 0 11.90123

07
## 98 maquina2 5.136236 7 Sí 1 17.46687
## 99 maquina2 5.702205 5 Sí 1 17.85712
## 100 maquina2 3.896857 9 No 0 13.51478

5-
-0
Tablas de frecuencias
19
20
Tabla de frecuencias de una variable:
table(ejDatos$defecto)
or

##
## No Sí
ad

## 48 52

Tabla de frecuencias conjunta de dos atributos:


rr

table(ejDatos$defecto, ejDatos$maquina)
Bo

##
## maquina1 maquina2
## No 25 23
## Sí 25 27

Representación gráfica
barplot(table(ejDatos$manchas))
2.5. PRÁCTICAS 163

25
20
15
10

07
5

5-
0

2 3 4 5 6 7 8 9 10 11 14

-0
pie(table(ejDatos$defecto))

19
20
or
ad
rr

No
Bo


datoshist <- hist(ejDatos$merma)
164 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

Histogram of ejDatos$merma
30
25
20
Frequency

15

07
10

5-
5
0

-0
3 4 5 6 7 8

cbind(datoshist$mids, datoshist$counts)
19
ejDatos$merma
20
## [,1] [,2]
## [1,] 3.25 1
## [2,] 3.75 11
or

## [3,] 4.25 18
## [4,] 4.75 18
## [5,] 5.25 32
ad

## [6,] 5.75 10
## [7,] 6.25 8
## [8,] 6.75 1
## [9,] 7.25 0
rr

## [10,] 7.75 1
Bo

Medidas de posición

summary(ejDatos$merma)

## Min. 1st Qu. Median Mean 3rd Qu. Max.


## 3.429 4.393 5.041 4.954 5.378 7.775
median(ejDatos$merma)

## [1] 5.04131
Representación gráfica
2.5. PRÁCTICAS 165

boxplot(merma ~ maquina, data = ejDatos)


7
6
merma

07
5

5-
4

-0
maquina1 maquina2

19 maquina
20
Varianza y desviación típica

var(ejDatos$merma)

## [1] 0.6008204
or

sd(ejDatos$merma)
ad

## [1] 0.775126

Práctica 2.3: Cálculo matricial sobre conjuntos de datos


rr

Introducción
Comenzamos como siempre limpiando el espacio de trabajo para que podamos ir viendo
Bo

cómo se van añadiendo los datos de forma clara. Puedes utilizar el icono de la escoba en la
pestaña Environment, o ejecutar la siguiente expresión:
rm(list = ls())

Vamos a realizar operaciones matriciales utilizando el conjunto de ejemplos irisde R.


str(iris)

## 'data.frame': 150 obs. of 5 variables:


## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
166 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
head(iris)

## Sepal.Length Sepal.Width Petal.Length Petal.Width Species


## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa

07
## 5 5.0 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa

5-
Seleccionamos las columnas numéricas solamente, ya que lo que nos interesa es realizar
operaciones matemáticas con las matrices.

-0
matriz <- as.matrix(iris[, 1:4])
head(matriz)

##
##
##
[1,]
[2,]
5.1
4.9
3.5
3.0
19
Sepal.Length Sepal.Width Petal.Length Petal.Width
1.4
1.4
0.2
0.2
20
## [3,] 4.7 3.2 1.3 0.2
## [4,] 4.6 3.1 1.5 0.2
## [5,] 5.0 3.6 1.4 0.2
## [6,] 5.4 3.9 1.7 0.4
or

Trasponer matriz
ad

matriztraspuesta <- t(matriz)


head(matriztraspuesta[, 1:5])

## [,1] [,2] [,3] [,4] [,5]


rr

## Sepal.Length 5.1 4.9 4.7 4.6 5.0


## Sepal.Width 3.5 3.0 3.2 3.1 3.6
Bo

## Petal.Length 1.4 1.4 1.3 1.5 1.4


## Petal.Width 0.2 0.2 0.2 0.2 0.2

Tipificar columnas de una matriz

matriztipificada <- scale(matriz)


head(matriztipificada)

## Sepal.Length Sepal.Width Petal.Length Petal.Width


## [1,] -0.8976739 1.01560199 -1.335752 -1.311052
## [2,] -1.1392005 -0.13153881 -1.335752 -1.311052
2.5. PRÁCTICAS 167

## [3,] -1.3807271 0.32731751 -1.392399 -1.311052


## [4,] -1.5014904 0.09788935 -1.279104 -1.311052
## [5,] -1.0184372 1.24503015 -1.335752 -1.311052
## [6,] -0.5353840 1.93331463 -1.165809 -1.048667

Matriz de varianzas-covarianzas

varcovar <- var(matriz)


varcovar

07
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Sepal.Length 0.6856935 -0.0424340 1.2743154 0.5162707
## Sepal.Width -0.0424340 0.1899794 -0.3296564 -0.1216394

5-
## Petal.Length 1.2743154 -0.3296564 3.1162779 1.2956094
## Petal.Width 0.5162707 -0.1216394 1.2956094 0.5810063

-0
Matriz de correlaciones

correlaciones <- cor(matriz)


correlaciones
19
20
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Sepal.Length 1.0000000 -0.1175698 0.8717538 0.8179411
## Sepal.Width -0.1175698 1.0000000 -0.4284401 -0.3661259
## Petal.Length 0.8717538 -0.4284401 1.0000000 0.9628654
or

## Petal.Width 0.8179411 -0.3661259 0.9628654 1.0000000


var(matriztipificada)
ad

## Sepal.Length Sepal.Width Petal.Length Petal.Width


## Sepal.Length 1.0000000 -0.1175698 0.8717538 0.8179411
## Sepal.Width -0.1175698 1.0000000 -0.4284401 -0.3661259
rr

## Petal.Length 0.8717538 -0.4284401 1.0000000 0.9628654


## Petal.Width 0.8179411 -0.3661259 0.9628654 1.0000000
Bo

Invertir matriz

matrizinversa <- solve(varcovar)


matrizinversa

## Sepal.Length Sepal.Width Petal.Length Petal.Width


## Sepal.Length 10.314699 -6.713189 -7.314483 5.739951
## Sepal.Width -6.713189 11.058417 6.480589 -6.170932
## Petal.Length -7.314483 6.480589 10.031679 -14.513767
## Petal.Width 5.739951 -6.170932 -14.513767 27.693635
168 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

varcovar%*%matrizinversa

## Sepal.Length Sepal.Width Petal.Length Petal.Width


## Sepal.Length 1.000000e+00 -1.332268e-15 8.881784e-16 1.776357e-15
## Sepal.Width -2.220446e-16 1.000000e+00 0.000000e+00 0.000000e+00
## Petal.Length 1.776357e-15 0.000000e+00 1.000000e+00 0.000000e+00
## Petal.Width 4.440892e-16 4.440892e-16 -1.776357e-15 1.000000e+00
Nótese la forma de multiplicar matrices

07
Determinante de una matriz

det(varcovar)

5-
## [1] 0.00191273

-0
det(matrizinversa)

## [1] 522.813
det(varcovar%*%matrizinversa)

## [1] 1
19
20
2.5.0.1. Diagonal de una matriz

diag(varcovar)
or

## Sepal.Length Sepal.Width Petal.Length Petal.Width


## 0.6856935 0.1899794 3.1162779 0.5810063
ad

Funciona para matrices no cuadradas


diag(matriz)
rr

## [1] 5.1 3.0 1.3 0.2


Bo

Se puee utilizar para crear matrices identidad, con ceros salvo la diagonal:
diag(5)

## [,1] [,2] [,3] [,4] [,5]


## [1,] 1 0 0 0 0
## [2,] 0 1 0 0 0
## [3,] 0 0 1 0 0
## [4,] 0 0 0 1 0
## [5,] 0 0 0 0 1
diag(2:4)
2.5. PRÁCTICAS 169

## [,1] [,2] [,3]


## [1,] 2 0 0
## [2,] 0 3 0
## [3,] 0 0 4

Para calcular la traza de una matriz:


sum(diag(varcovar))

## [1] 4.572957

07
Autovalores y autovectores de una matriz

5-
eigen(varcovar)

## eigen() decomposition

-0
## $values
## [1] 4.22824171 0.24267075 0.07820950 0.02383509
##
##
##
##
$vectors

[1,]
[,1] [,2]
19 [,3] [,4]
0.36138659 -0.65658877 -0.58202985 0.3154872
20
## [2,] -0.08452251 -0.73016143 0.59791083 -0.3197231
## [3,] 0.85667061 0.17337266 0.07623608 -0.4798390
## [4,] 0.35828920 0.07548102 0.54583143 0.7536574
or

Matriz de distancias
ad

d <-dist(matriz)
as.matrix(d)[1:5, 1:5]

## 1 2 3 4 5
rr

## 1 0.0000000 0.5385165 0.509902 0.6480741 0.1414214


## 2 0.5385165 0.0000000 0.300000 0.3316625 0.6082763
Bo

## 3 0.5099020 0.3000000 0.000000 0.2449490 0.5099020


## 4 0.6480741 0.3316625 0.244949 0.0000000 0.6480741
## 5 0.1414214 0.6082763 0.509902 0.6480741 0.0000000

Práctica 2.4: Análisis exploratorio multivariante


Crea un script para esta práctica (o abre el script descargado de la web de material del
curso). Antes de empezar a crear estructuras de datos, vamos a limpiar el espacio de trabajo
para que podamos ir viendo cómo se van añadiendo los datos de forma clara. Puedes utilizar
el icono de la escoba en la pestaña Environment, o ejecutar la siguiente expresión:
170 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

rm(list = ls())

Datos
Vamos a trabajar con el conjunto de datos ejdatos
download.file("http://emilio.lcano.com/b/adr/p/datos/ejdatos.csv", "datos/ejdatos.csv")

ejDatos <- read.csv2("datos/ejdatos.csv")

07
Exploremos el conjunto de datos:
str(ejDatos)

5-
## 'data.frame': 100 obs. of 6 variables:
## $ maquina : Factor w/ 2 levels "maquina1","maquina2": 1 1 1 1 1 1 1 1 1 1 ...
## $ merma : num 5.38 6.01 4.82 6.01 3.89 ...

-0
## $ manchas : int 4 8 8 8 10 8 2 5 8 7 ...
## $ defecto : Factor w/ 2 levels "No","Sí": 2 2 1 2 1 2 1 1 1 1 ...
## $ defecto2: int 1 1 0 1 0 1 0 0 0 0 ...
## $ temp
head(ejDatos)
19
: num 14.7 18.6 13.4 18 10.7 ...
20
## maquina merma manchas defecto defecto2 temp
## 1 maquina1 5.376656 4 Sí 1 14.68176
## 2 maquina1 6.007177 8 Sí 1 18.59629
## 3 maquina1 4.822433 8 No 0 13.44364
or

## 4 maquina1 6.014084 8 Sí 1 18.02711


## 5 maquina1 3.891563 10 No 0 10.73874
## 6 maquina1 5.379198 8 Sí 1 17.23989
ad

tail(ejDatos)

## maquina merma manchas defecto defecto2 temp


rr

## 95 maquina2 5.912731 6 Sí 1 17.71192


## 96 maquina2 3.676500 7 No 0 10.83811
Bo

## 97 maquina2 4.227713 8 No 0 11.90123


## 98 maquina2 5.136236 7 Sí 1 17.46687
## 99 maquina2 5.702205 5 Sí 1 17.85712
## 100 maquina2 3.896857 9 No 0 13.51478

Correlación

cov(ejDatos[, c(2,3,6)])

## merma manchas temp


## merma 0.60082036 -0.05769031 1.83199012
2.5. PRÁCTICAS 171

## manchas -0.05769031 5.32080808 -0.07149528


## temp 1.83199012 -0.07149528 6.55382473
micor <- cor(ejDatos[, c(2,3,6)])
micor

## merma manchas temp


## merma 1.00000000 -0.03226575 0.92321616
## manchas -0.03226575 1.00000000 -0.01210713

07
## temp 0.92321616 -0.01210713 1.00000000

Representación gráfica

5-
library(corrplot)

-0
## corrplot 0.84 loaded
corrplot(micor, method = "ellipse")
19
20
manchas
merma

temp

1
or

0.8
merma
ad

0.6

0.4
rr

0.2

manchas 0
Bo

−0.2

−0.4

−0.6
temp
−0.8

−1

plot(merma ~ temp, data = ejDatos)


172 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

7
6
merma

07
4

5-
10 12 14 16 18 20 22 24

-0
temp

Gráficos multivariantes
Utilizando el paquete lattice:
19
20
library(lattice)
xyplot(merma ~ temp | maquina, data = ejDatos)
10 15 20
or

maquina1 maquina2
ad

7
rr

6
merma

Bo

10 15 20

temp
2.5. PRÁCTICAS 173

Utilizando el paquete ggplot2 (Grammar of graphics, Wickham et al. (2019a)).


library(ggplot2)
ggplot(ejDatos, aes(temp, merma)) + geom_point() + geom_smooth() + facet_grid(maquina~d

## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

No Sí

07
7

maquina1
6

5-
5

-0
4
merma

7
19

maquina2
20
6

4
or

10 15 20 10 15 20
temp
ad

Práctica 2.5: Ajuste de un modelo lineal


rr

Objetivo
Bo

En esta práctica vamos a ajustar un sencillo modelo de regresión lineal

Limpiar el espacio de trabajo

Crea un script para esta práctica (o abre el script descargado de la web de material del
curso). Antes de empezar a crear estructuras de datos, vamos a limpiar el espacio de trabajo
para que podamos ir viendo cómo se van añadiendo los datos de forma clara. Puedes utilizar
el icono de la escoba en la pestaña Environment, o ejecutar la siguiente expresión:
rm(list = ls())
174 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

Datos
Vamos a trabajar con el conjunto de datos de recursos humanos.
library(readxl)
RRHH <- read_excel("datos/RRHH.xlsx")

Exploremos el conjunto de datos:


str(RRHH)

## Classes 'tbl_df', 'tbl' and 'data.frame': 100 obs. of 10 variables:

07
## $ nivel_satisfaccion : num 0.22 0.89 0.63 0.8 0.42 0.77 0.51 0.15 0.98 0.19 ..
## $ ultima_evaluacion : num 0.98 0.65 0.76 0.96 0.48 0.82 0.5 0.75 0.99 1 ...
## $ numero_proyectos : num 4 5 4 3 2 4 5 3 3 4 ...

5-
## $ promedio_horas_mensuales: num 185 195 245 161 155 217 176 259 235 192 ...
## $ antiguedad : num 3 6 3 3 3 5 5 8 3 4 ...
## $ accidente : chr "No" "No" "No" "No" ...

-0
## $ abandona : chr "No" "Sí" "No" "No" ...
## $ promocionado : chr "No" "No" "No" "No" ...
## $ departamento
## $ salario
head(RRHH)
19
: chr "soporte" "soporte" "otro" "ingeniería" ...
: chr "bajo" "bajo" "bajo" "bajo" ...
20
## # A tibble: 6 x 10
## nivel_satisfacc~ ultima_evaluaci~ numero_proyectos promedio_horas_~
## <dbl> <dbl> <dbl> <dbl>
## 1 0.22 0.98 4 185
or

## 2 0.89 0.65 5 195


## 3 0.63 0.76 4 245
ad

## 4 0.8 0.96 3 161


## 5 0.42 0.48 2 155
## 6 0.77 0.82 4 217
## # ... with 6 more variables: antiguedad <dbl>, accidente <chr>,
rr

## # abandona <chr>, promocionado <chr>, departamento <chr>, salario <chr>


Bo

Ajuste del modelo

modelo <- lm(nivel_satisfaccion ~ ultima_evaluacion + numero_proyectos + promedio_horas_


data = RRHH)

summary(modelo)

##
## Call:
## lm(formula = nivel_satisfaccion ~ ultima_evaluacion + numero_proyectos +
## promedio_horas_mensuales, data = RRHH)
2.5. PRÁCTICAS 175

##
## Residuals:
## Min 1Q Median 3Q Max
## -0.51849 -0.16055 0.01814 0.19965 0.43562
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.4635894 0.1250164 3.708 0.000349 ***
## ultima_evaluacion 0.0988790 0.1664402 0.594 0.553855
## numero_proyectos -0.0565945 0.0241336 -2.345 0.021084 *

07
## promedio_horas_mensuales 0.0011603 0.0005949 1.950 0.054055 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

5-
##
## Residual standard error: 0.2515 on 96 degrees of freedom
## Multiple R-squared: 0.06981, Adjusted R-squared: 0.04074

-0
## F-statistic: 2.401 on 3 and 96 DF, p-value: 0.07245
selección automática de variables
modelo2 <- step(modelo)

## Start: AIC=-272.12
19
20
## nivel_satisfaccion ~ ultima_evaluacion + numero_proyectos + promedio_horas_mensuales
##
## Df Sum of Sq RSS AIC
## - ultima_evaluacion 1 0.02233 6.0962 -273.75
or

## <none> 6.0738 -272.12


## - promedio_horas_mensuales 1 0.24066 6.3145 -270.23
## - numero_proyectos 1 0.34793 6.4218 -268.55
ad

##
## Step: AIC=-273.75
## nivel_satisfaccion ~ numero_proyectos + promedio_horas_mensuales
rr

##
## Df Sum of Sq RSS AIC
Bo

## <none> 6.0962 -273.75


## - promedio_horas_mensuales 1 0.31503 6.4112 -270.71
## - numero_proyectos 1 0.32561 6.4218 -270.55
summary(modelo2)

##
## Call:
## lm(formula = nivel_satisfaccion ~ numero_proyectos + promedio_horas_mensuales,
## data = RRHH)
##
## Residuals:
176 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

## Min 1Q Median 3Q Max


## -0.51740 -0.17056 0.01958 0.20290 0.42770
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.4984906 0.1099842 4.532 1.67e-05 ***
## numero_proyectos -0.0530253 0.0232958 -2.276 0.0250 *
## promedio_horas_mensuales 0.0012664 0.0005656 2.239 0.0274 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

07
##
## Residual standard error: 0.2507 on 97 degrees of freedom
## Multiple R-squared: 0.06639, Adjusted R-squared: 0.04714

5-
## F-statistic: 3.449 on 2 and 97 DF, p-value: 0.03573

-0
19
20
Representación gráfica - validación
plot(nivel_satisfaccion ~ numero_proyectos + promedio_horas_mensuales,
data = RRHH)
or
1.0

ad
0.8
nivel_satisfaccion

rr
0.6
Bo 0.4
0.2

2 3 4 5 6

numero_proyectos
2.5. PRÁCTICAS 177

1.0
0.8
nivel_satisfaccion

0.6
0.4

07
0.2

5-
100 150 200 250

-0
promedio_horas_mensuales
par(mfrow=c(2,2))
plot(modelo2) 19
20 Standardized residuals
or

Residuals vs Fitted Normal Q−Q


2
Residuals

−0.6 0.0

ad
0
−2

61 8 76 861
76

0.40 0.50 0.60 0.70 −2 −1 0 1 2


rr

Fitted values Theoretical Quantiles


Bo
Standardized residuals

Standardized residuals

Scale−Location Residuals vs Leverage


8 76
2

61 29
1.0

Cook's distance
−2
0.0

8 76

0.40 0.50 0.60 0.70 0.00 0.02 0.04 0.06 0.08

Fitted values Leverage


178 CAPÍTULO 2. ANÁLISIS EXPLORATORIO DE DATOS CON R

Predicción

predict(modelo2, data.frame(numero_proyectos = 1, promedio_horas_mensuales =200),


interval = "prediction")

## fit lwr upr


## 1 0.6987388 0.1824442 1.215033
predict(modelo2, data.frame(numero_proyectos = 1, promedio_horas_mensuales =200),
interval = "confidence")

07
## fit lwr upr
## 1 0.6987388 0.5609063 0.8365714

5-
-0
19
20
or
ad
rr
Bo
07
5-
Parte II

-0
19
Técnicas multivariantes
20
or
ad
rr
Bo

179
Bo
rr
ad
or
20
19
-0
5-
07
Capítulo 3

07
Análisis de la varianza con R

5-
3.1. Introducción

-0
El análisis de la varianza es una técnica estadística de análisis de dependencias, donde se bus-
ca explicar una o varias variables cuantitativas a partir de una o varias variables cualitativas
19
o factores. Es decir, buscamos un modelo del tipo:
20
X) + ε
Y = f (X (3.1)

donde Y es un vector de variables respuesta numéricas que queremos explicar o predecir,


y X es un vector de variables predictivas cualitativas con las que pretendemos explicar las
or

variables respuesta. Como todo modelo estadístico, está sujeto a un error ε.


En realidad el análisis de la varianza incluye un conjunto amplio de técnicas cuyo análisis
varía ligeramente según la naturaleza y el número de variables en los vectores aleatorios Y y
ad

X . En los apartados siguientes se irán detallando los distintos modelos desde el más sencillo
al más complejo. A medida que se avance en los modelos, se presentan más ejemplos y menos
teoría, ya que el fundamento es muy similar y se puede consultar en la bibliografía citada.
rr

La técnica del análisis de la varianza se puede abordar desde dos perspectivas: explicativa
y predictiva. Desde una perspectiva explicativa, se puede aplicar la técnica para realizar es-
Bo

tudios observacionales a datos ya existentes. Estos estudios observacionales confirmarán la


relación entre las variables. Desde el punto de vista predictivo, se pueden diseñar experimen-
tos antes de la recogida de datos. Estos estudios predictivos permiten confirmar la relación
de causa-efecto entre las variables.

3.2. Análisis de la varianza de un factor


El caso más sencillo que podemos aplicar al modelo general (3.1), es aquel en el que tenemos
una única variable continua en el vector aleatorio Y y una sola variable cualitativa (factor)
en el vector aleatorio X con k > 2 niveles. Cuando la variable cualitativa tiene solamente dos

181
182 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

Tabla 3.1: Tiempo de permanencia en la tienda


tipo tiempo
fria 37.384
fria 76.250
fria 13.499
fria 38.632
fria 78.729
fria 14.572
calida 5.314

07
calida 5.711
calida 27.511
calida 56.797

5-
calida 15.230
calida 40.784
calida_intensa 2.416

-0
calida_intensa 6.442
calida_intensa 6.833

19
calida_intensa 27.010
calida_intensa
calida_intensa
6.180
8.853
20
posibles niveles, podemos utilizar simplemente contrastes de hipótesis para la comparación
de poblaciones mediante test paramétricos como el de la t de Student, o no paramétricos
or

como el test de Wilcoxon, o el test de Wilcoxon-Mann-Whitney, que no se tratan en este


texto.
ad

Una empresa de comercio minorista quiere estudiar el efecto que tiene el tipo de
iluminación en sus tiendas en el tiempo que pasan los clientes en la misma. Para ello diseña
rr

un experimento en el que selecciona a doce clientes de tres tiendas distintas (suponemos que
un cliente siempre compra en la misma tienda). Se asigna aleatoriamente a cada tienda un
tipo de iluminación de entre las siguientes: fría, cálida suave, cálida intensa. El tiempo que
Bo

pasa cada cliente en la tienda se recoge en la tabla 3.1, que están guardados en el data frame
danova1 . Vamos a utilizar este ejemplo a lo largo de este capítulo. El primer paso en toda
técnica estadística es hacer un análisis exploratorio. Como son muy pocos puntos por cada
grupo, vamos a obtener un resumen numérico y a representarlos todos con un gráfico de
puntos (figura 3.1).
A la vista de las medias parece que el tiempo con luz cálida intensa es menor. En los otros
dos no está tan claro que haya diferencia. Por otra parte parece que hay menos variabilidad
con luz cálida intensa. Una vez ajustado el modelo lo comprobaremos numéricamente.

tapply(danova$tiempo, danova$tipo, summary)


3.2. ANÁLISIS DE LA VARIANZA DE UN FACTOR 183

80

60
tiempo

40

07
5-
20

-0
0
calida
19 calida_intensa

Figura 3.1: Gráfico de puntos del experimento en tiendas


fria
20
## $calida
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 5.314 8.091 21.370 25.224 37.466 56.797
or

##
## $calida_intensa
## Min. 1st Qu. Median Mean 3rd Qu. Max.
ad

## 2.416 6.245 6.638 9.622 8.348 27.010


##
## $fria
rr

## Min. 1st Qu. Median Mean 3rd Qu. Max.


## 13.50 20.27 38.01 43.18 66.85 78.73
Bo

lattice::dotplot(tiempo ~ tipo, data = danova)

3.2.1. Modelo
Tenemos una variable Y que toma valores reales y una variable cualitativa o factor X con
niveles 1, 2, . . . , i, . . . , k. La variable Y toma valores yij , j = 1, . . . , ni en el nivel i del factor X,
siendo ni el número de observaciones en el nivel i del factor X. Cuando todos los niveles tienen
el mismo número de observaciones, ni = ni′ ∀i, i′ , decimos que el diseño está balanceado o
equilibrado. El modelo puede escribirse de dos formas:
184 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

yij = µ + αi + εij , (3.2)

yij = µi + εij , (3.3)

En la ecuación (3.2), µ es la media de la variable Y , mientras que αi es el efecto en la media


del nivel i, es decir, cuánto aumenta o disminuye la media de Y por pertenecer a la categoría
i. En la ecuación (3.3), µi es la media de la variable Y para el nivel i del factor X, de donde
tenemos que el efecto es:

07
αi = µi − µ,

5-
y el término de error, que representa toda la variabilidad que no explica el modelo, es:

-0
εij = yij − µi .

Se cumple que:

∑ 19
αi = 0; εij ∼ N (0, σ 2 )
20
i

Podríamos representar matemáticamente nuestro ejemplo como:


or

tiempo = µ + αtipo + ε,

o:
ad

tiempo = µtipo + ε.

El modelo ANOVA se ajusta en R con la función aov. El siguiente código ajusta el modelo
de nuestro ejemplo, pero de momento solo lo guardamos, veremos en los siguientes apartados
rr

cómo extraer información e interpretarla.


Bo

modelo.aov <- aov(tiempo ~ tipo, danova)

3.2.2. Estimación de los parámetros



Si tenemos un total de n datos de los cuales hay ni de cada nivel i, de forma que i ni = n,
los estimadores obtenidos tanto por el método de mínimos cuadradados como por el método
de máxima verosimilitud (véase por ejemplo Lawson (2015)) son los siguientes:


ni
yij
j=1
µ̂i = y i· = ,
ni
3.2. ANÁLISIS DE LA VARIANZA DE UN FACTOR 185


k ∑
k ∑
ni
yi· yij
i=1 i=1 j=1
µ̂ = y ·· = = ,
k n

α̂i = µ̂i − µ̂,

es decir, las medias dentro de cada nivel del factor, y la media total. Con estos estimadores
de los parámetros, la estimación de valores de Y vendrá dada por:

07
ŷij = µ̂i = µ̂ + α̂i ,
y por tanto los residuos del modelo son:

5-
eij = yij − ŷij

-0
Nótese que, si tenemos k niveles solo tenemos que estimar k − 1, ya que:

19 ∑
αi = 0.
20
i

Esta última restricción hace que no se puedan estimar los efectos con la representación
matricial:
or

y = Xβ + ε
ad

     
y11 1 1 0 ··· 0 ε11
 .   . .. .. . .   .. 
 ..   .. . . . 0   . 
     
rr

     


y1n1 



1 1 0 ··· 0  
  

ε1n1 

 y21   1 0 1 ··· 0  µ  ε21 
      
 ..   .. .. .. . .   α   .. 
Bo

 .   . . . . 0   1   . 
    α   
  =   2  +  

 y2n2 

 1 0 1 ··· 0    
  ...   ε2n2 
 ..   .. .. .. . . ..     .. 
 .   . . . . .   . 
    α  

yk1    
εk1 
k
   1 0 0 ··· 1   
 ..   .. .. 
.. . . ..   .. 
    
 .   . . . . .   . 
yknk 1 0 0 ··· 1 εknk

Debido a la singularidad de la matriz X T X (véase por ejemplo Lawson (2015)), lo que se


hace es fijar uno de los niveles del factor como nivel “base”, y estimar la media del nivel base
y los efectos de los otros niveles con respecto a la media del nivel base, es decir:
186 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

 
µ̂ + α̂1
 
β̂ =  α̂2 − α̂1 
α̂3 − α̂1

El nivel base que se toma en R de un factor no ordenado es el primero en orden alfabético,


y se puede cambiar con la función relevel.

Sobre el objeto modelo.aov que guardamos antes, podemos aplicar funciones genéricas

07
que devuelvan ciertos resultados. Por ejemplo, la función coef nos devuelve los estimadores
de los coeficientes, teniendo en cuenta que toma calida como nivel de referencia del factor
tipo. Podemos comprobar cómo se corresponden los coeficientes con los efectos estimados.

5-
La función confint nos devuelve un intervalo de confianza para los parámetros. Vemos que,
con respecto al nivel base calida, el tiempo de visita se reduce en 15 minutos cuando la luz
es calida_intensa y aumenta 17 cuando la luz es fria. Se pueden visualizar los efectos con

-0
el paquete effect, como se muestra en la figura 3.2.

## El primer nivel es el de referencia


levels(danova$tipo)

## [1] "calida"
19
"calida_intensa" "fria"
20
## Estimación de los coeficientes
coef(modelo.aov)

## (Intercept) tipocalida_intensa tipofria


or

## 25.22450 -15.60217 17.95317


## Coeficiente nivel 1
ad

a1 <- coef(modelo.aov)[1] - mean(danova$tiempo); a1

## (Intercept)
## -0.7836667
rr

## Coeficiente nivel 2
a2 <- coef(modelo.aov)[2] + a1; a2
Bo

## tipocalida_intensa
## -16.38583
## Coeficiente nivel 3
a3 <- coef(modelo.aov)[3] + a1; a3

## tipofria
## 17.1695
## Comprobación
aggregate(tiempo ~ tipo, danova, mean)$tiempo - mean(danova$tiempo)
3.2. ANÁLISIS DE LA VARIANZA DE UN FACTOR 187

tipo effect plot

60

50

40

07
tiempo

30

20

5-
10

-0
0

−10
calida 19calida_intensa
tipo
fria
20
Figura 3.2: Visualización de los efectos
or

## [1] -0.7836667 -16.3858333 17.1695000


## Intervalo de confianza
ad

confint(modelo.aov, alpha = 0.99)


rr

## 2.5 % 97.5 %
## (Intercept) 6.948564 43.50044
## tipocalida_intensa -41.448244 10.24391
Bo

## tipofria -7.892910 43.79924


plot(effects::effect("tipo", modelo.aov))

## Registered S3 methods overwritten by 'lme4':


## method from
## cooks.distance.influence.merMod car
## influence.merMod car
## dfbeta.influence.merMod car
## dfbetas.influence.merMod car
188 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

3.2.3. Contrastes
En el análisis de la varianza de un factor, lo que nos interesa demostrar es que hay diferencias
entre los niveles del factor (la X explica la Y ). Si no hubiera diferencias entre los niveles,
entonces las medias µi serían iguales, o lo que es lo mismo, los efectos αi serían nulos. Por
tanto, la hipótesis nula del modelo ANOVA de un factor es:

H0 : µ1 = µ2 = · · · = µk ,
o equivalentemente:

07
H0 : αi = 0 ∀i.

5-
Nótese que la hipótes alternativa es que hay diferencia entre los niveles, pero eso no significa
que todos los niveles sean diferentes. Es decir, si rechazamos la hipótesis nula, y por tanto

-0
tenemos evidencia para aceptar la alternativa:

19
H1 : αi ̸= 0 para algún i,

Para contrastar la hipótesis nula, dividimos la variabilidad total de los datos entre la variabi-
20
lidad que existe “dentro” de los grupos y la variabilidad que existe “entre” los grupos. Esta
variabilidad la representamos por las sumas de cuadrados, de manera que la suma de cua-
drados total (SCT ) la podemos descomponer en la suma de cuadrados entre grupos (SCE)
más la suma de cuadrados dentro de grupos (SCD):
or

∑ ∑ ∑
(yij − y ·· )2 = ni (y i· − y ·· )2 + (yij − yi· )2 ,
ad

ij i ij

SCT = SCE + SCD.

Los grados de libertad de la suma de datos total es n − 1, que se descomponen también


rr

en k − 1 grados de libertad para la suma de cuadrados entre grupos y n − k grados de


libertad para la suma de cuadrados dentro de los grupos, de forma que podemos calcular los
Bo

cuadrados medios totales, entre grupos y dentro de grupos:


(yij − y ·· )2
ij
CM T = ,
n−1

ni (y i· − y ·· )2
i
CM E = ,
k−1

ni (y i· − y ·· )2
i
CM D = ,
n−k
3.2. ANÁLISIS DE LA VARIANZA DE UN FACTOR 189

Tabla 3.2: Contenido de la tabla ANOVA


GL SC CM F p-valor
factor $k-1$ SCE CME F p
residuos $n-k$ SCD CMD

Entonces, si se cumplen las condiciones para aplicar el modelo y la hipótesis nula es cierta,
el estadístico:

07
CM E
F =
CM D
sigue una distribución F con k − 1 y n − k grados de libertad, y podemos bien realizar el

5-
contraste de hipótesis para un nivel de confianza determinado, bien interpretar el p-valor,
para llegar a una conclusión o decisión. En Análisis de la Varianza aquí descrito se resume
normalmente en la llamada tabla ANOVA (ver tabla 3.2), que incluye las sumas de cuadrados,

-0
cuadrados medios, estadístico F y el p-valor.

19
La función genérica summary aplicada a un modelo ANOVA devuelve precisamente la
tabla ANOVA. En nuestro ejemplo, el p-valor es pequeño, menor de 0.05 (aunque por poco).
Luego para un nivel de significación del 5 % podemos rechazar la hipótesis nula y aceptamos
20
que hay diferencias en las medias2 .

summary(modelo.aov)

## Df Sum Sq Mean Sq F value Pr(>F)


or

## tipo 2 3383 1691.7 3.835 0.0452 *


## Residuals 15 6617 441.1
## ---
ad

## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Como se ha indicado anteriormente, al rechazar la hipótesis nula aceptamos que no todos
rr

los niveles del factor producen una misma respuesta en la variable Y . Una vez rechazada
la hipótesis nula, tendremos que comprobar qué niveles son realmente distintos para, en
última instancia, sacar conclusiones o tomar decisiones. Un enfoque erróneo sería realizar
Bo

comparaciones con el test de la t de Student para cada par de niveles del factor. En su lugar,
utilizamos el método HSD3 de Tukey, que utiliza el estadístico de los rangos estudentizados,
R/σ̂ para realizar todos los contrastes siguientes:

H0 : µi = µj ∀i ̸= j.

La función TukeyHSD realiza los contrastes dos a dos de un modelo ANOVA, con
3
Honestly Significance Difference
190 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

95% family−wise confidence level

fria−calida_intensa fria−calida

07
5-
-0
−40 −20 0 20 40 60

19
Differences in mean levels of tipo
20
Figura 3.3: Visualización de las diferencias por pares

en el siguiente ejemplo. La salida proporciona las diferencias entre cada par de niveles, un
intervalo de confianza y el p-valor del contraste. Vemos que hay diferencias significativas
or

entre la luz fria y la calida intensa, pero no en el resto de comparaciones. Estas diferencias
se pueden visualizar utilizando la función plot, que produce la figura @fig(fig:tukeytipo).
ad

TukeyHSD(modelo.aov)

## Tukey multiple comparisons of means


rr

## 95% family-wise confidence level


##
Bo

## Fit: aov(formula = tiempo ~ tipo, data = danova)


##
## $tipo
## diff lwr upr p adj
## calida_intensa-calida -15.60217 -47.099237 15.89490 0.4237931
## fria-calida 17.95317 -13.543904 49.45024 0.3276133
## fria-calida_intensa 33.55533 2.058263 65.05240 0.0361638
plot(TukeyHSD(modelo.aov))

Recordemos que en un estudio observacional si se rechaza la hipótesis nula estamos confir-


mando que existe relación entre el factor y la variable. Para confirmar la relación causa-efecto
3.2. ANÁLISIS DE LA VARIANZA DE UN FACTOR 191

del factor sobre la variable, el ANOVA de un factor debe realizarse a partir de un experimento
diseñado correctamente, véase 3.6.

Aunque en nuestro ejemplo no habíamos encontrado diferencias, por completitud


vamos a obtener las diferencias entre grupos.

3.2.4. Validación del modelo y alternativas

07
Las hipótesis del test de la F y de los tests HSD de Tukey son la igualdad de varianzas
entre grupos, y la normalidad de los residuos. La igualdad de varianzas se pueden comprobar
fácilmente con el test de Bartlett4 . La normalidad de los residuos se puede verificar con

5-
alguno de los múltiples tests de normalidad existentes, como por ejemplo el de Kolmogorov-
Smirnoff, el de Shapiro-Wilk o el de Anderson-Darling. La función genérica plot de R sobre
un modelo ANOVA guardado produce una serie de gráficos de diagnóstico que nos dan una

-0
idea a veces suficiente del cumplimiento de las hipótesis.

19
La función genérica residuals sobre el objeto modelo.aov devuelve los residuos del
modelo. Podemos entonces hacer un contraste de normalidad. El p-valor es grande, mucho
mayor de 0,05, por lo que no podemos rechazar que los residuos sean normales. La función
20
bartlett.test contrasta la hipótesis de homogeneidad de varianzas. El p-valor de este
contraste es grande, mayor de 0.05 (aunque no mucho mayor). Podemos aceptar la igualdad
de varianzas y por tanto las conclusiones de las pruebas de Fisher y de Tukey son válidas.
or

La figura 3.4 muestra los gráficos de diagnóstico generados con la función plot. Nótese que
para mostrar los cuatro gráficos en un mismo panel hemos dividido el espacio gráfico en 2
filas y 2 columnas (función par, véase la ayuda de esta función). El gráfico superior izquierdo
ad

deberia mostrar una línea recta si el modelo lineal se ajusta, y también se aprecia la homoge-
neidad de varianzas. A menudo cuando no se cumple esta hipótesis el gráfico muestra forma
de embudo. El gráfico inferior izquierdo muestra la misma información pero a otra escala,
donde tampoco se aprecian varianzas distintas. El gráfico superior derecho es un gráfico
rr

cuantil-cuantil para comprobar la normalidad de los residuos, en este caso se ajusta bastante
bien. El gráfico inferior derecho sirve para detectar observaciones con gran influencia en el
Bo

modelo. En este caso no se etiqueta ninguna.

shapiro.test(residuals(modelo.aov))

##
## Shapiro-Wilk normality test
##
## data: residuals(modelo.aov)
## W = 0.92539, p-value = 0.161

4
Hay otras alternativas, como el test de Levene en la función levene.test del paquete car.
192 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

Standardized residuals
Residuals vs Fitted Normal Q−Q
5
2 10 2 5
Residuals
10
20

1
−20

−1
10 15 20 25 30 35 40 −2 −1 0 1 2

Fitted values Theoretical Quantiles

07
Constant Leverage:
Standardized residuals

Standardized residuals
Scale−Location Residuals vs Factor Levels

5-
10 5
2 5
10 2

1
0.8

-0
−1
0.0

tipo :
10 15 20 25 30 35 40 calida fria

Fitted values 19
Figura 3.4: Gráficos de diagnóstico modelo ANOVA
Factor Level Combinations
20
bartlett.test(tiempo ~ tipo, data = danova)
or

##
## Bartlett test of homogeneity of variances
ad

##
## data: tiempo by tipo
## Bartlett's K-squared = 5.3399, df = 2, p-value = 0.06926
rr

par(mfrow = c(2,2))
plot(modelo.aov)
Bo

par(mfrow = c(1,1))

En caso de no cumplimiento de las hipótesis, podemos realizar contrastes no paramétricos.


Para el contraste de hipótesis de igualdad entre los niveles, utilizamos el contraste de Kruskal-
Wallis, que también dispone de un método para realizar comparaciones múltiples, como
veremos en los ejemplos. Es importante tener en cuenta que la función kruskal.test de R
requiere que la variable cualitativa sea de tipo factor y no carácter.

Otra alternativa es transformar los datos originales para conseguir normalidad y/o homoge-
neidad de varianzas y realizar el análisis con los datos transformados.
3.2. ANÁLISIS DE LA VARIANZA DE UN FACTOR 193

En el conjunto de datos hay una variable que no hemos usado. Es el factor


temperatura, que tiene tres niveles (tabla 3.3. Se deja al lector como ejercicio realizar un
análisis exploratorio de los datos. Ajustamos el modelo ANOVA para estudiar el efecto de
este factor en el tiempo que el cliente pasa en la tienda. Toma los valores baja, media,
alta. En este caso, el contraste de hipótesis no permite rechazar la igualdad de medias.
No obstante, al validar las hipótesis del modelo5 vemos que no se cumple la hipótesis de
normalidad, por lo que hay que hacer el contraste de Kruskal-Wallis para confirmar que
la temperatura no explica el tiempo. Obtenemos un p-valor muy grande, por lo que no

07
podemos rechazar que los datos vengan de la misma población, y por tanto llegamos a
la conclusión de que no hay diferencias. Aunque en este caso no sería necesario seguir,
por completitud del ejemplo vamos a realizar las comparaciones por pares utilizando la

5-
función kruskalmc del paquete pgirmess. Obtenemos en este caso la siferencias observadas
y críticas (para un determinado nivel de significación) y un indicador (TRUE/FALSE) de
diferencia significativa. Como era de esperar, no se encuentra ningún par de niveles con

-0
diferencias significativas.

modelo.aov2 <- aov(tiempo ~ temperatura, danova)


summary(modelo.aov2)

##
19
Df Sum Sq Mean Sq F value Pr(>F)
20
## temperatura 2 43 21.6 0.033 0.968
## Residuals 15 9957 663.8
shapiro.test(residuals(modelo.aov2))
or

##
## Shapiro-Wilk normality test
ad

##
## data: residuals(modelo.aov2)
## W = 0.84498, p-value = 0.007066
rr

bartlett.test(tiempo ~ temperatura, danova)

##
Bo

## Bartlett test of homogeneity of variances


##
## data: tiempo by temperatura
## Bartlett's K-squared = 3.4015, df = 2, p-value = 0.1825
kruskal.test(tiempo ~ temperatura, danova)

##
## Kruskal-Wallis rank sum test
##
## data: tiempo by temperatura
194 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

Tabla 3.3: Tiempo de permanencia en la tienda


temperatura tiempo
baja 37.384
baja 76.250
media 13.499
alta 38.632
baja 78.729
alta 14.572
baja 5.314

07
baja 5.711
media 27.511
alta 56.797

5-
baja 15.230
alta 40.784
baja 2.416

-0
alta 6.442
baja 6.833

alta
baja
19
media 27.010
6.180
8.853
20
## Kruskal-Wallis chi-squared = 0.5653, df = 2, p-value = 0.7538
pgirmess::kruskalmc(tiempo ~ temperatura, data = danova)
or

## Multiple comparison test after Kruskal-Wallis


## p.value: 0.05
ad

## Comparisons
## obs.dif critical.dif difference
## alta-baja 1.9444444 6.735838 FALSE
## alta-media 0.1666667 9.037076 FALSE
rr

## baja-media 1.7777778 8.520237 FALSE


Bo

Realice la práctica 3.1 cuyo guión se encuentra en el apartado 3.7 para realizar análisis
de la varianza de un factor.

3.3. Análisis de la varianza de varios factores


La principal diferencia con el análisis de la varianza de un factor es que, además de los efectos
principales de cada uno de los factores, es decir, cuánto varía la media según los niveles del
factor, se puede estudiar el efecto de las interacciones entre factores. Intuitivamente, la
interacción entre factores es similar a la que podemos observar en la vida diaria, por ejemplo
3.3. ANÁLISIS DE LA VARIANZA DE VARIOS FACTORES 195

el efecto de un tranquilizante tiene un efecto sobre el bienestar de una persona. El efecto


de una copa de vino también. Pero utilizados conjuntamente, producen una interacción que
afecta negativamente en el bienestar de la persona. Del mismo modo, podemos observar que
una variable dependiente Y toma mejores valores para ciertos niveles de los factores X1 y
X2 . Pero se deben estudiar las interacciones, porque puede ser que dichos niveles combinados
produzcan peor resultado.
El modelo de dos factores, que en la literatura en inglés de encuentra como two-way anova,
es el siguiente:

07
Y = µ + αi + βj + (αβ)ij + ε,

donde (αβ)ij representa el efecto de la interacción, y el resto de términos tienen la misma

5-
interpretación que en el ANOVA de un factor (o one-way anova). En la tabla ANOVA se
añaden nuevas filas y contrastes para los efectos principales y las interacciones. Las hipótesis

-0
del modelo son las mismas, luego comprobamos normalidad de los residuos y homogeneidad
de variazas. Para este último caso, utilizamos mejor el test de Levene que permite incluir el
término de la interacción.

19
En el ajuste del modelo y estimación de efectos, se toma como base el primer nivel de todos
los factores.
20
Para especificar modelos con más de un factor e interacción en R, ampliamos el lado derecho
de la fórmula del modelo. Los nuevos efectos se añaden “sumando”. La interacción se expresa
separando los factores con dos puntos. Si utilizamos el símbolo asterisco, entonces el modelo
incluye todos los efectos principales y las interacciones. Por ejemplo, para dos factores a y b,
or

el modelo completo se pouede expresar como a*b o como a + b + a:b.


ad

En el apartado anterior hemos analizado por separado el tiempo frente a los factores
iluminación y temperatura. Pero deberíamos analizarlos en un modelo multifactorial como
el generado con el siguiente código.
rr

La tabla ANOVA nos muestra que el término de la interacción es altamente significativo,


con un p-valor muy bajo, incluso inferior a 0,01. También el tipo de iluminación. No lo es el
efecto principal de la temperatura, pero como este factor está en una interacción significativa,
Bo

no deberíamos eliminarlo del modelo.


Las hipótesis del modelo y el modo de proceder son análogos al caso unifactorial. Se verifica
la normalidad de los residuos y la homegenidad de varianzas. El mayor tiempo de estancia
en la tienda se consigue con la combinación iluminación fria y temperatura baja.
El gráfico de las interacciones (figura 3.5) muestra claramente las grandes diferencias entre
las combinaciones de factores. Si no hubiera interacción, las líneas serían paralelas. En el
apartado anterior habíamos llegado a la conclusión de que la mejor iluminación para retener
más tiempo a los clientes era la luz fría, pero era indiferente utilizar una temperatura u otra.
Si no analizáramos las interacciones, podríamos cometer el error de utilizar en las tiendas
196 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

luz fría y temperatura media, lo que sería una pésima decisión ya que esta interacción baja
drásticamente el tiempo de permanencia en la tienda.

modelo.aov3 <- aov(tiempo ~ tipo*temperatura, danova)


summary(modelo.aov3)

## Df Sum Sq Mean Sq F value Pr(>F)


## tipo 2 3383 1691.7 9.650 0.00577 **
## temperatura 2 43 21.6 0.123 0.88563
## tipo:temperatura 4 4996 1249.0 7.125 0.00719 **

07
## Residuals 9 1578 175.3
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

5-
shapiro.test(residuals(modelo.aov3))

-0
##
## Shapiro-Wilk normality test
##
## data: residuals(modelo.aov3)
## W = 0.90973, p-value = 0.08508 19
car::leveneTest(tiempo ~ tipo*temperatura, danova)
20
## Levene's Test for Homogeneity of Variance (center = median)
## Df F value Pr(>F)
## group 8 0.5545 0.7908
or

## 9
coef(modelo.aov3)
ad

## (Intercept) tipocalida_intensa
## 48.79050 -42.47950
## tipofria temperaturabaja
rr

## -22.18850 -40.03883
## temperaturamedia tipocalida_intensa:temperaturabaja
Bo

## -21.27950 39.76183
## tipofria:temperaturabaja tipocalida_intensa:temperaturamedia
## 77.55783 41.97850
## tipofria:temperaturamedia
## 8.17650
effects::allEffects(modelo.aov3)

## model: tiempo ~ tipo * temperatura


##
## tipo*temperatura effect
## temperatura
3.3. ANÁLISIS DE LA VARIANZA DE VARIOS FACTORES 197

60 temperatura

baja
50 alta
media
mean of tiempo

40

30

07
20

5-
10

-0
calida calida_intensa fria

19 tipo

Figura 3.5: Visualización de las interacciones entre iluminación y temperatura.


20
## tipo alta baja media
## calida 48.7905 8.751667 27.511
or

## calida_intensa 6.3110 6.034000 27.010


## fria 26.6020 64.121000 13.499
with(danova,
ad

interaction.plot(x.factor = tipo,
trace.factor = temperatura,
response = tiempo,
rr

las = 1))
Bo

El caso de dos factores con interacción se extiende fácilmente a más de dos factores aña-
diento términos a la fórmula. No obstante, las interacciones de más de dos factores se suele
despreciar. En el modelo resultante final se deberian eliminar los efectos no significativos,
aunque manteniendo aquellos efectos principales que intervengan en alguna interacción.

Si no se cumplieran las hipótesis del modelo podríamos usar el contraste de Kruskal-Wallis


para los efectos principales. Para la interacción también hay métodos paramétricos, aunque
no están tan extendidos, véase una revisión en Feys (2016). En muchas ocasiones una trans-
formación de Box-Cox en la variable respuesta es suficiente para ajustar un modelo válido,
vésae 2.2.4.2.
198 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

Realice la práctica 3.2 cuyo guión se encuentra en el apartado 3.7 para realizar análisis
de la varianza multifactorial.

3.4. Introducción a los modelos mixtos: efectos fijos y


efectos aleatorios
El modelo de análisis de la varianza y los contrastes vistos hasta ahora asumen que los

07
individuos se han asignado aleatoriamente a los distintos niveles. Incluso en estudios obser-
vacionales, podemos asumir que esta asignación se ha hecho de forma aleatoria y controlada,
y son efectos fijos.

5-
Pero esto no siempre se puede asumir, o directamente la naturaleza del propio factor es
aleatoria, y el tratamiento que le tenemos que dar a los factores es distinto. En particular, los

-0
efectos de estos factores no son una constante que queramos estimar, sino variables aleatorias
de las cuales queremos estudiar su varianza en el modelo. El modelo para un factor fijo α y
otro aleatorio β sería el siguiente:
19
Y = µ + αi + βj + ε,
20
donde el efecto aleatorio β ∼ N (0, σβ2 ). No tiene por tanto sentido estimar el efecto, cuya
media es cero, sino la variabilidad, y ver si es importante con respecto al resto de factores.
or

Imaginemos por un momento que la variable temperatura de nuestro ejemplo no se


refiera a la temperatura del interior de la tienda, sino a la temperatura ambiente del exterior.
Está claro que este factor no es algo que podamos controlar, y por tanto su efecto es aleatorio.
ad

En este caso tendríamos que ajustar un modelo mixto. En este ejemplo vemos que el factor
temperatura afecta poco o nada a la variable respuesta, ya que la varianza es prácticamente
nula6 . Podemos obtener una estimación de los efectos con la función ranef del paquete lme4.
rr

library(lme4)
Bo

## Loading required package: Matrix


modelo.mixto <- lmer(tiempo ~ 1 + tipo + (1|temperatura), danova)

## boundary (singular) fit: see ?isSingular


summary(modelo.mixto)

## Linear mixed model fit by REML ['lmerMod']


## Formula: tiempo ~ 1 + tipo + (1 | temperatura)
## Data: danova
##
3.4. INTRODUCCIÓN A LOS MODELOS MIXTOS: EFECTOS FIJOS Y EFECTOS ALEATORIOS199

## REML criterion at convergence: 139.3


##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -1.4131 -0.4427 -0.1577 0.5828 1.6927
##
## Random effects:
## Groups Name Variance Std.Dev.
## temperatura (Intercept) 0.0 0
## Residual 441.1 21

07
## Number of obs: 18, groups: temperatura, 3
##
## Fixed effects:

5-
## Estimate Std. Error t value
## (Intercept) 25.225 8.574 2.942
## tipocalida_intensa -15.602 12.126 -1.287

-0
## tipofria 17.953 12.126 1.481
##
##
##
##
Correlation of Fixed Effects:
(Intr) tpcld_
tipcld_ntns -0.707
19
20
## tipofria -0.707 0.500
## convergence code: 0
## boundary (singular) fit: see ?isSingular
ranef(modelo.mixto)
or

## $temperatura
## (Intercept)
ad

## alta 0
## baja 0
## media 0
rr

##
## with conditional variances for "temperatura"
Bo

Los modelos mixtos (o incluso aleatorios puros) tienen muchas aplicaciones tanto en modelos
económicos como en cualquier otro ámbito. Algunos ejemplos son:
Efectos aleatorios puros, como el que se ha mostrado en el ejemplo.
Modelos de panel, donde tenemos mediciones en diferentes periodos, y la unidad ob-
servable dentro del tiempo forman el factor aleatorio
Medidas repetidas, donde el individuo es el factor aleatorio
Modelos anidados y jerarquizados, donde unos niveles están dentro de otros
Como se ha podido comprobar, el análisis de modelos mixtos no es tan sencillo como el de
200 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

efectos fijos. Para una revisión más completa se recomienda consultar el libro de Faraway
(2016).

3.5. Análisis multivariante de la varianza


Hasta ahora hemos analizado el efecto que uno o varios factores tienen sobre una única
variable Y . En ocasiones, tenemos en el lado izquierdo de la formula un vector aleatorio Y con
p variables respuesta Yi , . . . , Yp con cierta estructura de correlación y queremos determinar
si esta variable multivariante se comporta de forma distinta para los distintos niveles de las

07
variables en el vector de variables independientes X . El método calcula una matriz de errores
y una matriz de hipótesis7 , y mediante el cálculo de un estadístico (por defecto Pillai8 ) se
contrasta la hipótesis.

5-
En el conjunto de datos de ejemplo tenemos otra variable en escala métrica que es el

-0
gasto realizado por cada cliente durante la compra. El siguiente ejemplo realiza el análisis
multivariante de la varianza para estas dos variables agrupadas en una matriz. El modelo se
puede ajustar con la función aov, o bien con la función maov, que es realmente un wrapper de
19
la anterior. Los contrastes multivariantes se obtienen con la función summary.manova, si no
le añadimos .manova tenemos los contrastes univariantes para cada componente del vector
aleatorio Y . El resultado que obtenemos en este caso es muy similar al obtenido en el ejemplo
20
univariante. En ocasiones puede suceder que los contrastes univariantes no son significativos
pero sí lo es el contraste multivariante.

Y <- as.matrix(danova[, c("tiempo", "gasto")])


or

modelo.manova <- aov(Y ~ tipo*temperatura, data = danova)


summary.manova(modelo.manova)
ad

## Df Pillai approx F num Df den Df Pr(>F)


## tipo 2 0.97815 4.3075 4 18 0.01282 *
## temperatura 2 0.15289 0.3725 4 18 0.82516
## tipo:temperatura 4 1.14378 3.0057 8 18 0.02499 *
rr

## Residuals 9
## ---
Bo

## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
summary(modelo.manova)

## Response tiempo :
## Df Sum Sq Mean Sq F value Pr(>F)
## tipo 2 3383.4 1691.70 9.6499 0.005768 **
## temperatura 2 43.2 21.58 0.1231 0.885628
## tipo:temperatura 4 4995.9 1248.98 7.1245 0.007186 **
7
Ver: https://rpubs.com/aaronsc32/manova-test-statistics
8
ver una descripción de las alternativas en https://rpubs.com/aaronsc32/manova-test-statistics.
3.6. INTRODUCCIÓN AL DISEÑO DE EXPERIMENTOS 201

## Residuals 9 1577.8 175.31


## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Response gasto :
## Df Sum Sq Mean Sq F value Pr(>F)
## tipo 2 28556 14278.2 31.1899 8.974e-05 ***
## temperatura 2 251 125.7 0.2745 0.7660582
## tipo:temperatura 4 34424 8606.0 18.7994 0.0002142 ***
## Residuals 9 4120 457.8

07
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

5-
Realice la práctica 3.3 cuyo guión se encuentra en el apartado 3.7 para realizar análisis
multivariante de la varianza.

-0
3.6. Introducción al diseño de experimentos
3.6.1. Introducción
19
20
El Diseño y Análisis de Experimentos (que abreviaremos como DoE), como cualquier otra
técnica estadística, se basa en el estudio de la variabilidad. DoE es la herramienta más
potente para la mejora, lo que ha llevado a algunos autores a llamarlo “the jewel of quality
engineering” (Ver por ejemplo Allen (2010)).
or

En apartados anteriores del libro hemos aprendido las herramientas básicas para analizar
la variabilidad de los datos. En este apartado vamos a revisar las técnicas de Diseño de
ad

Experimentos y su posterior análisis. Demasiado a menudo los esfuerzos se centran en intentar


analizar un experimento sin diseño, lo que provoca frustración en los equipos involucrados
en el análisis de datos. Vamos a mostrar la importancia de la fase de diseño, así como su
planificación y correcta ejecución. No obstante la parte de análisis es igualmente importante,
rr

sobre todo en lo que concierne a la correcta interpretación de los resultados.


Bo

3.6.2. Bases del DoE: origen, importancia, objetivos y requeri-


mientos
El DoE moderno surge a principios del siglo XX de la mano de Ronald A. Fisher cuando
trabajaba en el “Rothamsted Experimental Station” en Inglaterra. Sus estudios se centraban
en reducir la variación natural y prevenir la confusión con la variación de los restantes efectos.
En última instancia, detectar las relaciones causa-efecto con el menor esfuerzo experimental.
Básicamente, necesitamos el DoE frente a estudios observacionales u otras estrategias como
“un factor cada vez” para estudiar las interacciones y encontrar relaciones de causa-efecto
con el menor uso de recursos posible. Así, podremos tomar decisiones respaldadas por los
202 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

datos.
El objetivo del diseño de experimentos es encontrar los niveles de ciertos factores que opti-
mizan una determinada característica medible. Esto se consigue con un método sistemático9
que evita salidas en falso y respuestas incompletas. Mediante la reducción del error experi-
mental se consigue evitar la confusión de los efectos y anular los efectos sin interés para el
estudio.
Para empezar, lo primero que necesitamos es definir los datos del problema objeto de estudio
y disponer de una forma de obtenerlos adecuadamente, en particular:

07
Una variable respuesta en escala métrica
Factores controlables
Posiblemente, otros factores aleatorios

5-
Esta recogida de datos se debe realizar de forma sistemática y teniendo en cuenta los tres
pilares del DoE: aleatorización, bloqueo y replicación.

-0
3.6.3. Importancia del diseño

19
Con la experimentación básicamente controlamos los niveles a los que operan ciertos factores
controlables, a la vez que se asignan dichos niveles (configuraciones, tratamientos, etc.) a las
unidades experimentales. Esto permite, unido a las apropiadas estrategias de aleatorización,
20
bloqueo y replicación, realizar predicciones acerca del desempeño de un determinado proceso.
Estas predicciones así establecidas serán el resultado de la identificación de una relación
causa-efecto, que no se puede conseguir simplemente analizando datos recogidos sin diseño.
En los estudios observacionales:
or

Recogemos información
No controlamos factores
Análisis descriptivos
ad

Descubrir relaciones
Mientras que con experimentos diseñados:
rr

Se controlan los factores


Se analizan efectos
Bo

Incluidas las interacciones


Se verifica la relación causa-efecto
Si la experimentación se lleva a cabo variando una vez cada factor, buscando el valor óptimo
para la respuesta para cada factor individualmente dejando fijos el resto arbitrariamente,
estaremos obviando un aspecto fundamental: el efecto de las interacciones. La interacción es
el efecto que tiene un factor a distintos niveles de otros factores. Por otra parte, el número
de experimentos necesarios para llegar a conclusiones válidas es mucho mayor (y por tanto
el experimento más costoso). Con diseño de Experimentos obtenemos el mayor número de
combinaciones posibles para estimar interacciones, con el mínimo número de experimentos.
9
En realidad, el método científico.
3.6. INTRODUCCIÓN AL DISEÑO DE EXPERIMENTOS 203

El análisis de datos, por muy sofisticado que sea, no puede nunca arreglar un experi-
mento mal diseñado (chapucero, según Lawson)
Sometimes the only thing you can do with a poorly designed experiment is to
try to find out what it died of
R.A. Fisher
As we know from Murphy’s Law, if anything can go wrong it will, and analysis
of data can never compensate for botched experiments

07
John Lawson Lawson (2015)

El análisis de la varianza sin diseño de experimentos tiene algunas limitaciones importantes.

5-
Sin Diseño de Experimentos, los datos pueden ser inconsistentes o incompletos, al no incluir
factores de ruido o Factores latentes. Si tenemos variables correlacionadas, y alguna de ellas
no se mide, su efecto puede quedar enmascarado por las otras, como en el ejemplo de la figura

-0
3.6, donde si miramos solo la relación de la variable respuesta con el factor 1 (gráfico de la
izquierda), podemos llegar a la conclusión errónea de que el factor 1 es determinante. Pero

19
podría ser que la causa real sea el factor 2, que no ha sido medido y está muy correlacionado
con el factor 1. En el gráfico de la derecha vemos que la variable respuesta crece en el mismo
sentido que los factores 1 y 2, pero podría ser que el factor 2, no medido al principio, sea la
20
causa, y no el que realmente se ha medido.

Por otra parte, el rango de valores de la variable respuesta está limitado por su rango normal
de operación, que puede ocultar relaciones más amplias. En la figura 3.7, el gráfico de la
derecha se corresponde con el rango de variación normal de los factores de un proceso. En el
or

de la izquierda, ampliamos el rango de posibles valores de la variable, y vemos una relación


más clara, que queda oculta en el otro caso.
ad

3.6.4. Planificación de la experimentación


rr

El conocimiento de la materia (subject matter knowledge) en cuestión es fundamental para


desarrollar cambios que resulten en mejoras. Sin embargo, es necesario otro tipo de cono-
cimiento (profound knowledge), en el que se incluye la Estadística. Combinar ambos cono-
Bo

cimientos, lleva a una mayor capacidad de mejora. Estas ideas, originarias de Deming, se
recogen en Moen et al. (2012). Algunas capacidades necesarias fruto de esta combinación
son:

Entender las interdependencias entre los sistemas donde se lleva a cabo la experimen-
tación;
Entender la relación entre las predicciones y el conocimiento del sistema que se quiere
cambiar;
Entender el efecto temporal de los cambios;
Entender la importancia de la estabilidad del proceso;
Entender la extrapolación de los resultados de las pruebas para mejorar el sistema.
204 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

07
138
28.0

5-
136 27.5

-0
response

19 27.0
response

134 130
factor2

132
20
134
26.5
136

132
or

26.0
ad

130

25.5
rr

78 79 80 81 82 78 79 80 81 82
factor1 factor1
Bo

Figura 3.6: Efecto de no medir un factor


3.6. INTRODUCCIÓN AL DISEÑO DE EXPERIMENTOS 205

Rango ampliado Rango normal de operación

14

10 11 12 13
12
Y

y
9 10

07
8
8

5-
7

7
8 9 10 11 12 9.0 9.5 10.0 10.5 11.0

-0
X x

19
Figura 3.7: Efecto de la limitación del rango de valores

En general, se pueden seguir tres estrategias de planificación para el diseño de experimentos.


20
Sin planificación se pueden ir cambiando niveles de factores cada vez y haciendo pruebas
(ensayo-error), definitivamente poco efectivo. Una planificación completa desde el inicio pue-
de llevar a no explorar alternativas surgidas durante la experimentación, y por tanto a no
cumplir los objetivos. La estrategia óptima la secuencia, es decir, llevar a cabo un número
or

de experimentos al inicio, cuyas conclusiones supondrán la planificación de una segunda fase


donde centrarnos en los factores realmente relevantes y hacer análisis más detallados y pre-
cisos. En las primeras fases se suelen realizar diseños de screening para descartar factores no
ad

significativos. En realidad, es la aplicación del método científico, en un proceso iterativo de


aprendizaje como se muestra en la figura 3.8.
En Moen et al. (2012) se propone el ciclo PDSA (Plan-Do-Study-Act) para la mejora que se
rr

muestra en la figura 3.9. Básicamente consiste en:


Bo

1. Planifica un cambio o prueba, dirigido a la mejora


2. Lleva a cabo el cambio o prueba (corto alcance)
3. Estudia el resultado: ¿qué has aprendido? ¿qué ha ido mal?
4. Actúa:
Adopta el cambio
Abandónalo
Empieza el ciclo de nuevo
¡Documenta todas las acciones de mejora!
Una buena forma de empezar el ciclo es a partir de un análisis de causa y efecto, por ejemplo
con un diagrama de Ishikawa como el que aparece en la figura 3.10.
206 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

Datos

Deducción Deducción Deducción

07
Inducción Inducción

5-
-0
Idea (modelo, hipótesis, ...)

19
Figura 3.8: Método iterativo de aprendizaje
20
or

Act Plan
ad
rr
Bo

Study Do

Figura 3.9: Ciclo PDSA para la mejora


3.6. INTRODUCCIÓN AL DISEÑO DE EXPERIMENTOS 207

07
Six Sigma Cause−and−effect Diagram

5-
-0
Operator Environment Tools
operator #1 height scissors
operator #2
operator #3
19
cleaning tape
20
Flight Time

paperclip
or

model marks rotor.width2


calibrate thickness rotor.length

Measure.Tool Raw.Material Design


ad

Paper Helicopter Project


rr

Figura 3.10: Ejemplo diagrama de causa-efecto


Bo
208 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

Lo siguiente probablemente sería determinar el presupuesto/recursos disponibles, en especial


determinar el número de experimentos que se pueden realizar realísticamente.

Hasta ahora, hemos ido mencionando algunos conceptos básicos del diseño de experimentos.
Ahora vamos a definirlos un poco más formalmente.

variable respuesta: La variable de interés que pretendemos mejorar. Será una cuan-
tificación de alguna característica de calidad, en sentido amplio.
factor: Variable independiente que puede ser causa de la respuesta. La inferencia que
haremos con DoE será confirmar o rechazar esta hipótesis.

07
variable de bloque: Variable que no tiene interés en la investigación, pero puede
influir en la respuesta. Mediante la formación de bloques confundimos su efecto con
los factores que realmente nos interesan.
variable ruido: Variable que puede influir en la respuesta, pero de la que no tenemos

5-
control.
nivel: Valor que fijamos de un factor. En variables cualitativas, una categoría. En

-0
variables cuantitativas, un valor numérico determinado fijado con antelación. A menudo
se le llama también tratamiento.
unidad experimental: La división más pequeña posible de unidades de un expe-

factores y niveles. 19
rimento tal que a dos cualesquiera se les pueden aplicar distintas combinaciones de

unidad observable: Cada uno de los elementos que forman la unidad experimental.
20
A veces, un tratamiento no se puede aplicar a un solo elemento, sino a varios a la vez.
bloque: Grupos de unidades experimentales que son tratados de forma similar en el
experimento.
efecto: El principal resultado de interés del experimento: qué pasa con la variable
or

respuesta.
réplica: Repetición de un experimento sobre una misma combinación de factores y
niveles, a diferentes unidades experimentales.
ad

repetición: Repetición de la medición de la respuesta con las mismas condiciones


experimentales, a la misma unidad experimental.
aleatorización: Asignación de niveles y bloques a unidades experimentales de forma
rr

aleatoria

Al utilizar un modelo para simplificar una realidad, estamos cometiendo un error. El error
Bo

experimental es aquel que se debe exclusivamente a las réplicas de las mismas condiciones
experimentales. En cada diseño el error experimental se calcula de una forma distinta, de
forma que se separa de la variabilidad total para ver cuánta variaación se debe al modelo y
poder así tomar decisiones.

Los siguientes principios son cruciales a la hora de diseñar el experimento.

Aleatorización. Los tratamientos deben ser asignados de forma aleatoria a las unida-
des experimentales. Esto incluye bloques, factores controlables, anidamientos, etc.

Formación de bloques. Cuando no se puedan replicar exactamente las condiciones


experimentales (por ejemplo, días diferentes), se deben organizar en bloques.
3.6. INTRODUCCIÓN AL DISEÑO DE EXPERIMENTOS 209

Réplicas. Para poder estimar el error experimental y hacer contrastes de hipótesis, es


necesario tener más de una corrida de cada combinación de tratamientos.
Lawson (2015) propone la siguiente checklist a la hora de planificar experimentos:
1. Definir objetivos
2. Identificar unidades experimentales
3. Definir variable respuesta medible y con sentido
4. Identificar los factores controlables y latentes
5. Ejecutar pruebas piloto
6. Hacer diagrama de flujo para cada experimento

07
7. Elegir el diseño experimental
8. Determinar el número de réplicas necesarias
9. Aleatorizar las condiciones experimentales a las unidades experimentales

5-
10. Definir método de análisis de datos
11. Calendario y presupuesto para la ejecución

-0
3.6.5. Tipos de diseños de experimentos
3.6.5.1. Experimentos con un factor
19
Podemos comparar una variable a distintos niveles de un solo factor. El contraste de la t de
Student es la técnica utilizada para dos niveles. Para más niveles, utilizamos el análisis de la
20
varianza de un factor (véase sec:anova1). Cuando hay algún factor más que no es de interés,
pero puede afectar a la variable resupesta, se debe introducir como variable de bloque. Los
diseños de cuadrados latinos y cuadrados greco-latinos se utilizan para introducir dos o tres
factores de bloque respectivamente.
or

El diseño experimental para el ANOVA de un factor sigue las siguientes pautas:


ad

1. Se quiere estudiar el efecto de un solo factor sobre una población. No hay otros factores
controlables que puedan influir.
2. Se realiza el plan de recogida de datos, posiblemente con prueba piloto.
rr

3. Se decide el número de unidades experimentales del experimento.


4. Se asignan aleatoriamente las unidades a los niveles del factor.
Bo

5. Se recogen los datos (experimento físico, cuestionario, etc.)


6. Se realiza un análisis descriptivo, sobre todo gráfico, de los datos recogidos.
7. Los datos se verifican y se preparan adecuadamente para el análisis.
8. Se ajusta el modelo.
9. Se comprueba la validez del modelo. Si no es válido, se busca modelo alternativo de
análisis.
10. Se estiman los parámetros.
210 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

11. Se comprueba las hipótesis principal.


12. Si hay diferencias, se realizan comparaciones por pares.
13. Se comprueba la significación práctica y se obtienen conclusiones o se toman decisiones.

3.6.5.2. Diseños multifactoriales


Cuando analizamos más de un factor a varios niveles, aplicamos lo explicado en el apartado
3.3. Recordemos que en estos diseños es de vital importancia estudiar las interacciones.

07
3.6.5.3. Diseños factoriales a dos niveles 2k
Un tipo especial de diseño multifactorial es aquél en el que todos los factores tienen solamente

5-
dos niveles. El número de experimentos necesarios para probar todas las combinaciones de
niveles para k factores es 2k , de ahi su nombre.

-0
Diseño factorial 22
Modelo:

19
yijk = αi + βj + αβij + εijk
20
Datos:
Aleatorizar tratamientos
Realizar k réplicas
or

Número de experimentos: k × 22
Análisis: - Efectos principales - Interacción
ad

library(xtable)
library(DoE.base)
rr

## Loading required package: conf.design


##
Bo

## Attaching package: 'conf.design'


## The following object is masked from 'package:lme4':
##
## factorize
## Registered S3 method overwritten by 'DoE.base':
## method from
## factorize.factor conf.design
##
## Attaching package: 'DoE.base'
3.6. INTRODUCCIÓN AL DISEÑO DE EXPERIMENTOS 211

## The following objects are masked from 'package:stats':


##
## aov, lm

## The following object is masked from 'package:graphics':


##
## plot.design

## The following object is masked from 'package:base':


##

07
## lengths
library(effects)

5-
## Use the command
## lattice::trellis.par.set(effectsTheme())
## to customize lattice options for effects plots.

-0
## See ?effectsTheme for details.
library(reshape2)
datosf22 <- scan(text = "
-
-
-
-
28
25
19
20
- - 27
+ - 36
+ - 32
+ - 32
or

- + 18
- + 19
- + 23
ad

+ + 31
+ + 30
+ + 29
",
rr

what = list(character(), character(), numeric()),


sep = "\t")
Bo

datosf22 <- as.data.frame(datosf22)


colnames(datosf22) <- c("A", "B", "respuesta")
datosf22$replica <- rep(1:3, 4)
library(knitr)
kable(dcast(datosf22, A + B ~ replica, value.var = "respuesta"))

A B 1 2 3
- - 28 25 27
- + 18 19 23
+ - 36 32 32
+ + 31 30 29
212 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

modelof22 <- lm(respuesta ~ A + B + A*B, data = datosf22)


# kable(anova(modelof22))
anova(modelof22)

## Analysis of Variance Table


##
## Response: respuesta
## Df Sum Sq Mean Sq F value Pr(>F)
## A 1 208.333 208.333 53.1915 8.444e-05 ***

07
## B 1 75.000 75.000 19.1489 0.002362 **
## A:B 1 8.333 8.333 2.1277 0.182776
## Residuals 8 31.333 3.917

5-
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

-0
Gráficos de los efectos
library(lattice)
trellis.par.set(background = list(col = "white"))
plot(effect(term = "A", mod = modelof22))
19
## NOTE: A is not a high-order term in the model
20
A effect plot
or

32
ad

30
respuesta

rr

28
Bo

26

24

22

− +
A
3.6. INTRODUCCIÓN AL DISEÑO DE EXPERIMENTOS 213

plot(effect(term = "B", mod = modelof22))

07
## NOTE: B is not a high-order term in the model

5-
-0
19
20
B effect plot

32
or

30
ad
respuesta

28
rr
Bo

26

24

− +
B
plot(effect(term = "A:B", mod = modelof22))
214 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

A*B effect plot


− +
B=− B=+
35

30

07
respuesta

25

5-
-0
20

− 19 +
A
20
modelof22 <- lm(respuesta ~ A + B, data = datosf22)
anova(modelof22)
or
ad
rr
Bo

## Analysis of Variance Table


##
## Response: respuesta
## Df Sum Sq Mean Sq F value Pr(>F)
## A 1 208.333 208.333 47.269 7.265e-05 ***
## B 1 75.000 75.000 17.017 0.002578 **
## Residuals 9 39.667 4.407
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
plot(effect(term = "A", mod = modelof22))
3.6. INTRODUCCIÓN AL DISEÑO DE EXPERIMENTOS 215

A effect plot

32

30
respuesta

07
28

26

5-
24

-0
22

− 19 A
+
20
plot(effect(term = "B", mod = modelof22))

B effect plot
or

32
ad

30
rr
respuesta

28
Bo

26

24

− +
B
216 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

Diseño factorial 23
Modelo:

yijkl = αi + βj + γk + αβij + αγik + βγjk + αβγijk + εijkl

Datos: - Aleatorizar tratamientos - l réplicas (o no) - Número de experimentos: l × 23


Análisis:

07
Efectos principales
Interacciones (más de dos difícil de ver)
Eliminar no significativas para aumentar precisión

5-
Ejemplo:
datosf23 <- scan(text = "

-0
- - - 60
+ - - 72
- + - 54
+
-
+
+
-
-
-
+
+
68
52
83
19
20
- + + 45
+ + + 80
",
what = list(character(), character(), character(), numeric()),
or

sep = "\t")
datosf23 <- as.data.frame(datosf23)
colnames(datosf23) <- c("T", "C", "K", "rendimiento")
ad

kable(dcast(datosf23, T + C + K ~ ., value.var = "rendimiento"))

T C K .
- - - 60
rr

- - + 52
- + - 54
Bo

- + + 45
+ - - 72
+ - + 83
+ + - 68
+ + + 80
modelof23 <- lm(rendimiento ~ T + C + K + T*C + T*K + C*K, data = datosf23)
anova(modelof23)

## Analysis of Variance Table


##
## Response: rendimiento
3.6. INTRODUCCIÓN AL DISEÑO DE EXPERIMENTOS 217

## Df Sum Sq Mean Sq F value Pr(>F)


## T 1 1058.0 1058.0 2116 0.01384 *
## C 1 50.0 50.0 100 0.06345 .
## K 1 4.5 4.5 9 0.20483
## T:C 1 4.5 4.5 9 0.20483
## T:K 1 200.0 200.0 400 0.03180 *
## C:K 1 0.0 0.0 0 1.00000
## Residuals 1 0.5 0.5
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

07
Gráfico de efectos e interacciones:

5-
plot(effect(term = "T", mod = modelof23))

-0
## NOTE: T is not a high-order term in the model

19
T effect plot
20
80

75
or

70
rendimiento

ad

65

60
rr

55
Bo

50

− +
T
plot(effect(term = "C", mod = modelof23))

## NOTE: C is not a high-order term in the model


218 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

C effect plot

70

68
rendimiento

66

07
64

5-
62

60

-0
58

− 19 C
+
20
plot(effect(term = "K", mod = modelof23))
or
ad
rr
Bo

## NOTE: K is not a high-order term in the model


3.6. INTRODUCCIÓN AL DISEÑO DE EXPERIMENTOS 219

K effect plot

68

66
rendimiento

07
64

5-
62

-0
60

− 19 K
+
20
plot(effect(term = "T:C", mod = modelof23))

T*C effect plot


or

− +
C=− C=+
ad

80
rr

70
rendimiento

Bo

60

50

− +
T
220 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

plot(effect(term = "T:K", mod = modelof23))

07
5-
-0
19
20
T*K effect plot
− +
or

K=− K=+
ad

80
rendimiento

rr

70
Bo

60

50

− +
T
plot(effect(term = "C:K", mod = modelof23))
3.6. INTRODUCCIÓN AL DISEÑO DE EXPERIMENTOS 221

C*K effect plot


− +
K=− K=+

70
rendimiento

07
65

5-
60

-0
55

− 19 +
C
20
Diseño factorial 2k

Misma estructura que los dos anteriores


or

Más interacciones, pero más allá de 3 es muy difícil que se produzcan …


… Y más difícil de interpretar
El número de experimentos necesarios aumenta exponencialmente
ad

Se suelen preferir experimentos fraccionados


Herramientas gráficas para seleccionar efectos significativos (Pareto y gráfico normal)
Formacion de bloques:
• Multiplicar los signos y dividir en dos bloques
rr

• Confundir bloques con efectos de interacciones de orden superior


Pasar a diseños fraccionales 2k−p
Bo

3.6.6. Diseños avanzados


Existen otros diseños avanzados que no se tratan en este texto, como son:

Plackett and Burman


Diseños anidados
Split-plot
Medidas repetidas
Superficie respuesta
222 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

3.7. Prácticas
En este apartado se presentan las prácticas a las que se han hecho referencia durante el
capítulo. La reproducibilidad del código ha sido comprobada con la sesión de R que se
detalla en el Prefacio. El lector puede teclear el código o copiarlo y pegarlo en la consola o
el editor. También se puede descargar el script con el código de todas las prácticas con la
siguiente expresión:
download.file("http://emilio.lcano.com/b/adr/practicas/03-anova.R",
destfile = "practicas/03-anova.R")

07
Práctica 3.1: ANOVA de un factor

5-
Ejemplo 1
El primer ejemplo de ANOVA trata de verificar si la variable dependiente “Rendimiento por

-0
árbol” depende, en media, del factor “Tipo de fertilizante utilizado”. Dicho factor tiene tres
niveles: (1) fertilizante de tipo químico y (2) fertilizante de tipo orgánico y (3) fertilizante
tipo cuántico.

19
Las expresiones utilizadas se encuentran en el script de las prácticas del capítulo. Para tu
comodidad, puedes descargarlo a una carpeta dentro de tu proyecto de RStudio, por ejemplo,
“prácticas”, o cualquier otro nombre de tu elección. En lo sucesivo, vamos a suponer que
20
estamos trabajando en un proyecto que contiene una carpeta llamada “datos” donde se
encuentran los ficheros de datos.
Opcionalmente, podemos en primer lugar limpiar el espacio de trabajo eliminando todos los
or

objetos existentes:
rm(list = ls())
ad

3.7.0.0.0.1. Análisis exploratorio de datos


En este ejemplo, como tenemos pocos datos, vamos a introducirlos en el propio script. Intro-
rr

ducimos las variables para 6 casos (plantaciones) mediante dos vectores, uno numérico para
la variable “Rendimiento” y otro de tipo factor para la variable “(Tipo de) Fertilizante”,
Bo

que puede ser Q(uímico), O(rgánico) o C(uántico). Luego formamos la hoja de trabajo o
data.frame uniendo ambos vectores, y calculamos los principales estadísticos de la variable
y el factor con la función summary. Esta función nos devuelve, para variables numéricas, el
resumen de cinco números más la media, y para factores, una tabla de frecuencias.
Rendimiento <- c(1, 2, 5, 3, 7, 8, 8, 8.5, 10)
Fertilizante <- factor(c("Q", "Q", "Q", "O", "O", "O", "C", "C", "C"))
Datos <- data.frame(Rendimiento, Fertilizante)
summary(Datos)

## Rendimiento Fertilizante
## Min. : 1.000 C:3
3.7. PRÁCTICAS 223

## 1st Qu.: 3.000 O:3


## Median : 7.000 Q:3
## Mean : 5.833
## 3rd Qu.: 8.000
## Max. :10.000

07
La función tapply ofrece la información sobre la primera variable para cada uno de los
grupos formados por los diferentes niveles del factor que se pasa como segunda variable. En

5-
nuestro caso, nos interesa estudiar el rendimiento para cada fertilizante. Esta información
puede ser un summary o cualquier otra función.

-0
tapply(Rendimiento, Fertilizante, summary)

19
20
## $C
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.000 8.250 8.500 8.833 9.250 10.000
or

##
## $O
## Min. 1st Qu. Median Mean 3rd Qu. Max.
ad

## 3.0 5.0 7.0 6.0 7.5 8.0


##
## $Q
rr

## Min. 1st Qu. Median Mean 3rd Qu. Max.


## 1.000 1.500 2.000 2.667 3.500 5.000
Bo

A continuación generamos unos gráficos de caja o “boxplot” de la variable “Rendimiento”


para cada uno de los grupos formados por el factor “Fertilizante”:
boxplot(Rendimiento ~ Fertilizante,
main = "Boxplot del Rendimiento por clase de fertilizante",
col = "green4", las = 1)
224 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

Boxplot del Rendimiento por clase de fertilizante

10

8
Rendimiento

07
4

5-
2

-0
C O Q

19 Fertilizante

Los gráficos “boxplot” ya nos indican cómo todo hace pensar que entre los grupos de distinto
20
tipo de fertilizante va a haber apreciables diferencias en la media. Interpretación del gráfico:
La caja contiene una banda que es la mediana. La caja contiene el 50 % de los casos centrales.
Por arriba sale una línea que llega al valor más grande que no llega a ser atípico; y por debajo
de la caja lo mismo pero mínimo. Un valor atípico es el que se aleja más de 1.5 longitudes de
or

caja del percentil 75, por arriba; o del 25, por debajo. Si hubiera, saldrían dibujos de círculos.
Valores extremos son aquellos que se alejan más de 3 longitudes de caja del percentil 75, por
arriba; o del 25, por debajo.
ad

3.7.0.0.0.2. Estimación del modelo


rr

Pasamos al Análisis de la Varianza propiamente dicho. Si las hipótesis de normalidad y


homogeneidad en las varianzas se cumplen, se realizará el contraste F de diferencia en las
medias (función aov), que se guarda como el objeto “Datos.aov”, y que luego se muestra en
Bo

forma resumida. Nótese la forma en la que debemos especificar el modelo en R utilizando


un objeto de clase “fórmula”. Estas fórmulas consisten en dos expresiones separadas por el
símbolo ~. A la izquierda ponemos la variable (o matriz de variables) dependientes, y a la
derecha, las variables independientes combinadas con los operadores apropiados (véase la
ayuda en R con ?formula). En nuestro caso, como el modelo a utilizar es:

Rendimiento = µ + F ertilizantei + ε,

entonces tenemos que utilizar como fórmula la expresión Rendimiento ~ Fertilizante.


3.7. PRÁCTICAS 225

Datos.aov <- aov(Rendimiento ~ Fertilizante,


data = Datos)
summary(Datos.aov)

## Df Sum Sq Mean Sq F value Pr(>F)


## Fertilizante 2 57.17 28.583 6.906 0.0278 *
## Residuals 6 24.83 4.139

07
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

5-
El valor del estadístico F es de 6.906, con un p-value de 0.0278. Como el p-value es menor

-0
que 0.05, se rechaza la hipótesis nula de medias iguales para un nivel de confianza del 95 %;
por lo que podremos decir que el tipo de fertilizante explica, en media, el rendimiento de la
explotación.
19
20
or

3.7.0.0.0.3. Validación de hipótesis


ad

Sabemos que las conclusiones a las que lleguemos con el análisis de la varianza (ANOVA)
rr

serán válidas en la medida en que se cumplan las hipótesis de normalidad de los residuos y
homogeneidad en las varianzas de la variable dependiente (“Rendimiento”) en los grupos en
que queda dividida la muestra por los niveles o categorías del factor (“Fertilizante”). Hemos
Bo

de comprobar, pues, ambas hipótesis.

Ahora que tenemos el modelo, vamos a validar la hipótesis de normalidad. La función plot
sobre el modelo ajustado del análisis de la varianza nos proporciona varios gráficos de diag-
nóstico. Para verlos todos juntos, utilizamos la función par para crear una matriz de 2 × 2
gráficos.
par(mfrow = c(2, 2))
plot(Datos.aov)
226 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

Standardized residuals
Residuals vs Fitted Normal Q−Q
3 3
Residuals

2 6 6

0.5
0

−1.5
−3

4 4

3 4 5 6 7 8 9 −1.5 −0.5 0.5 1.0 1.5

Fitted values Theoretical Quantiles

07
Constant Leverage:
Standardized residuals

Standardized residuals
Scale−Location Residuals vs Factor Levels

5-
4 3
3 6 6
0.8

-0
0.0

−2
4
Fertilizante :
3 4 5 6 7 8 9 C O Q

par(mfrow = c(1,1))
Fitted values 19 Factor Level Combinations
20
El gráfico de los residuos frente a los valores estimados (fitted) sirve para comprobar la
homogeneidad de varianzas. Una forma de embudo de la nube de puntos significaría un
problema en este sentido. El gráfico QQ debería mostrar los puntos aproximadamente sobre
or

la línea recta para confirmar la normalidad de los residuos. Los gráficos inferiores pueden
ser útiles para identificar dónde puede estar el problema concreto si los gráficos superiores
muestran alguna violación de las hipótesis.
ad

Podemos utilizar contrastes de hipótesis si los métodos gráficos no son suficientemente claros.
Para contrastar la homogeneidad en las varianzas (varianzas constantes entre los grupos),
podemos proceder a un análisis de la dispersión mediante la prueba de Bartlett.
rr

bartlett.test(Rendimiento ~ Fertilizante, data = Datos)


Bo

##
## Bartlett test of homogeneity of variances
##
## data: Rendimiento by Fertilizante
## Bartlett's K-squared = 1.2584, df = 2, p-value = 0.533

El p-valor es mucho mayor a 0.05, luego no se rechaza la hipótesis nula de homogeneidad


entre las varianzas de los grupos. El gráfico boxplot sí daba, aparentemente, cierta diferencia
en la dispersión de los grupos; pero no la suficiente para considerar sus varianzas distintas.

Para contrastar la hipótesis de normalidad de los residuos, podemos utilizar el test de Shapiro-
3.7. PRÁCTICAS 227

Wilk. Los residuos los podemos obtener directamente con la función residuals aplicada al
modelo,
shapiro.test(residuals(Datos.aov))

##
## Shapiro-Wilk normality test
##
## data: residuals(Datos.aov)
## W = 0.96032, p-value = 0.8016

07
El p-valor es muy grande, por lo que no tenemos evidencia para rechazar la hipótesis de
normalidad, y por tanto consideramos válido el resultado del contraste de la F .

5-
3.7.0.0.0.4. Análisis del modelo

-0
El análisis no ha terminado, hay que proceder al análisis de “comparaciones múltiples”. Este
análisis indica qué grupos concretos difieren significativamente entre sí en la media de la

19
variable dependiente (test HSD de Tukey).
TukeyHSD(Datos.aov, conf.level = 0.95)
20
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov.default(formula = Rendimiento ~ Fertilizante, data = Datos)
or

##
## $Fertilizante
## diff lwr upr p adj
ad

## O-C -2.833333 -7.93005 2.263383 0.2781535


## Q-C -6.166667 -11.26338 -1.069950 0.0231845
## Q-O -3.333333 -8.43005 1.763383 0.1913278
rr

La tabla nos proporciona las diferencias reales entre cada grupo, un intervalo de confianza
(lwr límite inferior, upr límite superior) al 95 % (por defecto, pero se puede cambiar), y
Bo

un p-valor con el contraste de Tukey para comparaciones múltiples. Vemos cómo solo hay
diferencias significativas entre el fertilizante cuántico y el químico, ya que el intervalo de
confianza no contiene al cero. A partir de aquí, el analista deberá combinar otra información,
como el coste de los fertilizantes y otras consideraciones para tomar una decisión sobre cuál
utilizar.

Aunque en este caso no habría que hacerlo, si no se hubieran cumplido las hipótesis de
normalidad y/o homogeneidad en las varianzas, existen varias pruebas robustas para saber
si, en media, el factor influye sobre el valor de la variable dependiente. Aquí mostramos la
prueba de Kruskal-Wallis. En este caso, para un nivel de confianza del 95 % se rechaza la
hipótesis nula de igualdad en las medias, aunque por poco.
228 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

kruskal.test(Rendimiento ~ Fertilizante, data = Datos)

##
## Kruskal-Wallis rank sum test
##
## data: Rendimiento by Fertilizante
## Kruskal-Wallis chi-squared = 6.1176, df = 2, p-value = 0.04694
Para las comparaciones múltiples, en este caso también existe una prueba de Kruskal; pero
para poder ejecutarla hay que cargar en el espacio de trabajo el paquete “pgirmess”. La

07
instalación desde RStudio es trivial a través de la pestaña “Packages” del panel inferior
derecho. Una vez el paquete está instalado, hay que cargarlo con la función library para
que sus funciones estén disponibles.

5-
library("pgirmess")

-0
La prueba, una vez cargado el paquete anterior, se ejecuta con la función “kruskalmc”:
kruskalmc(Rendimiento ~ Fertilizante, data = Datos)

##
##
##
p.value: 0.05
Comparisons
19
Multiple comparison test after Kruskal-Wallis
20
## obs.dif critical.dif difference
## C-O 3.0 5.353102 FALSE
## C-Q 5.5 5.353102 TRUE
## O-Q 2.5 5.353102 FALSE
or

Para cada posible diferencia se da la diferencia observada en los rangos medios, el valor
crítico, y la conclusión (si es verdadera o falsa la relevancia de la diferencia). En este caso,
se llega a la misma conclusión que con el test paramétrico.
ad

Ejemplo 2
rr

En este ejemplo vamos a intentar verificar la influencia del nivel de renta per cápita provin-
cial (factorizado mediante la variable NIV_RENT_04 en tres niveles de renta, “Alta” para
provincias con renta superior a 20000 euros / habitante; “Media” para provincias con rentas
Bo

entre 20000 y 15000, y “Baja” para provincias con renta inferior a 15000)) sobre la tasa
de paro (variable TASA_PARO_05). Los datos se encuentran en el archivo de texto con
separación mediante tabulaciones “rentas_paro.txt”.
Las expresiones utilizadas se encuentran en el script de las prácticas del capítulo. En lo
sucesivo, vamos a suponer que estamos trabajando en un proyecto que contiene una carpeta
llamada “datos” donde se encuentran los ficheros de datos. El fichero se puede descargar a
la carpeta de datos del proyecto con la siguiente expresión:
download.file("http://emilio.lcano.com/b/adr/datos/rentas_paro.txt",
"datos/rentas_paro.txt")
3.7. PRÁCTICAS 229

Opcionalmente, podemos en primer lugar limpiar el espacio de trabajo eliminando todos los
objetos existentes:
rm(list = ls())

3.7.0.0.0.5. Análisis exploratorio


A continuación se van a cargar los datos. Esta vez se cargaran a partir de un archivo de texto
llamado “rentas_paro.txt”. Las columnas están separadas por tabuladores, puedes abrir el
archivo en el editor de texto para ver su aspecto.

07
Para cargar los datos correctamente ejecutaremos la siguiente expresión:
Datos <- read.table("datos/rentas_paro.txt",
header = TRUE, sep = "\t", dec = ",",

5-
na.strings = "NA", row.names = 1,
encoding = "latin1")

-0
Datos

## TASA_PARO_05 PROV_COSTERA NIV_RENT_04


##
##
##
Albacete
Badajoz
Cáceres
19
10.008567
17.505084
12.981455
0
0
0
1
1
1
20
## Córdoba 14.767194 0 1
## Granada 12.901665 1 1
## Jaén 15.916338 0 1
## Lugo 6.684967 1 1
## Ourense 10.488246 0 1
or

## A Coruña 9.859223 1 2
## Alicante 9.611898 1 2
ad

## Almería 9.162806 1 2
## Asturias 10.240363 1 2
## Ávila 8.844508 0 2
## Cádiz 17.652023 1 2
rr

## Cantabria 8.502295 1 2
## Ciudad Real 10.580164 0 2
Bo

## Cuenca 6.478210 0 2
## Guadalajara 7.050285 0 2
## Huelva 15.876516 1 2
## Las Palmas 12.830075 1 2
## León 10.819949 0 2
## Málaga 11.657573 1 2
## Murcia 8.009366 1 2
## Palencia 7.474227 0 2
## Pontevedra 11.021749 1 2
## Salamanca 9.088000 0 2
## Santa Cruz de Tenerife 10.492766 1 2
230 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

## Segovia 6.816655 0 2
## Sevilla 13.857495 0 2
## Soria 5.118602 0 2
## Teruel 4.662379 0 2
## Toledo 9.117195 0 2
## Valencia 8.586980 1 2
## Zamora 9.996733 0 2
## Álava 7.088059 0 3
## Baleares 7.215780 1 3
## Barcelona 6.965572 1 3

07
## Burgos 6.730066 0 3
## Castellón 7.315701 1 3
## Girona 7.331990 1 3

5-
## Guipúzcoa 5.648889 1 3
## Huesca 6.886841 0 3
## Lleida 5.885396 0 3

-0
## Madrid 6.804290 0 3
## Navarra 5.647241 0 3
##
##
##
Rioja
Tarragona
Valladolid
19
6.180243
7.062623
9.229526
0
1
0
3
3
3
20
## Vizcaya 8.451806 1 3
## Zaragoza 5.761757 0 3
El argumento “encoding” nos asegura la correcta importación de los caracteres no ASCII
(acentos, eñes, etc.). Por ejemplo, el fichero fue creado con Windows en la codificación “la-
or

tin1”, si no ponemos esta opción en Mac o Linux, los textos no se verían correctamente.
El resto de argumentos indican que la primera fila en dicho archivo es el nombre de las
ad

variables, éstas están separadas por tabulaciones (\t), los decimales se expresan con comas,
si faltara algún dato (que no es el caso) en el archivo vendría expresado como “NA”. Con
el argumento row.names = 1 se informa de que la primera columna de datos del archivo
no es una variable, sino que se considera como la columna que informa del nombre de cada
rr

observación (provincia). Los datos son asignados a un data.frame llamado “Datos”. Pode-
mos comprobar cómo la columna “NIV_RENT_04”, al contener números, se ha importado
Bo

automáticamente como una variable numérica que toma los valores 1, 2, y 3:


is.factor(Datos$NIV_RENT_04)

## [1] FALSE
table(Datos$NIV_RENT_04)

##
## 1 2 3
## 8 26 16
Vamos a convertir esta variable numérica en un factor, asignando a los valores 1, 2, 3 los
3.7. PRÁCTICAS 231

niveles Bajo, Medio, Alto respectivamente:


Datos$NIV_RENT_04 <- factor(Datos$NIV_RENT_04,
labels = c("Bajo", "Medio", "Alto"))
summary(Datos$NIV_RENT_04)

## Bajo Medio Alto


## 8 26 16
Ahora pedimos un “summary” de la variable TASA_PARO_05 para tener los princi-
pales estadísticos de la misma. Nótese que el conjunto de datos contiene otra variable

07
(PROV_COSTERA) que no se utiliza en este ejemplo.
summary (Datos)

5-
## TASA_PARO_05 PROV_COSTERA NIV_RENT_04
## Min. : 4.662 Min. :0.00 Bajo : 8

-0
## 1st Qu.: 6.907 1st Qu.:0.00 Medio:26
## Median : 8.716 Median :0.00 Alto :16
## Mean : 9.297 Mean :0.44
##
##
3rd Qu.:10.558
Max. :17.652 Max. 19
3rd Qu.:1.00
:1.00
La instrucción tapply ofrece la información sobre la primera variable (TASA_PARO_05)
20
para cada uno de los grupos formados por los diferentes niveles del factor (NIV_RENT_04):
with(Datos,
tapply(TASA_PARO_05, NIV_RENT_04, summary)
)
or

## $Bajo
## Min. 1st Qu. Median Mean 3rd Qu. Max.
ad

## 6.685 10.368 12.942 12.657 15.054 17.505


##
## $Medio
rr

## Min. 1st Qu. Median Mean 3rd Qu. Max.


## 4.662 8.133 9.387 9.746 10.760 17.652
Bo

##
## $Alto
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 5.647 6.107 6.926 6.888 7.241 9.230
A continuación generamos unos gráficos de caja o boxplot de la variable 2 para cada uno de
los grupos formados por el factor “NIV_RENT_04”:
boxplot(TASA_PARO_05 ~ NIV_RENT_04,
main = "Boxplot de la Tasa de Paro por nivel de Renta.",
col = "steelblue",
data = Datos,
232 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

las = 1)

Boxplot de la Tasa de Paro por nivel de Renta.

18

16
TASA_PARO_05

14

07
12

10

5-
8

-0
6

Bajo 19 Medio Alto


20
NIV_RENT_04 Los
gráficos “boxplot” a nos indican cómo todo hace pensar que entre los grupos de distinto
2

nivel de renta va a haber apreciables diferencias en la media.


or

3.7.0.0.0.6. Estimación del modelo

Pasamos al Análisis de la Varianza propiamente dicho. Si las hipótesis de normalidad y


ad

homogeneidad en las varianzas se cumplieran, se realizaría el contraste F de diferencia en las


medias (función aov), que se guardaría como el objeto (por ejemplo) Datos.aov, y que luego
se mostraría en forma resumida.
rr

Datos.aov <- aov(TASA_PARO_05 ~ NIV_RENT_04,


data = Datos)
Bo

summary(Datos.aov)

## Df Sum Sq Mean Sq F value Pr(>F)


## NIV_RENT_04 2 188.4 94.21 13.76 1.98e-05 ***
## Residuals 47 321.9 6.85
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Como el p-value es muy pequeño, incluso mucho menor que 0.05, se rechazaría la hipótesis
nula de medias iguales; por lo que podríamos decir que el nivel de renta está relacionado, en
media, con la tasa de paro de las provincias.
3.7. PRÁCTICAS 233

3.7.0.0.0.7. Validación del modelo


Sabemos que las conclusiones a las que lleguemos con el análisis de la varianza (ANOVA)
serán válidas en la medida en que se cumplan las hipótesis de normalidad y homogeneidad en
las varianzas de la variable dependiente (“TASA_PARO_05”) en los grupos en que queda
dividida la muestra por los niveles o categorías del factor (“NIV_RENT_04”). Hemos de
contrastar, pues, ambas hipótesis.
Al igual que en ejemplo anterior, vamos a estudiar los diagnósticos gráficos y los contrastes
de hipótesis.

07
par(mfrow = c(2,2))
plot(Datos.aov)

Standardized residuals

5-
Residuals vs Fitted Normal Q−Q
Cádiz Cádiz

3
Residuals

Huelva Huelva
5

-0
1
−5

−2
Lugo Lugo

7 8 9 10

Fitted values
11 12
19 −2 −1 0

Theoretical Quantiles
1 2
20
Standardized residuals

Standardized residuals

Scale−Location Residuals vs Leverage


or

Cádiz Cádiz
Huelva Lugo 0.5
Badajoz
0 2
1.0

Cook's distance
ad
0.0

−3

Lugo

7 8 9 10 11 12 0.00 0.04 0.08 0.12


rr

Fitted values Leverage

par(mfrow = c(1,1))
Bo

Vamos a comprobar la normalidad de los residuos con el test de Shapiro-Wilk:


shapiro.test(residuals(Datos.aov))

##
## Shapiro-Wilk normality test
##
## data: residuals(Datos.aov)
## W = 0.95283, p-value = 0.04465
Para un nivel de confianza del 95 %, los rechazaríamos la hipótesis nula de normalidad de
234 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

los residuos. En cuanto a la homogeneidad en las varianzas (varianzas constantes entre los
grupos), procedemos a un análisis de la dispersión mediante la pruebas de Bartlett.
bartlett.test(TASA_PARO_05 ~ NIV_RENT_04,
data = Datos)

##
## Bartlett test of homogeneity of variances
##
## data: TASA_PARO_05 by NIV_RENT_04
## Bartlett's K-squared = 18.279, df = 2, p-value = 0.0001073

07
La igualdad de varianzas tampoco se cumple, y la normalidad de los residuos está muy
dudosa, ya que aunque se rechazaria la hipótesis de normalidad para un nivel de confianza

5-
del 95 %, el p-valor es muy próximo a 0.05.

3.7.0.0.0.8. Análisis del modelo

-0
Hagamos el análisis de “comparaciones múltiples”. Este análisis indica qué grupos concretos
difieren significativamente entre sí en la media de la variable dependiente (test HSD de
Tukey):
TukeyHSD(Datos.aov, conf.level = 0.95)
19
20
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov.default(formula = TASA_PARO_05 ~ NIV_RENT_04, data = Datos)
or

##
## $NIV_RENT_04
## diff lwr upr p adj
ad

## Medio-Bajo -2.910227 -5.470768 -0.3496856 0.0225052


## Alto-Bajo -5.768828 -8.511189 -3.0264676 0.0000182
## Alto-Medio -2.858602 -4.870944 -0.8462590 0.0034822
rr

Vemos cómo entre cada dos grupos de renta el intervalo de valores definido por los extremos
(lwr) y (upr) no contienen al 0. Esto indicaría que las diferencias entre los distintos grupos,
Bo

considerados dos a dos, son siempre significativas.


No obstante, hemos visto cómo no se cumplía la hipótesis de igualdad de varianzas, y había
dudas sobre si se cumplía la hipótesis de normalidad, por lo que el análisis sobre la influencia
de los niveles del factor (renta) sobre el valor medio de la variable dependiente (tasa de paro)
debe realizarse por medio de otras pruebas de tipo robusto, como la de Kruskal-Wallis, que
se realizará mediante el código:
kruskal.test(TASA_PARO_05 ~ NIV_RENT_04,
data = Datos)

##
3.7. PRÁCTICAS 235

## Kruskal-Wallis rank sum test


##
## data: TASA_PARO_05 by NIV_RENT_04
## Kruskal-Wallis chi-squared = 18.698, df = 2, p-value = 8.707e-05
Se rechaza la hipótesis nula de igualdad en las medias para un nivel de confianza del 95 %,
y además el p-valor es muy pequeño. Por lo tanto concluimos que sí influye sobre la tasa de
paro medio el hecho de que se tenga uno u otro nivel de renta.
Para las comparaciones múltiples también existe una prueba no-paramétrica de Kruskal;

07
pero para poder ejecutarla hay que cargar en memoria el paquete “pgirmess” como vimos
en el primer ejemplo.
library ("pgirmess")

5-
La prueba, una vez cargado el paquete anterior, se ejecuta con la instrucción “kruskalmc”:

-0
kruskalmc(TASA_PARO_05 ~ NIV_RENT_04,
data = Datos)

##
##
##
p.value: 0.05
Comparisons
19
Multiple comparison test after Kruskal-Wallis
20
## obs.dif critical.dif difference
## Bajo-Medio 9.778846 14.10937 FALSE
## Bajo-Alto 25.125000 15.11126 TRUE
## Medio-Alto 15.346154 11.08863 TRUE
or

Esta prueba nos informa de que las diferencias en la tasa de paro media entre los grupos de
renta “alta” y “media”; y “alta” y “baja” son relevantes; no así entre los grupos de renta
“media” y “baja”.
ad

Práctica 3.2: ANOVA multifactorial


rr

Borramos el espacio de trabajo:


rm(list = ls())
Bo

En el segundo ejemplo de la práctica 3.1 teníamos una variable que en principio no hemos
utilizado, pero que ahora vamos a analizar para realizar un ANOVA con dos factores. Esta
variable llamada “PROV_COSTERA” tiene un 0 si la provincia es de interior, y un 1 si
la provincia es de costa. Como hemos borrado el espacio de trabajo para empezar de cero,
vamos a importar el conjunto de datos de nuevo:
Datos <- read.table("datos/rentas_paro.txt",
header = TRUE, sep = "\t", dec = ",",
na.strings = "NA", row.names = 1,
encoding = "latin1")
236 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

Vamos a recodificar las variables cualitativas TIPO_PROV y NIV_RENTA_04 como factores para
una aplicación correcta del método, y a la vez facilitar la interpretación:
Datos$TIPO_PROV <- factor(Datos$PROV_COSTERA, labels = c("Interior", "Costa"))
Datos$NIV_RENT_04 <- factor(Datos$NIV_RENT_04,
labels = c("Bajo", "Medio", "Alto"))

Como ahora tenemos dos factores, el modelo que queremos ajustar es:

07
5-
Y = µ + αi + βj + (αβ)ij + ε

-0
siendo Y la variable TASA_PARO_05, A el factor NIV_RENTA_04 y B el factor TI-
PO_PROV. Para especificar este modelo con interacción podemos utilizar en la parte dere-

19
cha de la fórmula la forma a*b, que indica todos los efectos principales y sus interacciones, o
equivalentemente a + b + a:b, que incluye explícitamente cada término. Así, para nuestro
ejemplo:
20
Datos.aov2 <- aov(TASA_PARO_05 ~ NIV_RENT_04*TIPO_PROV, data = Datos)
summary(Datos.aov2)
or

## Df Sum Sq Mean Sq F value Pr(>F)


## NIV_RENT_04 2 188.42 94.21 16.206 5.33e-06 ***
ad

## TIPO_PROV 1 13.83 13.83 2.380 0.1301


## NIV_RENT_04:TIPO_PROV 2 52.25 26.13 4.494 0.0167 *
## Residuals 44 255.78 5.81
rr

## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Bo

Lo que nos indica que, si bien el efecto principal del tipo de provincia no es significativo
de por sí, sí que lo es la interacción entre el nivel de renta y el tipo de provincia. Esto lo
podemos visualizar claramente en los siguientes gráficos de los efectos:
with(Datos,
interaction.plot(NIV_RENT_04, TIPO_PROV, TASA_PARO_05,
las = 1, ylab = "Tasa de Paro", xlab = "Nivel de Renta",
lwd = 2, col = "steelblue")
)
3.7. PRÁCTICAS 237

TIPO_PROV
13
Costa
12 Interior
Tasa de Paro

11

10

07
8

5-
Bajo Medio Alto

-0
Nivel de Renta

diferencia: 19
Sin embargo comparando el tipo de provincia por separado no hubiéramos observado ninguna

boxplot(TASA_PARO_05 ~ TIPO_PROV, data = Datos, col = "lightblue", las = 1,


20
xlab = "Tasa de paro")
18

16
or
TASA_PARO_05

14
ad

12

10
rr

8
Bo

Interior Costa

Tasa de paro

Conclusión: Asegúrate siempre de medir todas las variables que puedas. Si te dejas
algunas, información relevante puede quedar oculta.
Comprobamos finalmente que las hipótesis del modelo para asegurarnos de que las conclusio-
238 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

nes son válidas. Para la homogeneidad de varianzas utilizamos el test de Levene, que permite
incluir el término de interacción.
shapiro.test(residuals(Datos.aov2))

##
## Shapiro-Wilk normality test
##
## data: residuals(Datos.aov2)
## W = 0.95677, p-value = 0.06508

07
car::leveneTest(TASA_PARO_05 ~ NIV_RENT_04*TIPO_PROV, data = Datos)

## Levene's Test for Homogeneity of Variance (center = median)

5-
## Df F value Pr(>F)
## group 5 2.4295 0.0498 *
## 44

-0
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

19
Para un nivel de confianza del 95 % no rechazamos la normalidad de los residuos. Sí recha-
zaríamos la homogeneidad de la varianza, pero por muy poquito. Sería aceptable dar por
bueno el modelo, informando de este resultado ajustado para la igualdad de varianzas.
20
Práctica 3.3: Análisis de un experimento con efectos aleatorios
Limpiamos el espacio de trabajo:
or

rm(list = ls())

en preparación
ad

Práctica 3.4: MANOVA


Limpiamos el espacio de trabajo para empezar de cero:
rr

rm(list = ls())
Bo

Para el caso en el que tengamos más de una variable respuesta que puedan estar afectadas
por los niveles de un factor conjuntamente, la función que utilizaremos en R es manova. En
este caso, en la especificación del modelo tenemos que indicar en el lado izquierdo de la
fórmula una matriz con las variables respuesta.
Vamos a ilustrar el MANOVA con un conjunto de datos de ejemplo disponible en R llamado
iris. Este conjunto de datos contiene las dimensiones del pétalo y el sépalo de una serie de
flores de tres especies distintas:
summary(iris)

## Sepal.Length Sepal.Width Petal.Length Petal.Width


3.7. PRÁCTICAS 239

## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100


## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
## Median :5.800 Median :3.000 Median :4.350 Median :1.300
## Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
## Species
## setosa :50
## versicolor:50
## virginica :50

07
##
##
##

5-
Podemos estudiar si los vectores de estas mediciones son significativamente diferentes para
cada especie así:

-0
X <- iris$Species
Y <- as.matrix(iris[, 1:4])
modelo <- manova(Y ~ X)
summary(modelo)

##
19
Df Pillai approx F num Df den Df Pr(>F)
20
## X 2 1.1919 53.466 8 290 < 2.2e-16 ***
## Residuals 147
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
or

El contraste de hipótesis nos indica que sí hay diferencias, que podríamos ir buscando en
cada una de las variables con los métodos vistos anteriormente.
ad

Como ejercicio, prueba a realizar el MANOVA con grupos de dos variables (las referidas al
sépalo y al pétalo), en vez de las cuatro en conjunto.
rr
Bo
240 CAPÍTULO 3. ANÁLISIS DE LA VARIANZA CON R

07
5-
-0
19
20
or
ad
rr
Bo
Capítulo 4

07
Análisis de componentes principales
con R

5-
-0
4.1. Introducción
19
El análisis de componentes principales (ACP) es una técnica multivariante de análisis de
interdependencias. Esto quiere decir que no tenemos una variable dependiente que queramos
predecir o explicar, sino que lo que nos interesa es explicar el conjunto de las variables,
20
reduciendo la dimensión para una fácil interpretación o posterior uso. Forma parte de un
conjunto de técnicas llamadas genéricamente análisis factorial que no veremos en este texto.
Los métodos matemáticos difieren, la interpretación es similar pero se utilizan para distintos
propósitos.
or

El análisis de componentes principales tiene dos aplicaciones relevantes en el análisis multi-


variante:
ad

1. Reducir la dimensión para utilizar en otras técnicas. Por ejemplo, en regresión múltiple,
donde es necesario que las variables independientes estén incorreladas, y que sean pocas
en relación al número de observaciones.
rr

2. Explicar las relaciones entre las variables. Por ejemplo para agrupar características de
productos, servicios, etc., o detectar variables latentes.
Bo

Partimos de una muestra de n individuos en la cual medimos una serie de p variables


(X1 , · · · , Xj , · · · , Xp ) = X en escala métrica (de intervalo). El objetivo de esta técnica es
obtener una nueva variable multidimensional U que reduzca la dimensionalidad de X , de p
dimensiones. Esta nueva variable será de r dimensiones, de forma que = (U1 , · · · , Uk , · · · , Ur ),
tal que r < p, cuyas componentes son combinación lineal de las variables originales Xj .
La técnica tiene sentido solo cuando las variables Xj están correlacionadas, siendo más po-
tente cuanto mayor sea esa correlación en valor absoluto. Por contra, las variables resultantes
Uk van a estar totalmente incorrelacionadas entre sí.
El objetivo final es que la nueva variable U explique una proporción suficientemente grande

241
242 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

de la dispersión total incluida en los datos originales X . Matemáticamente, podemos expresar


el problema matricialmente como:

   
x11 x12 · · · x1j · · · x1p u11 ··· u1k · · · u1r
 x21 x22 · · · x2j · · · x2p   u21 ··· u2k · · · u2r 
 
  −→ 


 r < p,
 ··· ··· ··· ··· ··· ···   ··· ··· ··· ··· ··· 
xn1 xn2 · · · xnj · · · xnp un1 ··· unk · · · unr

de forma que uik = β1k xi1 + · · · + βpk xip , y el problema por tanto es encontrar los vectores
β⃗k que expliquen la máxima cantidad de variabilidad de X .

07
4.2. Obtención de las componentes principales

5-
Aunque el análisis de componentes principales se puede realizar sobre las variables originales
Xj , es aconsejable hacerlo con las variables tipificadas a las que llamaremos Zj . De esta

-0
forma, evitaremos que variables en una escala mayor tengan más influencia en las variables
transformadas Uk por el mero hecho de estar expresadas en una escala mayor, y no por la

19
propia variabilidad de los datos, que es lo que nos interesa. Recordemos que una variable
tipificada se obtiene restando la media y dividiendo por la desviación típica:

X j − µj
20
Zj = .
σj

Al trabajar con un conjunto de datos haríamos:


or

xij − xj
zij = .
sj
ad

La tabla 4.1 contiene los datos de un ejemplo extremadamente sencillo de forma


deliberada con propósitos ilustrativos. El conjunto de datos consta de tres variables (p = 3)
rr

y seis observaciones (n = 6). Las tres variables están en escala métrica. Vamos a utilizar el
conjunto de datos a lo largo del capítulo para ilustrar la técnica. El código siguiente crea el
Bo

conjunto de datos en forma de matriz en R y tipifica las variables con la función scale. Los
valores ya tifificados se muestran en la tabla 4.2.

ejacp <- matrix(c(23, 31, 24, 35, 52, 46,


13, 21, 14, 23, 41, 37,
6.5, 5, 4.5, 5, 7.5, 6),
ncol = 3,
dimnames = list(casos = paste0("caso", 1:6),
variables = paste0("variable",
1:3)))
ejacpt <- scale(ejacp)
4.2. OBTENCIÓN DE LAS COMPONENTES PRINCIPALES 243

Tabla 4.1: Datos ejemplo ilustrativo


variable1 variable2 variable3
caso1 23 13 6.5
caso2 31 21 5.0
caso3 24 14 4.5
caso4 35 23 5.0
caso5 52 41 7.5
caso6 46 37 6.0

07
Tabla 4.2: Datos tificados ejemplo ilustrativo
variable1 variable2 variable3
caso1 -1.035 -1.011 0.664

5-
caso2 -0.354 -0.328 -0.664
caso3 -0.950 -0.926 -1.107

-0
caso4 -0.014 -0.157 -0.664
caso5 1.432 1.381 1.550
caso6 0.922 1.040 0.221

19
Antes de empezar a aplicar la técnica, debemos comprobar que los datos cumplen con las
20
condiciones mínimas para aplicar la técnica. Recordemos que las variables tienen que estar en
escala métrica, y debe existir cierta correlación entre ellas para que tenga sentido reducir la
dimensión del conjunto con la mínima pérdida de información. La función cor de R nos ofrece
la matriz de correlaciones. Es indiferente calcularlas sobre las variables originales o sobre las
tipificadas, ya que la estructura de correlación se mantiene. La matriz de correlaciones es
or

una matriz cuadrada simétrica, en las diagonales tenemos unos y fuera de las diagonales, las
correlaciones de cada par de variables fila-columna.
ad

Debemos comprobar que las variables tienen clase num o int para poder aplicar la
técnica, por ejemplo con la función str o simplemente explorando el objeto en la pestaña
rr

Environment de R Studio. La matriz de correlaciones indica una alta correlación entre las
tres variables, especialmente entre la primera y la segunda.
Bo

str(ejacp)

## num [1:6, 1:3] 23 31 24 35 52 46 13 21 14 23 ...


## - attr(*, "dimnames")=List of 2
## ..$ casos : chr [1:6] "caso1" "caso2" "caso3" "caso4" ...
## ..$ variables: chr [1:3] "variable1" "variable2" "variable3"
cor(ejacp)

## variable1 variable2 variable3


## variable1 1.0000000 0.9961326 0.6065117
244 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

## variable2 0.9961326 1.0000000 0.6091628


## variable3 0.6065117 0.6091628 1.0000000
Veamos pues cómo calcular las componentes principales. En principio, se calculan tantas
componentes como variables, es decir, p. Posteriormente veremos los criterios a seguir para
seleccionar sólo las r principales. Ya hemos dicho que cada componente se calcula como
combinación lineal de todas las variables originales, es decir, para cada individuo i tenemos
que los valores del factor Uk son (usando ya las variables tipificadas):

uik = β1k zi1 + · · · + βjk zij + · · · + βpk zip .

07
En forma matricial:

5-
Uk = X β k , (4.1)

-0
donde βk es el vector de coeficientes de la componente principal k, que nos disponemos a
calcular1 . Esto se hace de forma iterativa, encontranto primero la componente (combinación
lineal) que explique el máximo de varianza posible de X . Es decir, para U1 Buscamos los
19
coeficientes β1 que hagan máxima la varianza de U1 , operando matricialmente:
20
V (U1 ) = E[β1′ X ′ Xβ1 ] = β1′ E[X ′ X]β1 = β1′ Σβ1 ,

donde Σ es la matriz de varianzas-covarianzas de X .


Se trata pues de maximizar esta varianza, a la que pondremos una condición de normalización,
or

lo que quiere decir que los coeficientes al cuadrado sumen 1, ya que si no podríamos aumentar
la varianza sin más que aumentar los coeficientes. Así pues, el problema de maximización es:
ad

máx β1′ Σβ1 s.a.β1′ β1 = 1.


rr

Se demuestra que la solución a este problema viene dada por el autovector de la matriz Σ
correspondiente a la primera componente, es decir λ∗1 = máx{λ1 , . . . , λp }. Los coeficientes de
Bo

la componente con máxima varianza se obtienen resolviendo:

(Σ − λ∗1 I)β1 = 0.

A continuación se calcularían iterativamente el resto de vectores de coeficientes βk con el


mismo criterio, es decir, maximizar la varianza que no haya sido explicada por las anteriores
componentes. Se añadiría una restricción más: que cada nueva componente esté incorrelada
con las anteriores:
1
Algunas veces se les llama en inglés variable loadings, aunque el término es un poco confuso ya que el
término loading se utiliza más para las cargas factoriales (ver más adelante).
4.2. OBTENCIÓN DE LAS COMPONENTES PRINCIPALES 245

máx βk′ Σβk (4.2)


s.a. βk′ βk = 1 (4.3)
βk′ β1 = βk′ β2 = · · · = βk′ βk−1 = 0. (4.4)

Para cada iteración, la solución es el autovector correspondiente al siguiente autovalor de Σ


ordenados de forma decreciente, λ1 > λ2 > . . . > λp , y así tenemos todos los vectores de
coeficientes βk para todas las p componentes iniciales.

07
Volviendo a los datos tipificados del ejemplo anterior, podemos obtener la matriz

5-
de varianzas-covarianzas con la función cov sobre el conjunto de datos. A continuación, es
trivial obtener los autovalores y autovectores con la función eigen.

-0
S <- cov(ejacpt)
S

## variable1 variable2
## variable1 1.0000000 0.9961326
## variable2 0.9961326 1.0000000
19variable3
0.6065117
0.6091628
20
## variable3 0.6065117 0.6091628 1.0000000
auto <- eigen(S)
auto
or

## eigen() decomposition
## $values
## [1] 2.491546458 0.504591729 0.003861813
ad

##
## $vectors
## [,1] [,2] [,3]
rr

## [1,] 0.6123787 -0.3553737 0.706188260


## [2,] 0.6129108 -0.3507865 -0.708017763
## [3,] 0.4993322 0.8664054 0.002998225
Bo

Nótese que, al estar las variables tipificadas, la matriz de varianzas-covarianzas es en realidad


idéntica a la matriz de correlaciones. Además, hay que tener en cuenta que la función cov
calcula la matriz de varianzas-covarianzas muestrales S, mientras que Σ se refiere a la matriz
de varianzas-covarianzas poblacionales2
La función eigen devuelve una lista con dos elementos:
values: un vector con los autovalores, ordenados de mayor a menor.
2
Recuérdese, de Estadística descriptiva, la diferencia en el cálculo utilizando en el denominador de la
varianza n − 1 en lugar de n.
246 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

vectors: una matriz cuyas columnas son los autovectores asociados a cada autovalor.
Es decir, los coeficientes factoriales.

Las siguientes matrices representan los coeficientes calculados para nuestro ejemplo.

     
0,612 −0,355 0,706
     
β1 =  0,613  ; β2 =  −0,351  ; β3 =  −0,708 

07
0,499 0,866 0,003

Una vez tenemos los coeficientes podemos calcular los valores de las nuevas variables para

5-
cada individuo. Estos valores se denominan puntuaciones o scores, y es necesario calcularlas
cuando vamos a utilizar las nuevas variables en otras aplicaciones, como regresión o clasifi-
cación mediante la operación matricial de la ecuación (4.1).

-0
Las siguientes operaciones matriciales obtienen los scores para todas las componentes
19
y solo para la primera componente respectivamente. Por ejemplo, la puntuación del primer
individuo en la primera componente de nuestro ejemplo se calcula como se indica en la
ecuación (4.5).
20
factores <- ejacpt %*% auto$vectors
factores
or

##
## casos [,1] [,2] [,3]
## caso1 -0.9219151 1.2979978 -0.01307735
ad

## caso2 -0.7494908 -0.3346067 -0.02041171


## caso3 -1.7018787 -0.2968117 -0.01880682
## caso4 -0.4363583 -0.5154861 0.09890737
rr

## caso5 2.4975183 0.3492833 0.03792631


## caso6 1.3121246 -0.5003765 -0.08453781
Bo

primerfactor <- ejacpt %*% auto$vectors[, 1]


primerfactor

##
## casos [,1]
## caso1 -0.9219151
## caso2 -0.7494908
## caso3 -1.7018787
## caso4 -0.4363583
## caso5 2.4975183
## caso6 1.3121246
4.3. SELECCIÓN E INTERPRETACIÓN DE COMPONENTES 247

u11 = β11 z11 + β21 z12 + β31 z13 = 0,612 · (−1,035) + 0,613 · (−1,011) + 0,499 · 0,664 = −0,922.
(4.5)

Podemos comprobar cómo los coeficientes y las componentes cumplen con los requisi-
tos que se impusieron para su cálculo. En primer lugar, la condición de normalización de los
coeficientes βk′ βk = 1. En segundo lugar, las correlaciones entre los nuevos factores Ui son
cero.

07
t(auto$vectors[, 1]) %*% auto$vectors[, 1]

## [,1]

5-
## [1,] 1
t(auto$vectors[, 2]) %*% auto$vectors[, 2]

-0
## [,1]
## [1,] 1

## [,1]
19
t(auto$vectors[, 3]) %*% auto$vectors[, 3]
20
## [1,] 1
cor(factores)

## [,1] [,2] [,3]


or

## [1,] 1.000000e+00 4.129860e-16 -4.242141e-16


## [2,] 4.129860e-16 1.000000e+00 8.653886e-16
ad

## [3,] -4.242141e-16 8.653886e-16 1.000000e+00

4.3. Selección e interpretación de componentes


rr

El significado de los autovalores λj es la varianza explicada por cada componente. Efecti-


Bo

vamente, la matriz de varianzas-covarianzas Λ de las variables transformadas Ui , muestra,


además de que los factores están incorrelados, que los autovalores son las varianzas de los
factores:

 
λ1 0 · · · 0
 .. 
 . λ2 · · · 0 
 
Λ=  .. .. . . . 
 
 . . . .. 
0 0 · · · λp

Podemos ver esto claramente en el ejemplo comprobando que la traza de la matriz de


248 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

varianzas-covarianzas tipificada3 , p, es igual a la traza de la matriz de varianzas-covarianzas


de los factores, o lo que es lo mismo, a la suma de los autovalores.
sum(diag(S))

## [1] 3
sum(diag(cov(factores)))

## [1] 3
sum(auto$values)

07
## [1] 3
Otra forma de verlo es calculando la varianza de los factores, que se corresponde con los

5-
autovalores como podemos comprobar en nuestro ejemplo:
apply(factores, 2, var)

-0
## [1] 2.491546458 0.504591729 0.003861813
auto$values

## [1] 2.491546458 0.504591729 0.003861813


19
20
Con todas las componentes tenemos explicadas todas las variables, es decir, la varianza total.
Por tanto, podemos expresar esta varianza explicada como un porcentaje. Así, el porcentaje
de varianza explicada por la primera componente será:
or

λ1 λ1

p × 100 = × 100.
λj p
j=1
ad

Estos porcentajes los podemos acumular y obtenemos el porcentaje acumulado de varianza


explicado por k componentes, lo que nos proporcionará un criterio para decidir el número
rr

de componentes principales r seleccionadas finalmente, como veremos más adelante. En el


ejemplo, los porcentajes acumulados son:
cumsum(auto$values)/sum(auto$values)
Bo

## [1] 0.8305155 0.9987127 1.0000000


Lo que quiere decir que con la primera componente ya explicamos el 83 % de la varianza de
X , y con las dos primeras el 99,9 %, con lo que habríamos reducido la dimensión.
Del cálculo de las componentes principales obtenemos p nuevas variables Uk . No obstante,
hay una diferencia importante con respecto al conjunto de datos original X , y es que estas
nuevas variables están incorreladas. Por otra parte, al estar los nuevos factores ordenados
de mayor a menor varianza explicada, estos van perdiendo importancia a medida que vamos
3
Si se hiciera con las variables sin tipificar también se cumpliría, pero a otra escala.
4.3. SELECCIÓN E INTERPRETACIÓN DE COMPONENTES 249

reteniendo componentes principales, por lo que es fácil reducir la dimensión descartando las
últimas. Existen varios criterios para decidir cuántas componentes retener el la matriz de
datos U final. Un criterio muy extendido es quedarse con las componentes Uk cuya varianza,
o lo que es lo mismo, su autovalor asociado, sea mayor que la media de todos los autovalores:

Uk : λk > λ.
Si se han tipificado las variables originales como es habitual, esto equivale a aquellos auto-
valores mayores de 1:

07
Uk : λk > 1.

Un criterio gráfico es utilizar el llamado gráfico de sedimentación (scree plot). En este gráfico

5-
se representan en el eje vertical los autovalores, y en el eje horizontal el número de orden del
autovalor de las componentes. Así, tenemos un gráfico decreciente con forma de ladera de

-0
montaña, y el criterio sería quedarse con las componentes antes de llegar a la meseta.

19
El gráfico 4.1 muestra el gráfico de sedimentación de nuestro ejemplo, que se puede
generar con el código a continuación. Por otra parte, el criterio del autovalor mayor de uno
nos estaría indicando que una componente es suficiente. Se puede incorporar esta información
20
al gráfico como una línea horizontal.

plot(auto$values,
main = "Gráfico de sedimentación",
type = "b", pch = 16,
or

axes = FALSE,
xlab = "Número de componente",
ylab = "Autovalor")
ad

axis(1, at = 1:3)
axis(2, las = 1)
abline(h = 1, col = "blue", lty = 2)
rr

box()

Estos criterios deben servir de guía, pero el analista puede decidir tomar más o menos
Bo

componentes si esto favorece a los objetivos del análisis. Por ejemplo, para una más fácil
comprensión de los resultados, especialmente el análisis gráfico que se verá en el apartado
siguiente, lo ideal es tener dos componentes, ya que la representación en dos dimensiones de
las componentes facilita la interpretación. Por otra parte, si el criterio indica utilizar una
sola componente como en el ejemplo, utilizar dos puede enriquecer igualmente el análisis e
interpretación. En todo caso, es importante tener en cuenta que mantener menos componen-
tes de las necesarias explicarán peor el conjunto total mientras que quedarse con más de las
necesarias explicarán mejor el modelo, pero complicarán su interpretación y uso.
Una vez seleccionados los factores, vamos a intentar interpretarlos en relación a las variables
originales. Esto no siempre es sencillo, y depende principalmente de la estructura de correla-
250 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

Gráfico de sedimentación

2.5

2.0
Autovalor

1.5

07
1.0

0.5

5-
0.0

-0
1 2 3

19
Número de componente

Figura 4.1: Gráfico de sedimentación


20
ción de las variables X . Una forma de interpretar dicha relación es mediante las correlaciones
entre las componentes seleccionadas Uk y las variables originales Xj . Cuando las variables
or

están tipificadas, estas correlaciones vienen dadas por:


ad

rjk = βjk λk .

Estos coeficientes se denominan cargas factoriales o saturaciones4 , y forman la llamada matriz


factorial. De esta forma, podemos analizar las componentes Uk una por una, y ver con
rr

qué variables Xj están más correlacionadas. La situación ideal es cuando cada componente
está altamente correlacionada con un grupo distinto de variables, y poco con el resto. Las
Bo

componentes principales heredarán el significado de las variables X con las que comparte
una mayor carga factorial o saturación.

Para el ejemplo de las tres variables que estamos utilizando, el siguiente código calcula
las saturaciones de los dos primeros componentes

auto$vectors[,1]*sqrt(auto$values[1])

## [1] 0.9666173 0.9674572 0.7881776


4
En inglés, factor loadings o loadings a secas.
4.4. ANÁLISIS GRÁFICO DE LOS COMPONENTES PRINCIPALES 251

auto$vectors[,2]*sqrt(auto$values[2])

## [1] -0.2524384 -0.2491799 0.6154478

Podemos calcularlo en una sola operación:


t(auto$vectors[,1:2])*sqrt(auto$values[1:2])

## [,1] [,2] [,3]


## [1,] 0.9666173 0.9674572 0.7881776

07
## [2,] -0.2524384 -0.2491799 0.6154478

Y comprobar que coincide con la correlación:

5-
cor(ejacp[, 1], factores[, 1])

## [1] 0.9666173

-0
La primera componente está más correlacionada con las variables X1 y X2 , y la segunda
componente está más correlacionada con la variable X3 . En este ejemplo de variables ge-

19
néricas no podemos decir mucho más, pero cuando las variables tienen un significado las
conclusiones pueden ser muy interesantes.
20
4.4. Análisis gráfico de los componentes principales
Previamente al cálculo de los componentes principales, podemos visualizar los datos multi-
or

variantes mediante herramientas gráficas. La función ggpairs del paquete GGally realiza
una matriz de gráficos. Por defecto, en la diagonal muestra una línea de densidad5 de cada
variable, debajo de la diagonal, las nubes de puntos para cada par de variables, y sobre
ad

la diagonal, los coeficientes de correlación. Cuando hay muchas variables estos gráficos se
ven muy pequeños y quizás merece la pena trazar solo algunos, filtrando las variables. Las
correlaciones se pueden visualizar con la función corrplot del paquete del mismo nombre.
rr

También podemos hacer una matriz de gráficos solo con los histrogramas o gráficos de caja
que nos pueden servir para detectar posibles errores, ya que en esta técnica es indiferente la
distribución que sigan los datos.
Bo

A continuación se muestra código para el análisis exploratorio gráfico de los datos


del ejemplo. La figura 4.2 muestra la salida de la función ggpairs, que requiere un objeto
de tipo data frame. La figura 4.3 muestra la salida de la función corrplot, que requiere
como entrada la matriz de correlaciones. La figura 4.4 muestra histogramas de todas las
variables, para lo que antes debemos “apilar” los datos de las mismas en una sola columna.
Las opciones por defecto proporcionan una visualización adecuada, aunque en ambos casos
se puede personalizar su contenido, véase la documentación de las funciones para los detalles.

5
Una línea de densidad tiene la forma del histograma, pero suavizada.
252 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

variable1 variable2 variable3


0.03

variable1
0.02
Corr: Corr:
0.01
0.996 0.607

0.00
40

07
variable2
30 Corr:
0.609
20

5-
-0
7

variable3
6

5 19
20
30 40 50 20 30 40 5 6 7

Figura 4.2: Matriz de gráficos por pares


or

gdata <- as.data.frame(ejacp)


library(GGally)
ggpairs(gdata)
ad

correlaciones <- cor(ejacp)


library(corrplot)
corrplot(correlaciones, addCoef.col = "white", number.digits = 3)
rr

library(lattice)
Bo

library(reshape2)
gdata <- melt(ejacp)
histogram(~ value | variables, data = gdata,
scales = list(x = list(relation = "free")),
breaks = NULL)

Ya vimos en el apartado anterior una visualización de los autovalores mediante el screeplot.


Una vez seleccionadas las componentes principales, podríamos hacer una visualización de
los datos multivariantes y univariantes de las nuevas variables. Además, podemos visualizar
cómo se relacionan las variables con las componentes en los llamados biplots, que son gráficos
en dos dimensiones en los cuales cada dimensión se corresponde con una componente. En
4.4. ANÁLISIS GRÁFICO DE LOS COMPONENTES PRINCIPALES 253

07
variable1

variable2

variable3

5-
1

-0
0.8
variable1 1 0.996 0.607
0.6

19 0.4
20
0.2

variable2 0.996 1 0.609 0

−0.2
or

−0.4
ad

−0.6
variable3 0.607 0.609 1
−0.8
rr

−1

Figura 4.3: Matriz de gráficos por pares


Bo
254 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

variable1 variable2 variable3


50

40
Percent of Total

30

07
20

5-
10

-0
0

25 30 35 40 45 50
19
15 20 25 30 35 40 4.5 5.0 5.5 6.0 6.5 7.0 7.5

value
20
Figura 4.4: Histogramas de las variables del ejemplo
or

el siguiente aparatado veremos cómo realizar biplots más completos, pero con los cálculos
realizados hasta ahora podemos hacer un gráfico sencillo con las saturaciones para ver qué
ad

componentes explican qué variables.

La figura 4.5 muestra una visualización de las saturaciones o cargas factoriales pa-
rr

ra las dos primeras componentes del ejemplo. Vemos claramente cómo la componente 1 se
correspondería con el significado de las variables 1 y 2, mientras que el componente 2 repre-
Bo

sentaría el significado de la variable 3 (aunque con la primera componente en este caso ya


tendríamos bastante). El gráfico se ha obtenido con el código a continuación.

paleta <- RColorBrewer::brewer.pal(3, "Dark2")


cargas <- t(auto$vectors[,1:2])*sqrt(auto$values[1:2])
plot(t(cargas), pch = 19, col = paleta,
xlab = "Componente 1",
ylab = "Componente 2",
las = 1, cex = 1.5,
main = "Cargas factoriales")
legend(0.93, 0.6, legend = paste0("variable", 1:3), col = paleta, pch = 19)
4.5. ANÁLISIS DE COMPONENTES PRINCIPALES CON R 255

Cargas factoriales

0.6
variable1
variable2
0.4 variable3
Componente 2

0.2

07
0.0

5-
−0.2

-0
0.80 0.85 0.90 0.95

19 Componente 1

Figura 4.5: Representación de las cargas factoriales


20
4.5. Análisis de componentes principales con R
En los apartados anteriores se ha descrito el método general para obtener los componentes
or

principales, utilizando el método de los autovalores y la matriz de varianzas-covarianzas


muestral. En realidad, se pueden utilizar otros métodos diferentes con el mismo objetivo. En
ad

este apartado vamos a revisar las funciones base de R y las proporcionadas por el paquete
FactoMineR.
rr

4.5.1. Funciones base de R para ACP


En R, disponemos principalmente de dos funciones para realizar análisis de componentes prin-
Bo

cipales: prcomp y princomp. La función prcomp utiliza la matriz de varianzas-covarianzas


muestral, es decir, dividiendo por n − 1 para calcular los estadísticos, y el método de descom-
posición en valores singulares (SVD, singular-value decomposition por sus siglas en inglés)
en vez del método de los autovectores de la matriz de varianzas-covarianzas. La función
princomp utiliza por defecto la matriz de varianzas-covarianzas poblacional, es decir, divi-
diendo por n para calcular los estadísticos, y el método de los autovalores explicado an-
teriormente. Generalmente los resultados de ambas funciones deben ser similares. En la
documentación de R se recomienda utilizar prcomp por precisión numérica.
Las funciones requieren como argumento de entrada las variables en escala métrica, que
pueden especificarse como una matriz o data frame, o como una fórmula sin variable respuesta.
256 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

Por defecto, los datos se centran, pero no se escalan. Este comportamiento se puede cambiar
con los argumentos center y scale.

El resultado de la función prcomp es un objeto de clase prcomp, que será una lista con cinco
elementos:

sdev: Desviaciones típicas de los factores, es decir, λ
rotation: Son los coeficientes o variable loadings, es decir, β i
center: Las medias de las variables originales
scale: Las desviaciones típicas de las variables originales

07
x: Las puntuaciones o scores de cada individuo en cada componente

El método print del objeto muestra solamente los dos primeros. El método summary nos

5-
devuelve para cada componente las desviaciones típicas, y proporción de varianza explicada
por cada una y acumulada. La función screeplot6 genera un gráfico de sedimentación
sencillo7 . Por último, existe un método predict que se explicará en el apartado 4.6.

-0
La función biplot crea la visualización más utilizada para el análisis de componentes prin-
cipales. Este gráfico en dos dimensiones representa las cargas factoriales de cada variable, en

19
la escala de los ejes superior y derecho, y las puntuaciones de las observaciones en los ejes
inferior e izquierdo. No obstante, los valores están escalados por los autovalores de cada com-
ponente representada (véase ?biplot.prcomp). Por defecto se representan las dos primeras
20
componentes, pero se pueden representar cualquier par de componentes con el argumento
choices. En este gráfico se interpretan las componentes en función de las variables que
mejor explican cada una de ellas. Gráficamente las variables que explican bien un factor se
situarán próximas y con valores de los loadings altos (en valor absoluto).
or

A continuación vamos a realizar el análisis de los datos del ejemplo utilizando ambas funcio-
nes.
ad

El siguiente código realiza el análisis de componentes principales utilizando la fun-


ción prcomp. Podemos pasar los datos originales y el argumento scale y hace la tipificación

rr

automáticamente. Mostramos el resultado del objeto y vemos las desviaciones típicas ( λ)


y los autovectores de la matriz de varianzas covarianzas (βi ). Con la función summary obte-
Bo

nemos los porcentajes de varianza explicada, de cada componente y acumulada. La función


screeplot obtiene un gráfico de sedimentación (véase la figura 4.6), con el argumento type
elegimos el tipo línea en vez de barras. La figura 4.7 muestra el biplot por defecto para
nuestro ejemplo. Vemos cómo forman dos grupos: uno con las dos primeras variables, y otro
con la tercera. Los casos también se representan en función de sus puntuaciones factoria-
les, de forma que se pueden interpretar sus proximidades en función del significado de las
componentes. Las puntuaciones factoriales o scores se pueden obtener directamente con el
elemento x del objeto guardado.

6
El método plot realiza lo mismo.
7
Por defecto, gráfico de barras, pero se puede cambiar el aspecto.
4.5. ANÁLISIS DE COMPONENTES PRINCIPALES CON R 257

modelo.cp

2.5
2.0
Variances

1.5

07
1.0
0.5

5-
0.0

-0
1 2 3

19
Figura 4.6: Gráfico de sedimentación con la función screeplot
20
modelo.cp <- prcomp(ejacp, scale = TRUE)
modelo.cp

## Standard deviations (1, .., p=3):


or

## [1] 1.57846332 0.71034620 0.06214349


##
## Rotation (n x k) = (3 x 3):
ad

## PC1 PC2 PC3


## variable1 0.6123787 -0.3553737 0.706188260
## variable2 0.6129108 -0.3507865 -0.708017763
rr

## variable3 0.4993322 0.8664054 0.002998225


summary(modelo.cp)
Bo

## Importance of components:
## PC1 PC2 PC3
## Standard deviation 1.5785 0.7103 0.06214
## Proportion of Variance 0.8305 0.1682 0.00129
## Cumulative Proportion 0.8305 0.9987 1.00000
screeplot(modelo.cp, type = "l")

biplot(modelo.cp)
258 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

−2 −1 0 1 2 3

caso1

3
0.6

2
0.4
variable3

0.2

1
caso5
PC2

07
0.0

0
caso3 caso2 variable2
variable1

5- −1
caso4 caso6
−0.4

−2
-0
−0.4 0.0 0.2 0.4 0.6

19 PC1

Figura 4.7: Biplot de las dos primeras componentes del ejemplo


20
modelo.cp$x

##
or

## casos PC1 PC2 PC3


## caso1 -0.9219151 1.2979978 -0.01307735
## caso2 -0.7494908 -0.3346067 -0.02041171
ad

## caso3 -1.7018787 -0.2968117 -0.01880682


## caso4 -0.4363583 -0.5154861 0.09890737
## caso5 2.4975183 0.3492833 0.03792631
rr

## caso6 1.3121246 -0.5003765 -0.08453781


Además de la distinta forma de calcular la matriz de varianzas-covarianzas, la función
Bo

princomp produce el resultado de forma ligeramente diferente. Los coeficientes β i se guardan


en el elemento loadings, que además tiene un método print que muestra otra información
utilizada en análisis factorial. El signo de los coeficientes es arbitrario, pero esto no influye
en la interpretación final ya que los scores también tendrán los signos invertidos. Por otra
parte, las puntuaciones o scores de cada individuo en cada componente se guardan en el
elemento scores.

A continuación se muestra el mismo análisis con la función princomp. Al mostrar el


objeto solamente aparecen las desviaciones típicas, el número de variables y de observaciones.
Los coeficientes se encuentran en el elemento loadings del objeto. Nótese que al utilizar la
4.5. ANÁLISIS DE COMPONENTES PRINCIPALES CON R 259

matriz de varianzas-covarianzas poblacional y ser un conjunto de datos tan pequeño, algunos


resultados pueden diferir. Además, observamos que los signos de los coeficientes pueden estar
invertidos, como en este caso. No obstante, el número de componentes seleccionados (figura
4.8) y el agrupamiento de las variables es el mismo (figura 4.9). La forma de construir el
biplot también es ligeramente distinta (véase ?plot.prcompy ?plot.princomp).

modelo.cp2 <- princomp(ejacpt)


modelo.cp2

07
## Call:
## princomp(x = ejacpt)
##
## Standard deviations:

5-
## Comp.1 Comp.2 Comp.3
## 1.44093328 0.64845440 0.05672898

-0
##
## 3 variables and 6 observations.
modelo.cp2$loadings

##
## Loadings:
19
20
## Comp.1 Comp.2 Comp.3
## variable1 0.612 0.355 0.706
## variable2 0.613 0.351 -0.708
## variable3 0.499 -0.866
or

##
## Comp.1 Comp.2 Comp.3
## SS loadings 1.000 1.000 1.000
ad

## Proportion Var 0.333 0.333 0.333


## Cumulative Var 0.333 0.667 1.000
summary(modelo.cp2)
rr

## Importance of components:
Bo

## Comp.1 Comp.2 Comp.3


## Standard deviation 1.4409333 0.6484544 0.056728982
## Proportion of Variance 0.8305155 0.1681972 0.001287271
## Cumulative Proportion 0.8305155 0.9987127 1.000000000
screeplot(modelo.cp2, type = "l")

biplot(modelo.cp2)

modelo.cp2$scores

##
260 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

modelo.cp2
2.0
1.5
Variances

07
1.0

5-
0.5

-0
0.0

Comp.1 Comp.2 Comp.3


19
Figura 4.8: Screeplot con la función princomp
20
−2 −1 0 1 2
or

2
ad 0.5

caso4
1

caso6
caso3caso2 variable1
variable2
Comp.2

0.0

0
rr

caso5
−1
Bo
−0.5

variable3
−2

caso1

−0.5 0.0 0.5

Comp.1

Figura 4.9: Biplot con la función princomp


4.5. ANÁLISIS DE COMPONENTES PRINCIPALES CON R 261

## casos Comp.1 Comp.2 Comp.3


## caso1 -0.9219151 -1.2979978 -0.01307735
## caso2 -0.7494908 0.3346067 -0.02041171
## caso3 -1.7018787 0.2968117 -0.01880682
## caso4 -0.4363583 0.5154861 0.09890737
## caso5 2.4975183 -0.3492833 0.03792631
## caso6 1.3121246 0.5003765 -0.08453781
Las funciones vistas no guardan las cargas factoriales, que son fundamentales para interpretar
las componentes. Esta información está implícita en el gráfico biplot, y se pueden calcular

07
con los coeficientes y los autovalores.

5-
Las cargas factoriales se pueden calcular utilizando los datos almacenados en el objeto
de clase prcomp8 , como en la siguiente expresión.

-0
t(modelo.cp$rotation)*modelo.cp$sdev

## variable1 variable2 variable3


## PC1 0.9666173 0.96745724 0.7881776363
## PC2 -0.2524384 -0.24917987 0.6154477873
## PC3 0.0438850 -0.04399869 0.0001863201
19
20
Realice la práctica 4.1 cuyo guión se encuentra en el apartado 4.7 para realizar análisis
de componentes principales del ejemplo básico presentado en el capítulo.
or

4.5.2. Análisis de componentes principales con otros paquetes


ad

Además de las funciones incluidas en la instalación base de R, hay algunos paquetes que
contienen funciones más avanzadas para realizar análisis de componentes principales. El más
conocido y uno de los más completos es FactoMineR (Husson et al., 2018)9 . La función
rr

PCA realiza el análisis de componentes principales. Permite incluir variables auxiliares para
mejorar la interpretación. El objeto creado tiene más información que las otras funciones,
Bo

tanto para cada variable como para cada observación. En concreto, para cada dimensión:
Observaciones
• Dim.X es la puntuación factorial de la observación
• ctr es la contribución de la observación a la dimensión (en porcentaje, con los
coeficientes al cuadrado)
• cos2 Es una medida de la calidad de la componente para explicar la observa-
ción, calculada como (Dim.X/Dist)^2. Cuanto más próximo a 1, mejor refleja la
componente todas las características de la observación.
9
En la Task View “Multivariate” se pueden encontrar algunos más: https://cran.r-project.org/web/views/
Multivariate.html
262 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

Además, para las observaciones se muestra Dist, que es una medida de la distancia de la
observación al centro de gravedad de los datos.

Variables
• Dim.X es la carga factorial de la variable (correlación con la componente)
• ctr es la contribución de la variable a la dimensión (en porcentaje)
• cos2 Es una medida de la calidad de la dimensión para explicar la variable,
calculada como el cuadrado de la carga factorial. Cuanto más próximo a 1, mejor
refleja la componente todas las características de la observación.

07
El paquete factoextra contiene algunas funciones para mejorar la visualización. En el si-
guiente ejemplo se explican todas estas particularidades.

5-
El código a continuación realiza el análisis de componentes principales de los datos
de ejemplo con el paquete FactoMineR. Automáticamente crea dos gráficos: uno con las

-0
puntuaciones individuales y otro con el mapa de factores (figura 4.10). El método print
muestra la descripción de los objetos guardados. Las cargas factoriales se encuentran en el
elemento var$cor. El método summary muestra los autovalores y su contribución. Además,

19
dos tablas para las observaciones y las variables, con información de cada dimensión: las
cargas factoriales para las variables, y las puntuaciones factoriales para los casos. Muestra
además dos métricas adicionales: contrib y cos2, que indican la contribución de cada va-
20
riable/observación y la calidad de la representación. Los coeficientes se encuentran en el
elemento svd$V. Las figuras 4.11 y 4.12 muestran una representación alternativa del scree-
plot y el biplot utilizando el paquete factoextra. La figura 4.13 es una visualización de las
cargas factoriales de las variables en las dos primeras componentes, con una escala de colores
or

según la calidad de la representación (cos2).

par(mfrow=c(1,2))
ad

library(FactoMineR)
modelo.cp3 <- PCA(ejacp, ncp = 2)

modelo.cp3
rr

## **Results for the Principal Component Analysis (PCA)**


Bo

## The analysis was performed on 6 individuals, described by 3 variables


## *The results are available in the following objects:
##
## name description
## 1 "$eig" "eigenvalues"
## 2 "$var" "results for the variables"
## 3 "$var$coord" "coord. for the variables"
## 4 "$var$cor" "correlations variables - dimensions"
## 5 "$var$cos2" "cos2 for the variables"
## 6 "$var$contrib" "contributions of the variables"
## 7 "$ind" "results for the individuals"
4.5. ANÁLISIS DE COMPONENTES PRINCIPALES CON R 263

07
Individuals factor map (PCA) Variables factor map (PCA)

5-
1.5
4

-0
1.0
variable3
variable3

0.5
Dim 2 (16.82%)

Dim 2 (16.82%)

19
2

caso1
0.0
caso5
20
variable2
variable2
0

caso2 caso4
caso3 variable1
variable1
−0.5

caso6
−2

or
−1.5
−4

ad

−2 −1 0 1 2 3 −1.0 0.0 0.5 1.0


rr

Dim 1 (83.05%) Dim 1 (83.05%)

Figura 4.10: Gráficos del análisis de componentes principales con ‘FactoMineR‘


Bo
264 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

## 8 "$ind$coord" "coord. for the individuals"


## 9 "$ind$cos2" "cos2 for the individuals"
## 10 "$ind$contrib" "contributions of the individuals"
## 11 "$call" "summary statistics"
## 12 "$call$centre" "mean of the variables"
## 13 "$call$ecart.type" "standard error of the variables"
## 14 "$call$row.w" "weights for the individuals"
## 15 "$call$col.w" "weights for the variables"
modelo.cp3$var$cor

07
## Dim.1 Dim.2
## variable1 0.9666173 -0.2524384

5-
## variable2 0.9674572 -0.2491799
## variable3 0.7881776 0.6154478
summary(modelo.cp3)

-0
##
##
##
##
Call:
PCA(X = ejacp, ncp = 2) 19
20
##
## Eigenvalues
## Dim.1 Dim.2 Dim.3
## Variance 2.492 0.505 0.004
or

## % of var. 83.052 16.820 0.129


## Cumulative % of var. 83.052 99.871 100.000
##
ad

## Individuals
## Dist Dim.1 ctr cos2 Dim.2 ctr cos2
## caso1 | 1.744 | -1.010 6.822 0.335 | 1.422 66.779 0.665 |
rr

## caso2 | 0.899 | -0.821 4.509 0.833 | -0.367 4.438 0.166 |


## caso3 | 1.893 | -1.864 23.250 0.970 | -0.325 3.492 0.030 |
## caso4 | 0.748 | -0.478 1.528 0.409 | -0.565 10.532 0.570 |
Bo

## caso5 | 2.763 | 2.736 50.070 0.981 | 0.383 4.836 0.019 |


## caso6 | 1.541 | 1.437 13.820 0.870 | -0.548 9.924 0.127 |
##
## Variables
## Dim.1 ctr cos2 Dim.2 ctr cos2
## variable1 | 0.967 37.501 0.934 | -0.252 12.629 0.064 |
## variable2 | 0.967 37.566 0.936 | -0.249 12.305 0.062 |
## variable3 | 0.788 24.933 0.621 | 0.615 75.066 0.379 |
par(mfrow=c(1,1))
modelo.cp3$svd$V
4.5. ANÁLISIS DE COMPONENTES PRINCIPALES CON R 265

Scree plot

80
Percentage of explained variances

60

07
40

5-
20

-0
0

1
19 2
Dimensions
3
20
Figura 4.11: Screeplot con el paquete ‘factoextra‘
or
ad

## [,1] [,2]
## [1,] 0.6123787 -0.3553737
## [2,] 0.6129108 -0.3507865
rr

## [3,] 0.4993322 0.8664054


factoextra::fviz_eig(modelo.cp3)
Bo

factoextra::fviz_pca_biplot(modelo.cp3)

factoextra::fviz_pca_var(modelo.cp3, col.var = "cos2",


repel = TRUE,
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"))

Realice la práctica 4.2 cuyo guión se encuentra en el apartado 4.7 para realizar
análisis de componentes principales en un conjunto de datos de provincias. Se utilizan tanto
las funciones base como las del paquete FactoMineR.
266 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

07
PCA − Biplot
1.5 caso1

5-
-0
1.0 variable3

19
Dim2 (16.8%)

0.5
caso5
20
0.0
or

caso3 caso2 variable2


variable1
ad

−0.5 caso4 caso6

−2 −1 0 1 2
rr

Dim1 (83.1%)

Figura 4.12: Biplot con el paquete ‘factoextra‘


Bo
4.5. ANÁLISIS DE COMPONENTES PRINCIPALES CON R 267

07
Variables − PCA
1.0

5-
-0
variable3
0.5
cos2

19
Dim2 (16.8%)

0.9995
0.0
20
0.9990
variable2
0.9985
variable1
−0.5
or
ad

−1.0

−1.0 −0.5 0.0 0.5 1.0


rr

Dim1 (83.1%)

Figura 4.13: Biplot con el paquete ‘factoextra‘


Bo
268 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

4.6. Aplicación del Análisis de Componentes Principa-


les a la regresión múltiple
En la introducción del capítulo ya se indicó que una de las aplicaciones del análisis de compo-
nentes principales es ajustar modelos de regresión múltiple cuando estamos en presencia de
multicolinealidad. Una de las hipótesis del modelo de regresión lineal múltiple es que no debe
haber correlación entre las variables predictivas. Un enfoque para solucionar este problema
es sacar del modelo variables de forma que las incluidas no estén correlacionadas. Además,
la reducción de la dimensionalidad ayuda a aumentar los grados de libertad del modelo, lo

07
que suele redundar en una mejora en la precisión del modelo y su capacidad predictiva. Otro
enfoque sería reducir la dimensión del conjunto de datos original a unas pocas componentes
principales y ajustar el modelo sobre dichas componentes en vez de sobre las variables origi-

5-
nales. Es decir, que si tenemos una variable respuesta Y y un vector de p variables predictivas
X , en lugar de ajustar el modelo:

-0

p
Y = β0 + βi Xi + ε,

19 i=1

obtenemos r componentes principales U como hemos visto en los apartados anteriores, y


ajustamos el modelo:
20

r
Y = β0′ + βi′ Ui + ε.
i=1
or

Por definición, las variables (componentes principales) U van a estar incorreladas, lo que
ad

soluciona el problema de la multicolinealidad. Como ventaja, estaremos utilizando todas las


variables explicativas, con cierta pérdida de información. Se puede evaluar este modelo con
el modelo resultante de una selección de variables, y ver cuál obtiene mejores resultados.
El principal inconveniente es que se pierde en parte la interpretación de los coeficientes de
rr

la regresión, βi′ . Pero esto va a depender de la interpretación que se le pueda dar a las
componentes Ui en base a las cargas factoriales.
Bo

Supongamos que en el ejemplo básico utilizado en el capítulo tenemos una


cuarta variable que queremos explicar con las otras tres, y que toma los valores
30,3, 30, 26,1, 32,5, 47,6, 39,5 para cada uno de los seis casos. El siguiente código ajus-
ta primero el modelo de regresión lineal múltiple con las variables originales. Muestra un
R2 muy alto y contraste F significativo, pero baja significación de los coeficientes. Este
resultado es típico de situaciones de multicolinealidad. A continuación se ajusta el modelo
con las dos primeras componentes obtenidas anteriormente, y ahora sí, la primera es
altamente significativa. La segunda no, por lo que podemos reducir el modelo a una sola
variable explicativa, manteniendo un alto R2 .
4.6. APLICACIÓN DEL ANÁLISIS DE COMPONENTES PRINCIPALES A LA REGRESIÓN MÚLTIPL

ejacpml <- data.frame(ejacp,


variable4 = c(30.3, 30, 26.1, 32.5, 47.6, 39.5),
modelo.cp$x[, 1:2])
ml1 <- lm(variable4 ~ ., ejacpml)
summary(ml1)

##
## Call:
## lm.default(formula = variable4 ~ ., data = ejacpml)

07
##
## Residuals:
## caso1 caso2 caso3 caso4 caso5 caso6

5-
## -0.1953 -0.2113 0.5652 -0.2625 0.3144 -0.2106
##
## Coefficients: (2 not defined because of singularities)

-0
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.3447 2.8104 -0.478 0.6795
## variable1 0.8016 0.2400 3.340 0.0791 .
##
##
##
variable2
variable3
PC1
-0.3276
2.7172
NA
0.2768
NA
19
0.2417 -1.356
9.817
NA
0.3079
0.0102 *
NA
20
## PC2 NA NA NA NA
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
or

## Residual standard error: 0.5542 on 2 degrees of freedom


## Multiple R-squared: 0.998, Adjusted R-squared: 0.995
## F-statistic: 334.5 on 3 and 2 DF, p-value: 0.002982
ad

ml2 <- lm(variable4 ~ PC1 + PC2, ejacpml)


summary(ml2)
rr

##
## Call:
Bo

## lm.default(formula = variable4 ~ PC1 + PC2, data = ejacpml)


##
## Residuals:
## caso1 caso2 caso3 caso4 caso5 caso6
## -0.3179 -0.4027 0.3888 0.6651 0.6701 -1.0034
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 34.3333 0.3584 95.786 2.51e-06 ***
## PC1 4.9521 0.2488 19.907 0.000277 ***
## PC2 0.6548 0.5528 1.185 0.321465
270 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.878 on 3 degrees of freedom
## Multiple R-squared: 0.9925, Adjusted R-squared: 0.9875
## F-statistic: 198.9 on 2 and 3 DF, p-value: 0.0006478
ml3 <- lm(variable4 ~ PC1, ejacpml)
summary(ml3)

07
##
## Call:
## lm.default(formula = variable4 ~ PC1, data = ejacpml)

5-
##
## Residuals:
## caso1 caso2 caso3 caso4 caso5 caso6

-0
## 0.5320 -0.6218 0.1945 0.3275 0.8988 -1.3310
##
## Coefficients:
##
##
##
(Intercept) 34.3333
PC1 4.9521
0.3761
0.2610
19
Estimate Std. Error t value
91.29
18.97
Pr(>|t|)
8.63e-08 ***
4.54e-05 ***
20
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.9212 on 4 degrees of freedom
or

## Multiple R-squared: 0.989, Adjusted R-squared: 0.9863


## F-statistic: 360 on 1 and 4 DF, p-value: 4.545e-05
ad

La estimación y predicción de nuevos valores se va a poder realizar con las transformaciones


pertinentes entre variables y factores, como se ilustra en el siguiente ejemplo.
rr

Supongamos que llega un nuevo caso con los valores 50, 40, y 7 para las tres variables
en estudio. ¿Qué predicción podemos hacer del valor que tomará la variable respuesta? Con
Bo

la función predict sobre el objeto prcomp podemos obtener las puntuaciones factoriales del
nuevo caso. Entonces ahora podemos hacer la predicción de la variable respuesta utilizando
el valor de la primera componente, e incluso obtener un intervalo de confianza.

nuevo.cp <- predict(modelo.cp,


newdata = data.frame(variable1 = 50,
variable2 = 40,
variable3 = 7))
nuevo.cp

## PC1 PC2 PC3


4.7. PRÁCTICAS 271

## [1,] 2.119844 0.05607221 -0.02306086


predict(ml3, newdata = as.data.frame(nuevo.cp), interval = "prediction")

## fit lwr upr


## 1 44.83092 41.67 47.99183

Realice la práctica 4.3 cuyo guión se encuentra en el apartado 4.7 para aplicar el
análisis de componentes principales al ajuste de un modelo de regresión lineal múltiple cuando
hay multicolinealidad.

07
5-
4.7. Prácticas
En este apartado se presentan las prácticas a las que se han hecho referencia durante el

-0
capítulo. La reproducibilidad del código ha sido comprobada con la sesión de R que se
detalla en el Prefacio. El lector puede teclear el código o copiarlo y pegarlo en la consola o
el editor. También se puede descargar el script con el código de todas las prácticas con la
siguiente expresión:
19
download.file("http://emilio.lcano.com/b/adr/practicas/11-acp.R",
20
destfile = "practicas/11-acp.R")

Aparte de estas prácticas guiadas, se invita al lector a que realice un análisis de componentes
principales con el conjunto de datos iris disponible en R, y que ya se ha utilizado en capítulos
anteriores.
or

Práctica 4.1: Ejemplo básico


ad

Opcionalmente, podemos en primer lugar limpiar el espacio de trabajo eliminando todos los
objetos existentes:
rr

rm(list = ls())

Vamos a considerar una serie de variables cuantitativas (escala métrica) que caracterizan a
Bo

una población. Nuestro objetivo es encontrar una serie de combinaciones lineales de estas
variables (cada combinación es una “componente principal”) que recojan la mayor parte de
la varianza de las variables originales (“comunalidad”), y que sean menos numerosas que las
variables originales, de manera que puedan usarse como variables que resumen o sintetizan
la información que las variables originales ofrecen sobre los casos que componen la muestra,
con una pérdida mínima de información, y además siendo incorrelacionadas entre sí.
Las expresiones utilizadas se encuentran en el script de las prácticas del capítulo.
Opcionalmente, se recomienda en primer lugar limpiar el espacio de trabajo eliminando todos
los objetos existentes:
272 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

rm(list = ls())

Durante la práctica utilizaremos algunos paquetes que no se encuentran en la instalación


base de R. La primera vez que los usemos hay que instalarlos, véase el apartado 1.2.3. Una
vez instalado un paquete, lo tenemos que cargar con la función library para poder utilizar
las funciones que contiene.

Datos
En este ejemplo vamos a introducir los datos mediante código. Introducimos los datos de las

07
variables a incluir en el modelo.
Datos <- data.frame(Casos = c("caso1", "caso2", "caso3",

5-
"caso4", "caso5", "caso6"),
Variable1 = c(23, 31, 24, 35, 52, 46),
Variable2 = c(13, 21, 14, 23, 41, 37),

-0
Variable3 = c(6.5, 5, 4.5, 5, 7.5, 6),
row.names = 1)

tenemos una matriz de datos así:


Datos
19
Hemos creado el data.frame “Datos” de 3 variables (columnas) y 6 casos (filas). En definitiva,
20
## Variable1 Variable2 Variable3
## caso1 23 13 6.5
## caso2 31 21 5.0
or

## caso3 24 14 4.5
## caso4 35 23 5.0
## caso5 52 41 7.5
ad

## caso6 46 37 6.0

Análisis exploratorio de datos


rr

El análisis de componentes principales tiene sentido cuando las variables originales están
muy correlacionadas entre sí. Es como si aportaran casi la misma información acerca de los
Bo

casos de la muestra. Por tanto, vamos a comprobar que exista tal correlación obteniendo la
matriz de correlaciones.
correlaciones <- cor(Datos)
correlaciones

## Variable1 Variable2 Variable3


## Variable1 1.0000000 0.9961326 0.6065117
## Variable2 0.9961326 1.0000000 0.6091628
## Variable3 0.6065117 0.6091628 1.0000000
Vemos como las correlaciones son altas, sobre todo entre las variables 1 y 2, aunque también
4.7. PRÁCTICAS 273

son altas las correlaciones entre la 2 y 3, y entre la 1 y 3. Podemos visualizar estas correlacio-
nes gráficamente con el paquete corrplot. La función con el mismo nombre que el paquete
nos devuelve una matriz de gráficos con la correlación representada de distintas formas, por
ejemplo en forma de elipse. Cuanto más oscura y estrecha sea la elipse, mayor correlación.
library(corrplot)
corrplot(correlaciones, method = "ellipse" )

07
5-
Variable1

Variable2

Variable3

-0
1

Variable1 19 0.8

0.6
20
0.4

0.2

Variable2
or

−0.2
ad

−0.4

−0.6
Variable3
rr

−0.8
Bo

−1

Otra visualización interesante es la que nos proporcionan los gráficos de dispersión de las
variables dos a dos, que podemos obtener de la siguiente forma:
pairs(Datos, pch = 19, col = "steelblue")
274 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

15 20 25 30 35 40

45
Variable1

35
25
35

Variable2

07
25
15

7.5
5-
6.5
Variable3

-0
5.5
4.5
25 30 35 40 45 50
19 4.5 5.0 5.5 6.0 6.5 7.0 7.5
20
or
ad
rr
Bo

Una visualización más elaborada se puede conseguir con funciones de otros paquetes como
por ejemplo el paquete ez:
library(ez)
ezCor(Datos)
4.7. PRÁCTICAS 275

Variable1
1 .61

07
Variable2 .61

5-
-0
19 Variable3
20
or
ad

Este gráfico nos proporciona los valores numéricos de las correlaciones, los gráficos de disper-
sión dos a dos, su recta de regresión, y una representación de la densidad de cada variable.
rr
Bo

Aunque para el análisis de componentes principales no es necesario verificar la normalidad


de los datos, los histogramas de las variables siempre son recomendables en el análisis explo-
ratorio de datos:
library(Hmisc)
hist(Datos)
276 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

2.0
4
Frequency

Frequency

1.0
2

0.0
0

20 30 40 50 60 10 20 30 40 50

Variable1 Variable2
n:6 m:0 n:6 m:0

07
4
Frequency

5-
2
0

-0
4 5 6 7 8

Variable3
n:6 m:0
19
Para calcular componentes principales, se suelen tipificar las variables, para lo cual hacemos:
20
ZDatos <- scale(Datos)
ZDatos

## Variable1 Variable2 Variable3


or

## caso1 -1.03507059 -1.0111129 0.6642112


## caso2 -0.35447623 -0.3275436 -0.6642112
## caso3 -0.94999630 -0.9256667 -1.1070186
ad

## caso4 -0.01417905 -0.1566513 -0.6642112


## caso5 1.43208397 1.3813796 1.5498260
## caso6 0.92163820 1.0395950 0.2214037
rr

## attr(,"scaled:center")
## Variable1 Variable2 Variable3
## 35.16667 24.83333 5.75000
Bo

## attr(,"scaled:scale")
## Variable1 Variable2 Variable3
## 11.754432 11.703276 1.129159
Con esta matriz de variables tipificadas, “ZDatos”, es con la que se realizarán los cálculos.

Estimación del modelo


Vamos a proceder al cálculo de las componentes principales propiamente dicho. Hay varias
funciones en R que las calculan, aunque nosotros vamos a utilizar la función prcomp. El
primer argumento puede ser el data.frame con los datos tipificacos (ZDatos) o los datos
4.7. PRÁCTICAS 277

originales incluyendo el argumento scale = TRUE.


modelo.cp <- prcomp(Datos, scale = TRUE)
summary(modelo.cp)

## Importance of components:
## PC1 PC2 PC3
## Standard deviation 1.5785 0.7103 0.06214
## Proportion of Variance 0.8305 0.1682 0.00129
## Cumulative Proportion 0.8305 0.9987 1.00000

07
El “summary” de las componentes calculadas y guardadas en el objeto “modelo.cp”, devuelve
3 informaciones correspondientes a las 3 componentes principales obtenidas. La “Standard
Desviation” es la raíz cuadrada de los autovalores asociados a cada componente. “Proportion

5-
of Variance” nos dice la proporción de la varianza o comportamiento de las variables origina-
les recogido por cada componente, proporción que se acumula en “Cumulative Proportion”.

-0
Nótese que las componentes aparecen ordenadas de más a menos importantes en función de
la cantidad de varianza que capturan.

19
Los coeficientes que multiplican a las variables originales (tipificadas) para cada componente
se guardan en el elemento “rotation” del objeto “modelo.cp” (que realmente es una lista de
objetos):
20
names(modelo.cp)

## [1] "sdev" "rotation" "center" "scale" "x"


modelo.cp
or

## Standard deviations (1, .., p=3):


## [1] 1.57846332 0.71034620 0.06214349
ad

##
## Rotation (n x k) = (3 x 3):
## PC1 PC2 PC3
rr

## Variable1 0.6123787 -0.3553737 0.706188260


## Variable2 0.6129108 -0.3507865 -0.708017763
## Variable3 0.4993322 0.8664054 0.002998225
Bo

Vamos a guardar estos coeficientes en un objeto de tipo data.frame que utilizaremos después:
coeficientes <- modelo.cp$rotation

La primera componente, por ejemplo, será:

yi1 = xi1 , ·0,612 + xi2 , ·0,613 + xi3 , ·0,499

Con los datos en sus valores tipificados.


278 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

Selección de componentes e interpretación

Nosotros queremos menos componentes que variables (originales), porque así simplificare-
mos la información suministrada por dichas variables. Hay varios métodos de selección de
componentes principales. Nos vamos a quedar con aquel que selecciona las varianzas de las
componentes (o autovalores) mayores a uno. Para ello primero calculamos los autovalores y
los mostramos, y luego comprobaremos cuántos autovalores son mayores que 1. Esa canti-
dad se la asignaremos, en el texto del script, al objeto “selec” (directamente o utilizando un

07
vector lógico como a continuación):
autovalores <- modelo.cp$sdev^2
autovalores

5-
-0
selec <- sum(autovalores > 1)
selec
19
## [1] 2.491546458 0.504591729 0.003861813
20
or

## [1] 1
ad
rr

En nuestro caso vale 1, lo que quiere decir que con una única componente principal podemos
recoger la mayoría de la información contenida en las tres variables originales.
Bo

También se puede obtener el llamado gráfico de sedimentación con la instrucción:


plot(autovalores, main = "Gráfico de Sedimentación",
xlab = "Nº de Autovalor", ylab = "Valor", pch = 16, col = "red4", type = "b",
lwd = 2, las = 1)
abline(h = 1, lty = 2, col = "green4")
4.7. PRÁCTICAS 279

Gráfico de Sedimentación

2.5

2.0

1.5
Valor

07
1.0

0.5

5-
0.0

-0
1.0 1.5 2.0 2.5 3.0

19Nº de Autovalor

Posteriormente vamos a estudiar las “cargas factoriales” o “saturaciones”, que son las corre-
20
laciones entre las componentes principales retenidas y las variables originales:
cargas <- t(coeficientes[, 1:selec])*(sqrt(autovalores[1:selec]))
cargas
or

## Variable1 Variable2 Variable3


## [1,] 0.9666173 0.9674572 0.7881776
ad

Sólo hay una fila porque sólo hemos retenido una componente principal. El primer número
muestra una alta correlación entre la primera componente y la primera variable original.
Lo mismo ocurre con la segunda variable original, mientras que la relación de la primera
rr

componente principal y la tercera variable original es algo menos intensa.


Bo

Por último vamos a obtener las puntuaciones (scores) que alcanza nuestra componente princi-
pal retenida para cada caso o individuo (ya sabemos que recoge 83 % de la varianza común de
las variables originales). Estos datos se encuentran en el modelo almacenado y los podemos
recuperar directamente:
modelo.cp$x[, 1]

## caso1 caso2 caso3 caso4 caso5 caso6


## -0.9219151 -0.7494908 -1.7018787 -0.4363583 2.4975183 1.3121246

Podemos comprobar que es el mismo resultado que si utilizamos la multiplicación matricial


en R:
280 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

puntuaciones <- ZDatos%*%coeficientes[, 1:selec]


puntuaciones

## [,1]
## caso1 -0.9219151
## caso2 -0.7494908
## caso3 -1.7018787
## caso4 -0.4363583
## caso5 2.4975183

07
## caso6 1.3121246
Por ejemplo, para el primer caso la puntuación de la componente principal ha sido:

5-
yi1 = −1,035 · 0,612 − 1,011 · 0,613 + 0,664 · 0,499 = −0,922.

-0
Recordemos que las variables originales entran en la ecuación tipificadas.

Práctica 4.2: Provincias


19
Es aconsejable en primer lugar limpiar el espacio de trabajo eliminando todos los objetos
existentes:
20
rm(list = ls())

Vamos a considerar una serie de variables cuantitativas (escala métrica) que caracterizan a la
población constituida por las provincias españolas. Nuestro objetivo es encontrar una serie de
or

combinaciones lineales de estas variables (cada combinación es una “componente principal”)


que recojan la mayor parte de la varianza de las variables originales (“comunalidades”), y
que sean menos numerosas que las variables originales, de manera que puedan usarse como
ad

variables que resumen o sintetizan la información que las variables originales ofrecen sobre
las provincias españolas, con una pérdida mínima de información.
rr

Carga de datos
Las variables originales serán:
Bo

CREC_NAT_MIL_05: Crecimiento natural de la población: diferencia entre nacimien-


tos y defunciones por cada mil habitantes, 2005.
NUM_HIJ_FERT_05: Número de hijos por mujer en edad fértil (de 15 a 49 años),
2005.
TAS_FECUN_05: Tasa de fecundidad: número de nacimientos por cada 100 mujeres
en edad fértil, 2005.
ACTIVOS_MIL_05: Número de activos por cada mil habitantes, 2005.
KM_AUTOVIAS_1000_KM2_05: Kilómetros de autopistas o autovías por cada 1000
Km2 de superficie, 2005.
DENSID_05: Densidad de población.
4.7. PRÁCTICAS 281

Las expresiones utilizadas se encuentran en el script de las prácticas del capítulo. En lo


sucesivo, vamos a suponer que estamos trabajando en un proyecto que contiene una carpeta
llamada “datos” donde se encuentran los ficheros de datos. El fichero se puede descargar a
la carpeta de datos del proyecto con la siguiente expresión:
download.file("http://emilio.lcano.com/b/adr/datos/provilogit.txt",
"datos/provilogit.txt")

Ahora vamos a leer el valor de las variables que están en el archivo de texto “provilogit.txt”
(podemos limpiar primero el espacio de trabajo). El fichero contiene en total 64 variables,

07
que se guardarán en el data.frame “provincias”. A continuación, de “provincias” se extraerán
las variables de nuestro análisis, que se guardan en el data.frame “Datos”.
provincias <- read.table("datos/provilogit.txt", header = TRUE,

5-
sep = "\t", dec = ",", encoding = "latin1")
colnames(provincias)

-0
## [1] "NAME_PROV" "AUTONOMIA"
## [3] "POB_05" "PORC_MUJ_05"
##
##
##
[5]
[7]
[9]
"NACIM_MIL_05"
"CREC_NAT_MIL_05"
"INMI_ESP_CIENMIL_05"
19 "DEFUN_MIL_05"
"INMI_EXT_CIENMIL_05"
"MATRIM_MIL_05"
20
## [11] "PORC_MATRIM_CIV_05" "NUM_HIJ_FERT_05"
## [13] "TAS_FECUN_05" "EDAD_MATER_05"
## [15] "NUM_NAC_05" "PROP_ANALF_05"
## [17] "PROP_EST_SUP_05" "UDS_ED_INF_0405"
## [19] "PROF_NO_SUP_0405" "ACTIVOS_MIL_05"
or

## [21] "POR_MUJ_ACT_05" "TASA_ACT_05"


## [23] "TASA_PARO_05" "POR_TRAB_CONV_05"
ad

## [25] "AUM_SALAR_CONV_05" "IND_INCID_ACCID_05"


## [27] "IND_INCID_ACCID_MORT_05" "PIB_04"
## [29] "PIB_HAB_04" "VAR_IPC_05"
## [31] "AFIL_SS_ALTA_05" "POR_COB_PREST_DESEMP_05"
rr

## [33] "MED_CIENMIL_05" "CAMAS_HOSP_DIEZMIL_04"


## [35] "CONS_EXTER_MIL_05" "HERID_ACC_TRAF_CIENMIL_05"
Bo

## [37] "PROD_NETA_ENE_ELEC_05" "AUTO_MIL_HAB_05"


## [39] "AUTO_KM2_05" "POR_TIERR_CULT_05"
## [41] "VIV_TER_05" "POR_VIV_PO_05"
## [43] "OFF_ENTID_CRED_CIENMIL_05" "KM_AUTOVIAS_1000_KM2_05"
## [45] "PERNOC_HOT_100_HAB_05" "PLAZAS_HOT_MIL_05"
## [47] "DETENIDOS_MIL_05" "MUERTES_VIOL_CIENMIL_05"
## [49] "LOC_HOST_07" "LOC_AGENC_07"
## [51] "LOC_INMOB_07" "LOC_COM_MAY_07"
## [53] "LOC_COM_MIN_07" "LOC_IND_ALIM_07"
## [55] "PROV_COSTERA" "POLITIC_CCAA"
## [57] "NUM_HIPOTEC_05" "IMPORT_MED_HIPOT_05"
282 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

## [59] "NIV_RENT_04" "SUPERFIC"


## [61] "DENSID_05" "GRUPOS_2"
## [63] "GRUPOS_3" "GRUPOS_OK"
Datos <- subset(provincias,
select = c(CREC_NAT_MIL_05, NUM_HIJ_FERT_05,
TAS_FECUN_05, ACTIVOS_MIL_05, KM_AUTOVIAS_1000_KM2_05, DENSID_05))
rownames(Datos) <- provincias[, 1]
summary(Datos)

07
## CREC_NAT_MIL_05 NUM_HIJ_FERT_05 TAS_FECUN_05 ACTIVOS_MIL_05
## Min. :-8.32617 Min. :0.867 Min. :2.617 Min. : 40.05
## 1st Qu.:-2.35610 1st Qu.:1.158 1st Qu.:3.599 1st Qu.: 155.18

5-
## Median : 0.53840 Median :1.294 Median :3.969 Median : 271.61
## Mean :-0.05204 Mean :1.276 Mean :3.917 Mean : 416.55

-0
## 3rd Qu.: 2.68197 3rd Qu.:1.410 3rd Qu.:4.378 3rd Qu.: 451.31
## Max. : 5.60666 Max. :1.594 Max. :5.000 Max. :3067.55
## KM_AUTOVIAS_1000_KM2_05 DENSID_05
##
##
##
Min. : 4.852
1st Qu.:13.291
Median :24.892
Min.
19
: 8.891
1st Qu.: 26.107
Median : 57.617
20
## Mean :27.686 Mean :120.274
## 3rd Qu.:33.729 3rd Qu.:136.295
## Max. :93.298 Max. :732.407
head(Datos)
or

## CREC_NAT_MIL_05 NUM_HIJ_FERT_05 TAS_FECUN_05 ACTIVOS_MIL_05


ad

## A Coruña -2.387739 1.022 3.181741 520.325


## Álava 0.978757 1.156 3.652711 149.900
## Albacete 1.075956 1.281 3.906811 175.100
rr

## Alicante 2.732500 1.330 4.142446 813.575


## Almería 5.392930 1.591 4.900016 312.950
## Asturias -4.931347 0.956 2.895130 451.400
Bo

## KM_AUTOVIAS_1000_KM2_05 DENSID_05
## A Coruña 34.33530 139.44403
## Álava 48.73230 97.86570
## Albacete 16.08148 25.46744
## Alicante 56.38645 289.52587
## Almería 31.90883 68.78268
## Asturias 28.57412 99.84317

Hemos creado la hoja de datos o data.frame “Datos” de 6 columnas (todas variables numé-
ricas) y 50 filas (casos, las 50 provincias españolas).
4.7. PRÁCTICAS 283

Análisis exploratorio de datos

El análisis de componentes principales tiene sentido cuando las variables originales (columnas
de la matriz “Datos”) están muy correlacionadas entre sí. Es como si informaran casi lo mismo
acerca de los casos de la muestra. Por tanto, vamos a comprobar que exista tal correlación:
correlaciones <- cor(Datos)

07
correlaciones

5-
-0
##
## CREC_NAT_MIL_05
19
CREC_NAT_MIL_05 NUM_HIJ_FERT_05 TAS_FECUN_05
1.0000000 0.8323874 0.8785990
20
## NUM_HIJ_FERT_05 0.8323874 1.0000000 0.9871412
## TAS_FECUN_05 0.8785990 0.9871412 1.0000000
## ACTIVOS_MIL_05 0.4280085 0.2724936 0.3364654
## KM_AUTOVIAS_1000_KM2_05 0.4289928 0.1214923 0.2219890
or

## DENSID_05 0.4261992 0.1626441 0.2466408


## ACTIVOS_MIL_05 KM_AUTOVIAS_1000_KM2_05 DENSID_05
## CREC_NAT_MIL_05 0.4280085 0.4289928 0.4261992
ad

## NUM_HIJ_FERT_05 0.2724936 0.1214923 0.1626441


## TAS_FECUN_05 0.3364654 0.2219890 0.2466408
## ACTIVOS_MIL_05 1.0000000 0.7111536 0.8700265
## KM_AUTOVIAS_1000_KM2_05 0.7111536 1.0000000 0.8677470
rr

## DENSID_05 0.8700265 0.8677470 1.0000000


Bo

Esta instrucción nos lleva a una matriz de correlaciones en la que destacan altas correlaciones
entre algunas variables. Gráficamente:
corrplot(correlaciones, method = "number" )
284 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

KM_AUTOVIAS_1000_KM2_05
CREC_NAT_MIL_05
NUM_HIJ_FERT_05

ACTIVOS_MIL_05
TAS_FECUN_05

DENSID_05

07
1
CREC_NAT_MIL_05 1 0.83 0.88 0.43 0.43 0.43 0.8

5-
0.6
NUM_HIJ_FERT_05 0.83 1 0.99 0.27 0.12 0.16
0.4

-0
TAS_FECUN_05 0.88 0.99 1 0.34 0.22 0.25 0.2
0
ACTIVOS_MIL_05 0.43 0.27 0.34 1 0.71 0.87 −0.2

19
KM_AUTOVIAS_1000_KM2_05 0.43 0.12 0.22 0.71 1 0.87
DENSID_05 0.43 0.16 0.25 0.87 0.87 1
−0.4
−0.6
−0.8
20
−1

ezCor(Datos, r_size_lims = c(4, 8), label_size = 3)


or
ad
rr
Bo
4.7. PRÁCTICAS 285

CREC_NAT_MIL_05 .83 .88 .43 .43 .43

NUM_HIJ_FERT_05
.99 .27 .12 .16

TAS_FECUN_05 .34 .22 .25

07
ACTIVOS_MIL_05 .71 .87

5-
-0
.87
KM_AUTOVIAS_1000_KM2_05

19 DENSID_05
20
Para calcular componentes principales, se suelen tipificar las variables, para lo cual hacemos:
ZDatos <- scale(Datos)
or

head(ZDatos)
ad

## CREC_NAT_MIL_05 NUM_HIJ_FERT_05 TAS_FECUN_05 ACTIVOS_MIL_05


## A Coruña -0.6527861 -1.38511462 -1.21714141 0.18819000
## Álava 0.2880891 -0.65357844 -0.43704003 -0.48356416
rr

## Albacete 0.3152545 0.02882471 -0.01615598 -0.43786475


## Alicante 0.7782288 0.29632674 0.37414316 0.71998971
## Almería 1.5217712 1.72118452 1.62896066 -0.18787808
Bo

## Asturias -1.3636788 -1.74542348 -1.69187575 0.06319667


## KM_AUTOVIAS_1000_KM2_05 DENSID_05
## A Coruña 0.34911653 0.1227507
## Álava 1.10504100 -0.1434821
## Albacete -0.60931335 -0.6070600
## Alicante 1.50692757 1.0837494
## Almería 0.22171292 -0.3297054
## Asturias 0.04662168 -0.1308200

Con esta matriz de variables tipificadas, “ZDatos”, es con la que se realizarán los cálculos.
286 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

Estimación del modelo


Vamos a proceder al cálculo de las componentes principales propiamente dicho. Hay varias
funciones en R que las calculan, aunque nosotros vamos a utilizar la función “prcomp”:
modelo2.cp <- prcomp(Datos, scale = TRUE)
summary(modelo2.cp)

## Importance of components:
## PC1 PC2 PC3 PC4 PC5 PC6
## Standard deviation 1.9004 1.3703 0.5591 0.34409 0.27039 0.08217

07
## Proportion of Variance 0.6019 0.3130 0.0521 0.01973 0.01219 0.00113
## Cumulative Proportion 0.6019 0.9149 0.9670 0.98669 0.99887 1.00000

5-
El “summary” de las componentes calculadas y guardadas en el objeto “modelo2.cp”, se
obtienen 3 informaciones correspondientes a las 6 componentes principales obtenidas. La
“Standard Desviation” es la raíz cuadrada de los autovalores asociados a cada componente.

-0
“Proportion of Variance” nos dice la proporción de la varianza o comportamiento de las va-
riables originales recogido por cada componente, proporción que se acumula en “Cumulative
Proportion”. Nótese que las componentes aparecen ordenadas de más a menos importantes
19
en función de la cantidad de varianza que capturan.
Los coeficientes que multiplican a las variables originales (tipificadas) para cada componente
20
se guardan en el elemento “rotation” del objeto “modelo.cp” (que realmente es una lista de
objetos):
names(modelo2.cp)
or

## [1] "sdev" "rotation" "center" "scale" "x"


modelo2.cp
ad

## Standard deviations (1, .., p=6):


## [1] 1.90036102 1.37031837 0.55910392 0.34408566 0.27039012 0.08217425
##
rr

## Rotation (n x k) = (6 x 6):
## PC1 PC2 PC3 PC4
Bo

## CREC_NAT_MIL_05 0.4586414 -0.2664555 0.34733401 0.75655651


## NUM_HIJ_FERT_05 0.3901948 -0.4741460 -0.15603495 -0.37096172
## TAS_FECUN_05 0.4229004 -0.4245544 -0.05999382 -0.30064351
## ACTIVOS_MIL_05 0.4037777 0.3607731 -0.69168687 0.11104829
## KM_AUTOVIAS_1000_KM2_05 0.3713368 0.4356074 0.60868589 -0.42261992
## DENSID_05 0.3970188 0.4516963 -0.04983663 0.09318695
## PC5 PC6
## CREC_NAT_MIL_05 0.14369146 0.070594865
## NUM_HIJ_FERT_05 -0.12243740 0.667819662
## TAS_FECUN_05 -0.04654687 -0.738076171
## ACTIVOS_MIL_05 0.46477260 0.005510554
4.7. PRÁCTICAS 287

## KM_AUTOVIAS_1000_KM2_05 0.34535312 0.063089518


## DENSID_05 -0.79177831 -0.016314890

Vamos a guardar estos coeficientes en un objeto de tipo data.frame que utilizaremos después:
coeficientes <- modelo2.cp$rotation

07
5-
Selección de componentes e interpretación

-0
Nosotros queremos menos componentes que variables (originales), porque así simplificaremos
la información suministrada por dichas variables. Hay varios métodos de selección de compo-
nentes Principales. Nosotros nos vamos a quedar con aquel que selecciona las varianzas de

19
las componentes (o autovalores) mayores que uno. Para ello primero calculamos los autova-
lores y los mostramos, y luego le damos al objeto selec el valor correspondiente al número de
autovalores mayores que 1. Ese número será el número de componentes principales a retener:
20
autovalores <- modelo2.cp$sdev^2
autovalores
or

## [1] 3.611371997 1.877772443 0.312597191 0.118394944 0.073110817 0.006752608


selec <- sum(autovalores > 1)
ad

selec
rr

## [1] 2
Bo

En nuestro caso “selec” vale 2, lo que quiere decir que con 2 componentes principales podemos
recoger la mayoría de la información contenida en las 6 variables originales.

También se puede obtener el gráfico de sedimentación con las expresiones siguientes:


plot(autovalores, main = "Gráfico de Sedimentación",
xlab = "Nº de Autovalor", ylab="Valor", pch = 16, col = "red4", type = "b",
lwd = 2, las = 1)
abline(h = 1, lty = 2, col = "green4")
288 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

Gráfico de Sedimentación

2
Valor

07
1

5-
0

-0
1 2 3 4 5 6

19Nº de Autovalor

El problema de las componentes principales es la dificultad para dotarlas de un sentido eco-


20
nómico, ya que no dejan de ser combinaciones lineales (transformaciones matemáticas) de
las variables originales (tipificadas). Vamos a estudiar las “cargas factoriales” o “saturacio-
nes”, que son las correlaciones entre las componentes principales retenidas y las variables
originales. Esta tabla puede dar una idea del significado de cada componente, aunque como
or

puede apreciarse, en este ejemplo no está muy claro.


cargas <- t(coeficientes[, 1:2])*(sqrt(autovalores[1:2]))
ad

cargas

## CREC_NAT_MIL_05 NUM_HIJ_FERT_05 TAS_FECUN_05 ACTIVOS_MIL_05


rr

## PC1 0.8715842 0.741511 0.8036634 0.7673234


## PC2 -0.3651289 -0.649731 -0.5817747 0.4943740
## KM_AUTOVIAS_1000_KM2_05 DENSID_05
Bo

## PC1 0.7056740 0.7544790


## PC2 0.5969208 0.6189677

Con las instrucciones anteriores se generan una matriz de 2 filas (componentes retenidas)
por 6 columnas (variables originales).

Cuando se seleccionan más de dos componentes, se suele utilizar el gráfico biplot para intentar
obtener una interpretación de las componentes acorde con el problema que se está estudiando.
En nuestro caso:
biplot(modelo2.cp)
4.7. PRÁCTICAS 289

−4 −2 0 2 4 6 8

0.4 Madrid

8
6
Vizcaya Barcelona
DENSID_05
KM_AUTOVIAS_1000_KM2_05
0.2

Ourense

4
Asturias
Lugo ACTIVOS_MIL_05
ZamoraA Coruña
León Pontevedra
Guipúzcoa
PC2

Santa Cruz de Tenerife

2
Palencia Alicante
Salamanca Álava Valencia
Valladolid
Cantabria
Las Palmas

07
0.0

Cuenca
Burgos

0
SoriaZaragoza Málaga
Cáceres
Ávila
Teruel
Huesca Rioja
Baleares
Segovia
Albacete
Badajoz
Navarra

−2
Ciudad Real
Castellón
Granada
JaénTarragona
Sevilla
Toledo
Cádiz
Córdoba CREC_NAT_MIL_05

5-
Huelva
−0.2

Girona
Lleida Murcia

−4
Guadalajara TAS_FECUN_05
Almería
NUM_HIJ_FERT_05

-0
−0.2 0.0 0.2 0.4

PC1
19
Se trata de un gráfico bidimensional en el que los ejes horizontal y vertical representan dos
20
de las componentes elegidas. Los individuos (en nuestro caso provincias) se sitúan en sus
puntuaciones o “scores” para cada componente (escala superior y derecha). Por último, las
variables se sitúan donde corresponde a sus coeficientes (loadings, escala inferior e izquierda).
Así, se puede intentar agrupar las variables, en este caso parece más o menos claro que hay
dos grupos de variables, y podríamos decir que puntuaciones bajas de la segunda compo-
or

nente están representando a variables relacionadas con las familias, y las puntuaciones altas
con variables relacionadas con la economía. Esto desde luego es subjetivo y en todo caso
descriptivo (no estamos haciendo inferencia)
ad

Por último vamos a generar las puntuaciones que alcanzan nuestras componentes principales
retenidas para cada caso o individuo (ya sabemos que recogen el 91.49 % de la varianza
rr

común de las variables originales). Para ello utilizamos la multiplicación matricial en R:


scores <- ZDatos%*%coeficientes[,1:selec]
Bo

head(scores)

## PC1 PC2
## A Coruña -1.1002277 1.6228455
## Álava -0.1495928 0.6607728
## Albacete -0.4950711 -0.7884073
## Alicante 1.9113407 0.8989976
## Almería 1.9340026 -2.0332879
## Asturias -2.0310979 1.8932562

Recordemos que las puntuaciones también se guardan en el elemento x del objeto guardado.
290 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

modelo2.cp$x[1:5, 1:2]

## PC1 PC2
## A Coruña -1.1002277 1.6228455
## Álava -0.1495928 0.6607728
## Albacete -0.4950711 -0.7884073
## Alicante 1.9113407 0.8989976
## Almería 1.9340026 -2.0332879

Recordemos que las variables originales entran en la ecuación tipificadas (multiplicación

07
matricial por ZDatos, para eso calculamos esa matriz).

A continuación se incluyen las expresiones para realizar el análisis con el paquete FactoMineR.

5-
Se deja al lector como ejercicio su interpretación.
library(FactoMineR)

-0
library(factoextra)

## Welcome! Related Books: `Practical Guide To Cluster Analysis in R` at https://goo.gl/


prov.fm <- PCA(Datos, graph = FALSE)
prov.fm$eig 19
20
## eigenvalue percentage of variance
## comp 1 3.611371997 60.1895333
## comp 2 1.877772443 31.2962074
## comp 3 0.312597191 5.2099532
or

## comp 4 0.118394944 1.9732491


## comp 5 0.073110817 1.2185136
## comp 6 0.006752608 0.1125435
ad

## cumulative percentage of variance


## comp 1 60.18953
## comp 2 91.48574
rr

## comp 3 96.69569
## comp 4 98.66894
## comp 5 99.88746
Bo

## comp 6 100.00000
summary(prov.fm, ncp = 2)

##
## Call:
## PCA(X = Datos, graph = FALSE)
##
##
## Eigenvalues
## Dim.1 Dim.2 Dim.3 Dim.4 Dim.5 Dim.6
4.7. PRÁCTICAS 291

## Variance 3.611 1.878 0.313 0.118 0.073 0.007


## % of var. 60.190 31.296 5.210 1.973 1.219 0.113
## Cumulative % of var. 60.190 91.486 96.696 98.669 99.887 100.000
##
## Individuals (the 10 first)
## Dist Dim.1 ctr cos2 Dim.2 ctr
## A Coruña | 2.020 | -1.111 0.684 0.303 | 1.639 2.862
## Álava | 1.490 | -0.151 0.013 0.010 | 0.667 0.475
## Albacete | 1.026 | -0.500 0.139 0.237 | -0.796 0.676
## Alicante | 2.212 | 1.931 2.064 0.762 | 0.908 0.878

07
## Almería | 2.879 | 1.954 2.114 0.460 | -2.054 4.493
## Asturias | 2.820 | -2.052 2.331 0.529 | 1.912 3.896
## Ávila | 1.947 | -1.810 1.814 0.864 | -0.254 0.069

5-
## Badajoz | 1.173 | -0.653 0.236 0.310 | -0.842 0.756
## Baleares | 1.479 | 0.887 0.436 0.359 | -0.684 0.499
## Barcelona | 5.959 | 4.993 13.806 0.702 | 2.741 8.002

-0
## cos2
## A Coruña 0.659 |
##
##
##
Álava
Albacete
Alicante
19
0.201 |
0.602 |
0.168 |
20
## Almería 0.509 |
## Asturias 0.460 |
## Ávila 0.017 |
## Badajoz 0.516 |
## Baleares 0.214 |
or

## Barcelona 0.212 |
##
ad

## Variables
## Dim.1 ctr cos2 Dim.2 ctr cos2
## CREC_NAT_MIL_05 | 0.872 21.035 0.760 | -0.365 7.100 0.133 |
## NUM_HIJ_FERT_05 | 0.742 15.225 0.550 | -0.650 22.481 0.422 |
rr

## TAS_FECUN_05 | 0.804 17.884 0.646 | -0.582 18.025 0.338 |


## ACTIVOS_MIL_05 | 0.767 16.304 0.589 | 0.494 13.016 0.244 |
Bo

## KM_AUTOVIAS_1000_KM2_05 | 0.706 13.789 0.498 | 0.597 18.975 0.356 |


## DENSID_05 | 0.754 15.762 0.569 | 0.619 20.403 0.383 |
fviz_pca_var(prov.fm, repel = TRUE)
292 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

Variables − PCA
1.0

DENSID_05
KM_AUTOVIAS_1000_KM2_05
0.5
ACTIVOS_MIL_05
Dim2 (31.3%)

0.0

07
CREC_NAT_MIL_05

5-
−0.5 TAS_FECUN_05

NUM_HIJ_FERT_05

-0
−1.0

−1.0 −0.5 0.0 0.5 1.0


Dim1 (60.2%)

fviz_pca_biplot(prov.fm, col.var = "cos2",


19
20
repel = TRUE,
col.ind = gray(0.4))
or

PCA − Biplot
4 Madrid
ad

DENSID_05
Ourense Vizcaya Barcelona
KM_AUTOVIAS_1000_KM2_05
Asturias cos2
rr

2 Lugo
Pontevedra ACTIVOS_MIL_05
Zamora
Dim2 (31.3%)

Guipúzcoa
A Coruña 0.96
Palencia León Santa Cruz de Tenerife Alicante
Bo

ValladolidÁlava
0.92
Salamanca
Burgos Cantabria Valencia
0 Cuenca Ávila CáceresZaragoza Las Palmas Málaga 0.88
Soria Albacete Rioja Baleares Tarragona
0.84
Teruel Segovia Castellón
Navarra
Jaén Sevilla
Huesca Badajoz Granada Cádiz
Toledo
Ciudad Real CREC_NAT_MIL_05
−2 HuelvaGirona Murcia
Córdoba TAS_FECUN_05
Almería
Guadalajara
LleidaNUM_HIJ_FERT_05
−2 0 2 4 6
Dim1 (60.2%)
4.7. PRÁCTICAS 293

Práctica 4.3: Aplicación al problema de regresiones con multicoli-


nealidad
Una de las aplicaciones más usuales de la técnica de Componentes Principales es la de reducir
el número de variables explicativas en el análisis de regresión, cuando se sospecha que puede
existir multicolinealidad entre algunos regresores o incluso problemas derivados de muestras
pequeñas.
El ejemplo consiste en lo siguiente: se estima una regresión lineal múltiple que intenta
explicar el comportamiento de la variable EDAD_MATER_05 (edad media de materni-

07
dad) en función de las variables MATRIM_1000_05 (matrimonios por cada mil habitantes),
NUM_HIJ_FERT_05 (número de hijos por mujer en edad fértil), TAS_FECUN_05 (ta-
sa de fecundidad), POR_MUJ_ACT_05 (porcentaje de mujeres por respecto al total de
activos) y PIB_HAB_04 (P.I.B. a precios de mercado por habitante). La muestra está

5-
constituida por 16 provincias españolas.
Las expresiones utilizadas se encuentran en el script de las prácticas del capítulo. En lo

-0
sucesivo, vamos a suponer que estamos trabajando en un proyecto que contiene una carpeta
llamada “datos” donde se encuentran los ficheros de datos. El fichero se puede descargar a

19
la carpeta de datos del proyecto con la siguiente expresión:
download.file("http://emilio.lcano.com/b/adr/datos/Regre_mater.txt",
"datos/Regre_mater.txt")
20
Opcionalmente, podemos en primer lugar limpiar el espacio de trabajo eliminando todos los
objetos existentes:
rm(list = ls())
or

Carga de datos
ad

Los datos se encuentran en el fichero “Regre_mater.txt”, que suponemos en la carpeta


“datos”.
provincias <- read.table("datos/Regre_mater.txt",
rr

head = T, sep = "\t",


dec = ",", row.names = 1)
Bo

Análisis exploratorio de datos


Vemos que todas las variables son numéricas con su resumen:
summary(provincias)

## PORC_MUJ_05 INMI_ESP_CIENMIL_05 MATRIM_MIL_05 NUM_HIJ_FERT_05


## Min. :49.66 Min. :17.43 Min. :3.572 Min. :1.143
## 1st Qu.:49.85 1st Qu.:28.76 1st Qu.:4.597 1st Qu.:1.295
## Median :50.29 Median :45.53 Median :4.788 Median :1.343
## Mean :50.33 Mean :45.96 Mean :4.869 Mean :1.353
294 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

## 3rd Qu.:50.77 3rd Qu.:55.19 3rd Qu.:5.187 3rd Qu.:1.413


## Max. :51.18 Max. :82.83 Max. :6.114 Max. :1.594
## TAS_FECUN_05 EDAD_MATER_05 POR_MUJ_ACT_05 PIB_HAB_04
## Min. :3.393 Min. :30.10 Min. :58.11 Min. :12747
## 1st Qu.:3.936 1st Qu.:30.49 1st Qu.:59.46 1st Qu.:15259
## Median :4.143 Median :30.80 Median :60.94 Median :16229
## Mean :4.162 Mean :30.83 Mean :61.09 Mean :17368
## 3rd Qu.:4.355 3rd Qu.:31.04 3rd Qu.:61.97 3rd Qu.:19325
## Max. :5.000 Max. :31.75 Max. :65.34 Max. :24744

07
Unos histogramas para visualizar las distribuciones:
library(ggplot2)
library(reshape2)

5-
gdata <- melt(provincias)

-0
## No id variables; using all as measure variables
ggplot(gdata, aes(value)) +
geom_histogram(bins = 7) +
facet_wrap(variable ~ ., scales = "free")

PORC_MUJ_05
19
INMI_ESP_CIENMIL_05 MATRIM_MIL_05
20
4 4
6
3 3
2 2 4

1 1 2
or

0 0 0
49.5 50.0 50.5 51.0 25 50 75 4 5 6

NUM_HIJ_FERT_05 TAS_FECUN_05 EDAD_MATER_05


ad

5 4
4 6
3
count

3 4 2
2
rr

2 1
1
0 0 0
1.1 1.2 1.3 1.4 1.5 1.6 3.5 4.0 4.5 5.0 30.0 30.5 31.0 31.5
Bo

POR_MUJ_ACT_05 PIB_HAB_04
5 6
4
3 4
2 2
1
0 0
58 60 62 64 66 15000 20000 25000
value

En R es muy sencillo estimar una regresión lineal multivariante por mínimos cuadrados
ordinarios. La función clave es lm. Así, estimaremos nuestra regresión y la almacenaremos
4.7. PRÁCTICAS 295

en el objeto regre1 (por ejemplo). Luego visualizamos los resultados con un “summary”:
regre1 <- lm(EDAD_MATER_05 ~ MATRIM_MIL_05 + NUM_HIJ_FERT_05 + TAS_FECUN_05 + POR_MUJ_AC
data = provincias)
summary(regre1)

##
## Call:
## lm.default(formula = EDAD_MATER_05 ~ MATRIM_MIL_05 + NUM_HIJ_FERT_05 +
## TAS_FECUN_05 + POR_MUJ_ACT_05 + PIB_HAB_04, data = provincias)

07
##
## Residuals:
## Min 1Q Median 3Q Max

5-
## -0.4854 -0.1063 0.0530 0.1334 0.4120
##
## Coefficients:

-0
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.403e+01 4.265e+00 7.980 1.2e-05 ***
## MATRIM_MIL_05 1.528e-01 1.986e-01 0.770 0.459
##
##
##
TAS_FECUN_05
19
NUM_HIJ_FERT_05 -2.427e+00 5.992e+00 -0.405
-1.125e-01 1.778e+00 -0.063
POR_MUJ_ACT_05 -2.874e-02 5.587e-02 -0.514
0.694
0.951
0.618
20
## PIB_HAB_04 9.004e-05 4.457e-05 2.020 0.071 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
or

## Residual standard error: 0.2984 on 10 degrees of freedom


## Multiple R-squared: 0.7663, Adjusted R-squared: 0.6495
## F-statistic: 6.559 on 5 and 10 DF, p-value: 0.005911
ad

Puede observarse cómo el coeficiente de determinación lineal corregido es relativamente alto


(64 %) mientras que, paradójicamente, todas las variables explicativas salvo PIB_HAB_04
rr

son no-significativas (valores del estadístico muy próximos a 0 y p-values muy altos). Esto
puede dar algún indicio de existencia de multicolinealidad entre los regresores. Las variables
explicativas tienen un comportamiento parecido y comparten sus efectos, dando lugar a pa-
Bo

rámetros estimados poco significativos. Además, un elevado número de variables explicativas


y un número reducido de elementos muestrales o casos (provincias) puede dar lugar a una
pérdida de eficiencia en los estimadores como consecuencia de reducidos grados de libertad.

Una estrategia, como sabemos, para comprobar de un modo exploratorio o inicial la existencia
de esta multicolinealidad es calcular las correlaciones entre las variables explicativas. Para
ello tenemos el siguiente código:
Datos <- subset(provincias, select = c(MATRIM_MIL_05, NUM_HIJ_FERT_05, TAS_FECUN_05,
POR_MUJ_ACT_05, PIB_HAB_04))
correlaciones <- cor(Datos)
296 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

Se ha creado una hoja de datos o data.frame con el nombre “Datos” con las variables expli-
cativas, y se ha calculado la correspondiente matriz de correlaciones:
correlaciones

07
## MATRIM_MIL_05 NUM_HIJ_FERT_05 TAS_FECUN_05 POR_MUJ_ACT_05
## MATRIM_MIL_05 1.0000000 0.64801785 0.68305915 -0.32203281
## NUM_HIJ_FERT_05 0.6480179 1.00000000 0.97823916 -0.06468868

5-
## TAS_FECUN_05 0.6830591 0.97823916 1.00000000 -0.20189896
## POR_MUJ_ACT_05 -0.3220328 -0.06468868 -0.20189896 1.00000000

-0
## PIB_HAB_04 -0.1030421 -0.17467692 -0.01403294 -0.62623599
## PIB_HAB_04
## MATRIM_MIL_05 -0.10304214
##
##
##
NUM_HIJ_FERT_05 -0.17467692
TAS_FECUN_05 -0.01403294
POR_MUJ_ACT_05 -0.62623599
19
20
## PIB_HAB_04 1.00000000
or
ad

Puede comprobarse como en efecto existen correlaciones altas (en valor absoluto) entre al-
gunas variables, en especial entre las variables MATRIM_1000_05, NUM_HIJ_FERT_05
y TAS_FECUN_05 por un lado; y POR_MUJ_ACT_05 y PIB_HAB_04 por otro.
rr
Bo

Gráficamente, podemos utilizar la función corrplot para visualizar las correlaciones, inclui-
do un contraste de significación de los coeficientes con la función cor.mtest, del mismo
paquete:
library(corrplot)
res1 <- cor.mtest(Datos, conf.level = 0.95)
corrplot(correlaciones, method = "number", type = "lower", p.mat = res1[[1]])
MATRIM_MIL_05
4.7. PRÁCTICAS 297

NUM_HIJ_FERT_05

TAS_FECUN_05
MATRIM_MIL_05 1

POR_MUJ_ACT_05
NUM_HIJ_FERT_05 0.65 1

07
TAS_FECUN_05

PIB_HAB_04
0.68 0.98 1

5-
POR_MUJ_ACT_05 −0.32 −0.06 −0.2 1

-0
PIB_HAB_04 −0.1 −0.17 −0.01 −0.63 1

−1 −0.8 −0.6 −0.4 −0.2


19 0 0.2 0.4 0.6 0.8 1
20
Las aspas indican las correlaciones no significativas. Vemos que todas las variables tienen
una correlación significativa con al menos una de las otras variables.
or

Cuando ajustamos un modelo lineal, también podemos evaluar la multicolinalidad con el


método VIF (Variance Inflation Factor, factor de inflación de la varianza), que tenemos
disponible en el paquete car:
ad

library(car)
vif(regre1)
rr

## MATRIM_MIL_05 NUM_HIJ_FERT_05 TAS_FECUN_05 POR_MUJ_ACT_05


## 2.567077 70.132041 74.618395 2.297604
## PIB_HAB_04
Bo

## 3.484586

Con valores mayores de 1 ya deberíamos dudar de la validez de la regresión, y con valores


mayores de 5 debemos descartar este tipo de análisis.

Con estas evidencias, se va a proceder a aplicar Componentes Principales a estas variables. La


idea es poder sustituir en la regresión estas variables por otras que no estén correlacionadas
entre sí, que tengan un poder explicativo del comportamiento de la variable dependiente
similar, y que sean menos numerosas.

Como en los ejemplos anteriores, tipificamos y guardamos el número de columnas:


298 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

ZDatos <- scale(Datos)


ZDatos

## MATRIM_MIL_05 NUM_HIJ_FERT_05 TAS_FECUN_05 POR_MUJ_ACT_05


## Albacete -0.55359521 -0.664028771 -0.68100852 -0.12681200
## Alicante -0.25324792 -0.208960103 -0.05149286 -0.88158660
## Badajoz -0.42349888 -0.348266838 -0.61825599 0.59804613
## Cantabria 0.51637695 -1.304839752 -1.10946441 -1.01255717
## Ciudad Real -0.25882021 0.004643558 -0.37448314 0.60954264

07
## Cuenca -2.08588923 -1.945650733 -2.05428691 2.03518420
## Granada 0.14601082 0.654741655 0.39207343 -0.02633628
## Huelva 1.06012443 0.682603002 0.59594904 0.34244047

5-
## Murcia 0.30775373 2.242838435 2.24071782 0.15841544
## Navarra -0.48080471 -0.069653368 0.34409469 -1.42244265

-0
## Rioja -0.22614411 -0.116088946 -0.04676685 -0.63819171
## Segovia -1.51741710 -0.487573573 -0.59698761 0.36652043
## Sevilla 2.00218799 1.379136677 1.35200633 -0.11393625
##
##
##
Toledo
Valencia
Zaragoza
0.51048453
1.29231568
-0.03583676
190.534009151
0.311118375
0.52400630
0.51491494
-0.664028771 -0.43101626
1.95585057
-1.10025138
-0.74388584
20
## PIB_HAB_04
## Albacete -0.83968167
## Alicante 0.02421934
## Badajoz -1.43213248
## Cantabria 0.55029736
or

## Ciudad Real -0.43805034


## Cuenca -0.64198626
ad

## Granada -1.13483580
## Huelva -0.42806192
## Murcia -0.27823740
## Navarra 2.28614199
rr

## Rioja 1.23638929
## Segovia 0.77491842
Bo

## Sevilla -0.56435516
## Toledo -0.68844454
## Valencia 0.33887530
## Zaragoza 1.23494387
## attr(,"scaled:center")
## MATRIM_MIL_05 NUM_HIJ_FERT_05 TAS_FECUN_05 POR_MUJ_ACT_05
## 4.868945 1.352500 4.161720 61.087460
## PIB_HAB_04
## 17368.135018
## attr(,"scaled:scale")
## MATRIM_MIL_05 NUM_HIJ_FERT_05 TAS_FECUN_05 POR_MUJ_ACT_05
4.7. PRÁCTICAS 299

## 0.6216470 0.1076761 0.3743116 2.0902863


## PIB_HAB_04
## 3226.4921171
NCol<-ncol(Datos)
NCol

## [1] 5

Estimación del modelo

07
Vamos a proceder al cálculo de las componentes principales propiamente dicho. Vamos a
utilizar la función “prcomp”:

5-
modelo3.cp <- prcomp (Datos, scale = TRUE)
summary (modelo3.cp)

-0
## Importance of components:
## PC1 PC2 PC3 PC4 PC5
## Standard deviation 1.6182 1.2795 0.7177 0.47177 0.08285
##
##
19
Proportion of Variance 0.5237 0.3274 0.1030 0.04451 0.00137
Cumulative Proportion 0.5237 0.8511 0.9541 0.99863 1.00000
20
El “summary” de las componentes calculadas y guardadas en el objeto “resul”, se obtienen
3 informaciones correspondientes a las 5 componentes principales obtenidas. La “Standard
Deviation”.es la raíz cuadrada de los autovalores asociados a cada componente. “Proportion
of Variance” nos dice la proporción de la varianza o comportamiento de las variables origina-
or

les recogido por cada componente, proporción que se acumula en “Cumulative Proportion”.
Nótese que las componentes aparecen ordenadas de más a menos importantes en función de
la cantidad de varianza que capturan
ad

Los coeficientes que multiplican a las variables originales (tipificadas) en cada componente
se obtienen como hemos visto arriba:
coeficientes <- modelo3.cp$rotation
rr

coeficientes
Bo

## PC1 PC2 PC3 PC4 PC5


## MATRIM_MIL_05 0.52274405 0.01746261 -0.6476999 0.55227977 -0.04365301
## NUM_HIJ_FERT_05 0.57939993 -0.16724385 0.3537425 -0.18289782 -0.69118728
## TAS_FECUN_05 0.59486311 -0.03822871 0.3576532 -0.08598268 0.71369996
## POR_MUJ_ACT_05 -0.19088527 -0.68015202 0.3502839 0.61466126 0.02118445
## PIB_HAB_04 -0.02711234 0.71250007 0.4524781 0.52567477 -0.10265549

Selección de componentes
Seleccionamos de nuevo aquellas componentes con autovalor mayor que 1 (podría ser otro
criterio, por ejemplo que se explique más del 90 % de la variabilidad de los datos)
300 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

autovalores <- modelo3.cp$sdev^2


autovalores

## [1] 2.61848464 1.63703347 0.51504933 0.22256783 0.00686472


selec <- sum(autovalores > 1)
selec

## [1] 2
Seleccionamos pues dos componentes, gráficamente:

07
plot(autovalores, main = "Gráfico de Sedimentación",
xlab = "Nº de Autovalor", ylab="Valor", pch = 16, col = "red4", type = "b",

5-
lwd = 2, las = 1)
abline(h = 1, lty = 2, col = "green4")

-0
Gráfico de Sedimentación

2.5

2.0
19
20
1.5
Valor

or

1.0

0.5
ad

0.0
rr

1 2 3 4 5
Bo

Nº de Autovalor

Las cargas factoriales son:


cargas <- t(coeficientes[, 1:2])*(sqrt(autovalores[1:2]))
cargas

## MATRIM_MIL_05 NUM_HIJ_FERT_05 TAS_FECUN_05 POR_MUJ_ACT_05 PIB_HAB_04


## PC1 0.84589044 0.9375695 0.96259157 -0.3088854 -0.04387247
## PC2 0.02234281 -0.2139828 -0.04891234 -0.8702314 0.91161968
Puede comprobarse como en la primera componente (primera fila), las mayores cargas se
4.7. PRÁCTICAS 301

concentran en las tres primeras variables, de tipo demográfico. En cambio, en la segunda


componente (segunda fila), las mayores cargas se concentran en las dos últimas variables,
de tipo económico. Por tanto, a la primera componente la podemos denominar “Factores
Demográficos” y a la segunda “Factores Económicos”. Esto lo podemos ver también en el
gráfico bi-plot, que podemos realizar con el paquete factoextra para una visualización más
eficaz:
library(factoextra)
fviz_pca_biplot(modelo3.cp)

07
PCA − Biplot
Navarra
PIB_HAB_04

5-
2
Zaragoza
Cantabria Rioja

-0
Valencia
1
Alicante
Dim2 (32.7%)

0
19
Segovia

Albacete
MATRIM_MIL_05
TAS_FECUN_05
20
Ciudad Real Huelva NUM_HIJ_FERT_05
Sevilla
Murcia
Granada
−1
Badajoz
Cuenca
or

Toledo
−2 POR_MUJ_ACT_05
ad

−4 −2 0 2
Dim1 (52.4%)
rr

Los valores que, para cada caso, toman estas dos componentes, los podemos obtener direc-
tamente del objeto guardado, y añadirlas al conjunto de datos original:
Bo

provincias <- cbind(provincias, modelo3.cp$x[, 1:2])

Estimaremos ahora de nuevo la regresión lineal que intenta explicar el comportamiento de


la variable EDAD_MATER_05, pero utilizando como regresores PC1 (es decir, la variable
“factores demográficos”) y PC2 (“factores económicos”). Para ello se estima la regresión y se
almacena en el objeto “regre2”. Por último, se muestran los resultados con “summary”:
regre2 <- lm(EDAD_MATER_05 ~ PC1 + PC2, data = provincias)
summary(regre2)

##
302 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

## Call:
## lm.default(formula = EDAD_MATER_05 ~ PC1 + PC2, data = provincias)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.53892 -0.16163 0.01028 0.20208 0.40661
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 30.83313 0.07204 428.02 < 2e-16 ***

07
## PC1 -0.12322 0.04598 -2.68 0.018899 *
## PC2 0.29482 0.05815 5.07 0.000215 ***
## ---

5-
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2881 on 13 degrees of freedom

-0
## Multiple R-squared: 0.7167, Adjusted R-squared: 0.6731
## F-statistic: 16.44 on 2 and 13 DF, p-value: 0.0002751

19
En primer lugar, puede destacarse que el valor del coeficiente de determinación lineal co-
rregido se incrementa, debido al aumento de grados de libertad. Además, los parámetros
correspondientes a las dos variables explicativas son significativas (p-values pequeños). El
20
efecto de PC1 (“factores demográficos”) sobre la edad media de maternidad es negativo (a
mayor número de matrimonios, número de hijos en edad fértil y tasa de fecundidad, menor
edad media); mientras que el efecto de PC2 (“factores económicos”) sobre la edad media de
maternidad es positivo (a mayor PIB por habitante y menor proporción de mujeres activas,
or

mayor edad media de maternidad) además de más intenso que el efecto de los “factores
demográficos”. Por último, puede comprobarse como la correlación entre las componentes
principales, que ahora son las variables explicativas, es prácticamente nula, y el vif es igual
ad

a 1.
cor(provincias[, 9:10])
rr

## PC1 PC2
## PC1 1.000000e+00 -1.254361e-17
Bo

## PC2 -1.254361e-17 1.000000e+00


car::vif(regre2)

## PC1 PC2
## 1 1

Estimación de nuevos valores


Vamos ahora a suponer que queremos estimar la variable respuesta para una hipotética
provincia cuyos valores de las variables explicativas son las medianas de las variables en las
provincias disponibles. Los nuevos datos de la provincia serían:
4.7. PRÁCTICAS 303

summary(Datos)

## MATRIM_MIL_05 NUM_HIJ_FERT_05 TAS_FECUN_05 POR_MUJ_ACT_05


## Min. :3.572 Min. :1.143 Min. :3.393 Min. :58.11
## 1st Qu.:4.597 1st Qu.:1.295 1st Qu.:3.936 1st Qu.:59.46
## Median :4.788 Median :1.343 Median :4.143 Median :60.94
## Mean :4.869 Mean :1.353 Mean :4.162 Mean :61.09
## 3rd Qu.:5.187 3rd Qu.:1.413 3rd Qu.:4.355 3rd Qu.:61.97
## Max. :6.114 Max. :1.594 Max. :5.000 Max. :65.34

07
## PIB_HAB_04
## Min. :12747
## 1st Qu.:15259
## Median :16229

5-
## Mean :17368
## 3rd Qu.:19325

-0
## Max. :24744
nuevaProvincia <- data.frame(MATRIM_MIL_05 = 4.788, NUM_HIJ_FERT_05 = 1.342, TAS_FECUN_0

19
Como ya realizamos el ajuste con los datos originales, podemos obtener los scores de la nueva
provincia en las componentes con la función predict:
20
newScores <- predict(modelo3.cp, newdata = nuevaProvincia)
newScores

## PC1 PC2 PC3 PC4 PC5


## [1,] -0.1313679 -0.1880161 -0.1523811 -0.2784865 0.07215929
or

Y obtener una estimación de la edad de maternidad media para la nueva provincia:


predict(regre2, as.data.frame(newScores), interval = "confidence")
ad

## fit lwr upr


## 1 30.79388 30.63593 30.95183
rr
Bo
304 CAPÍTULO 4. ANÁLISIS DE COMPONENTES PRINCIPALES CON R

07
5-
-0
19
20
or
ad
rr
Bo
Capítulo 5

07
Análisis Cluster con R

5-
5.1. Introducción al análisis cluster

-0
El análisis cluster, o análisis de conglomerados, es una técnica de análisis multivariante de
interdependencias, es decir, todas las variables juegan el mismo papel, sin que unas expliquen
a otras.
19
Consiste en identificar observaciones (objetos, individuos, etc.) que son similares con respecto
20
a un criterio, y clasificarlos en grupos o tipos que internamente sean homogéneos y que
entre sí sean heterogéneos. El análisis cluster entra dentro de las técnicas de clasificación no
supervisadas. Esto quiere decir que no hay unos grupos predeterminados, sino que se van a
crear a partir de la información interna de los datos.
or

Aunque el análisis cluster se puede utilizar con variables en cualquier escala, en este capítulo
nos vamos a centrar exclusivamente en variables en escala métrica, es decir, cuantitativas.
En lo que sigue, asumimos que tenemos un conjunto de datos de n individuos en los que se
ad

han observado m variables cuantitativas. Este conjunto lo podemos simbolizar con la matriz
X = (X1 , · · · , Xj , · · · , Xm ). Así, xij será el valor de la variable Xj en el individuo i.
Para realizar las agrupaciones, necesitamos una medida de proximidad entre los individuos,
rr

que cuantifique lo que dos individuos o grupos se parecen, en función de los valores que
presente cada variable. Estas medidas pueden estar basadas en la distancia, en coeficientes
Bo

de correlación, o en similaridad entre atributos para variables en escala nominal.


En este capítulo utilizaremos el concepto de distancia para realizar las agrupaciones. A partir
de las distancias, existen dos procedimientos para formar los grupos: métodos jerárquicos y
métodos no jerárquicos.
Una vez obtenidos los grupos, se pueden describir, comparar, o utilizar en otras técnicas
como variable cualitativa.

La figura 5.1 muestra visualmente un ejemplo muy sencillo de lo que vamos a hacer.
Aquí, disponemos de n = 8 observaciones y m = 2 variables. Queremos agrupar los individuos

305
306 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

15

10
X2

07
0

5-
0 5 10 15

-0
X1

19
Figura 5.1: Agrupamiento sencillo
20
en base a esas observaciones, y lo que buscamos es que sean muy parecidos (próximos) entre
ellos y que los grupos sean diferentes (lejanos). En este sencillo ejemplo se ve claramente la
agrupación natural que haríamos a simple vista. Usaremos los métodos numéricos del análisis
cluster para agrupar muchos más individuos en base a un gran número de variables.
or

Resumiendo, el análisis cluster se realiza en las siguientes etapas:


1. Se cuenta con n individuos en los que se observan m variables.
ad

2. Se establece una medida de proximidad (distancia) entre cada dos individuos, utilizan-
do los valores de las m variables.
3. Se crean los grupos utilizando el criterio de proximidad.
rr

4. Se describen y comparan los grupos.


Bo

5.2. Cálculo de distancias


Una vez que tenemos nuestro conjunto de datos multidimensional, el siguiente paso es cuan-
tificar lo próximas que están las observaciones, y los grupos de estos que se vayan formando,
de forma que los grupos (clusters) que se vayan formando, estén muy próximos entre sí, y
los grupos muy distantes entre ellos.
Antes de calcular distancias, debemos evaluar la conveniencia de tipificar las variables, ya que
su escala puede condicionar mucho la formación de los grupos. A menos que las variables estén
medidas en escalas similares, se debe trabajar con los datos tipificados, es decir, transformar
cada variable Xj en:
5.2. CÁLCULO DE DISTANCIAS 307

Xj − x̄j
Zj = .
sj

donde x̄j y sj son la media y la desviación típica de la variable Xj respectivamente. A lo


largo del capítulo utilizaremos la notación de las variables originales, Xj , aunque se debe
tener presente en todo momento que pueden ser las variables originales o las tipificadas.
Existen varias medidas de distancia entre dos observaciones i e i′ , que denotaremos por dii′ .
A continuación vamos a definir las más utilizadas. En todos los casos, lo que hacemos es

07
resumir de alguna manera las m diferencias que hay entre los valores de todas y cada una
de las variables Xj , es decir, xij − xi′ j .
La distancia euclídea se define como:

5-
v
u∑
um

-0
dii′ = t (xij − xi′ j )2 .
j=1

19
En ocasiones se utiliza la distancia euclídea al cuadrado, para quitar la raíz y reducir el coste
computacional:
20

m
d2ii′ = (xij − xi′ j )2 .
j=1
or

Otra medida de la distancia es la distancia de Minkowski:

 1
ad


m p

d2ii′ =  |xij − xi′ j | p


.
j=1
rr

Los valores más habituales de p son 1 y 2, que se corresponden con la distancia de Manhattan
y la distancia euclidea respectivamente. Además, cuando p tiende a infinito o a menos infinito,
Bo

la distancia de Minkowski se corresponde, respectivamente, con la distancia máxima (o de


Chebyshev) y mínima.
Las medidas anteriores no tienen en cuenta la estructura de correlación del conjunto de datos
multivariante. Una medida más completa es la distancia de Mahalanobis (D2 ):

xi − x i′ )′Σ −1 (x
Dii2 ′ = (x xi − x i′ ),

donde x i y x i′ son los vectores fila de las observaciones i e i′ respectivamente, y Σ es la matriz


de varianzas-covarianzas de todas las variables.
308 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

Tabla 5.1: Datos de ejemplo sencillo para análisis cluster


Var1 Var2 Var3
caso 1 0.9 0.8 70
caso 2 0.6 0.5 30
caso 3 0.7 0.7 40
caso 4 0.8 0.7 70
caso 5 0.7 0.5 30

07
La tabla 5.1 muestra un conjunto de datos muy pequeño X con n = 5 observaciones
de m = 3 variables, que nos servirá para practicar. Como ejercicio, el lector debe crear un

5-
data frame llamado cdata1 en su espacio de trabajo, bien con código, bien creando los datos
en un fichero externo (hoja de cálculo o texto plano). A modo de ejemplo, a continuación se
calculan las distancias entre los dos primeros casos operando directamente con los vectores

-0
de la matriz de datos previamente tipificada con la función scale.

Tipificación de las variables:


zdata1 <- scale(cdata1) 19
20
Distancia euclídea:
sqrt(sum((zdata1[1, ] - zdata1[2, ])^2))

## [1] 3.966434
or

Distancia euclídea al cuadrado:


sum((zdata1[1, ] - zdata1[2, ])^2)
ad

## [1] 15.7326
Distancia de Minkowski1 (p = 3):
rr

sum(abs(zdata1[1, ] - zdata1[2, ])^3)^(1/3)


Bo

## [1] 3.327158
Distancia de Manhattan:
sum(abs(zdata1[1, ] - zdata1[2, ]))

## [1] 6.819042
Distancia de Chebyshev (máxima):
max(abs(zdata1[1, ] - zdata1[2, ]))
1
Puede comprobarse que para p = 2 coincide con la euclídea.
5.2. CÁLCULO DE DISTANCIAS 309

## [1] 2.631174
Distancia mínima:
min(abs(zdata1[1, ] - zdata1[2, ]))

## [1] 1.9518
Distancia de Mahalanobis:
t(zdata1[1, ] - zdata1[2, ]) %*% solve(cov(zdata1)) %*% (zdata1[1, ] - zdata1[2, ])

07
## [,1]
## [1,] 7.971831

5-
Si calculamos las distancias de todos los pares de observaciones de un conjunto de datos,
obtendríamos una matriz de distancias:

-0
 
d11 d12 · · · d1i ··· d1n
 


d21 d22 · · · d2i ··· d2n 

D=








..
.
19
..
.
. . . ..
.
di1 di2 · · · dii
..
.
..
.
..
.
..
.
..
.
···
...
..
.



din 

.. 
. 

20
dn1 dn2 · · · dni ··· dnn

La matriz de distancias es una matriz simétrica, cuya diagonal son ceros, ya que la distan-
cia de una observación a sí misma (dii ) es nula. Por tanto se puede representar de forma
or

simplificada con los elementos bajo la diagonal:

 
ad

d21
 
 d31 d32 
 
 .. .. ... 
 . . 
 
rr

D=  
 di1 di2 · · · di,i−1 
 .. .. .. .. ... 
 
 . . . . 
Bo

dn1 dn2 · · · dni · · · dn,n−1

Podemos obtener la matriz de distancias con R con una única expresión, utilizando la función
dist. Esta función devuelve una matriz de distancias entre observaciones a partir de un
conjunto de variables numéricas. Por defecto devuelve las distancias euclídeas, aunque se
pueden obtener también la de Manhattan, la máxima y la de Minkowski, entre otras. La
función mahalanobis calcula las distancias de Mahalanobis de cada observación con respecto
al vector de medias, por lo que hay que utilizarla dentro de una función vectorizada para
obtener una matriz con las distancias. Esta matriz se puede convertir a un objeto de clase
dist para ser utilizado en otros métodos mediante la función as.dist.
310 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

El código a continuación devuelve las matrices de distancias para los datos del ejemplo.
Nótese cómo la distancia entre los casos 1 y 2 coinciden con los calculados operando con los
vectores fila. En el caso de la distancia de Mahalanobis, es aconsejable calcular previamente
la inversa de la matriz de varianzas-covarianzas, y así reducir el tiempo de cálculo.

Distancia euclídea (por defecto):


dist(zdata1)

07
## caso 1 caso 2 caso 3 caso 4
## caso 2 3.966434
## caso 3 2.403193 1.797094

5-
## caso 4 1.150994 3.018057 1.706484
## caso 5 3.447673 0.877058 1.568540 2.607868

-0
Distancia de Minkowski2 (p = 3):
dist(zdata1, method = "minkowski", p = 3)

##
## caso 2
caso 1
3.327158
caso 2 caso 3 19
caso 4
20
## caso 3 2.076085 1.600980
## caso 4 1.028748 2.527452 1.562061
## caso 5 2.885022 0.877058 1.507939 2.252115
Distancia de Manhattan:
or

dist(zdata1, method = "manhattan")


ad

## caso 1 caso 2 caso 3 caso 4


## caso 2 6.819042
## caso 3 3.963322 2.855720
## caso 4 1.622414 5.196628 2.340908
rr

## caso 5 5.941984 0.877058 1.978662 4.319570


Distancia de Chebyshev (máxima):
Bo

dist(zdata1, method = "maximum")

## caso 1 caso 2 caso 3 caso 4


## caso 2 2.631174
## caso 3 1.754116 1.490712
## caso 4 0.877058 1.951800 1.463850
## caso 5 2.236068 0.877058 1.490712 1.951800
Distancia de Mahalanobis:
2
De nuevo, puede comprobarse que para p = 2 coinciden con las euclídeas.
5.2. CÁLCULO DE DISTANCIAS 311

invS <- solve(cov(zdata1))


D <- sapply(1:nrow(zdata1), function(x){
mahalanobis(x = zdata1,
center = zdata1[x, ],
cov = invS,
inverted = TRUE)
})
D

07
## [,1] [,2] [,3] [,4] [,5]
## caso 1 0.000000 7.971831 5.183099 4.591549 5.183099
## caso 2 7.971831 0.000000 4.591549 3.943662 4.591549
## caso 3 5.183099 4.591549 0.000000 7.971831 8.000000

5-
## caso 4 4.591549 3.943662 7.971831 0.000000 7.971831
## caso 5 5.183099 4.591549 8.000000 7.971831 0.000000

-0
as.dist(D)

##
##
##
##
caso
caso
caso
2
3
4
caso 1
7.971831
caso 2

5.183099 4.591549
caso 3

4.591549 3.943662 7.971831


19 caso 4
20
## caso 5 5.183099 4.591549 8.000000 7.971831

Ya hemos visto cómo calcular las distancias entre observaciones. Ahora bien, a medida que
vamos formando los grupos, también debemos comprobar la proximidad de las observaciones
or

a los grupos, de forma que podamos asignar la observación al grupo más próximo. Por
otra parte, hay que calcular distancias entre grupos, para cuantificar cómo de diferentes
(distantes) son los grupos. Para ambas tareas, una vez tenemos dos o más observaciones
ad

agrupadas, calculamos un valor que los represente a todos, y que llamaremos centroide.
Este centroide será un vector con valores para las m variables, calculado a partir de los
valores de las observaciones que están dentro del grupo. Lo más habitual es utilizar como
rr

centroide las medias de las observaciones en cada variable, aunque se podría utilizar cualquier
otra medida representativa, como por ejemplo la mediana.
Bo

Supongamos a modo ilustrativo que los dos primeros casos forman un grupo. Entonces,
podemos calcular el centroide de ese grupo como el vector de medias de los dos primeros
casos como se muestra en el código a continuación. Después se pueden calcular las distancias
del resto de observaciones a este centroide. La figura 5.2 muestra los centroides de los grupos
que se veían evidentes en la figura 5.2.

centroide <- colMeans(zdata1[1:2, ]); centroide

## Var1 Var2 Var3


## 0.08770580 0.07453560 0.09759001
312 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

15

10
X2

07
0

5-
0 5 10 15

-0
X1

19
Figura 5.2: Centroides para dos variables

dist(rbind(centroide, zdata1[3:5, ]))


20
## centroide caso 3 caso 4
## caso 3 0.7545143
## caso 4 1.1329508 1.7064841
or

## caso 5 1.5474782 1.5685399 2.6078682


Una vez hemos decidido los criterios para calcular distancias, elegimos un método de agrupa-
ad

ción. Los distintos métodos pueden dar soluciones distintas. La idoneidad del método elegido
va a depender tanto de la estructura interna de los datos como del problema que se está abor-
dando. En general, se probarán varios métodos y se seleccionará aquella agrupación que sea
más coherente desde el punto de vista teórico, y estable desde el punto de vista empírico. En
rr

los siguientes apartados vamos a estudiar los dos métodos más extendidos de agrupación.
Bo

5.3. Métodos jerárquicos


5.3.1. Agrupación de observaciones paso a paso
En el método jerárquico (hierarchical clustering) no tenemos un número predeterminado de
grupos a formar. Los grupos se van formando sucesivamente. Partimos de tantos grupos
como observaciones, y los vamos agrupando uno a uno hasta llegar a un único grupo que los
contiene a todos, tomando una forma piramidal. Esta estructura se representa gráficamente
mediante el llamado dendrograma.
El primer grupo se formará con las dos observaciónes más próximas. Después, se calculan
5.3. MÉTODOS JERÁRQUICOS 313

de nuevo las distancias del resto de observaciones al nuevo grupo. A partir de ahí, se van
creando nuevos grupos o añadiendo a alguno existente, y combinándose en función de la
distancia.
Existen varios métodos para realizar las sucesivas agrupaciones, según cómo calculemos las
distancias entre grupos. El método más sencillo sería el de los centroides, ya que bastaría con
ir sustituyendo las observaciones agrupadas por su centroide. No obstante se pueden utilizar
otros métodos:
1. Método del vecino más cercano (Single linkage). La distancia entre grupos es la dis-
tancia entre sus elementos más próximos.

07
2. Método del vecino más lejano (Complete linkage). La distancia entre grupos es la
distancia entre sus elementos más lejanos.

5-
3. Métodos UPGMA3 , WPGMA4 , basados en promedios de distancias de observaciones
de los centroides.

-0
4. Método UPGMC5 o de los centroides.
5. Método WPGMC6 o de las medianas.

19
6. Métodos de Ward. Se unen los conglomerados que dan lugar a otro cuyos individuos
tienen una menor suma de los cuadrados de sus distancias respecto al centroide de
dicho grupo (menor varianza).
20
El código a continuación realiza paso a paso la secuencia de agrupación del ejemplo
de cinco casos y tres variables utilizando el criterio de los centroides.
or

Paso 1: calculamos todas las distancias


dist(zdata1)
ad

## caso 1 caso 2 caso 3 caso 4


## caso 2 3.966434
rr

## caso 3 2.403193 1.797094


## caso 4 1.150994 3.018057 1.706484
## caso 5 3.447673 0.877058 1.568540 2.607868
Bo

Paso 2: agrupamos los dos casos más cercanos (menor distancia), que en este caso son el 2 y
el 5. Sustituimos las dos observaciones por el nuevo grupo y recalculamos distancias.
grupo.2.5 <- colMeans(zdata1[c(2, 5), ])
agrupacion1 <- rbind(grupo.2.5, zdata1[c(1, 3,4), ]); agrupacion1

## Var1 Var2 Var3


3
Unweighted Pair Group Method with Arithmetic Mean.
4
Weighted Pair Group Method with Arithmetic Mean.
5
Unweighted Pair Group Method with Centroids.
6
Weighted Pair Group Method with Centroids.
314 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

## grupo.2.5 -0.7893522 -1.0434984 -0.8783101


## caso 1 1.4032928 1.1925696 1.0734901
## caso 3 -0.3508232 0.4472136 -0.3903600
## caso 4 0.5262348 0.4472136 1.0734901
dist(agrupacion1)

## grupo.2.5 caso 1 caso 3


## caso 1 3.690151
## caso 3 1.628688 2.403193

07
## caso 4 2.786129 1.150994 1.706484
Paso 3: agrupamos los dos grupos más cercanos, en este caso los casos 1 y 4 y volvemos a
reorganizar:

5-
grupo.1.4 <- colMeans(agrupacion1[c(2, 4), ])
agrupacion2 <- rbind(grupo.1.4, agrupacion1[-c(2,4), ])

-0
agrupacion2

## Var1 Var2 Var3

19
## grupo.1.4 0.9647638 0.8198916 1.0734901
## grupo.2.5 -0.7893522 -1.0434984 -0.8783101
## caso 3 -0.3508232 0.4472136 -0.3903600
20
dist(agrupacion2)

## grupo.1.4 grupo.2.5
## grupo.2.5 3.218489
or

## caso 3 2.003126 1.628688


Paso 4: agrupamos los dos grupos más cercanos, en este caso el caso 3 y el grupo formado
ad

por los casos 2 y 5.


grupo.2.5.3 <- colMeans(agrupacion2[c(2, 3), ])
agrupacion3 <- rbind(grupo.2.5.3, agrupacion2[-c(2, 3), , drop = FALSE])
rr

agrupacion3

## Var1 Var2 Var3


Bo

## grupo.2.5.3 -0.5700877 -0.2981424 -0.634335


## grupo.1.4 0.9647638 0.8198916 1.073490
dist(agrupacion3)

## grupo.2.5.3
## grupo.1.4 2.553906
Paso 5: El último paso sería agrupar los dos grupos resultantes en uno solo con todos los
casos.
En este ejemplo con tan pocos casos, parece evidente la formación de dos grupos, uno formado
5.3. MÉTODOS JERÁRQUICOS 315

por los casos 1 y 4, y el otro formado por los casos 2, 5, y 3. Posteriormente veremos cómo
caracterizar estos grupos para darles significado.
Hemos utilizado el método de los centroides, pero podríamos haber utilizado cualquiera de los
otros. En este ejemplo tan sencillo, los resultados hubieran sido los mismos. En la práctica,
es habitual probar varios métodos y quedarse con el que mejor se adapte al problema en
cuestión. La práctica ha mostrado en numerosas ocasiones que algunos métodos funcionan
mejor que otros según sea la estructura interna de los datos. Por ejemplo:
El método del vecino más cercano es más sensible a la presencia de observaciones raras
(outliers) que el del vecino más lejano.

07
El método del vecino más lejano suele identificar grupos muy homogéneos con indivi-
duos muy parecidos entre sí.

5-
El método de Ward tiende a encontrar grupos muy compactos de tamaño similar.
El método del vecino más cercano tiende a crear menos grupos que el del vecino más

-0
lejano.
Una vez agrupadas las observaciones, debemos decidir cuáles son los grupos con los que nos

19
queremos quedar. Recordemos que partíamos de tantos grupos como observaciones, y termi-
namos con un solo grupo. En los siguientes apartados veremos criterios gráficos y numéricos
para ello.
20
5.3.2. Análisis Cluster jerárquico con R
Hemos realizado los cálculos paso paso a modo ilustrativo. Ahora vamos a ver cómo realizar
or

todo el proceso de forma sencilla con la función hclust de R. La función hclust crea un
objeto de clase hclust según varios criterios7 . La clasificación se representa gráficamente
mediante un dendrograma con la función hclust. Este dendrograma nos puede dar una idea
ad

de cuántos grupos nos interesa formar. La idea es podar el dendrograma haciendo un corte
horizontal que determine los grupos que nos interesan, digamos k grupos. Con la función
rect.hclust podemos visualizar esa poda, la dimensión de los grupos, y los casos que lo
rr

forman. Se pueden probar con varios valores de k hasta que encontremos el que más se adecúe
al problema. Se busca un equilibrio entre el número de grupos y una suficiente diferenciación
entre ellos, a la vez que homogeneidad dentro de cada uno. Una vez decididos el número de
Bo

grupos, podemos aplicar al objeto de clase hclust la función cuttree, que devuelve un vector
con los grupos formados, realizando la poda a una altura h determinada (distancia según el
criterio utilizado) o un número de grupos k. Este vector lo podemos añadir al conjunto de
datos como factor para utilizar en análisis posteriores.

El código a continuación crea la agrupación del conjunto de datos de la tabla 5.1


utilizando el método jerárquico por el método de Ward. Primero guardamos las distancias
7
El método del centroide difiere ligeramente de la simple distancia entre medias. Utiliza también los
valores de los centroides de los que procede.
316 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

Cluster Dendrogram

2.0
1.6
Altura

1.2

caso 3

07
caso 1

caso 4
0.8

5- caso 2

caso 5
-0
19 Casos
Ejemplo básico
20
Figura 5.3: Dendrograma de la agrupación del ejemplo básico

euclídeas (por defecto en la función dist) en un objeto para pasárselas como primer argu-
or

mento, y usamos el método de los centroides (argumento method). La función genérica plot
crea el dendrograma de la figura 5.3. Con esta figura podemos intuir los grupos que queremos
quedarnos. La función hclust añade la poda del dendrograma para crear 2 grupos como se
ad

ve en la figura 5.4. La altura indica cómo se han ido añadiendo los casos según el criterio
utilizado, como vemos en el mismo orden en que lo hicimos paso a paso anteriormente.
rr

Crear agrupamientos sucesivos y representarlos:


ddata1 <- dist(zdata1)
Bo

gdata1 <- hclust(ddata1, method = "centroid")


plot(gdata1, sub = "Ejemplo básico", xlab = "Casos", ylab = "Altura")

Podar dendrograma gráficamente:


plot(gdata1, sub = "Ejemplo básico", xlab = "Casos", ylab = "Altura")
rect.hclust(tree = gdata1, k = 2, border = c("red4", "blue4"))

Podar dendrograma y obtener el vector de grupos:


grupos <- cutree(tree = gdata1, k = 2)
grupos
5.3. MÉTODOS JERÁRQUICOS 317

07
Cluster Dendrogram

5-
2.0

-0
1.6

19
Altura

1.2

caso 3
20
caso 1

caso 4
0.8

caso 2

caso 5
or
ad

Casos
Ejemplo básico
rr

Figura 5.4: Dendrograma de la agrupación del ejemplo básico seleccionando dos grupos
Bo
318 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

## caso 1 caso 2 caso 3 caso 4 caso 5


## 1 2 2 1 2
cdata1$grupo <- factor(grupos)

En el apartado5.6 veremos algunos índices que nos pueden ayudar a decidir el número de
clusters óptimo con criterios numéricos.

5.4. Métodos no jerárquicos

07
Los métodos no jerárquicos se suelen utilizar para agrupar un gran número de observaciones.
En estos métodos, se establece de antemano el número de grupos que se van a formar, k. Se
utilizan métodos iterativos de forma que, a partir de k grupos iniciales semilla, las observa-

5-
ciones van cambiando de grupo hasta que se consigue un cierto criterio de homogeneidad
de los grupos. El método de las k-medias es el más importante, y el que veremos en este

-0
apartado.
Proceso de formación de grupos:

19
1. Se establece número k de grupos a formar
2. Se establece un centroide inicial para cada grupo
20
3. Se añaden a cada grupo las observaciones más cercanas a los centroides iniciales
4. Se calculan los nuevos centroides y se vuelven a asignar los más próximos
5. Se repite el proceso hasta que las agrupaciones se mantienen estables
or

Las iteraciones pueden hacer muy largo el proceso paso a paso, vamos a ver directamente
cómo hacerlo con las funciones de R. La función kmeans realiza el agrupamiento cluster no
jerárquico por el método de las k medias. Esta función requiere como argumento de entrada
ad

un conjunto de datos, y no una matriz de distancias como antes. Además, el número de


grupos k se indica con el argumento centers. El resto de argumentos tienen unos valores
predeterminados que son válidos para la mayoría de las situaciones. El argumento algorithm
rr

permite seleccionar entre cuatro diferentes. Por defecto se utiliza el de Hartigan and Wong
(1979); el argumento iter.max controla el número máximo de iteraciones del método, por
Bo

defecto 10; el argumento nstart indica el número de conjuntos aleatorias elegir al empezar.
Por defecto es 1, pero con frecuencia se aconseja utilizar un número mayor. La función
produce un objeto de clase kmeans que es una lista de 9 componentes. Los más importantes
son cluster, vector con el grupo al que pertenece cada observación, y centers, los centroides
de los grupos.

El código a continuación aplica el método de las k-medias para el ejemplo sencillo


que estamos utilizando en el capítulo. Fijamos el número de grupos en k = 2, ya que esto era
lo que habíamos deducido con el método jerárquico. El método print de un objeto kmeans
muestra el tamaño de cada cluster, sus centroides, el vector con los grupos y una medida
5.5. CARACTERIZACIÓN DE GRUPOS 319

de bondad de ajuste en forma de porcentaje, que se puede interpretar como la varianza


explicada por los agrupamientos.

kcdata1 <- kmeans(x = zdata1, centers = 2)


kcdata1

## K-means clustering with 2 clusters of sizes 3, 2


##
## Cluster means:
## Var1 Var2 Var3

07
## 1 -0.6431759 -0.5465944 -0.7156601
## 2 0.9647638 0.8198916 1.0734901
##

5-
## Clustering vector:
## caso 1 caso 2 caso 3 caso 4 caso 5
## 2 1 1 2 1

-0
##
## Within cluster sum of squares by cluster:
##
##
##
[1] 2.1530322 0.6623932
(between_SS / total_SS = 76.5 %) 19
20
## Available components:
##
## [1] "cluster" "centers" "totss" "withinss"
## [5] "tot.withinss" "betweenss" "size" "iter"
## [9] "ifault"
or

Guardamos los grupos en el conjunto de datos original para utilizar posteriormente:


kcdata1$cluster
ad

## caso 1 caso 2 caso 3 caso 4 caso 5


## 2 1 1 2 1
rr

cdata1$grupo2 <- factor(kcdata1$cluster)


Bo

Realice la práctica 5.1 cuyo guión se encuentra en el apartado 5.7 para realizar análisis
cluster del ejemplo utilizado en el capítulo.

5.5. Caracterización de grupos


Una vez obtenidos los grupos o clusters, es importante caracterizarlos para su interpretación
y uso posterior. Una forma gráfica de visualizar esta caracterización, es representando las
variables en gráficos de dispersión para cada par de variables, y ver cómo se disponen grá-
ficamente las observaciones. Si tenemos más de dos variables, podemos visualizar todos los
320 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

gráficos de dispersión como una matriz de gráficos. Esta representación se complica cuando
crece el número de variables. En este caso, podemos utilizar el análisis cluster conjuntamente
con el análisis de componentes principales, de forma que la representación la haremos de las
dos primeras componentes, identificando el grupo de cada observación.

En nuestro sencillo ejemplo solo tenemos tres variables. Podemos optar por representar
las tres combinaciones posibles de las variables como muestra la figura 5.5. La figura 5.6
muestra una matriz de gráficos con todos los pares de gráficos de una vez. La figura ??
muestra la representación de las dos componentes principales ajustadas con la función prcomp.

07
El siguiente código produce dichas figuras.

par(mfrow=c(3,1))

5-
plot(Var1 ~ Var2, data = cdata1, col = grupo, pch = 19, las = 1)
plot(Var1 ~ Var3, data = cdata1, col = grupo, pch = 19, las = 1)
plot(Var2 ~ Var3, data = cdata1, col = grupo, pch = 19, las = 1)

-0
par(mfrow=c(1,1))

library(lattice)
19
splom(~ cdata1[1:3], groups = grupo, data = cdata1, pch = 19)

plot(prcomp(scale(cdata1[1:3]))$x, type = "n")


20
text(prcomp(scale(cdata1[1:3]))$x, labels = rownames(cdata1), col = as.numeric(cdata1$gr

Además de gráficamente, podemos caracterizar los grupos de forma numérica. La forma más
básica sería interpretando los centroides de los grupos, pero los de las variables originales, ya
or

que lo que se guarda en el objeto kmeans son los centroides de las variables tipificadas, que no
son fáciles de interpretar. No obstante, podemos obtener cualquier otro estadístico (mediana,
ad

etc.) para ver las diferencias entre los grupos. Si se ha realizado el análisis de componentes
principales para resumir la información en dos dimensiones, y los componentes tienen un
sentido que se pueda explicar, también se pueden caracterizar los grupos en términos de las
componentes principales.
rr
Bo

El código a continuación muestra las medias de las tres variables en cada grupo. Las
observaciones del grupo 1 toman valores medios más altos en las tres variables que las del
grupo 2. A modo de ejemplo, después se muestra una expresión que obtiene un resumen más
completo de la variable Var1 para cada grupo.

aggregate(cbind(Var1, Var2, Var3) ~ grupo, data = cdata1, mean)

## grupo Var1 Var2 Var3


## 1 1 0.8500000 0.7500000 70.00000
## 2 2 0.6666667 0.5666667 33.33333
5.5. CARACTERIZACIÓN DE GRUPOS 321

0.90
0.85
0.80
Var1

0.75
0.70

07
0.65
0.60

0.50 0.55 0.60 0.65 0.70 0.75 0.80

5-
Var2

-0
0.90
0.85
0.80
19
Var1

0.75
0.70
20
0.65
0.60

30 40 50 60 70

Var3
or
ad

0.80
0.75
0.70
Var2

rr

0.65
0.60
0.55
Bo

0.50

30 40 50 60 70

Var3

Figura 5.5: Representación de las variables por pares con los grupos
322 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

70
50 60 70
60

50 Var3 50
40
30 40 50
30
0.80
0.75 0.65 0.75

07
0.70
0.65 Var2 0.65
0.60
0.55

5-
0.50 0.60
0.50
0.90
0.85 0.75 0.85

-0
0.80
0.75 Var1 0.75

0.60 0.70
0.70
0.65
0.60 19
Scatter Plot Matrix
20
Figura 5.6: Matriz de gráficos de dispersión
or
0.4

caso 5
ad

caso 4
0.2

caso 1
0.0

caso 2
rr
PC2

−0.6 −0.4 −0.2


Bo

caso 3

−2 −1 0 1

PC1
5.5. CARACTERIZACIÓN DE GRUPOS 323

tapply(cdata1$Var1, cdata1$grupo, summary)

## $`1`
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.800 0.825 0.850 0.850 0.875 0.900
##
## $`2`
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.6000 0.6500 0.7000 0.6667 0.7000 0.7000

07
Por último, podemos comprobar si con la agrupación que hemos realizado hemos conseguido
el objetivo que perseguíamos con esta técnica, recordemos: tener grupos que sean diferentes
entre sí, pero con los elementos del mismo grupo muy parecidos. Esto lo podemos visualizar

5-
gráficamente con gráficos de cajas. También podemos verificarlo estadísticamente mediante
el Análisis de la Varianza. Si observáramos que no hay diferencias entre dos grupos para un

-0
número importante de variables, deberíamos revisar el criterio de agrupación, e incluso el
número de grupos. Para un número importante de variables de clasificación, se puede consi-
derar realizar un análisis múltiple de la varianza (MANOVA) para comprobar las diferencias
entre los grupos conjuntamente.
19
20
La figura 5.7 muestra los gráficos de caja de las tres variables por grupos. Son muy
pocos datos, pero se aprecia la diferencia claramente. Para mayor seguridad, el ANOVA que
produce el código a continuación confirma que hay diferencias significativas, y además el test
HSD de Tukey indica que todos los grupos son diferentes en todas las variables.
or

library(reshape2)
gdata <- melt(cdata1, id.vars = 4, measure.vars = 1:3)
library(ggplot2)
ad

ggplot(gdata, aes(grupo, value)) + geom_boxplot() + facet_wrap( ~ variable, scales = "fr

modelo1 <- aov(Var1~grupo, data = cdata1)


rr

summary(modelo1)

## Df Sum Sq Mean Sq F value Pr(>F)


Bo

## grupo 1 0.04033 0.04033 10.37 0.0486 *


## Residuals 3 0.01167 0.00389
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
TukeyHSD(modelo1)

## Tukey multiple comparisons of means


## 95% family-wise confidence level
##
## Fit: aov.default(formula = Var1 ~ grupo, data = cdata1)
324 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

07
Var1 Var2 Var3

0.9 0.8 70

5-
-0
60

0.8 0.7

19
value

50
20
0.7 0.6

40
or
ad

0.6 0.5 30

1 2 1 2 1 2
rr

grupo

Figura 5.7: Gráficos de caja de las tres variables por grupos


Bo
5.5. CARACTERIZACIÓN DE GRUPOS 325

##
## $grupo
## diff lwr upr p adj
## 2-1 -0.1833333 -0.3645021 -0.002164608 0.0485669
modelo2 <- aov(Var2~grupo, data = cdata1)
summary(modelo2)

## Df Sum Sq Mean Sq F value Pr(>F)


## grupo 1 0.04033 0.04033 3.821 0.146

07
## Residuals 3 0.03167 0.01056
TukeyHSD(modelo2)

5-
## Tukey multiple comparisons of means
## 95% family-wise confidence level

-0
##
## Fit: aov.default(formula = Var2 ~ grupo, data = cdata1)
##
## $grupo
## diff lwr upr 19 p adj
## 2-1 -0.1833333 -0.4818104 0.1151438 0.1455963
20
modelo3 <- aov(Var3~grupo, data = cdata1)
summary(modelo3)
or

## Df Sum Sq Mean Sq F value Pr(>F)


## grupo 1 1613.3 1613.3 72.6 0.0034 **
## Residuals 3 66.7 22.2
ad

## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
TukeyHSD(modelo3)
rr

## Tukey multiple comparisons of means


Bo

## 95% family-wise confidence level


##
## Fit: aov.default(formula = Var3 ~ grupo, data = cdata1)
##
## $grupo
## diff lwr upr p adj
## 2-1 -36.66667 -50.36174 -22.9716 0.0033958

Realice la práctica 5.2 cuyo guión se encuentra en el apartado 5.7 para realizar análisis
cluster con datos de provincias.
326 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

5.6. Más análisis cluster


5.6.1. Estrategias de análisis y relación con otras técnicas
Los métodos jerárquicos y no jerárquicos se pueden utilizar por sí solos o conjuntamente. Si
conocemos a priori el número de grupos que queremos formar, empezamos directamente por
el método de las k-medias. Por ejemplo, si queremos repartir clientes entre k comerciales,
tareas entre k servidores, etc. Por el contrario, si no tenemos un número de grupos a priori,
se realiza primero un análisis jerárquico para decidir el número de grupos, y después se aplica
el análisis no jerárquico para optimizar dichos grupos.

07
5-
5.6.2. Análisis cluster con paquetes especializados
En este capítulo se ha introducido el análisis cluster con los métodos más habituales. Con

-0
la instalación base de R se instala el paquete cluster (Maechler et al., 2019) que tiene
algunas funciones adicionales. Existen otros métodos de agrupación como los utilizados por
el paquete mclust (Fraley et al., 2019), que está basado en modelos probabilísticos, véase
19
Everitt and Hothorn (2011). Por otra parte, el paquete NbClust (Charrad et al., 2015)
proporciona índices para la selección del número de grupos apropiado, véase Aldas and Uriel
(2017), donde aparecen además los métodos más detallados. El paquete FactoMineR (Husson
20
et al., 2018) también contiene herramientas de agrupamiento y visualización interesantes, y
el paquete factoextra proporciona herramientas de visualización muy potentes.
or

Vamos a utilizar los datos de la figura 5.1, que se muestran en la tabla 5.2, almacenados
en el objeto datos.cluster1. En la siguiente expresión, se calcula el número de clusters
óptimo según varios criterios, a partir de una medida de distancia y un método de agrupación,
ad

en este caso distancia euclídea y método de Ward. Podemos guardar el resultado en un objeto
para extraer después los índices, el número de grupos propuestos o la mejor partición que
encuentra. La salida proporciona una interpretación de todos los cálculos, informando de
rr

cuántos métodos proponen cada número de clusters, y cuál sería la decisión por mayoría. en
este ejemplo, parece claro que el número de grupos óptimo es 3, como se veía claramente
en el gráfico de la figura 5.1. Dos de los métodos son gráficos, cono se puede observar en la
Bo

salida por la consola y los gráficos producidos en la figura ??

nc <- NbClust::NbClust(data = scale(datos.cluster1),


distance = "euclidean",
method = "ward.D",
max.nc = 4)

El código a continuación crea los gráficos de las figuras 5.8 y 5.9 utilizando funciones
del paquete factoextra para los datos del ejemplo sencillo utilizado anteriormente.
5.6. MÁS ANÁLISIS CLUSTER 327

Tabla 5.2: Datos de ejemplo con dos variables y 8 observaciones


X1 X2 grupo
1.0 5.0 1
1.5 6.0 1
1.1 10.0 2
1.2 11.0 2
2.0 12.0 2
10.0 7.0 3
11.0 8.0 3

07
12.0 7.5 3

5-
library(factoextra)
fviz_dend(gdata1, k = 2, horiz = TRUE)

-0
fviz_cluster(object = kcdata1, data = zdata1)

5.6.2.1. Paquete cluster


19
El paquete cluster proporciona herramientas para calcular “distancias” entre observaciones
20
incluyendo variables en escala atributo (cualitativas). Ponemos entre comillas “distancias”
ya que, aunque el concepto es parecido, al incluir variables de tipo atributo, son realmente
matrices de disimilaridades. La función daisy calcula estas matrices de disimilaridades. El
cluster jerárquico aglomerativo se realiza con la función agnes. En contraposición al cluster
aglomerativo, es posible realizar cluster divisible con la función diana, es decir, partir de
or

un único grupo e ir dividiendo hasta tener tantos grupos como observaciones. La función
pam realiza análisis cluster no jerárquico, más robusto que el método de las k-medias. La
función clara realiza también análisis no jerárquico con el mismo algoritmo que pam, pero
ad

optimizado para conjuntos de datos grandes. La función fanny rambién realiza un análisis
no jerárquico, pero en vez de devolver a qué grupo pertenece cada observación, informa de
la probabilidad de pertenencia a cada grupo8 . Si lo que tenemos son variables binarias, la
rr

función mona utiliza un algoritmo específico.


En cuanto a las opciones de visualización, para conjuntos de datos con muchas observaciones,
Bo

el dendrograma puede ser difícil de ver. La función bannerplot permite una visualización más
efectiva en estos casos. Por otra parte, la función clusplot representa las observaciones en
dos dimensiones sobre las coordenadas de un análisis de componentes principales, agrupadas
según un análisis cluster realizado, y con elipses que nos dan una idea de cómo de separados
están los grupos.

En las siguientes expresiones se muestran ejemplos de uso del paquete cluster con

8
Se pueden ver un ejemplo interesante en http://is-r.tumblr.com/post/37826141731/
fuzzy-clustering-with-fanny
328 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

07
Cluster Dendrogram
caso 5

5-
-0
caso 2

19 caso 3
20
or

caso 4
ad

caso 1
rr

2.0 1.5 1.0 0.5 0.0


Height
Bo

Figura 5.8: Dendrograma generado con el paquete ‘factoextra‘


5.6. MÁS ANÁLISIS CLUSTER 329

Cluster plot
caso 5

07
caso 4
0.25

5-
-0
caso 1
caso 2
0.00

19
Dim2 (5.4%)

cluster
a 1
20
a 2

−0.25
or
ad

−0.50
rr

caso 3
Bo

−2 −1 0 1 2
Dim1 (91.2%)

Figura 5.9: Visualización clusters k-medias generado con el paquete ‘factoextra‘


330 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

Banner of agnes(x = zdata1) Dendrogram of agnes(x = zdata1)

caso

2.5
caso

Height

1.5
caso

07 caso 3
caso 1

caso 4
0.5
caso

caso 2

caso 5
caso

5-
0 1 2 2.86

-0
Height
zdata1
Agglomerative Coefficient = 0.6 Agglomerative Coefficient = 0.6

19
Figura 5.10: Cluster aglomerativo con paquete ‘cluster‘
20
los datos del ejemplo sencillo. La figura 5.10 muestra los gráficos del cluster aglomerativo.
La figura 5.11 muestra los gráficos del cluster no jerárquico. Con la función clusplot se puede
obtener el gráfico de la izquierda por separado.
or

par(mfrow=c(1,2))
library(cluster)
cag <- agnes(zdata1)
ad

plot(cag)

par(mfrow=c(1,1))
rr

cdi <- diana(zdata1)


par(mfrow=c(1,2))
Bo

cpa <- pam(zdata1, 2)


plot(cpa)

par(mfrow=c(1,1))

5.6.2.2. Paquete FactoMineR

El paquete FactoMineR permite realizar análisis cluster jerárquico sobre componentes prin-
cipales con la función HCPC.
5.7. PRÁCTICAS 331

clusplot(pam(x = zdata1, k = 2)) Silhouette plot of pam(x = zdata1, k =


n=5 2 clusters Cj
j : nj | avei∈Cj si
caso
0.4

1 : 2 | 0.59
caso
Component 2

0.0

caso
−0.4

07
caso 2 : 3 | 0.46

caso
−0.8

5-
−2 −1 0 1 2 0.0 0.2 0.4 0.6 0.8 1.0

-0
Silhouette width si
Component 1
These two components explain 96.63 % of the
Average
point variability.
silhouette width : 0.51

19
Figura 5.11: Cluster no jerárquico con paquete ‘cluster‘
20
La siguiente expresión realiza un clustering jerárquico sobre los datos del ejemplo,
después de extraer los componentes principales. La función produce varios gráficos. La figura
or

5.12 muestra la clasificación jerárquica en tres dimensiones. El resultado de los grupos se


puede visualizar con el paquete factoextra, como vemos en la figura 5.13.
ad

library(FactoMineR)
fm <- HCPC(PCA(zdata1, graph = FALSE), nb.clust = 2, graph = FALSE)
plot(fm)
rr

fviz_cluster(fm)
Bo

Realice la práctica 5.3 cuyo guión se encuentra en el apartado 5.7 para agrupar
individuos de una encuesta.

5.7. Prácticas
En este apartado se presentan las prácticas a las que se han hecho referencia durante el
capítulo. La reproducibilidad del código ha sido comprobada con la sesión de R que se
detalla en el Prefacio. El lector puede teclear el código o copiarlo y pegarlo en la consola o
el editor. También se puede descargar el script con el código de todas las prácticas con la
332 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

07
Hierarchical clustering on the factor map

5-
cluster 1
cluster 2

-0
2.5

19
2.0
1.5

20
height

1.0

Dim 2 (5.44%)
or
0.5

0.8
0.6
caso 3 0.4
0.2
0.0
−0.2
ad

−0.4
0.0

caso 2 caso 1 −0.6


caso 5 caso 4
−3 −2 −1 0 1 2 3

Dim 1 (91.19%)
rr

Figura 5.12: Cluster jerárquico sobre componentes principales con ‘FactoMiner‘


Bo
5.7. PRÁCTICAS 333

07
Cluster plot
caso 3
0.75

5-
-0
0.50

19
Dim2 (5.4%)

0.25 cluster
a 1
20
a 2
caso 2
0.00 caso 1
or

−0.25 caso 4
ad

caso 5
rr

−2 −1 0 1 2
Dim1 (91.2%)
Bo

Figura 5.13: Visualización de los clusters creados con ‘FactoMiner‘


334 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

siguiente expresión:
download.file("http://emilio.lcano.com/b/adr/practicas/12-acluster.R",
destfile = "practicas/12-acluster.R")

Práctica 5.1: Ejemplo básico


El objetivo del análisis clúster es crear grupos de individuos (conglomerados o “clústeres”)
en base a lo diferentes / parecidos que son los individuos que constituyen la población entre
sí de acuerdo con una serie de variables en escala métrica. R nos proporciona dos tipos de

07
métodos de agrupación: los métodos no-jerárquicos (en concreto el método de K medias)
y los procedimientos jerárquicos. El primer tipo se usa cuando existen muchos individuos,
pero requiere que se especifique a priori el número de grupos a formar. El segundo tipo de

5-
métodos no requiere el establecimiento previo del número de grupos, sino que estos grupos
se van creando de forma sucesiva a partir de la unión de grupos precedentes, hasta llegar a
uno solo.

-0
Las expresiones utilizadas se encuentran en el script de las prácticas del capítulo. En lo
sucesivo, vamos a suponer que estamos trabajando en un proyecto que contiene una carpeta

19
llamada “datos” donde se encuentran los ficheros de datos. No obstante, en esta práctica
crearemos los datos mediante código ya que son muy pocos datos.
20
Opcionalmente, podemos en primer lugar limpiar el espacio de trabajo eliminando todos los
objetos existentes:
rm(list = ls())
or

Ahora introducimos los datos de las variables del modelo. Esta vez lo haremos mediante el
propio script.
Data <- data.frame(Casos = c("caso 1", "caso 2", "caso 3", "caso 4", "caso 5"),
ad

Var1 = c(0.90, 0.60, 0.70, 0.80, 0.70),


Var2=c(0.80, 0.50, 0.70, 0.70, 0.50),
Var3=c(70, 30, 40, 70, 30),
rr

row.names = 1)

Se ha construido el data.fame “Data” que tiene 3 columnas (variables), y 5 casos, que son
Bo

los que tenemos que agrupar. En definitiva obtenemos la tabla de datos:


Data

## Var1 Var2 Var3


## caso 1 0.9 0.8 70
## caso 2 0.6 0.5 30
## caso 3 0.7 0.7 40
## caso 4 0.8 0.7 70
## caso 5 0.7 0.5 30
A continuación se construye el data.frame “ZData” con los datos tipificados, ya que estas
5.7. PRÁCTICAS 335

técnicas suelen ser muy sensibles a las distintas escalas de los datos.
ZData <- scale(Data)

La matriz tipificada “ZData” será:


ZData

## Var1 Var2 Var3


## caso 1 1.4032928 1.1925696 1.0734901
## caso 2 -1.2278812 -1.0434984 -0.8783101

07
## caso 3 -0.3508232 0.4472136 -0.3903600
## caso 4 0.5262348 0.4472136 1.0734901
## caso 5 -0.3508232 -1.0434984 -0.8783101

5-
## attr(,"scaled:center")
## Var1 Var2 Var3
## 0.74 0.64 48.00

-0
## attr(,"scaled:scale")
## Var1 Var2 Var3
## 0.1140175 0.1341641 20.4939015

19
Nótese cómo además de las variables tipificadas se obtienen las medias (center) y desviaciones
típicas (scale) originales, a las que podemos acceder en caso necesario mediante los atributos
20
del objeto ZData:
attr(ZData, "scaled:center")

## Var1 Var2 Var3


or

## 0.74 0.64 48.00


Pasamos ahora a plantear un análisis clúster jerárquico. La “distancia” entre los casos con-
ad

siderada será la distancia euclídea, muy sensible a la escala de las variables, por lo que
utilizaremos los datos tipificados (“ZData”). Primero vamos a calcular todas las distancias
y a crear la “matriz de distancias” que llamaremos “d”:
rr

d <- dist(ZData, method = "euclidean")

La matriz “d” obtenida es:


Bo

## caso 1 caso 2 caso 3 caso 4


## caso 2 3.966434
## caso 3 2.403193 1.797094
## caso 4 1.150994 3.018057 1.706484
## caso 5 3.447673 0.877058 1.568540 2.607868
Luego vamos a seleccionar el método de agrupación jerárquica mediante la función “hclust”.
Vamos a utilizar en concreto el método de Ward, cuya solución asignaremos al objeto “fit” y
dibujaremos el dendrograma correspondiente utilizando la función genérica plot:
336 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

fit <- hclust(d, method = "ward.D")


plot(fit, sub = "Ejemplo básico", xlab = "Casos", ylab = "Distancia entre clusters")

Cluster Dendrogram
5

07
Distancia entre clusters

4
3

5-
2

-0
caso 3
1

caso 1

caso 4

19
caso 2

caso 5
0

20
Casos
Ejemplo básico
or
ad

Examina la ayuda de la función hclust para ver los métodos disponibles.


rr

La solución obtenida muestra cómo existen dos grupos de casos claramente definidos: el
formado por los casos 1 y 4; y el formado por los casos 2, 5 y 3. Podemos escribir y señalar en
Bo

el gráfico tal solución con un poco de código más. Para ello definimos la variable “Numgrupos”
(o como queramos llamarla) y le asignamos un valor de 2:
Numgrupos <- 2 # Importante!!!! Aquí fijamos el número de grupos !!!!!!

Una vez fijamos el número de grupos, podemos enmarcar los grupos con la función
rect.hclust:
plot(fit, sub = "Ejemplo básico", xlab = "Casos", ylab = "Distancia entre clusters")
rect.hclust(fit, k = Numgrupos, border = c("red4", "blue4"))
5.7. PRÁCTICAS 337

Cluster Dendrogram

5
Distancia entre clusters

4
3
2

07
caso 3
1

caso 1

caso 4

5- caso 2

caso 5
0

-0
19 Casos
Ejemplo básico
20
or
ad
rr

Hemos utilizado el método de Ward, comúnmente empleado, pero podríamos haber em-
Bo

pleado otros métodos, como el método del “vecino más cercano” (method=“single”), el del
“vecino más lejano” (method=“complete”), o el método de “vinculación intergrupos” (met-
hod=“average”). Las soluciones alcanzadas con estos métodos son coincidentes debido a la
simpleza del caso planteado. Son las siguientes:
par(mfrow = c(1, 3))
for (metodo in c("single", "complete", "average")){
fit2 <- hclust(d, method = metodo)
plot(fit, sub = paste0("Método: ", metodo), xlab = "Casos", ylab = "Distancia entre cl
rect.hclust(fit2, k = Numgrupos, border = c("red4", "blue4"))
}
338 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

Cluster Dendrogram Cluster Dendrogram Cluster Dendrogram


5

5
4

4
Distancia entre clusters

Distancia entre clusters

Distancia entre clusters


3

07
2

5-
caso 3

caso 3

caso 3
-0
1

1
caso 1

caso 4

caso 1

caso 4

caso 1

caso 4
19
caso 2

caso 5

caso 2

caso 5

caso 2

caso 5
0

0
20
Casos Casos Casos
Método: single Método: complete Método: average

par(mfrow = c(1, 1))


or

Vamos a pasar ahora al planteamiento de un análisis clúster de K-medias. Este tipo de análisis
se suele plantear cuando hay muchos casos y cuando se tiene claro el número de grupos que
ad

se quieren obtener. También necesita como input los datos previamente tipificados (no las
distancias como en caso anterior). Hemos de recordar que el número de grupos lo tenemos
guardado en la variable “Numgrupos”, y que actualmente vale 2:
rr

set.seed(1)
Data.km <- kmeans(ZData, Numgrupos)
Bo

Como la asignación de grupos se realiza de forma aleatoria, fijamos la semilla para generación
de números aleatorios de forma que todos obtengamos los mismos resultados. La función
kmeans realiza la agrupación, que podemos ver al llamar al objeto creado en la consola:
Data.km

## K-means clustering with 2 clusters of sizes 2, 3


##
## Cluster means:
## Var1 Var2 Var3
## 1 0.9647638 0.8198916 1.0734901
5.7. PRÁCTICAS 339

## 2 -0.6431759 -0.5465944 -0.7156601


##
## Clustering vector:
## caso 1 caso 2 caso 3 caso 4 caso 5
## 1 2 2 1 2
##
## Within cluster sum of squares by cluster:
## [1] 0.6623932 2.1530322
## (between_SS / total_SS = 76.5 %)
##

07
## Available components:
##
## [1] "cluster" "centers" "totss" "withinss"

5-
## [5] "tot.withinss" "betweenss" "size" "iter"
## [9] "ifault"

-0
19
Vemos las coordenadas para cada variable (tipificada) de los dos centros de los grupos ob-
20
tenidos. Luego muestra la asignación de grupo para cada caso del problema. Las sumas de
cuadrados nos dan una idea de la dispersión de los grupos, y el porcentaje de variación expli-
cada por la agrupación realizada. Podemos acceder al resto de los componentes, por ejemplo
paraa guardar el tamaño de los grupos obtenidos:
or

datasize <- Data.km$size


datasize
ad
rr

## [1] 2 3
Bo

Podemos visualizar gráficamente los casos y sus grupos los grupos con las variables dos a
dos (los centroides representados por medio de triángulos):
plot(ZData, col = Data.km$cluster, pch = 19, bg = Data.km$cluster)
text(ZData, dimnames(ZData)[[1]], pos = 3, cex = .6)
points(Data.km$centers, col = 1:Numgrupos, pch = 17, cex = 1.5)
340 CAPÍTULO 5. ANÁLISIS CLUSTER CON R
caso 1

1.0
0.5
caso 3 caso 4
Var2

0.0
−0.5

07
−1.0

caso 2 caso 5

5-
−1.0 −0.5 0.0 0.5 1.0 1.5

-0
Var1

19
Nótese como el resultado vuelve a coincidir con el obtenido por los métodos jerárquicos,
debido a la extrema sencillez de los datos de ejemplo.

Repite el análisis utilizando distintos criterios para las distancias (por ejemplo Manhattan)
20
y para el método de agrupamiento (por ejemplo centroides).

Práctica 5.2: Agrupando provincias


or

En este ejemplo vamos a formar grupos de provincias españolas. Las variables que servirán
para formar los grupos serán:
ad

TASA_PARO_05: Tasa de paro


PIB_HAB_04: Producto interior bruto a precios de mercado por habitante, 2004.
rr

Una estrategia que se suele seguir si no se tiene pensado a priori un número de grupos a
formar es realizar un análisis jerárquico y, en función de los resultados, mejorar la solución
Bo

con el método no-jerárquico de k-medias. Vamos a proceder así.

Las expresiones utilizadas se encuentran en el script de las prácticas del capítulo. En lo


sucesivo, vamos a suponer que estamos trabajando en un proyecto que contiene una carpeta
llamada “datos” donde se encuentran los ficheros de datos. El fichero se puede descargar a
la carpeta de datos del proyecto con la siguiente expresión:
download.file("http://emilio.lcano.com/b/adr/datos/provilogit.txt",
"datos/provilogit.txt")

Se recomienda en primer lugar limpiar el espacio de trabajo eliminando todos los objetos
existentes:
5.7. PRÁCTICAS 341

rm(list = ls())

Ahora introducimos los datos de las variables del modelo. Esta vez lo haremos mediante
la lectura de un archivo de texto donde las variables se disponen en columnas separadas
por tabuladores. El archivo es “provilogit.txt”, y su información se guarda en el data.frame
“provincias”:
provincias <- read.table("datos/provilogit.txt",
header = TRUE,
sep = "\t",

07
dec = ",",
fileEncoding = "latin1",
row.names = 1)

5-
Utilizamos el argumento fileEncoding = latin1 porque el fichero de texto fue creado con
esa codificación, y los proyectos de RStudio trabajan por defecto con otra (utf8). Con el

-0
argumento row.names = 1 estamos diciendo que la primera columna del fichero de texto
contiene los nombres de columnas (en este caso, los nombre de las provincias españolas).

Análisis exploratorio de datos


19
Como no nos interesan todas las variables, vamos a crear ahora el data.frame “Data” sólo
20
con las variables en estudio:
Data <- subset(provincias, select = c(TASA_PARO_05, PIB_HAB_04))
summary(Data)
or

## TASA_PARO_05 PIB_HAB_04
## Min. : 4.662 Min. :12747
## 1st Qu.: 6.907 1st Qu.:15584
ad

## Median : 8.716 Median :17343


## Mean : 9.297 Mean :18495
## 3rd Qu.:10.558 3rd Qu.:21132
## Max. :17.652 Max. :27142
rr

Comprobamos cómo son los datos del conjunto de datos. Recordemos que para aplicar las
Bo

técnicas que hemos visto necesitamos todas las variables numéricas:


str(Data)

## 'data.frame': 50 obs. of 2 variables:


## $ TASA_PARO_05: num 9.86 7.09 10.01 9.61 9.16 ...
## $ PIB_HAB_04 : num 16558 27142 14659 17446 18419 ...
head(Data)

## TASA_PARO_05 PIB_HAB_04
## A Coruña 9.859223 16558.22
## Álava 7.088059 27141.54
342 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

## Albacete 10.008567 14658.91


## Alicante 9.611898 17446.28
## Almería 9.162806 18418.70
## Asturias 10.240363 16983.65
summary(Data)

## TASA_PARO_05 PIB_HAB_04
## Min. : 4.662 Min. :12747
## 1st Qu.: 6.907 1st Qu.:15584

07
## Median : 8.716 Median :17343
## Mean : 9.297 Mean :18495
## 3rd Qu.:10.558 3rd Qu.:21132

5-
## Max. :17.652 Max. :27142

Vemos que la escala de las variables es muy diferente para cada una de ellas. Exploremos los

-0
datos también gráficamente:
par(mfrow = c(2, 2))

hist(Data$PIB_HAB_04, main = "PIB", xlab = "")


boxplot(Data$TASA_PARO_05)
boxplot(Data$PIB_HAB_04)
19
hist(Data$TASA_PARO_05, main = "Tasa de Paro", xlab = "")
20
Tasa de Paro PIB
15
Frequency

Frequency
or
0 4 8
5

ad
0

4 6 8 10 12 14 16 18 15000 20000 25000


rr
Bo

26000
18
12

14000
6

par(mfrow = c(1, 1))

En la tasa de paro hay valores candidatos a valores atípicos que quizás habría que investigar
por si son datos erróneos. Asumimos en este caso que los datos son correctos y seguimos.
5.7. PRÁCTICAS 343

A partir de “Data” creamos el data.frame “ZData”, en el que aparecen las variables clasifi-
cadoras tipificadas para que no afecte a nuestro análisis el efecto escala:
ZData <- scale(Data)
head(ZData)

## TASA_PARO_05 PIB_HAB_04
## A Coruña 0.17411452 -0.51030503
## Álava -0.68461510 2.27809666
## Albacete 0.22039331 -1.01071975

07
## Alicante 0.09747333 -0.27632763
## Almería -0.04169151 -0.02012303
## Asturias 0.29222236 -0.39821569

5-
Previamente, y puesto que tenemos sólo dos variables clasificadoras, vamos a representar los
individuos en un diagrama de dispersión para ver si, a priori, pueden detectarse grupos. Para

-0
ello, haremos:
library(scales)

##
## Attaching package: 'scales' 19
20
## The following object is masked from 'package:readr':
##
## col_factor
plot(ZData, col = alpha("blue4", 0.5), pch = 19, las = 1)
or

text(ZData, rownames(ZData), pos = 3, cex = .6)


Álava
ad

Madrid
2 Guipúzcoa
Navarra
Lleida Tarragona
Girona
Barcelona Vizcaya

Baleares
rr

Burgos
PIB_HAB_04

1 Rioja
Zaragoza
Castellón Valladolid
Teruel Huesca
Segovia
Soria
Bo

PalenciaCantabria Las Palmas


Valencia
Almería
0 Alicante
SantaAsturias
Cruz de Tenerife
Guadalajara
Murcia Salamanca
A Coruña León
Ávila Ciudad RealMálaga
Pontevedra Huelva
Sevilla
Cuenca Toledo Zamora Cádiz
Lugo Albacete
Ourense
−1 Granada
Cáceres
Córdoba Jaén
Badajoz

−1 0 1 2

TASA_PARO_05
344 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

El paquete scales nos permite incorporar transparancia a los colores con la función alpha.
De esta forma si hay puntos que se suporponen se identifican mejor.
La función text escribe el nombre de la provincia en cada punto correspondiente.
Aparentemente habrá un grupo de provincias con alto PIB y baja Tasa de Paro, otro grupo
con bajo PIB y alta tasa de paro, y un grupo central de provincias con valores “medios” en
ambas variables. Lo vamos a verificar haciendo, primero, un clúster jerárquico.

Cluster jerárquico

07
En el análisis jerárquico no se determinan a priori los grupos a formar, sino que se muestran
sucesivas agrupaciones hasta llegar a un único grupo.

5-
El procedimiento comienza con el cálculo de la “matriz de distancias” entre todos los indi-
viduos. A partir de ahí, se buscan los dos individuos más próximos, y son agrupados en un
conglomerado, que se considera como una unidad indivisible o único individuo. Así se van

-0
agrupando unidades dos a dos, hasta llegar a una única unidad o conglomerado que contiene
a todos los individuos.

19
Las distancias pueden ser cuantificadas en base a muy distintas medidas. Además, existen
también múltiples criterios o métodos para agrupar los individuos. Todo ello confiere una
gran flexibilidad al análisis; pero también cierta dificultad a la hora de extraer conclusiones,
20
ya que distintos métodos pueden ofrecer muy diferentes resultados.
Vamos a utilizar la distancia euclídea, que es usualmente utilizada, y como método de aglo-
meración el método de Ward, que es el más utilizado. Este método crea grupos cohesionados
ya que poseen la mínima varianza interna posible.
or

La distancia euclídea es muy sensible a la escala de las variables, por lo que utilizaremos
los datos tipificados (“ZData”). Primero vamos a calcular todas las distancias y a crear la
ad

“matriz de distancias” que llamaremos “d”:


d <- dist(ZData, method = "euclidean")
rr

La matriz “d” obtenida es demasiado grande para escribirla en estas páginas, aunque pode-
mos consultarla en pantalla. Esta sería una muestra de la misma con las primeras distancias:
Bo

as.matrix(d)[1:3, 1:3]

## A Coruña Álava Albacete


## A Coruña 0.0000000 2.917636 0.5025501
## Álava 2.9176361 0.000000 3.4110634
## Albacete 0.5025501 3.411063 0.0000000
A modo de ejemplo de la interpretación, vemos que Albacete está más cerca de A Coruña
que de Álava, en términos de las variables estudiadas.
Luego vamos a seleccionar el método de agrupación jerárquica mediante la función “hclust”.
Vamos a utilizar en concreto el método de Ward, cuya solución asignaremos al objeto “fit”
5.7. PRÁCTICAS 345

y dibujaremos el dendrograma correspondiente (el argumento “cex” controla el tamaño del


texto):
fit <- hclust(d, method="ward.D")
plot(fit, cex = .6, xlab = "", ylab = "Distancia entre grupos", sub = "Cluster jerárquic

Cluster Dendrogram

07
30
20
Distancia entre grupos

5-
10
0

-0 Las Palmas
Badajoz
Sevilla

Valladolid
Cádiz
Huelva
Vizcaya

Palencia
Álava
Madrid

Córdoba
Jaén

Málaga
Barcelona

Guadalajara
Murcia
Zamora

Alicante

Cantabria
A Coruña
Salamanca
Castellón
Lleida

León
Albacete
Ourense
Ávila
Toledo

Almería
Valencia
Baleares
Burgos

Cuenca
Lugo
Soria
Teruel

Ciudad Real
Pontevedra
Girona
Tarragona

Rioja
Zaragoza

Asturias
Santa Cruz de Tenerife
Huesca
Segovia
Guipúzcoa
Navarra

Cáceres
Granada

19
20
Cluster jerárquico por el método de Ward para las provincias
or

En la solución se establecen dos grandes grupos de provincias, cada uno de los cuáles se divide
en otros dos. Si nos quedamos con dos grupos, el de la derecha parece que sería demasiado
ad

grande, vamos a probar con tres grupos.


rr

Podemos guardar el número de grupos en la variable “Numgrupos” para utilizar en el código


Bo

posterior):
Numgrupos <- 3

Gráficamente podemos agruparlos con la función rect.hclust:


library(RColorBrewer)
plot(fit, cex = .6, xlab = "", ylab = "Distancia entre grupos", sub = "Cluster jerárquic
rect.hclust(fit, k = Numgrupos, border = brewer.pal(Numgrupos, "Dark2"))
346 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

Cluster Dendrogram

30
20
Distancia entre grupos

10
0

Las Palmas
Badajoz
Sevilla

Valladolid
Cádiz
Huelva
Vizcaya

Palencia
Álava
Madrid

Córdoba
Jaén

Málaga
Barcelona

Guadalajara
Murcia
Zamora

Alicante

Cantabria
A Coruña
Salamanca
Castellón
Lleida

León
Albacete
Ourense
Ávila
Toledo

Almería
Valencia
Baleares
Burgos

Cuenca
Lugo
Soria
Teruel

Ciudad Real
Pontevedra
Girona
Tarragona

Rioja
Zaragoza

Asturias
Santa Cruz de Tenerife
Huesca
Segovia
Guipúzcoa
Navarra

Cáceres
Granada

07
5-
Cluster jerárquico por el método de Ward para las provincias

-0
En esta ocasión hemos utilizado una paleta de colores de las proporcionadas por el paquete
RColorBrewer (ver la ayuda del paquete para ver más opciones).
Con la función cutree obtenemos el grupo al que pertenece cada provincia:
grupos <- cutree(fit, k = Numgrupos)
grupos
19
20
## A Coruña Álava Albacete
## 1 2 1
## Alicante Almería Asturias
## 1 1 1
or

## Ávila Badajoz Baleares


## 1 3 2
ad

## Barcelona Burgos Cáceres


## 2 2 3
## Cádiz Cantabria Castellón
## 3 1 2
rr

## Ciudad Real Córdoba Cuenca


## 1 3 1
Bo

## Girona Granada Guadalajara


## 2 3 1
## Guipúzcoa Huelva Huesca
## 2 3 2
## Jaén Las Palmas León
## 3 1 1
## Lleida Lugo Madrid
## 2 1 2
## Málaga Murcia Navarra
## 1 1 2
## Ourense Palencia Pontevedra
5.7. PRÁCTICAS 347

## 1 2 1
## Rioja Salamanca Santa Cruz de Tenerife
## 2 1 1
## Segovia Sevilla Soria
## 2 3 2
## Tarragona Teruel Toledo
## 2 2 1
## Valencia Valladolid Vizcaya
## 1 1 2
## Zamora Zaragoza

07
## 1 2

Esto es muy útil para comprobaciones posteriores, vamos a guardar los grupos como un

5-
factor en el conjunto de datos:
Data$GRUPO <- factor(grupos)

-0
Se obtiene así la siguiente solución. El primer grupo se corresponde con las provincias con

19
mayores PIB y menores Tasas de Paro, el segundo con las provincias con menores PIB y
mayores Tasas de Paro, y el tercero es un grupo de provincias con una solución intermedia.
Gráficamente lo podemos visualizar con el diagrama de dispersión coloreado:
20
palette(brewer.pal(Numgrupos, "Dark2"))
plot(PIB_HAB_04 ~ TASA_PARO_05, col = alpha(GRUPO, 0.75), pch = 19, data = Data, las = 1
text(Data, rownames(Data), pos = 3, cex = .6)
Álava
or

Madrid
26000 Guipúzcoa
Navarra
Lleida Tarragona
Girona
Vizcaya
24000 Barcelona

BurgosBaleares
ad
PIB_HAB_04

22000 Rioja
Zaragoza
Castellón Valladolid
Teruel Soria Huesca
Segovia
20000 Palencia Cantabria Las Palmas
Valencia Almería
Alicante
18000 Guadalajara
Santa
Salamanca A Coruña
Cruz de Tenerife
Asturias
León
Murcia
rr

Ávila CiudadPontevedra
Real Huelva
Málaga Sevilla
Zamora
16000 Cuenca
Lugo
Toledo
Albacete
Cádiz
Ourense
Granada
Cáceres
14000 Córdoba Jaén
Badajoz
Bo

6 8 10 12 14 16 18

TASA_PARO_05

Para validar la estabilidad de los resultados, vamos a cambiar el método de agrupación al


de la “vinculación inter-grupos” (method=“average”):
fit2 <- hclust(d, method = "average")
plot(fit2, cex=.6)
Numgrupos <- 3
rect.hclust(fit2, k = Numgrupos, border = "red")
348 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

Cluster Dendrogram
2.0
1.0

Las Palmas
Height

Badajoz
0.0

Cádiz
Huelva
Sevilla

Valladolid
Vizcaya
Álava
Madrid
Córdoba
Jaén

Salamanca
Guadalajara
Murcia
Palencia

Málaga
Barcelona

Zamora
Alicante
Cantabria

A Coruña

León
Castellón
Lleida

Albacete
Ourense
Almería
Valencia

Ávila
Toledo
Baleares
Burgos

Cuenca
Lugo
Soria
Teruel

Ciudad Real
Pontevedra
Girona
Tarragona

Rioja
Zaragoza

Asturias
Santa Cruz de Tenerife
Huesca
Segovia
Guipúzcoa
Navarra
Cáceres
Granada

07
5-
d
hclust (*, "average")

-0
Obteniéndose una solución diferente, donde puede apreciarse que el grupo de provincias con
menores PIB y mayores Tasas de Paro se mantiene inalterado, mientras que hay un trasvase
de provincias desde el grupo de intermedias al de provincias con mayores PIB y menores
Tasas de Paro. Podemos verlo claramente si guardamos los grupos en el data.frame:
Data$GRUPO2 <- cutree(fit2, Numgrupos)
19
20
Data

## TASA_PARO_05 PIB_HAB_04 GRUPO GRUPO2


## A Coruña 9.859223 16558.22 1 1
## Álava 7.088059 27141.54 2 2
or

## Albacete 10.008567 14658.91 1 1


## Alicante 9.611898 17446.28 1 1
ad

## Almería 9.162806 18418.70 1 2


## Asturias 10.240363 16983.65 1 1
## Ávila 8.844508 15734.05 1 1
## Badajoz 17.505084 12747.37 3 3
rr

## Baleares 7.215780 22317.21 2 2


## Barcelona 6.965572 23276.77 2 2
Bo

## Burgos 6.730066 22127.51 2 2


## Cáceres 12.981455 13652.79 3 3
## Cádiz 17.652023 15237.39 3 3
## Cantabria 8.502295 19143.67 1 2
## Castellón 7.315701 20468.05 2 2
## Ciudad Real 10.580164 15954.77 1 1
## Córdoba 14.767194 13341.00 3 3
## Cuenca 6.478210 15296.77 1 1
## Girona 7.331990 24040.89 2 2
## Granada 12.901665 13706.60 3 3
## Guadalajara 7.050285 16726.07 1 1
5.7. PRÁCTICAS 349

## Guipúzcoa 5.648889 24973.30 2 2


## Huelva 15.876516 15987.00 3 3
## Huesca 6.886841 20113.82 2 2
## Jaén 15.916338 13189.86 3 3
## Las Palmas 12.830075 18929.69 1 1
## León 10.819949 16599.26 1 1
## Lleida 5.885396 24215.62 2 2
## Lugo 6.684967 14790.53 1 1
## Madrid 6.804290 25801.29 2 2
## Málaga 11.657573 15695.39 1 1

07
## Murcia 8.009366 16470.40 1 1
## Navarra 5.647241 24744.35 2 2
## Ourense 10.488246 14256.99 1 1

5-
## Palencia 7.474227 19207.71 2 2
## Pontevedra 11.021749 15878.08 1 1
## Rioja 6.180243 21357.34 2 2

-0
## Salamanca 9.088000 16611.92 1 1
## Santa Cruz de Tenerife 10.492766 17240.08 1 1
##
##
##
Segovia
Sevilla
Soria
19
6.816655
13.857495
5.118602
19868.40
15547.25
19775.75
2
3
2
2
3
2
20
## Tarragona 7.062623 24428.12 2 2
## Teruel 4.662379 19834.13 2 2
## Toledo 9.117195 15146.87 1 1
## Valencia 8.586980 18461.51 1 2
## Valladolid 9.229526 20418.43 1 2
or

## Vizcaya 8.451806 23512.06 2 2


## Zamora 9.996733 15367.67 1 1
ad

## Zaragoza 5.761757 21352.67 2 2


rr
Bo

Y gráficamente:
palette(brewer.pal(Numgrupos, "Dark2"))
plot(PIB_HAB_04 ~ TASA_PARO_05, col = alpha(GRUPO2, 0.75), pch = 19, data = Data, las =
text(Data, rownames(Data), pos = 3, cex = .6)
350 CAPÍTULO 5. ANÁLISIS CLUSTER CON R
Álava

Madrid
26000 Guipúzcoa
Navarra
Lleida Tarragona
Girona
Vizcaya
24000 Barcelona

BurgosBaleares
PIB_HAB_04

22000 Rioja
Zaragoza
Castellón Valladolid
Teruel Soria Huesca
Segovia
20000 Palencia Cantabria Las Palmas
Valencia Almería
Alicante
18000 Guadalajara
Santa
Salamanca A Coruña
Cruz de Tenerife
Asturias
León
Murcia
Ávila CiudadPontevedra
Real Huelva
Málaga Sevilla
Zamora
16000 Cuenca
Lugo
Toledo
Albacete
Cádiz
Ourense
Granada
Cáceres
14000 Córdoba Jaén
Badajoz

07
6 8 10 12 14 16 18

TASA_PARO_05

5-
En conclusión, vamos a considerar la existencia de 3 grupos homogéneos, y vamos a mejorar
su composición con el método no-jerárquico de k-medias, que tiene la ventaja de permitir la
salida de casos de grupos precedentes para su incorporación en otros distintos.

-0
Cluster no jerárquico

19
La técnica consiste sintéticamente en que se seleccionan k individuos o casos con algún
criterio (los más alejados, aleatorio, etc.), siendo k el número de grupos o conglomerados
que se desea formar. Estos constituirán los “centroides” iniciales o “semillas” de cada grupo.
20
Posteriormente se asignan los individuos a cada grupo, según su proximidad a los centroides.
En una nueva iteración, se recalcula el “centroide” de cada grupo (centro de gravedad del
grupo en cuestión) según los individuos que lo conforman en la etapa precedente, y estos
nuevos centroides se toman como referencia para asignar de nuevo todos los individuos o casos.
or

El proceso parará cuando las diferencias entre los centroides de una etapa y la predecesora
sean mínimas.
El criterio para asignar individuos a los grupos o conglomerados se basa en la “distancia
ad

euclídea” que tiene cada individuo con los centroides de los grupos. El problema es que la
distancia euclídea es muy sensible a las escalas de las variables, por lo que para eliminar este
efecto distorsionador conviene trabajar con variables tipificadas (matriz “ZData”). Recorde-
rr

mos que el método va a calcular tres grupos porque es el valor que le dimos a la variable
“Numgrupos”:
Bo

set.seed(1)
Data.km <- kmeans(ZData, Numgrupos)
Data.km

## K-means clustering with 3 clusters of sizes 20, 8, 22


##
## Cluster means:
## TASA_PARO_05 PIB_HAB_04
## 1 -0.80056519 1.0416799
## 2 1.82360774 -1.1379108
## 3 0.06465645 -0.5331959
5.7. PRÁCTICAS 351

##
## Clustering vector:
## A Coruña Álava Albacete
## 3 1 3
## Alicante Almería Asturias
## 3 3 3
## Ávila Badajoz Baleares
## 3 2 1
## Barcelona Burgos Cáceres
## 1 1 2

07
## Cádiz Cantabria Castellón
## 2 3 1
## Ciudad Real Córdoba Cuenca

5-
## 3 2 3
## Girona Granada Guadalajara
## 1 2 3

-0
## Guipúzcoa Huelva Huesca
## 1 2 1
##
##
##
Jaén
2
Lleida
19 Las Palmas
3
Lugo
León
3
Madrid
20
## 1 3 1
## Málaga Murcia Navarra
## 3 3 1
## Ourense Palencia Pontevedra
## 3 1 3
or

## Rioja Salamanca Santa Cruz de Tenerife


## 1 3 3
ad

## Segovia Sevilla Soria


## 1 2 1
## Tarragona Teruel Toledo
## 1 1 3
rr

## Valencia Valladolid Vizcaya


## 3 1 1
Bo

## Zamora Zaragoza
## 3 1
##
## Within cluster sum of squares by cluster:
## [1] 9.312996 3.079765 7.777594
## (between_SS / total_SS = 79.4 %)
##
## Available components:
##
## [1] "cluster" "centers" "totss" "withinss"
## [5] "tot.withinss" "betweenss" "size" "iter"
352 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

## [9] "ifault"
La primera expresión fija la semilla de la sesión de R para que los resultados sean repro-
ducibles. La seguna realiza el análisis y lo asigna al objeto “Data.km”. En nuestro caso el
resultado es la formación de tres grupos de provincias de 22, 20 y 8 provincias. Al mostrar
el objeto “Data.km” nos viene información sobre las coordenadas de los centroides de cada
grupo (en valores de las variables clasificadoras tipificadas) y la asignación de cada provincia
concreta a un grupo.
Posteriormente se asigna al objeto “datasize” el tamaño de cada uno de los grupos obtenidos
(24, 18 y 8 respectivamente):

07
datasize <- Data.km$size
datasize

5-
## [1] 20 8 22
Vamos a guardar la clasificación hecha por el método de k-medias junto con la matriz de

-0
datos tipificados en el objeto ZDatag:
ZDatag <- data.frame(ZData, GRUPO = factor(Data.km$cluster))

19
Veamos gráficamente una representación de los grupos y de sus centros (estos últimos apa-
recen como “triángulos” sin etiqueta):
20
plot(PIB_HAB_04 ~ TASA_PARO_05, col = alpha(GRUPO, 0.75), pch = 19, data = ZDatag, las =
text(ZDatag, rownames(ZDatag), pos = 3, cex = .6)
points(Data.km$centers, col = 1:Numgrupos, pch = 17, cex = 1.5)
Álava
or

Madrid
2 Guipúzcoa
Navarra
Lleida Tarragona
Girona
Barcelona Vizcaya
ad

Baleares
Burgos
PIB_HAB_04

1 Rioja
Zaragoza
Castellón Valladolid
Teruel Huesca
Segovia
Soria
rr

PalenciaCantabria Las Palmas


Valencia
Almería
0 Alicante
SantaAsturias
Cruz de Tenerife
Guadalajara
Murcia Salamanca
A Coruña León
Bo

Ávila Ciudad RealMálaga


Pontevedra Huelva
Sevilla
Cuenca Toledo Zamora Cádiz
Lugo Albacete
Ourense
−1 Granada
Cáceres
Córdoba Jaén
Badajoz

−1 0 1 2

TASA_PARO_05

Podemos guardar la nueva clasificación en el conjunto de datos original, y ver qué provincias
se han ido moviendo con los distintos métodos:
5.7. PRÁCTICAS 353

Data$GRUPO3 <- factor(Data.km$cluster)


Data

## TASA_PARO_05 PIB_HAB_04 GRUPO GRUPO2 GRUPO3


## A Coruña 9.859223 16558.22 1 1 3
## Álava 7.088059 27141.54 2 2 1
## Albacete 10.008567 14658.91 1 1 3
## Alicante 9.611898 17446.28 1 1 3
## Almería 9.162806 18418.70 1 2 3

07
## Asturias 10.240363 16983.65 1 1 3
## Ávila 8.844508 15734.05 1 1 3
## Badajoz 17.505084 12747.37 3 3 2

5-
## Baleares 7.215780 22317.21 2 2 1
## Barcelona 6.965572 23276.77 2 2 1

-0
## Burgos 6.730066 22127.51 2 2 1
## Cáceres 12.981455 13652.79 3 3 2
## Cádiz 17.652023 15237.39 3 3 2
##
##
##
Cantabria
Castellón
Ciudad Real
19
8.502295
7.315701
10.580164
19143.67
20468.05
15954.77
1
2
1
2
2
1
3
1
3
20
## Córdoba 14.767194 13341.00 3 3 2
## Cuenca 6.478210 15296.77 1 1 3
## Girona 7.331990 24040.89 2 2 1
## Granada 12.901665 13706.60 3 3 2
## Guadalajara 7.050285 16726.07 1 1 3
or

## Guipúzcoa 5.648889 24973.30 2 2 1


## Huelva 15.876516 15987.00 3 3 2
ad

## Huesca 6.886841 20113.82 2 2 1


## Jaén 15.916338 13189.86 3 3 2
## Las Palmas 12.830075 18929.69 1 1 3
## León 10.819949 16599.26 1 1 3
rr

## Lleida 5.885396 24215.62 2 2 1


## Lugo 6.684967 14790.53 1 1 3
Bo

## Madrid 6.804290 25801.29 2 2 1


## Málaga 11.657573 15695.39 1 1 3
## Murcia 8.009366 16470.40 1 1 3
## Navarra 5.647241 24744.35 2 2 1
## Ourense 10.488246 14256.99 1 1 3
## Palencia 7.474227 19207.71 2 2 1
## Pontevedra 11.021749 15878.08 1 1 3
## Rioja 6.180243 21357.34 2 2 1
## Salamanca 9.088000 16611.92 1 1 3
## Santa Cruz de Tenerife 10.492766 17240.08 1 1 3
## Segovia 6.816655 19868.40 2 2 1
354 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

## Sevilla 13.857495 15547.25 3 3 2


## Soria 5.118602 19775.75 2 2 1
## Tarragona 7.062623 24428.12 2 2 1
## Teruel 4.662379 19834.13 2 2 1
## Toledo 9.117195 15146.87 1 1 3
## Valencia 8.586980 18461.51 1 2 3
## Valladolid 9.229526 20418.43 1 2 1
## Vizcaya 8.451806 23512.06 2 2 1
## Zamora 9.996733 15367.67 1 1 3
## Zaragoza 5.761757 21352.67 2 2 1

07
Nótese que los identificadores de grupo, al ser aleatorios no significan lo mismo, hay que
mirar los “compañeros”.

5-
Caracterización

-0
Una vez establecidos los distintos grupos de individuos o casos, es conveniente caracterizar
dichos grupos con base en las variables clasificadoras que hemos empleado. Una posibilidad
es estudiar el valor que, en cada una de estas variables, toma el “centroide” de cada grupo.

19
Como ya tenemos guardado el grupo en el data.frame Data, podemos calcular los “centroides”
de cada grupo haciendo la media del valor que toman los casos pertenecientes a cada grupo
20
en cada variable con la función aggregate. Para omitir las columnas GRUPO y GRUPO2,
en el lado izquierdo de la formula ponemos sólo las columnas que nos interesan unidas con
la función cbind:
aggregate(cbind(TASA_PARO_05, PIB_HAB_04) ~ GRUPO3, data = Data, FUN = mean)
or

## GRUPO3 TASA_PARO_05 PIB_HAB_04


## 1 1 6.713882 22448.75
ad

## 2 2 15.182221 14176.16
## 3 3 9.505996 16471.34
Se observa que, para la primera Tasa de Paro, el centro del primer grupo toma un valor
rr

muy superior al de los otros dos grupos. En cambio con el PIB por habitante, la relación es
en sentido opuesto. En definitiva, la interpretación en este ejemplo es la que ya habíamos
Bo

adelantado al principio: el grupo 1 son provincias con mucho paro y poco PIB, el grupo 2
provincias con poco paro y mucho PIB y el grupo 3 son provincias intermedias en ambos
sentidos. Hay que tener en cuenta que la interpretación de los “centroides” ya no se hace
con las variables tipificadas; sino con las variables originales a fin de recuperar el sentido
económico de los valores.
Se puede acompañar la descripción de los grupos con unos diagramas de caja a partir del
siguiente código:
par(mfrow = c(1, 2))
boxplot(TASA_PARO_05 ~ GRUPO3, main = "Boxplot de la tasa de paro", col = 1:3, data = Da
boxplot(PIB_HAB_04 ~ GRUPO3, main = "Boxplot del PIB", col = 1:3, data = Data, las = 1)
5.7. PRÁCTICAS 355

Boxplot de la tasa de paro Boxplot del PIB

18
26000
16
24000
TASA_PARO_05

14

PIB_HAB_04
22000
12
20000

07
10
18000
8 16000

5-
6 14000

-0
1 2 3 1 2 3

par(mfrow = c(1, 1))


GRUPO3
19 GRUPO3
20
Por último, podemos realizar un ANOVA para verificar que los grupos que se han creado
hacen una buena discriminación de las variables, por ejemplo de la tasa de paro:
modelo.aov <- aov(TASA_PARO_05 ~ GRUPO3, data = Data)
or

summary(modelo.aov)

## Df Sum Sq Mean Sq F value Pr(>F)


ad

## GRUPO3 2 411.5 205.8 97.89 <2e-16 ***


## Residuals 47 98.8 2.1
## ---
rr

## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
TukeyHSD(modelo.aov)
Bo

## Tukey multiple comparisons of means


## 95% family-wise confidence level
##
## Fit: aov.default(formula = TASA_PARO_05 ~ GRUPO3, data = Data)
##
## $GRUPO3
## diff lwr upr p adj
## 2-1 8.468339 7.000613 9.936065 0e+00
## 3-1 2.792114 1.708127 3.876101 4e-07
## 3-2 -5.676225 -7.124764 -4.227686 0e+00
356 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

Y del PIB:
modelo.aov2 <- aov(PIB_HAB_04 ~ GRUPO3, data = Data)
summary(modelo.aov2)

## Df Sum Sq Mean Sq F value Pr(>F)


## GRUPO3 2 551956035 275978018 84.27 2.86e-16 ***
## Residuals 47 153921305 3274921
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

07
TukeyHSD(modelo.aov2)

## Tukey multiple comparisons of means

5-
## 95% family-wise confidence level
##
## Fit: aov.default(formula = PIB_HAB_04 ~ GRUPO3, data = Data)

-0
##
## $GRUPO3
## diff lwr upr p adj
##
##
##
19
2-1 -8272.590 -10104.7218 -6440.459 0.0000000
3-1 -5977.408 -7330.5267 -4624.289 0.0000000
3-2 2295.182 487.0013 4103.364 0.0097075
20
Efectivamente, la agrupación tiene sentido para todas las variables. Si obtuviéramos dos
grupos para los que no hubiera diferencias en ninguna variable, deberíamos unir esos grupos.
Por otra parte, también se puede comprobar la consistencia de los grupos con un análisis de
la varianza múltiple (MANOVA).
or

Práctica 5.3: Agrupando individuos a partir de encuestas


ad

En este ejemplo vamos a formar grupos de individuos en función de sus respestas a una
encuesta. En principio no sabemos el número de grupos a formar, por lo que comenzaremos
aplicando el método jerárquico.
rr

Las expresiones utilizadas se encuentran en el script de las prácticas del capítulo. En lo


sucesivo, vamos a suponer que estamos trabajando en un proyecto que contiene una carpeta
Bo

llamada “datos” donde se encuentran los ficheros de datos. El fichero se puede descargar a
la carpeta de datos del proyecto con la siguiente expresión:
download.file("http://emilio.lcano.com/b/adr/datos/encuesta_anonima_2018.RData",
"datos/encuesta_anonima_2018.RData")

Se recomienda en primer lugar limpiar el espacio de trabajo eliminando todos los objetos
existentes:
rm(list = ls())

Los datos se encuentran almacenados como archivo de datos de R, “.RData”. Para cargarlos
5.7. PRÁCTICAS 357

en el espacio de trabajo, utilizamos la función load.


load("datos/encuesta_anonima_2018.RData")

El conjunto de datos tiene un total de 22 variables para un total de 16 respuestas a un


cuestionario.
str(encuesta_anonima)

## 'data.frame': 16 obs. of 22 variables:


## $ curso : num 2018 2018 2018 2018 2018 ...

07
## $ id : int 6 7 1 3 16 4 15 2 8 11 ...
## $ sexo : Factor w/ 2 levels "Hombre","Mujer": 2 1 1 1 2 1 2 2 1 2 ...
## $ edad : num 23 23 22 23 23 20 32 24 21 21 ...

5-
## $ peso : num 59 77 95 60 65 91 80 61 81 60 ...
## $ altura : num 170 180 197 170 165 189 192 168 190 171 ...

-0
## $ pelo : Factor w/ 3 levels "castaño","moreno",..: 1 2 3 2 1 2 1 3 1 1 ...
## $ ojos : Factor w/ 2 levels "marrón","verde": 2 1 1 1 1 1 2 1 1 1 ...
## $ nota : num 6 8 5.9 7.1 6 8.72 7 8.03 7 7.2 ...

19
## $ hermanos : num 1 1 1 2 3 1 3 1 1 1 ...
## $ distancia : num 45 0.5 1 9 45 1.2 2 42 10 0.2 ...
## $ gafas : Factor w/ 3 levels "Gafas","Lentillas",..: 2 1 3 1 3 3 3 3 1 1 ...
20
## $ movil : num 1159 220 275 570 800 ...
## $ musica : Factor w/ 3 levels "Latina (reggaeton,...)",..: 2 3 2 3 2 1 3 1 1 2 ..
## $ cine : Factor w/ 4 levels "Comedia","Drama",..: 3 4 3 2 3 3 1 1 1 2 ...
## $ acceso : num 6.3 11.1 6.33 8.37 8 ...
## $ superficie: num 120 120 200 90 200 205 100 150 80 220 ...
or

## $ tv : num 5 4 3 1 4 1 1 2.5 1 3 ...


## $ actividad : Factor w/ 4 levels "Algo activo",..: 4 2 1 4 4 2 1 2 2 3 ...
ad

## $ dormir : num 7 7.5 8 8 7 7 7 7 7 8 ...


## $ fruta : num 5 10 5 7 2 20 7 20 20 4 ...
## $ g : Factor w/ 7 levels "21","22","23",..: 6 3 3 5 6 1 4 1 1 1 ...
rr

Para aplicar los métodos solo con variables en escala métrica, vamos a obtener un subconjunto
de datos solo con estas variables.
Bo

encuestam <- subset(encuesta_anonima,


select = c(edad, peso, altura, nota, hermanos,
distancia, movil, acceso, superficie,
tv, dormir, fruta))
encuestaz <- scale(encuestam)

Entonces podemos aplicar los métodos estándar jerárquico y no jerárquico:


d <- dist(encuestaz)
c1 <- hclust(d, method = "ward.D")
plot(c1)
358 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

Cluster Dendrogram
10
8
6
Height

a_15

07
4

a_14
a_2

a_11
a_5
2

a_9

a_4
a_8
a_6
a_16

a_1
a_12
5-
a_3
a_13
a_7
a_10

-0
19 d
hclust (*, "ward.D")
20
or
ad
rr
Bo

Parece que hay dos grandes grupos de tamaño similar. Veamos qué nos dice la función
NbClust sobre el número óptimo de grupos. Quitamos la variable “hermanos” porque da
problemas en el cálculo de algunos de los índices.
library(NbClust)
NbClust(data = encuestaz[, -c(5)],
distance = "euclidean",
method = "ward.D", max.nc = 5)
5.7. PRÁCTICAS 359

0.0025
Hubert statistic second differences
Hubert Statistic values

0.0100

0.0015
0.0090

07
0.0080

0.0005

5-
2.0 3.0 4.0 5.0 2.0 3.0 4.0 5.0

-0
Number of clusters Number of clusters

##
19
## *** : The Hubert index is a graphical method of determining the number of clusters.
## In the plot of Hubert index, we seek a significant knee that correspo
significant increase of the value of the measure i.e the significant
20
## index second differences plot.
##
0.038
Second differences Dindex Values
or
2.7

0.034
ad
Dindex Values

2.5

rr

0.030
2.3
Bo

0.026
2.1

2.0 3.0 4.0 5.0 2.0 3.0 4.0 5.0

Number of clusters Number of clusters

## *** : The D index is a graphical method of determining the number of clusters.


## In the plot of D index, we seek a significant knee (the significant p
360 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

## second differences plot) that corresponds to a significant increase o


## the measure.
##
## *******************************************************************
## * Among all indices:
## * 6 proposed 2 as the best number of clusters
## * 10 proposed 3 as the best number of clusters
## * 2 proposed 4 as the best number of clusters
## * 5 proposed 5 as the best number of clusters
##

07
## ***** Conclusion *****
##
## * According to the majority rule, the best number of clusters is 3

5-
##
##
## *******************************************************************

-0
## $All.index
##
##
##
KL CH Hartigan
2 1.0032 3.9113
3 1.5611 3.7603
19
CCC Scott Marriot TrCovW TraceW
3.2732 -1.2815 40.2842 6439393055 235.8926 128.9686
2.1126 -1.7898 96.3474 435793364 166.9860 104.5296
20
## 4 0.7867 3.3401 2.3850 -2.6630 132.0121 83386984 131.3204 89.9174
## 5 0.8906 3.2993 2.6938 -3.1400 203.9689 1451325 104.6044 75.0093
## Friedman Rubin Cindex DB Silhouette Duda Pseudot2 Beale
## 2 14.1230 1.2794 0.4462 1.8483 0.1429 0.7085 2.8798 2.6801
## 3 45.8743 1.5785 0.5998 1.5260 0.1649 0.6323 2.3262 3.4638
or

## 4 59.5123 1.8350 0.5743 1.3521 0.1599 0.6696 2.4669 3.0611


## 5 247.2988 2.1997 0.5016 1.3198 0.1631 1.0094 -0.0093 -0.0346
ad

## Ratkowsky Ball Ptbiserial Frey McClain Dunn Hubert SDindex


## 2 0.2802 64.4843 0.3598 -0.0498 0.9536 0.4508 0.0078 1.1028
## 3 0.3152 34.8432 0.5197 0.8951 1.6394 0.6101 0.0104 0.9104
## 4 0.3201 22.4794 0.4894 0.3934 2.2531 0.6101 0.0099 0.8113
rr

## 5 0.3183 15.0019 0.4587 -0.0213 4.0074 0.6101 0.0109 0.8515


## Dindex SDbw
Bo

## 2 2.7809 0.8563
## 3 2.5197 0.8220
## 4 2.2960 0.6743
## 5 2.0971 0.6510
##
## $All.CriticalValues
## CritValue_Duda CritValue_PseudoT2 Fvalue_Beale
## 2 0.5044 6.8785 0.0057
## 3 0.4060 5.8524 0.0016
## 4 0.4458 6.2167 0.0029
## 5 0.1839 4.4371 1.0000
5.7. PRÁCTICAS 361

##
## $Best.nc
## KL CH Hartigan CCC Scott Marriot TrCovW
## Number_clusters 3.0000 2.0000 3.0000 2.0000 5.0000 3 3.0000
## Value_Index 1.5611 3.9113 1.1606 -1.2815 71.9568 5651193312 68.9066
## TraceW Friedman Rubin Cindex DB Silhouette Duda
## Number_clusters 3.0000 5.0000 3.0000 2.0000 5.0000 3.0000 2.0000
## Value_Index 9.8269 187.7865 -0.0426 0.4462 1.3198 0.1649 0.7085
## PseudoT2 Beale Ratkowsky Ball PtBiserial Frey McClain
## Number_clusters 2.0000 5.0000 4.0000 3.0000 3.0000 1 2.0000

07
## Value_Index 2.8798 -0.0346 0.3201 29.6411 0.5197 NA 0.9536
## Dunn Hubert SDindex Dindex SDbw
## Number_clusters 3.0000 0 4.0000 0 5.000

5-
## Value_Index 0.6101 0 0.8113 0 0.651
##
## $Best.partition

-0
## a_6 a_7 a_1 a_3 a_16 a_4 a_15 a_2 a_8 a_11 a_13 a_10 a_5 a_12 a_9
## 1 2 3 1 1 2 3 2 2 1 1 2 2 3 2
##
##
a_14
1 19
20
or

Parece que la mayoría de métodos indican que la mejor partición es en tres clústers, aunque
ad

también hay 6 que proponen 2. Vamos a utilizar 3, aunque uno de los grupos va a quedar
con muy pocos individuos.
c2 <- kmeans(scale(encuestam), 3)
rr
Bo

Vamos a utilizar las herramientas de visualización del paquete factoextra para visualizar
estos resultados.
library(factoextra)
fviz_dend(c1, 3)
362 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

Cluster Dendrogram

10.0

7.5

07
Height

5.0

5-
2.5

-0
0.0
19
a_5

a_9

a_7

a_10

a_2

a_4

a_8

a_6

a_16

a_14

a_11

a_3

a_13

a_15

a_1

a_12
20
fviz_cluster(c2, encuestaz, show.clust.cent = TRUE,
ellipse.type = "euclid", star.plot = TRUE, repel = TRUE)
or
ad
rr
Bo
5.7. PRÁCTICAS 363

Cluster plot
a_14

2
a_11
a_5
a_13
Dim2 (19.2%)

a_7 a_10 cluster


a_9

07
0 a_3 a 1
a_12 a 2
a_6 a_4
a_2 a 3
a_16

5-
a_1
a_8
−2

-0
−2
a_15

0
19Dim1 (26%)
2
20
Vamos ahora a utilizar las funciones del paquete cluster para realizar el análisis de con-
glomerados. El análisis jerárquico lo podemos hacer aglomerativo con la función agnes y
divisivo con la función diana.
or

enc_aglo <- agnes(encuestaz)


summary(enc_aglo)
ad

## Object of class 'agnes' from call:


## agnes(x = encuestaz)
## Agglomerative coefficient: 0.3998408
rr

## Order of objects:
## [1] a_6 a_16 a_3 a_13 a_11 a_2 a_7 a_10 a_9 a_5 a_4 a_8 a_1 a_12
Bo

## [15] a_14 a_15


## Merge:
## [,1] [,2]
## [1,] -2 -12
## [2,] -4 -11
## [3,] -3 -14
## [4,] 1 -15
## [5,] -1 -5
## [6,] -6 -9
## [7,] 4 -13
## [8,] 2 -10
364 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

## [9,] 8 -8
## [10,] 7 6
## [11,] 5 9
## [12,] 11 10
## [13,] 12 3
## [14,] 13 -16
## [15,] 14 -7
## Height:
## [1] 3.472835 4.286897 2.695980 3.664288 3.952748 4.890671 2.129214
## [8] 3.295431 3.621709 4.196403 3.610680 5.061828 3.133947 5.183904

07
## [15] 5.789377
##
## 120 dissimilarities, summarized :

5-
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2.129 4.126 4.815 4.804 5.489 7.335
## Metric : euclidean

-0
## Number of objects : 16
##
##
##
##
Available components:
[1] "order"
[7] "method"
"height" "ac"
"order.lab" "data"
19 "merge" "diss" "call"
20
plot(enc_aglo)

Banner of agnes(x = encuestaz) Dend


or

a_6
a_16
a_3
5
ad

a_13
a_11
a_2
4

a_7
Height
rr

a_10
a_9
3

a_5
a_6
a_16
Bo

a_4
a_8
2

a_3
a_13
a_1
a_12
a_14
a_15

0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5 5.5


Height
Agglomerative Coefficient = 0.4
5.7. PRÁCTICAS 365

enc_div <- diana(encuestaz)


summary(enc_div)

## Merge:
## [,1] [,2]

07
## [1,] -2 -12
## [2,] -4 -11
## [3,] -3 -14
## [4,] -1 -5

5-
## [5,] 1 -15
## [6,] -6 -9

-0
## [7,] 2 -8
## [8,] -13 -16
## [9,] 5 -10
##
##
##
[10,]
[11,]
[12,]
4
9
10
7
6
-7
19
20
## [13,] 11 3
## [14,] 13 8
## [15,] 12 14
## Order of objects:
or

## [1] a_6 a_16 a_3 a_13 a_2 a_15 a_7 a_10 a_9 a_11 a_4 a_8 a_1 a_12
## [15] a_5 a_14
## Height:
ad

## [1] 3.472835 4.950599 2.695980 4.028618 5.846619 7.334780 2.129214


## [8] 3.572634 4.739488 5.402228 3.610680 6.007460 3.133947 6.908179
## [15] 4.209161
rr

## Divisive coefficient:
## [1] 0.5169334
##
Bo

## 120 dissimilarities, summarized :


## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2.129 4.126 4.815 4.804 5.489 7.335
## Metric : euclidean
## Number of objects : 16
##
## Available components:
## [1] "order" "height" "dc" "merge" "diss" "call"
## [7] "order.lab" "data"
plot(enc_div)
366 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

Banner of diana(x = encuestaz)

a_6

7
a_16
a_3

6
a_13
a_2
a_15

5
a_7

Height
a_10

4
a_9

07
a_11

3
a_4

a_6
a_16
a_8

2
a_1

5-
a_12
a_5
a_14

-0
7.33 6 5 4 3 2 1 0

Divisive Coefficient = 0.52


19
Height
20
or
ad

Nótese cómo el resultado no es el mismo, algunos individuos cambian de grupo.


rr
Bo

Como hemos visto antes que el número óptimo de grupos podría se tres, vamos a aplicar el
método no jerárquico con la función pam.
enc_pam <- pam(encuestaz, 3)
plot(enc_pam)
5.7. PRÁCTICAS 367

clusplot(pam(x = encuestaz, k = 3))

3
2
Component 2

1
0

07
−3 −2 −1

5-
-0
−4 −3 −2 −1 0 1 2

19
Component 1
These two components explain 45.21 % of the point variability.
Silhouette plot of pam(x = encuestaz, k = 3)
20
n = 16 3 clusters Cj
j : nj | avei∈Cj si
a_16
1 : 5 | 0.10
or

a_6
a_15
a_10
ad

a_4
a_7 2 : 9 | 0.13
rr

a_14
a_11
Bo

3 : 2 | 0.38
a_12

0.0 0.2 0.4 0.6 0.8 1.0


Silhouette width si
Average silhouette width : 0.15

Si usamos la función clara el resultado es el mismo. Nótese cómo el tercer grupo queda solo
de dos observaciones.
368 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

summary(enc_pam)

## Medoids:
## ID edad peso altura nota hermanos distancia
## a_3 4 0.04461441 -0.8036996 -0.6763020 -0.01847943 0.9682458 -0.3827249
## a_7 2 0.04461441 0.3348748 0.2407177 0.93189139 -0.3227486 -0.4099993
## a_12 14 0.40152972 1.7413491 0.6992275 -1.39123729 -0.3227486 -0.4083950
## movil acceso superficie tv dormir fruta
## a_3 0.4134404 -0.3776986 -0.7983481 -0.9179232 1.0978876 -0.3453727

07
## a_7 -0.6403904 0.9294779 -0.1852168 0.6280527 0.2614018 0.1569876
## a_12 -0.3995148 -1.0336809 -0.5939710 1.6587033 1.0978876 0.4918945
## Clustering vector:

5-
## a_6 a_7 a_1 a_3 a_16 a_4 a_15 a_2 a_8 a_11 a_13 a_10 a_5 a_12 a_9
## 1 2 3 1 1 2 1 2 2 2 1 2 2 3 2

-0
## a_14
## 2
## Objective function:
##
##
##
build swap
2.840709 2.840709 19
20
## Numerical information per cluster:
## size max_diss av_diss diameter separation
## [1,] 5 4.570157 2.989552 5.846619 3.353387
## [2,] 9 4.241882 3.041072 6.908179 3.353387
## [3,] 2 3.133947 1.566974 3.133947 3.696745
or

##
## Isolated clusters:
ad

## L-clusters: character(0)
## L*-clusters: [1] 3
##
## Silhouette plot information:
rr

## cluster neighbor sil_width


## a_16 1 3 0.167147567
Bo

## a_3 1 2 0.112372070
## a_6 1 3 0.100817583
## a_13 1 2 0.080085862
## a_15 1 3 0.056177025
## a_10 2 1 0.269481539
## a_5 2 1 0.234655588
## a_4 2 3 0.197533221
## a_9 2 1 0.174684352
## a_7 2 3 0.144623549
## a_8 2 3 0.128483552
## a_14 2 3 0.017919681
5.7. PRÁCTICAS 369

## a_2 2 1 0.002472266
## a_11 2 3 0.001534164
## a_1 3 2 0.399033341
## a_12 3 1 0.364938929
## Average silhouette width per cluster:
## [1] 0.1033200 0.1301542 0.3819861
## Average silhouette width of total data set:
## [1] 0.1532475
##
## 120 dissimilarities, summarized :

07
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2.129 4.126 4.815 4.804 5.489 7.335
## Metric : euclidean

5-
## Number of objects : 16
##
## Available components:

-0
## [1] "medoids" "id.med" "clustering" "objective" "isolation"
## [6] "clusinfo" "silinfo" "diss" "call" "data"

19
Podemos añadir la información del grupo al conjunto de datos original y caracterizar los
grupos:
20
resultado <- cbind(encuestam, grupo = enc_pam$clustering)
aggregate(. ~ grupo, resultado, mean)
or

## grupo edad peso altura nota hermanos distancia movil


## 1 1 25.20000 62.00000 171.2000 6.520000 2.0000000 28.2000 669.8000
## 2 2 21.55556 72.11111 177.7778 7.731111 0.8888889 212.1556 333.2222
ad

## 3 3 23.00000 96.50000 191.0000 5.850000 1.0000000 1.0000 287.5000


## acceso superficie tv dormir fruta
## 1 7.53400 120.0000 2.6 7.400000 6.20000
rr

## 2 10.61567 129.4444 2.5 7.166667 10.77778


## 3 6.66500 150.0000 4.5 8.000000 8.50000
Bo

table(resultado$grupo)

##
## 1 2 3
## 5 9 2

Los objetos obtenidos con el paquete cluster también se pueden visualizar con el paquete
factoextra, por ejemplo:
fviz_cluster(enc_pam)
370 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

Cluster plot
a_14

2
a_11 a_5
a_13
a_10
Dim2 (19.2%)

a_7 a_9 cluster

07
a_3 a 1
0 a_6
a_12 a_2 a 2
a_16 a_1 a_4
a 3

5-
a_8

−2

-0
−2
a_15

0
19Dim1 (26%)
2
20
or
ad
rr
Bo

Veamos el resultado que ofrecería el análisis cluster después de obtener las componentes
principales con el paquete FactoMineR.
par(mfrow=c(1,2))
library(FactoMineR)
HCPC(PCA(encuestam), nb.clust = 3)
5.7. PRÁCTICAS 371

Individuals factor map (PCA) Variables factor map (PCA)

1.5
6

1.0
a_15
4

movil
movil altura
altura

0.5
Dim 2 (19.18%)

Dim 2 (19.18%)
edad
edadhermanos peso
2

a_8 peso
a_16 a_1
fruta
superficie fruta

07
a_12 a_2 a_4

0.0
a_6 a_3 a_9
0

acceso
acceso
a_13 a_7 a_10 nota
tv

−0.5
a_11 dormir
tv dormir
a_5
−2

5-
distancia
distancia
a_14
−4

-0
−1.5
−6

−2 0 2 4 19 −1.0 0.0 0.5 1.0


20
Dim 1 (26.03%) Dim 1 (26.03%)
or
ad
rr
Bo
372

Height

0.0 0.5 1.0 1.5 2.0 2.5

a_5
Bo
a_10

a_7
rr a_9

a_4

a_2
ad
a_8

a_14

a_6
or
a_13

a_3

a_16
Hierarchical Classification

20
a_11
Hierarchical Clustering

a_15

a_12
19
a_1
0.0 1.0 2.0
-0
5-
inertia gain

07
CAPÍTULO 5. ANÁLISIS CLUSTER CON R
5.7. PRÁCTICAS 373

Hierarchical clustering on the factor map

cluster 1
cluster 2
cluster 3

3.0
2.5

07
2.0
height

Dim 2 (19.18%)
1.5

5-
1.0

4
a_15 2

-0
0.5

a_16 a_1 a_8


a_4
0
a_6 a_12
a_3 a_2
a_7 a_9
a_10 −2
a_13 a_11 a_5
0.0

−4
a_14
−3 −2 −1 0

19 1

Dim 1 (26.03%)
2 3 4
20
Factor map
or

cluster 1
4

cluster 2 a_15
cluster 3
ad
2

a_8
Dim 2 (19.18%)

rr

a_16 a_4
a_12 a_1 a_2
a_6
a_3
0

a_7 a_9
Bo

a_10
a_13 a_11 a_5
−2

a_14
−4

−4 −2 0 2 4 6

Dim 1 (26.03%)
374 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

## **Results for the Hierarchical Clustering on Principal Components**


## name
## 1 "$data.clust"
## 2 "$desc.var"
## 3 "$desc.var$quanti.var"
## 4 "$desc.var$quanti"
## 5 "$desc.axes"
## 6 "$desc.axes$quanti.var"
## 7 "$desc.axes$quanti"
## 8 "$desc.ind"

07
## 9 "$desc.ind$para"
## 10 "$desc.ind$dist"
## 11 "$call"

5-
## 12 "$call$t"
## description
## 1 "dataset with the cluster of the individuals"

-0
## 2 "description of the clusters by the variables"
## 3 "description of the cluster var. by the continuous var."
##
##
##
19
4 "description of the clusters by the continuous var."
5 "description of the clusters by the dimensions"
6 "description of the cluster var. by the axes"
20
## 7 "description of the clusters by the axes"
## 8 "description of the clusters by the individuals"
## 9 "parangons of each clusters"
## 10 "specific individuals"
## 11 "summary statistics"
or

## 12 "description of the tree"


par(mfrow=c(1,1))
ad

Se deja al lector como ejercicio la interpretación de las componentes.


rr

Por último, vamos a realizar un análisis cluster utilizando todas las variables: tanto las que
están en escala métrica como los atributos. Para ello, tenemos que calcular la matriz de
Bo

disimilaridades con la función daisy del paquete cluster:


encuesta_todas <- cbind(encuestaz, subset(encuesta_anonima,
select = c(sexo, pelo, ojos, gafas,
musica, cine, actividad)))
dis <- daisy(encuesta_todas)

Y después realizar el clustering con alguna de las funciones


enc_todas <- pam(dis, 3, TRUE)
clusplot(enc_todas)
5.7. PRÁCTICAS 375

clusplot(pam(x = dis, k = 3, diss = TRUE))

0.2
Component 2

0.0

07
−0.2

5-
−0.4

-0
−0.4 −0.2 0.0 0.2

19
Component 1
These two components explain 39.51 % of the point variability.
20
Parece que al añadir las variables de tipo atributo hemos mejorado la separación de los
grupos.
or
ad
rr
Bo
376 CAPÍTULO 5. ANÁLISIS CLUSTER CON R

07
5-
-0
19
20
or
ad
rr
Bo
Capítulo 6

07
Análisis de correspondencias con R

5-
-0
6.1. Introducción al análisis de correspondencias

19
El análisis de correspondencias es una técnica de análisis multivariante de interdependencias,
es decir, todas las variables siguen el mismo papel, sin que unas expliquen a otras. En esta
técnica estudiamos relaciones entre variables en escala nominal, es decir, variables cualita-
20
tivas o atributos que pueden tomar varios niveles o categorías en las que clasificamos a las
observaciones.

El objetivo de la técnica es representar en un espacio multidimensional reducido, típicamente


or

bidimensional, la relación entre las categorías de los atributos. en el caso de dos atributos,
que se resumen numéricamente mediante tablas de contingencia, la representación gráfica
muestra las distancias entre los niveles a partir de las frecuencias.
ad

El análisis de correspondencias es una técnica de reducción de la dimensión, como el análisis


de componentes principales o el análisis cluster, pero en este caso aplicado a variables cualita-
tivas. Como resultado se representa una realidad compleja descrita por dos o más atributos,
rr

cada uno de los cuales con varios niveles, en un contexto generalmente bidimensional.
Bo

Los datos de atributos se suelen resumir mediante tablas de de doble entrada, o de contin-
gencia, que representan las frecuencias absolutas conjuntas, es decir, el número de individuos
que presentan cada combinación de las categorías de los atributos. Por ejemplo, la tabla 6.1
muestra una tabla de contingencia para dos atributos (A y B) con dos niveles cada uno
(A1 , A2 y B1 , B2 respectivamente); nij es el número de observaciones que presentan el nivel i
del atributo A y el nivel j del atributo B; ni. y n.j son las frecuencias marginales del atributo
Ai y del atributo Bj respectivamente; N es el número total de observaciones, que también
se puede denotar por n.. .

Las frecuencias marginales se calculan como las sumas por filas y por columnas, correspon-
diendo el índice i a las filas, y el índice j a las columnas.

377
378 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

Tabla 6.1: Tabla de doble entrada para el atributo A (filas) y el atributo B (columnas)
B1 B2
A1 n11 n12 n1.
A2 n21 n22 n2.
n,1 n,2 N

6.2. Asociación entre atributos


Antes de intentar representar la relación entre atributos, debemos confirmar que existe tal

07
relación. Sobre los datos observados, podemos calcular un estadístico que mida el grado
de relación entre los atributos, en concreto el coeficiente de contingencia chi-cuadrado.
Posteriormente se puede realizar un contraste de hipótesis basado en el coeficiente de con-

5-
tingencia a través de la distribución Chi-cuadrado.
Para comprobar la relación entre atributos, vamos a utilizar el concepto contrario, es de-

-0
cir, la independencia entre variables. Si los atributos no están relacionados, entonces serán
independientes. Recordemos la definición de independencia basada en tablas de frecuencias:

fij =
nij
N
= 19
ni. n.j
N N
· = fi. · f.j ∀i, j.

Es decir, dos variables, en este caso atributos, son independientes si las frecuencias relativas
20
conjuntas fij son igual al producto de las frecuencias relativas marginales, fi · f.j .
Pero estamos trabajando con muestras de datos, y esta igualdad es muy difícil que se dé
exactamente en la realidad. Pero bajo el supuesto de que los atributos fuesen independientes,
or

y por tanto no estuvieran relacionados, podríamos obtener las frecuencias absolutas esperadas
nij de la siguiente forma:
ad

nij ni. n.j ni. · n.j


= · =⇒ Eij = .
N N N N
Es decir, bajo condiciones de independencia, las frecuencias absolutas esperadas Eij serían
rr

el producto de las frecuencias absolutas marginales, ni. · n.j , dividido por la frecuencia total
N . Con las frecuencias observadas y las esperadas, podemos calcular el siguiente estadístico:
Bo

∑∑ (nij − Eij )2
χ2 = ,
i j Eij
que valdrá cero si los atributos no están relacionados (frecuencias observadas igual a las
esperadas). A mayor valor del coeficiente, mayor grado de asociación.
El coeficiente de contingencia se distribuye como una Chi-cuadrado con (r −1)·(c−1) grados
de libertad, donde r es el número de categorías fila y c es el número de categorías columna.
Por tanto, se puede realizar el contraste de hipótesis:
H0 : No hay relación entre los atributos
6.2. ASOCIACIÓN ENTRE ATRIBUTOS 379

Tabla 6.2: Tabla de frecuencias para los atributos Estudios y Empleo


Aprueba No aprueba
Trabaja 23 43
No trabaja 67 31

H1 : Hay relación entre los atributos


Comparando el valor del estadístico con su distribución teórica:

07
χ2 ⇝ χ2(r−1)·(c−1) .

El contraste tiene ciertas limitaciones que hay que tener en cuenta, la población mínima N

5-
debe ser de 20 elementos, y la estimación de cada frecuencia esperada Eij debe ser mayor o
igual a 5.

-0
Se estudia en 164 individuos los atributos “Estudios”, con dos niveles: “aprueba”

19
y “no aprueba”, y “Empleo”, con dos niveles: “trabaja” y “no trabaja”. Las frecuencias
absolutas aparecen en la tabla 6.2. El código a continuación calcula los valores esperados y
el coeficiente de contingencia, que se compara con el valor teórico para un nivel de confianza
20
del 95 %, inferior al valor empírico por lo que se rechaza la hipótesis nula para ese nivel
de confianza. Visto de otra forma, el p-valor del contraste es muy inferior a 0.01, por lo
que podemos asegurar con mucha confianza que los atributos “Estudios” y “Empleo” están
relacionados, o lo que es lo mismo, no son independientes. El código a continuación crea
la tabla de frecuencias y realiza los cálculos, primero paso a paso y después utilizando la
or

función chisq.test de R.
ad

Creamos una matriz con la tabla de frecuencias:


absolutas <- matrix(c(23, 67, 43, 31), ncol = 2,
dimnames = list(Empleo = c("Trabaja", "No trabaja"),
rr

Estudios = c("Aprueba", "No aprueba")))

A partir de las tablas de frecuencias, calculamos y guardamos los datos que aparecen en las
Bo

fórmulas:
N <- sum(absolutas)

relativas <- absolutas/N

## Marginales:
ma.empleo <- rowSums(absolutas)
ma.estudios <- colSums(absolutas)
mr.empleo <- rowSums(relativas)
mr.estudios <- colSums(relativas)
380 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

Si los atributos no estuvieran relacionados, las siguientes dos matrices sería iguales:
mr.empleo %*% t(mr.estudios)

## Aprueba No aprueba
## [1,] 0.2208507 0.1815883
## [2,] 0.3279298 0.2696312
relativas

## Estudios

07
## Empleo Aprueba No aprueba
## Trabaja 0.1402439 0.2621951
## No trabaja 0.4085366 0.1890244

5-
Ya hemos dicho que esto es casi imposible. Vamos a calcular las frecuencias esperadas:
esperadas <- (ma.empleo %*% t(ma.estudios))/N

-0
esperadas

## Aprueba No aprueba
## [1,] 36.21951
## [2,] 53.78049
29.78049
44.21951 19
Ahora tenemos todos los datos para calcular el coeficiente de contingencia:
20
chicuadrado <- sum(((absolutas - esperadas)^2)/esperadas)
chicuadrado

## [1] 17.89444
or

Que podemos comparar con el cuantil 0,95 de la distribución teórica:


qchisq(p = 0.95, df = 1)
ad

## [1] 3.841459
Mucho menor, por lo que el estadístico empírico cae en la región de rechazo, y para un nivel
rr

de confianza del 95 % rechazamos la independencia entre los dos atributos. Nos lo confirma
el valor tan pequeño del p-valor obtenido para ese valor del coeficiente de contingencia:
Bo

pchisq(q = 17.89, df = 1, lower.tail = FALSE)

## [1] 2.340477e-05
A modo ilustrativo se han mostrado todos los pasos del contraste, pero la práctica habitual
es realizarlo de una vez con la función chisq.test:
chisq.test(absolutas, correct = FALSE)

##
## Pearson's Chi-squared test
##
6.3. ANÁLISIS DE CORRESPONDENCIAS SIMPLES 381

## data: absolutas
## X-squared = 17.894, df = 1, p-value = 2.335e-05
El argumento correct controla si se aplica la corrección por continuidad de Yates, aquí se
puesto a FALSE para verificar el resultado anterior, aunque para tablas 2 × 2 es adecuado
utilizarlo (véase la ayuda de la función).

6.3. Análisis de correspondencias simples


Una vez verificado que hay asociación entre los atributos, el análisis de correspondencias

07
nos va a servir para determinar unas coordenadas a cada categoría de cada atributo. Estas
coordenadas nos proporcionarán una distancia, que representaremos gráficamente en un
gráfico bidimensional, en ocasiones conocido como mapa perceptual. La distancia utilizada

5-
para ubicar las categorías en las coordenadas, será la distancia chi-cuadrado.

-0
6.3.1. Análisis de correspondencias simples paso a paso
Para la aplicación del método, vamos a dar por hecho que en la tabla de contingencia el

trasponer la matriz de frecuencias. 19


número de filas r es menor que el número de columnas c. Si no fuera así, bastaría con

El primer paso consiste en obtener los perfiles de fila y de columna. Los perfiles son vectores
20
(de fila y de columna) que contienen las frecuencias relativas condicionadas a esa fila o
columna. Es decir, en cada fila, dividimos la frecuencia absoluta conjunta entre la frecuencia
marginal de la fila o columna. Así, los elementos del perfil fila serán:
or

nik nik
pik = = ∑
c , k = 1, . . . , r,
ni. nij
j=1
ad

y el perfil completo de la fila i:

( )
pi1 pi2 . . . pic .
rr

Los elementos del perfil columna serán:


Bo

nkj nkj
pkj = = ∑
r , k = 1, . . . , c,
n.j nij
i=1

y el perfil completo de la columna i:

 
p1j
 
 p2j 
 .. .
 
 . 
prj
382 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

Además de los perfiles, tenemos que calcular las masas de las filas y de las columnas. En
este caso, tenemos un solo dato por fila y columna. Las masas son las frecuencias relativas
marginales fi. y f.j . Así, la masa de la fila i es:


c
nij
ni. j=1
mi. = fi. = = ∑∑ ,
n.. nij
i j

y la masa de la columna j es:

07

r
nij
n.j i=1
mj. = f.j = = ∑∑ .

5-
n.. nij
i j

Con las masas y los perfiles calculamos las distancias chi-cuadrado entre las categorías de

-0
un atributo. Así, la distancia chi-cuadrado entre dos categorías i e i′ del atributo fila son:

dii′ =
19 ∑
c

k=1
(pik − pi′ k )2
m.k
,
20
y la distancia chi-cuadrado entre dos categorías j y j ′ del atributo columna son:


r
(pkj − pkj ′ )2
d jj ′ = .
k=1 mk.
or

Es decir, para calcular la distancia, por ejemplo entre filas, restamos los c perfiles de las dos
filas (columnas), elevamos al cuadrado esos valores y los dividimos por la masa de su columna.
Finalmente se suman todos los valores (uno por columna). De forma análoga, para calcular
ad

la distancia entre atributos de columna, se restan los perfiles de cada fila, su cuadrado se
divide por su masa de fila, y se suman los valores de cada fila.
rr

El código a continuación calcula los perfiles y las masas del ejemplo con los atributos
“Empleo” y “Estudios” visto anteriormente.
Bo

Perfiles fila1 :
pfila <- absolutas / rowSums(absolutas)
pfila

## Estudios
## Empleo Aprueba No aprueba
## Trabaja 0.3484848 0.6515152
## No trabaja 0.6836735 0.3163265
1
R recicla el vector del denominador por columnas, de forma que el cálculo es adecuado sin más.
6.3. ANÁLISIS DE CORRESPONDENCIAS SIMPLES 383

Perfiles columna2 :
pcolumna <- absolutas / rep(colSums(absolutas), each = 2)
pcolumna

## Estudios
## Empleo Aprueba No aprueba
## Trabaja 0.2555556 0.5810811
## No trabaja 0.7444444 0.4189189
Masas fila:

07
mfila <- rowSums(absolutas)/N
mfila

5-
## Trabaja No trabaja
## 0.402439 0.597561

-0
Masa columna:
mcolumna <- colSums(absolutas)/N
mcolumna

##
##
Aprueba No aprueba
0.5487805 0.4512195
19
20
Distancia entre filas (trabajan/no trabajan):
sum((diff(pfila)^2)/mcolumna)
or

## [1] 0.4537243
Distancia entre columnas (aprueban/no aprueban):
ad

sum((diff(t(pcolumna))^2)/mfila)

## [1] 0.4406439
rr

Para representar gráficamente las distancias entre las categorías de los dos atributos, vamos
a utilizar el método de descomposición en valores singulares de la llamada matriz de dis-
crepancias. La matriz de discrepancias C es una matriz con las mismas dimensiones que la
Bo

tabla de contingencia, y cuyo elemento típico es:

nij − Eij
cij = √ .
Eij

La descomposición que vamos a hacer de la matriz C es la siguiente:

C = U DV t ,
2
Aquí hay que repetir las sumas por columnas para que las divisiones se hagan correctamente.
384 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

donde D es una matriz diagonal r × r cuyos elementos son las raíces cuadradas de los r
autovalores de CC t , U es una matriz cuyas columnas son los r autovectores de CC t y V es
una matriz cuyas filas son los primeros r autovectores de C t C. Además, U t U = I y V t V = I.
Las matrices U y V se utilizan para calcular las coordenadas de las categorías que después
se representarán gráficamente.

El código a continuación calcula la matriz C y la descompone utilizando la función svd


(de “singular value decomposition”). En el siguiente apartado se calcularán las coordenadas
para la respresentación gráfica utilizando funciones más específicas de R.

07
Cálculo matriz de discrepancias:
discrepancias <- (absolutas - esperadas)/sqrt(esperadas)

5-
discrepancias

## Estudios

-0
## Empleo Aprueba No aprueba
## Trabaja -2.196565 2.422420
## No trabaja 1.802615 -1.987964
19
Descomposición (de la matriz D solo se muestra la diagonal):
20
descomposicion <- svd(discrepancias)
descomposicion

## $d
## [1] 4.230182e+00 2.983075e-16
or

##
## $u
## [,1] [,2]
ad

## [1,] -0.7730207 0.6343808


## [2,] 0.6343808 0.7730207
##
rr

## $v
## [,1] [,2]
Bo

## [1,] 0.6717287 -0.7407972


## [2,] -0.7407972 -0.6717287
Podemos comprobar cómo se cumple la igualdad3 (la función diag crea una matriz diagonal
si el primer argumento es un vector):
descomposicion$u %*% diag(descomposicion$d) %*% t(descomposicion$v)

## [,1] [,2]
## [1,] -2.196565 2.422420
3
Cuando la tabla de contingencia no es cuadrada, en general no se cumple la igualdad, aunque las
coordenadas se calcularán exactamente igual.
6.3. ANÁLISIS DE CORRESPONDENCIAS SIMPLES 385

## [2,] 1.802615 -1.987964

6.3.2. Análisis de correspondencias simple con R


Existen varias funciones para realizar el análisis de correspondencias con R. La primera
es utilizar el paquete ca (Greenacre and Nenadic, 2018) y la función del mismo nombre. El
primer argumento de la función son los datos, que se le pueden suministrar directamente como
una tabla de frecuencias. Si tenemos los datos en un data frame con el detalle de las categorías
por individuo, podemos especificar el argumento data y el argumento formula = ~ F1 + F2,
donde F1 y F2 son los nombres de las columnas factor en el data frame. El argumento nd sirve

07
para indicar el número de dimensiones. Por defecto toma el número máximo de dimensiones,
lo que siempre es adecuado en un primer análisis para deteminar cuántas son finalmente
adecuadas. La otra opción en R es la función CA del paquete FactoMineR (Husson et al.,

5-
2018), que tiene otras muchas funciones para análisis multivariante. En este capítulo vamos
a ilustrar primero el uso del paquete ca. Con el análisis de correspondencias buscamos reducir
la dimensión. De forma similar al análisis de componentes principales (véase el capítulo 4),

-0
por defecto se calculan todas las dimensiones posibles. En este caso, el número máximo de
dimensiones es el número de categorías del atributo que menos tiene menos uno, es decir:

19
mı́n{(c − 1), (r − 1)}.
20
La variabilidad explicada por cada dimensión se expresa como la inercia. Así, la primera
dimensión tendrá la mayor inercia, la segunda menos, etc., y nos quedaremos con un número
de dimensiones que expliquen suficientemente todos los datos, y sea fácilmente representable
e interpretable. Idealmente nos quedaremos con dos dimensiones. Un criterio numérico para
or

decidir cuántas dimensiones se deberían retener (Bendixen, 1995) es tomar aquellos cuya
contribución sea mayor que el máximo valor entre 1/(c − 1) y 1/(r − 1):
{ }
ad

1 1
máx , × 100 %.
c−1 r−1
Para cada dimensión tendremos un porcentaje de inercia sobre el total, y un acumulado.
rr

Además de las inercias de las nuevas dimensiones, tendremos, tanto para filas como para
columnas: las masas, la distancia chi-cuadrado al centroide, las inercias (contribución a la
Bo

inercia total de cada categoría) y las coordenadas de cada categoría. Estas inercias se calculan
como la masa de la categoría multiplicada por la distancia al centroide al cuadrado. A su
vez, el centroide es la media ponderada de las coordenadas de todas las categorías.

En el ejemplo del apartado anterior teníamos una tabla de contingencia 2 × 2, que


ya de por sí es de una dimensión muy reducida. La función ca no produce gráficos para tan
pocos datos (solo se puede representar en una dimensión), pero sí podemos realizar el análisis
y obtener las coordenadas para respresentarlos en la recta real. El código a continuación crea
un objeto con el análisis. Los elemntos rowcoord y colcoord contienen las coordenadas, de
las categorías, y podemos representar como se ve en la figura 6.1.
386 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

library(ca)
corres1 <- ca(absolutas, nd = 1)
corres1

##
## Principal inertias (eigenvalues):
## 1
## Value 0.109112
## Percentage 100%
##

07
##
## Rows:
## Trabaja No trabaja

5-
## Mass 0.402439 0.597561
## ChiDist 0.402511 0.271079

-0
## Inertia 0.065201 0.043911
## Dim. 1 -1.218544 0.820652
##
##
##
##
Columns:
Aprueba No aprueba
19
20
## Mass 0.548780 0.451220
## ChiDist 0.299524 0.364286
## Inertia 0.049234 0.059879
## Dim. 1 0.906765 -1.102822
or

corres1$colcoord

## Dim1
ad

## Aprueba 0.9067647
## No aprueba -1.1028219
corres1$rowcoord
rr

## Dim1
## Trabaja -1.2185436
Bo

## No trabaja 0.8206518
with(corres1,{
plot(x = c(rowcoord, colcoord),
y = rep(0, 4),
type = "n",
xlim = c(-2, 1),
main = "Correspondencias Empleo - Estudios",
xlab = "Distancia", ylab = "",
las = 1)
text(x = c(rowcoord, colcoord),
6.3. ANÁLISIS DE CORRESPONDENCIAS SIMPLES 387

Correspondencias Empleo − Estudios

1.0
Empleo
Estudios
0.5

No aprueba Aprueba
Trabaja No trabaja
0.0

07
−0.5

5-
−1.0

-0
−2.0 −1.5 −1.0 −0.5 0.0 0.5 1.0

19 Distancia

Figura 6.1: Representación de las categorías de una tabla 2imes2


20
y = c(0.1, 0.1, 0.2, 0.2),
labels = c(rownames(rowcoord), rownames(colcoord)),
or

col = rep(c("steelblue", "tomato"), each = 2))


legend(x = 0.5, y = 1, legend = c("Empleo", "Estudios"), fill = c("steelblue", "tomato
abline(h = 0, col = gray(0.5))
ad

})

Además del gráfico bidimensional obtenido por defecto, se pueden realizar otras visualizacio-
nes y análisis de los resultados del análisis de correspondencias. Vamos a ilustrar algunos de
rr

estos métodos con el siguiente ejemplo, con un número mayor de categorías.


Bo

El conjunto de datos hobbies del paquete FactoMineR contiene respuestas de 8403


individuos sobre 18 diferentes aficiones (si las practican o no), más cuatro variables de clasi-
ficación (atributos): sexo, edad, estado civil, profesión, y una variable con el número total de
aficiones que practica. Vamos a realizar el análisis de correspondencias simple para dos de
los atributos: el estado civil y la profesión. En el primer fragmento de código a continuación,
filtramos los datos y transformamos los nombres de variables y categorías para una mejor
comprensión. La figura 6.3 muestra la representación gráfica estándar del objeto CA.

library(FactoMineR)
data(hobbies)
388 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

aficiones <- subset(hobbies, select = c(`Marital status`, Profession))


colnames(aficiones) <- c("estado.civil", "profesion")
levels(aficiones$estado.civil) <- c("Soltero", "Casado1", "Viudo", "Divorciado",
"Casado+")
levels(aficiones$profesion) <- c("No cualificado", "Obrero", "Técnico",
"Encargado", "Dirección", "Empleado", "Otros")
frecuencias <- table(aficiones)
frecuencias

## profesion

07
## estado.civil No cualificado Obrero Técnico Encargado Dirección Empleado
## Soltero 242 242 109 144 215 603
## Casado1 347 660 218 424 623 1247

5-
## Viudo 108 84 10 61 58 263
## Divorciado 72 104 44 70 92 312

-0
## Casado+ 23 71 20 36 64 127
## profesion
## estado.civil Otros
##
##
##
Soltero
Casado1
Viudo
54
112
17
19
20
## Divorciado 18
## Casado+ 11
En primer lugar, comprobamos si hay relaciones entre los atributos:
or

chisq.test(frecuencias)

##
ad

## Pearson's Chi-squared test


##
## data: frecuencias
## X-squared = 158.01, df = 24, p-value < 2.2e-16
rr

Efectivamente, el p-valor es muy bajo, prácticamente cero, por lo que aceptamos que hay
relación entre los atributos con una confianza muy alta. Aunque vemos numéricamente cómo
Bo

están distribuidas las frecuencias, por ejemplo el grupo más numeroso es el de los empleados
casados solo una vez. podemos hacer una visualización gráfica de la tabla de contingencia
como la del gráfico 6.2 que se crea con el siguiente código usando el paquete gplots (Warnes
et al., 2019):
library(gplots)
balloonplot(frecuencias, main = "Muestra aficiones",
label = FALSE, show.margins = TRUE)

Vamos a realizar ahora el análisis de correspondencias utilizando el paquete FactoMineR. El


número máximo de dimensiones será cuatro. Por defecto, la función CA produce el gráfico
6.3. ANÁLISIS DE CORRESPONDENCIAS SIMPLES 389

Muestra aficiones

estado.civil Soltero Casado1 ViudoDivorciado


Casado+
profesion
No cualificado 792
Obrero 1161
Técnico 401

07
Encargado 735
Dirección 1052
Empleado 2552

5-
Otros 212
1609 3631 601 712 352 6905

-0
Figura 6.2: Visualización de la tabla de contingencia del ejemplo de aficiones

19
bidimensional (Figura 6.3), realiza un contraste chi-cuadrado de independencia, y muestra
los objetos disponibles en el objeto creado. Con la función summary podemos obtener las
20
inercias de cada dimensión, porcentaje explicado y acumulado. Para filas y columnas, tenemos
también las incercias y otras medidas de la importancia (ctr y cos2, el cálculo difiere de la
función ca).
library(FactoMineR)
or

corres2 <- CA(frecuencias)


corres2
ad

## **Results of the Correspondence Analysis (CA)**


## The row variable has 5 categories; the column variable has 7 categories
## The chi square of independence between the two variables is equal to 158.0085 (p-valu
rr

## *The results are available in the following objects:


##
Bo

## name description
## 1 "$eig" "eigenvalues"
## 2 "$col" "results for the columns"
## 3 "$col$coord" "coord. for the columns"
## 4 "$col$cos2" "cos2 for the columns"
## 5 "$col$contrib" "contributions of the columns"
## 6 "$row" "results for the rows"
## 7 "$row$coord" "coord. for the rows"
## 8 "$row$cos2" "cos2 for the rows"
## 9 "$row$contrib" "contributions of the rows"
## 10 "$call" "summary called parameters"
390 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

CA factor map

0.20
0.10 Técnico
Dim 2 (13.13%)

Soltero
No cualificado Otros

07
Dirección
0.00

Empleado ObreroCasado1
Encargado
Divorciado

5-
Casado+
−0.10

Viudo

-0
−0.4 −0.3 −0.2 −0.1 0.0 0.1 0.2

19 Dim 1 (75.77%)

Figura 6.3: Análisis de correspondencias simple con el paquete FactoMiner


20
## 11 "$call$marge.col" "weights of the columns"
## 12 "$call$marge.row" "weights of the rows"
or

summary(corres2, ncp = 2)
ad

##
## Call:
## CA(X = frecuencias)
##
rr

## The chi square of independence between the two variables is equal to 158.0085 (p-valu
##
Bo

## Eigenvalues
## Dim.1 Dim.2 Dim.3 Dim.4
## Variance 0.017 0.003 0.002 0.000
## % of var. 75.768 13.131 9.954 1.146
## Cumulative % of var. 75.768 88.899 98.854 100.000
##
## Rows
## Iner*1000 Dim.1 ctr cos2 Dim.2 ctr cos2
## Soltero | 4.645 | -0.112 16.948 0.633 | 0.085 56.421 0.365 |
## Casado1 | 5.071 | 0.096 27.835 0.952 | -0.007 0.748 0.004 |
## Viudo | 9.104 | -0.300 45.210 0.861 | -0.103 30.748 0.101 |
6.3. ANÁLISIS DE CORRESPONDENCIAS SIMPLES 391

## Divorciado | 2.328 | -0.062 2.264 0.169 | -0.047 7.541 0.097 |


## Casado+ | 1.736 | 0.162 7.743 0.773 | -0.052 4.543 0.079 |
##
## Columns
## Iner*1000 Dim.1 ctr cos2 Dim.2 ctr cos2
## No cualificado | 8.723 | -0.259 44.520 0.885 | 0.062 14.563 0.050 |
## Obrero | 2.074 | 0.104 10.556 0.882 | -0.014 1.059 0.015 |
## Técnico | 3.009 | 0.117 4.580 0.264 | 0.170 56.092 0.560 |
## Encargado | 1.248 | 0.079 3.852 0.535 | -0.048 8.023 0.193 |
## Dirección | 4.247 | 0.165 23.897 0.976 | 0.012 0.678 0.005 |

07
## Empleado | 3.404 | -0.077 12.583 0.641 | -0.036 15.776 0.139 |
## Otros | 0.178 | 0.009 0.013 0.013 | 0.061 3.809 0.642 |

5-
Con las dos primeras dimensiones se explica casi el 90 % de la inercia, por lo que el gráfico
bidimensional va a ser muy adecuado. Según el criterio citado anteriormente, solo el primer
autovalor tiene una contribución mayor del 25 % (máximo entre 1/(c − 1) y 1/(r − 1)), por

-0
lo que dos son suficientes. Podemos visualizar las contribuciones de las dimensiones con un
gráfico de sedimentación (screeplot) como el que se muestra en la figura 6.4, a través del

19
paquete factoextra (Kassambara and Mundt, 2017).
max.porc <- max(1/(dim(frecuencias)-1)*100)
library(factoextra)
20
fviz_screeplot(corres2) +
geom_hline(yintercept = max.porc, linetype = 2, color = "red") +
labs(title = "Gráfico de sedimentación", x = "Dimensiones",
y = "Porcentaje de variabilidad explicada")
or

En el gráfico bidimensional vemos cómo los no cualificados están más próximos de los sol-
teros, los divorciados de los empleados, y los casados de profesiones de dirección, manuales
ad

y encargados. El grupo de viudos y el de técnicos están muy alejados de todos los demás.
Podemos visualizar las categorías fila o columna por separado, para buscar afinidades. Por
ejemplo con el siguiente código usando el paquete factoextra (figura ?(fig:carows)):
rr

fviz_ca_row(corres2, repel = TRUE)

La medida cos2 (coseno al cuadrado) mide la calidad de representación de las filas o columnas
Bo

de cada categoría. Podemos visualizar esta intensidad mediante una gradación de colores en
el gráfico como en la figura 6.6:
fviz_ca_row(corres2, col.row = "cos2",
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE)

El valor contrib de cada categoría y columna, mide el grado de contribución a cada una de las
dimensiones. Las podemos visualizar con la función fviz_contrib del paquete factoextra.
Con el argumento axes indicamos de qué dimensiones queremos representar la contribución,
que pueden ser más de una conjuntamente como en el siguiente ejemplo. La línea roja indica
392 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

07
Gráfico de sedimentación

5-
Porcentaje de variabilidad explicada

-0
60

40
19
20
20
or
ad

1 2 3 4
rr

Dimensiones

Figura 6.4: Gráfico de sedimentación


Bo
6.3. ANÁLISIS DE CORRESPONDENCIAS SIMPLES 393

07
Row points − CA
Soltero

5-
-0
0.05

19
Dim2 (13.1%)

0.00
20
Casado1

−0.05 Divorciado Casado+


or
ad

−0.10
Viudo
−0.3 −0.2 −0.1 0.0 0.1
rr

Dim1 (75.8%)

Figura 6.5: Visualización de categorías fila


Bo
394 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

07
Row points − CA
Soltero

5-
-0
0.05

cos2

19
Dim2 (13.1%)

0.00 0.8
20
Casado1
0.6

0.4

−0.05 Divorciado Casado+


or
ad

−0.10
Viudo
−0.3 −0.2 −0.1 0.0 0.1
rr

Dim1 (75.8%)

Figura 6.6: Visualización de categorías fila y la calidad de representación


Bo
6.3. ANÁLISIS DE CORRESPONDENCIAS SIMPLES 395

Contribution of rows to Dim−1−2

40

30
Contributions (%)

07
20

5-
10

-0
0

19
o

o1

ro

o+

do
ud

lte
ad

ia
ad
Vi

rc
So
as

as

ivo
C

C
20

D
Figura 6.7: Visualización de la contribución de las categorías fila a las dos primeras dimen-
siones
or

la contribución esperada si las contribuciones fueran uniformes. Vemos en la figura 6.7 que
la categoría que más contribuye a las dos dimensiones es “Viudo”.
ad

fviz_contrib(corres2, choice = "row", axes = 1:2)

Estas contribuciones también las podemos visualizar conjuntamente con el paquete corrplot
rr

(Wei and Simko, 2017), véase la figura 6.8:


library("corrplot")
Bo

corrplot(corres2$row$contrib, is.corr = FALSE)

El mismo análisis que se ha hecho para las categorías fila, se puede también hacer para las ca-
tegorías columna. Además, las funciones del paquete factoextra también se pueden aplicar
a objetos creados con el paquete ca y otros utilizados para análisis de correspondencias.

Realice la práctica 6.1 cuyo guión se encuentra en el apartado 6.5 para realizar
análisis de correspondencias simple sobre un ejemplo de color de ojos y pelo de una muestra
de individuos.
396 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

07
Dim 1

Dim 2

Dim 3

Dim 4

5-
80.63

Soltero 72.58

-0
64.53

Casado1
19 56.48

48.43
20
Viudo 40.38

32.33
or

Divorciado 24.28
ad

16.23

Casado+ 8.18
rr

0.13

Figura 6.8: Visualización de la contribución de las categorías fila a todas las dimensiones
Bo
6.4. ANÁLISIS DE CORRESPONDENCIAS MÚLTIPLE 397

Realice la práctica 6.2. En este caso no existe guión, consulte el apartado 6.5 para
realizar análisis de correspondencias simple sobre algunos atributos de los datos de encuesta
utilizados en el capítulo 5.

6.4. Análisis de correspondencias múltiple


Con el análisis de correspondencias simple visto en el apartado anterior, podemos estudiar la

07
asociación de atributos dos a dos. Pero si queremos estudiar dicha asociación para más de dos
atributos conjuntamente, tenemos que utilizar el análisis de correspondencias múltiple. La
idea es la misma: obtener unas coordenadas en un espacio de dimensión reducida (idealmente

5-
dos) para cada categoría de cada uno de los atributos. Para obtener estas coordenadas, uno
de los métodos utilizados es disponer los datos en forma de matriz indicadora, de forma que
para cada atributo tenemos tantas columnas como categorías, y los datos son indicadores de

-0
presencia o ausencia (1 y 0 respectivamente) de la características en cada observación. Por
ejemplo para tres atributos con tres categorías cada uno:

19
20
Atributo A Atributo B Atributo C A1 A2 A3 B1 B2 B3 C1 C
or

La matriz indicadora la podemos entonces representar como:


ad

Z = ⌊Z1 , Z2 , . . . , Zj , . . . , Zp ⌋,
rr

siendo Zj las matrices de los p atributos que forman Z. Con esta matriz se forma la llamada
matriz de Burt:
Bo

B = Z t Z.
Las coordenadas de cada modalidad se obtendrán a partir de los autovalores y autovectores
de Burt.

6.4.1. Análisis de correspondencias múltiple con R


Para realizar el análisis de correspondencias múltiples con el paquete ca tenemos la función
mjca. Con el paquete FactoMineR podemos usar la función CA. El análisis es similar al análisis
con dos atributos, aunque la representación de muchas categorías se puede complicar.
398 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

Vamos a añadir la información de las aficiones y las otras dos variables de atributo
al conjunto de datos. A continuación se explica el código a utilizar para el análisis.

aficiones <- cbind(hobbies[, 1:20], aficiones)


names(aficiones)[1:20] <- c("Leer", "Escuchar música", "Cine", "Show",
"Exposición", "Ordenador", "Deporte",
"Caminar", "Viajar", "Tocar música",
"Coleccionar", "Voluntariado", "Mecánica",

07
"Jardinería", "Punto", "Cocinar", "Pescar",
"TV", "Sexo", "Edad")

5-
Aplicamos el análisis a los datos originales con el paquete ca. El argumento reti nos sirve
para retener la matriz indicadora.
corres3 <- mjca(aficiones, lambda = "Burt", reti = FALSE)

-0
corres3

##
##
##
Eigenvalues:
1 2 3
19 4 5 6 7
20
## Value 0.032615 0.010208 0.00886 0.004362 0.003454 0.002754 0.002537
## Percentage 29.31% 9.17% 7.96% 3.92% 3.1% 2.47% 2.28%
## 8 9 10 11 12 13 14
## Value 0.002456 0.002368 0.002331 0.002256 0.002235 0.00213 0.002118
## Percentage 2.21% 2.13% 2.09% 2.03% 2.01% 1.91% 1.9%
or

## 15 16 17 18 19 20 21
## Value 0.00203 0.00201 0.001952 0.0019 0.001877 0.00181 0.001697
ad

## Percentage 1.82% 1.81% 1.75% 1.71% 1.69% 1.63% 1.52%


## 22 23 24 25 26 27 28
## Value 0.001611 0.001525 0.001378 0.001365 0.001286 0.001213 0.001131
## Percentage 1.45% 1.37% 1.24% 1.23% 1.16% 1.09% 1.02%
rr

## 29 30 31 32 33 34 35
## Value 0.001076 0.000942 0.00092 0.000882 0.000788 0.000746 0.000699
Bo

## Percentage 0.97% 0.85% 0.83% 0.79% 0.71% 0.67% 0.63%


## 36 37 38 39
## Value 0.000607 0.000601 0.000388 0.000168
## Percentage 0.55% 0.54% 0.35% 0.15%
##
##
## Columns:
## Leer:0 Leer:1 Escuchar.música:0 Escuchar.música:1 Cine:0
## Mass 0.015031 0.030781 0.013380 0.032431 0.027497
## ChiDist 0.385110 0.187809 0.440082 0.181396 0.256556
## Inertia 0.002229 0.001086 0.002591 0.001067 0.001810
6.4. ANÁLISIS DE CORRESPONDENCIAS MÚLTIPLE 399

## Dim. 1 1.499765 -0.730621 1.964121 -0.808718 1.267894


## Dim. 2 1.349761 -0.649708 -0.282383 0.125414 -0.475926
## Cine:1 Show:0 Show:1 Exposición:0 Exposición:1 Ordenador:0
## Mass 0.018315 0.032588 0.013224 0.031658 0.014154 0.028591
## ChiDist 0.385102 0.188842 0.464833 0.199660 0.445639 0.238200
## Inertia 0.002716 0.001162 0.002857 0.001262 0.002811 0.001622
## Dim. 1 -1.900601 0.901848 -2.218523 0.927982 -2.071810 1.141533
## Dim. 2 0.730284 0.191131 -0.449177 0.552124 -1.214483 -0.655956
## Ordenador:1 Deporte:0 Deporte:1 Caminar:0 Caminar:1 Viajar:0
## Mass 0.017220 0.028938 0.016874 0.023026 0.022785 0.027466

07
## ChiDist 0.395338 0.220893 0.378707 0.253179 0.254893 0.237236
## Inertia 0.002691 0.001412 0.002420 0.001476 0.001480 0.001546
## Dim. 1 -1.892238 1.022578 -1.750577 0.856097 -0.862822 1.083658

5-
## Dim. 2 1.105876 -0.451695 0.791777 0.984424 -0.982149 0.507331
## Viajar:1 Tocar.música:0 Tocar.música:1 Coleccionar:0
## Mass 0.018345 0.037859 0.007953 0.041100

-0
## ChiDist 0.354488 0.119669 0.569460 0.076595
## Inertia 0.002305 0.000542 0.002579 0.000241
##
##
##
Dim. 1
Dim. 2
-1.619545
-0.743817 19
0.482275
0.060386
-2.289035
-0.251118
0.150601
0.084760
Coleccionar:1 Voluntariado:0 Voluntariado:1 Mecánica:0 Mecánica:1
20
## Mass 0.004712 0.038799 0.007013 0.026486 0.019326
## ChiDist 0.664750 0.102408 0.564665 0.225029 0.307082
## Inertia 0.002082 0.000407 0.002236 0.001341 0.001822
## Dim. 1 -1.302468 0.296837 -1.634708 0.711900 -0.972878
## Dim. 2 -0.678051 0.276685 -1.489569 -0.011683 0.030961
or

## Jardinería:0 Jardinería:1 Punto:0 Punto:1 Cocinar:0 Cocinar:1


## Mass 0.027496 0.018316 0.038104 0.007708 0.025705 0.020107
ad

## ChiDist 0.200719 0.299916 0.110445 0.544700 0.222276 0.283446


## Inertia 0.001108 0.001648 0.000465 0.002287 0.001270 0.001615
## Dim. 1 0.292414 -0.436071 0.049393 -0.237293 0.666660 -0.849607
## Dim. 2 1.024303 -1.521875 0.716290 -3.503339 0.802077 -1.010984
rr

## Pescar:0 Pescar:1 TV:0 TV:1 TV:2 TV:3


## Mass 0.040658 0.005154 0.005543 0.006659 0.011757 0.009679
Bo

## ChiDist 0.081618 0.642532 0.600473 0.530273 0.371177 0.416532


## Inertia 0.000271 0.002128 0.001998 0.001872 0.001620 0.001679
## Dim. 1 0.016213 -0.117638 0.869988 -0.681072 -0.450354 0.007478
## Dim. 2 -0.159011 1.310543 0.713943 0.089529 -0.039784 -0.452447
## TV:4 Sexo:M Sexo:F Edad:[15,25] Edad:(25,35]
## Mass 0.012174 0.020651 0.025160 0.004610 0.007127
## ChiDist 0.364609 0.298075 0.244778 0.805882 0.541621
## Inertia 0.001618 0.001835 0.001508 0.002994 0.002091
## Dim. 1 0.409772 -0.032055 0.028415 -1.496217 -0.988578
## Dim. 2 0.047873 1.544283 -1.256047 5.265977 1.868610
## Edad:(35,45] Edad:(45,55] Edad:(55,65] Edad:(65,75] Edad:(75,85]
400 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

## Mass 0.008999 0.010044 0.006861 0.005094 0.002616


## ChiDist 0.449055 0.422039 0.540556 0.669835 0.973450
## Inertia 0.001815 0.001789 0.002005 0.002286 0.002479
## Dim. 1 -0.620189 -0.005260 0.577769 1.555941 2.364456
## Dim. 2 0.075791 -1.087924 -1.853136 -1.889023 -1.649851
## Edad:(85,100] estado.civil:Soltero estado.civil:Casado1
## Mass 0.000461 0.011630 0.023640
## ChiDist 2.229454 0.481543 0.231041
## Inertia 0.002290 0.002697 0.001262
## Dim. 1 3.374617 -1.170887 0.214262

07
## Dim. 2 -0.882572 3.392412 -0.902882
## estado.civil:Viudo estado.civil:Divorciado estado.civil:Casado+
## Mass 0.004001 0.004333 0.002208

5-
## ChiDist 0.814808 0.676185 0.962111
## Inertia 0.002656 0.001981 0.002043
## Dim. 1 2.069383 0.105757 -0.060455

-0
## Dim. 2 -2.865332 -0.883137 -1.144997
## profesion:No cualificado profesion:Obrero profesion:Técnico
##
##
##
Mass
ChiDist
Inertia
19
0.004353
0.699801
0.002132
0.006381
0.572086
0.002088
0.002204
0.964406
0.002050
20
## Dim. 1 1.670254 1.099295 -0.605833
## Dim. 2 1.179245 1.196346 1.644403
## profesion:Encargado profesion:Dirección profesion:Empleado
## Mass 0.004040 0.005782 0.014027
## ChiDist 0.699459 0.634858 0.341206
or

## Inertia 0.001976 0.002330 0.001633


## Dim. 1 -0.956070 -1.883154 0.068561
ad

## Dim. 2 -0.702801 -0.700192 -1.068857


## profesion:Otros
## Mass 0.001165
## ChiDist 1.315765
rr

## Inertia 0.002017
## Dim. 1 -0.234321
Bo

## Dim. 2 -0.496896
Nótese cómo al aumentar el número de factores la cantidad de información a interpretar
también lo hace. Aquí lo relevante es que las tres primeras dimensiones explican el 46 %
de la asociación entre categorías. En general, el porcentaje total que podemos explicar va
a ser menor que en el análisis de correspondencias simple. Podemos hacer un gráfico de
sedimentación como el de la figura 6.9, donde vemos que quizás en este caso deberíamos
coger una tercera dimensión.
fviz_screeplot(corres3, addlabels = TRUE, ylim = c(0, 45))

El gráfico de la figura 6.10 muestra la representación de las dos primeras dimensiones. Como
6.4. ANÁLISIS DE CORRESPONDENCIAS MÚLTIPLE 401

07
Scree plot

5-
40

-0
Percentage of explained variances

30 29.3%
19
20
20
or

10 9.2%
8%
3.9% 3.1% 2.5% 2.3%
ad

2.2% 2.1% 2.1%


0

1 2 3 4 5 6 7 8 9 10
rr

Dimensions

Figura 6.9: Gŕafico de sedimentación para el análisis de correspondencias múltiple


Bo
402 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

Edad:[15,25]

0.4
estado.civil:Soltero
Dimension 2 (9.2%)

0.2
Edad:(25,35]
profesion:Técnico
Sexo:M Leer:0
Ordenador:1 Pescar:1 profesion:Obrero
Jardinería:0 profesion:No cualificado
Caminar:0
Deporte:1
Cine:1 Punto:0Cocinar:0
TV:0
Exposición:0
Viajar:0
Voluntariado:0
Escuchar.música:1
Edad:(35,45]
TV:1 Show:0
Coleccionar:0
Tocar.música:0
Mecánica:1 TV:4
TV:2Pescar:0Mecánica:0
0.0

Tocar.música:1
Show:1 Leer:1 TV:3
profesion:Otros
profesion:Encargado
profesion:Dirección
Coleccionar:1
Viajar:1 Cine:0Escuchar.música:0
Deporte:0
Ordenador:0
Caminar:1
Cocinar:1 estado.civil:Divorciado
estado.civil:Casado1
profesion:Empleado
Edad:(45,55] Edad:(85,100]
Exposición:1 estado.civil:Casado+
Sexo:F

07
Voluntariado:1
Jardinería:1 Edad:(75,85]
Edad:(55,65]
Edad:(65,75]
−0.2

estado.civil:Viudo
Punto:1

5-
−0.5 0.0 0.5 1.0

-0
Dimension 1 (29.3%)

19
Figura 6.10: Representación del análisis de correspondencias múltiple
20
vemos, las etiquetas se solapan y es complicada su interpretación. No obstante, las categorías
más alejadas del origen. Por ejemplo valores altos de la dimensión 1 se corresponden con
personas mayores, que no escuchan música. Sin embargo valores pequeños se corresponden
con personas jóvenes, predomina el estado civil soltero, practican deportes como el ordenador,
deporte o cine.
or

plot(corres3)
ad

Vamos a continuar el ejemplo con el paquete FactoMineR, que nos ofrece más posibilidades
de visualización. Guardamos el resultado en un objeto, y por defecto se producen dos gráficos:
uno con todas las categorías, y otro solo con las variables, véase la figura ??.
rr

par(mfrow=c(2,1))
corres4 <- MCA(aficiones, method = "Burt")
Bo

Nótese que las funciones no utilizan exactamente los mismos métodos, ya que las inercias de
las dimensiones son ligeramente diferentes, como vemos en el gráfico de sedimentación para
este nuevo análisis, en la figura 6.12. No obstante la interpretación en este caso es la misma.
fviz_screeplot(corres4, addlabels = TRUE, ylim = c(0, 45))

Ahora podemos realizar las visualizaciones que vimos para el análisis de correspondencias
simple con el paquete factoextra, por ejemplo en la figura 6.13 se representan todas las
categorías en sus coordenadas de las dos primeras dimensiones y con una gradación de color
según su contribución.
6.4. ANÁLISIS DE CORRESPONDENCIAS MÚLTIPLE 403

MCA factor map

0.4
Punto_1
Viudo
(55,65]
(65,75] Jardinería_1
Voluntariado_1

0.2
(75,85] Casado+
(45,55]
F
Empleado
Casado1 Exposición_1
Caminar_1
Divorciado
Cocinar_1
Dirección
Encargado
Coleccionar_1
Ordenador_0
Escuchar Deporte_0
(85,100] música_0 Otros Viajar_1
Cine_0 TV_3 Leer_1 Show_1
Tocar Mecánica_1
Pescar_0
TV_2 Tocar
(35,45]
música_0 música_1
Dim 2 (9.09%)

0.0 TV_4
Coleccionar_0
Mecánica_0 TV_1
Escuchar
Show_0
Voluntariado_0 música_1
Viajar_0
Exposición_0
Punto_0
TV_0
Cocinar_0
Obrero Cine_1
Deporte_1
No cualificado
Leer_0 Pescar_1
Caminar_0
Jardinería_0 Ordenador_1
Técnico
M
profesion.NA
(25,35]
−0.2

07
Soltero

5-
[15,25]
−0.6

-0
−0.5 0.0 0.5

19 Dim 1 (28.64%)
20
1.0

or
0.8

ad
Dim 2 (9.09%)

0.6

Edad
rr

estado.civil
0.4
Bo

Punto
0.2

Jardinería
Sexo profesion
Caminar
Cocinar Leer Exposición
Ordenador
Voluntariado
Pescar TV Deporte Cine
Coleccionar
0.0

músicaShow
Mecánica
Tocar Viajar
Escuchar música

−0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2

Dim 1 (28.64%)

Figura 6.11: Visualización de las categorías con el paquete ‘FactoMineR‘


404 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

07
Scree plot

5-
40
Percentage of explained variances

-0
30 28.6%

19
20
20

9.1%
or

10
7.9%
4% 3.1% 2.5% 2.4% 2.2% 2.2% 2.1%
ad

1 2 3 4 5 6 7 8 9 10
Dimensions
rr

Figura 6.12: Gŕafico de sedimentación para el análisis de correspondencias múltiple con


Bo

‘FactoMineR‘
6.5. PRÁCTICAS 405

Variable categories − MCA


Punto_1
Empleado Jardinería_1 Voluntariado_1
Viudo (55,65] Casado+ Caminar_1
0.2 (65,75] Cocinar_1 Exposición_1
(75,85] Ordenador_0 (45,55]
Casado1 Otros Encargado Dirección
Cine_0
(85,100] Deporte_0 Divorciado F Leer_1 Show_1
(35,45]
Pescar_0 contrib
0.0 Escuchar música_0
Tocar música_0TV_3 Viajar_1
Coleccionar_0 5
Dim2 (9.1%)

Viajar_0 Show_0 Mecánica_0


Voluntariado_0
EscucharColeccionar_1
música_1
Tocar música_1

07
4
Exposición_0 Obrero TV_0 TV_4 TV_2 Mecánica_1 Cine_1
3
No cualificado Leer_0 Cocinar_0 M Pescar_1 Deporte_1
−0.2 2
Caminar_0 profesion.NA TV_1 Ordenador_1

5-
1
Jardinería_0 Punto_0 (25,35]
Técnico

-0
−0.4 Soltero

−0.6
−0.6 −0.4
19
−0.2
Dim1 (28.6%)
0.0 0.2
[15,25]

0.4
20
Figura 6.13: Visualización categorías MCA
or

fviz_mca_var(corres4, col.var = "contrib",


gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE, # avoid text overlapping (slow)
ad

ggtheme = theme_minimal()
)
rr

Finalmente, la figura 6.14 representa todas las variables en las dos primeras dimensiones.
fviz_mca_var(corres4, repel = TRUE, choice = "var",
ggtheme= theme_minimal())
Bo

Realice la práctica 6.3 para realizar análisis de correspondencias múltiples. Encontrará


el guión en el apartado 6.5.

6.5. Prácticas
En este apartado se presentan las prácticas a las que se han hecho referencia durante el
capítulo. La reproducibilidad del código ha sido comprobada con la sesión de R que se
406 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

07
Variables − MCA
Edad

5-
0.5
estado.civil

-0
0.4

19
Dim2 (9.1%)

0.3
20
0.2 Punto
Jardinería
profesion
or

Sexo Caminar
0.1
Exposición Ordenador
Cocinar Leer Viajar
ad

Pescar TV Voluntariado Deporte Cine


0.0
Coleccionar Mecánica Tocar música Escuchar música Show
0.0 0.1 0.2 0.3 0.4
rr

Dim1 (28.6%)

Figura 6.14: Representación de las variables del análisis


Bo
6.5. PRÁCTICAS 407

detalla en el Prefacio. El lector puede teclear el código o copiarlo y pegarlo en la consola o


el editor. También se puede descargar el script con el código de todas las prácticas con la
siguiente expresión:
download.file("http://emilio.lcano.com/b/adr/practicas/13-acorres.R",
destfile = "practicas/13-acorres.R")

Práctica 6.1: Ejemplo de color de ojos y pelo

07
El objetivo del análisis de correspondencias es representar gráficamente, en un espacio con
pocas dimensiones (preferentemente 2) las tablas de contingencia que muestran las relaciones
entre dos variables cualitativas o atributos.

5-
En este primer ejemplo (García Pérez, 2008) buscamos la relación entre los atributos “color
del pelo” y “color de ojos”, representado mediante la tabla de contingencia siguiente:

-0
library(knitr)
kable(read.table("datos/cabello_ojos.txt", header = TRUE, sep = "\t", dec = ",", row.nam

Azules
Claros
Rubio Rojizo Castaño
326
688
38
116
241
584
19Moreno Negro
110
188
3
4
20
Castaños 343 84 909 412 26
Oscuros 98 48 403 681 85
Las expresiones utilizadas se encuentran en el script de las prácticas del capítulo. En lo
sucesivo, vamos a suponer que estamos trabajando en un proyecto que contiene una carpeta
or

llamada “datos” donde se encuentran los ficheros de datos. El fichero se puede descargar a
la carpeta de datos del proyecto con la siguiente expresión:
ad

download.file("http://emilio.lcano.com/b/adr/datos/cabello_ojos.txt",
"datos/cabello_ojos.txt")

Se recomienda en primer lugar limpiar el espacio de trabajo eliminando todos los objetos
rr

existentes:
rm(list = ls())
Bo

Preparación de los datos


Vamos a necesitar el paquete ca. Si no se carga, hay que instalarlo previamente por cualquiera
de los métodos vistos en clase.
library (ca)

La tabla de contingencia con los datos de la aplicación se encuentra en el archivo de texto se-
parado por tabulaciones “cabello_ojos.txt”. Obtendremos esta tabla utilizando la instrucción
“read.table”, y asignándolos al objeto de tipo data.frame “X”:
408 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

X <- read.table("datos/cabello_ojos.txt", header = TRUE,


sep = "\t", dec = ",", row.names = 1, fileEncoding = "latin1")
X

## Rubio Rojizo Castaño Moreno Negro


## Azules 326 38 241 110 3
## Claros 688 116 584 188 4
## Castaños 343 84 909 412 26
## Oscuros 98 48 403 681 85

07
Comprobación de la hipótesis de independencia
Lo primero que hemos de comprobar es que existe algún grado de relación (asociación) entre

5-
los niveles de cada atributo. Para ello, recordemos que se calculan las frecuencias teóricas o
esperadas en caso de independencia, y se comparan globalmente con las realmente observadas

-0
en la muestra, mediante un estadístico que, bajo la hipótesis nula de independencia, se
comporta como una χ-Cuadrado de (r − 1) × (c − 1) grados de libertad (r = número de filas;
c = número de columnas). La función para realizar este contraste es chisq.test:
chisq.test(X)

##
19
20
## Pearson's Chi-squared test
##
## data: X
## X-squared = 1240, df = 12, p-value < 2.2e-16
or

La tabla de frecuencias observadas y la tabla de frecuencias esperadas en caso de indepen-


dencia se pueden obtener accediendo al objeto creado por la función:
ad

chisq.test(X)$observed

## Rubio Rojizo Castaño Moreno Negro


## Azules 326 38 241 110 3
rr

## Claros 688 116 584 188 4


## Castaños 343 84 909 412 26
Bo

## Oscuros 98 48 403 681 85


chisq.test(X)$expected

## Rubio Rojizo Castaño Moreno Negro


## Azules 193.9280 38.11918 284.8275 185.3978 15.72749
## Claros 426.7496 83.88342 626.7793 407.9785 34.60924
## Castaños 479.1479 94.18303 703.7383 458.0720 38.85873
## Oscuros 355.1745 69.81437 521.6549 339.5517 28.80453
El test nos aporta un p-value muy pequeño, mucho menor que 0.05, por lo que se rechaza la
hipótesis nula de independencia entre los atributos. Existe algún tipo de asociación.
6.5. PRÁCTICAS 409

Análisis de correspondencias
La pregunta, ahora que sabemos que hay asociación, es qué niveles concretos de cada factor
están relacionados entre sí, y cuáles no, y con qué intensidad. Esta cuestión puede ser resuelta
gráficamente mediante el Análisis de Correspondencias. Vamos a suponer que el número de
filas r es menor o igual que el número de columnas c de la tabla de contingencia. Si no es así,
la tabla se traspone.
Se construye una matriz de discrepancias C que recoge los cuadrados de las diferencias entre
las frecuencias conjuntas de cada combinación fila/columna de categorías de atributos y las

07
frecuencias esperadas en caso de independencia, divididas por la raíz de dichas frecuencias
esperadas. Se realiza una descomposición de dicha matriz y se obtiene la matriz D diagonal
(rxr) cuyos elementos son las raíces cuadradas de los r autovalores de CC t . A partir de estas
matrices se obtienen las coordenadas de cada nivel de cada factor para una dimensión dada,

5-
usualmente 2 (que es lo que supone la función ca por defecto). Vamos a guardar nuestro
análisis de correspondencias en un objeto con el nombre de, por ejemplo, “acorres”, y lo

-0
vamos a mostrar:
acorres <- ca(X)
acorres

##
## Principal inertias
19
(eigenvalues):
20
## 1 2 3
## Value 0.199245 0.030087 0.000859
## Percentage 86.56% 13.07% 0.37%
##
or

##
## Rows:
## Azules Claros Castaños Oscuros
ad

## Mass 0.133284 0.293299 0.329311 0.244106


## ChiDist 0.437855 0.450620 0.247359 0.715398
## Inertia 0.025553 0.059557 0.020149 0.124932
rr

## Dim. 1 -0.896793 -0.987318 0.075306 1.574347


## Dim. 2 0.953623 0.510004 -1.412478 0.772036
##
Bo

##
## Columns:
## Rubio Rojizo Castaño Moreno Negro
## Mass 0.270095 0.053091 0.396696 0.258214 0.021905
## ChiDist 0.571235 0.265854 0.212526 0.597901 1.132193
## Inertia 0.088134 0.003752 0.017918 0.092308 0.028079
## Dim. 1 -1.218714 -0.522575 -0.094147 1.318885 2.451760
## Dim. 2 1.002243 0.278336 -1.200909 0.599292 1.651357
Las informaciones más relevantes que nos aporta la función ca son las Inercias Principales,
que nos orientarán acerca de si dos es un número de dimensiones adecuada o es preferible otra
410 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

dimensión. En nuestro caso, con una sola dimensión recogeríamos el 86.5 % de la “Inercia
Total”. Recordemos que este análisis es muy parecido al de “Componentes Principales”, y
que “Inercia” puede considerarse un sinónimo de “Varianza”.

No obstante, podemos añadir una segunda dimensión para recoger un 13 % adicional de la


“Inercia Total”. Por lo tanto sabemos que con las dos dimensiones que utiliza el análisis por
defecto se recogerá más del 99 % del comportamiento de los individuos de la muestra en
relación a los atributos estudiados.

También se nos ofrecen las informaciones concernientes a los niveles de los factores o atributos,

07
tanto el dispuesto en filas como en columnas. Entre estas informaciones destacan las masas
o porcentajes que cada categoría del factor representa con respecto al total de individuos,
las distancias chi-cuadrado correspondientes a cada categoría de cada factor con respecto al
centroide, las inercias de cada categoría de cada factor (su suma debe dar igual a la inercia

5-
total), y las coordenadas de cada nivel de cada atributo o factor.

-0
Por último, para representar la solución final vamos a aplicar la función plot, con lo que se
obtiene:
plot(acorres, what = c("all", "all"), mass = TRUE,

19
contrib = "relative", main = "Análisis de Correspondencias Simple")

Análisis de Correspondencias Simple


20
0.4

Negro
or
Dimension 2 (13.1%)

0.2

Rubio Azules
Oscuros
Claros Moreno
ad

Rojizo
0.0

rr
−0.2

Castaño
Castaños
Bo −0.4

−0.5 0.0 0.5 1.0

Dimension 1 (86.6%)

Parece existir una relación estrecha en poseer ojos azules y/o claros y el pelo rubio o rojizo.
Por otro lado, los ojos castaños normalmente vienen asociados al pelo castaño. Y por último,
los ojos oscuros se asocian al pelo moreno o negro. El tamaño del punto que representa a una
categoría indica la masa o proporción de casos que cumplen con esa categoría con respecto
6.5. PRÁCTICAS 411

al total.

Explora otras visualizaciones


Utiliza las funciones del paquete factoextra para realizar otras visualizaciones y análisis de
los resultados. Haz el análisis con el paquete FactoMineR y compara los resultados.

Práctica 6.2: Análisis de correspondencias simple con

07
los datos de la encuesta
En esta práctica no existe un guión tan estructurado como en el resto. Se trata de realizar
análisis de correspondencias simple sobre atributos de un conjunto de datos que contiene

5-
respuestas a un cuestionario. El fichero se puede descargar a la carpeta datos con la siguiente
expresión:

-0
download.file("http://emilio.lcano.com/b/adr/datos/encuesta_anonima_2018.RData",
"datos/encuesta_anonima_2018.RData")

19
Se recomienda en primer lugar limpiar el espacio de trabajo eliminando todos los objetos
existentes:
20
rm(list = ls())

Los datos se encuentran almacenados como archivo de datos de R, “.RData”. Para cargarlos
en el espacio de trabajo, utilizamos la función load.
or

load("datos/encuesta_anonima_2018.RData")

A partir de aquí:
ad

Identifique las variables de tipo atributo sobre las que puede realizar análisis de corres-
pondencias
Encuentre algún/algunos pares de atributos para los que se confirme que hay asociación
rr

Realice el análisis de correspondencias e interprete los resultados


Bo

Práctica 6.3: Ejemplo de Análisis de Correspondencias


Múltiple
En el Análisis de Correspondencias Múltiple existen más de dos atributos o factores. Siguien-
do el ejemplo de García Pérez (2008), se tienen datos correspondientes a 20 granjas de una
isla, observándose los atributos “Niveles de Humedad” con categorías h1, h2, h4, h5; “Uso
del pasto” con categorías u1, u2, u3; “Uso de Abono” con categorías c0, c1, c2, c3, c4; y “Uti-
lización de la granja” con categorías estándar (es), biológico (bio), recreo (re) y conservación
de la Naturaleza (con).
412 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

Las expresiones utilizadas se encuentran en el script de las prácticas del capítulo. En lo


sucesivo, vamos a suponer que estamos trabajando en un proyecto que contiene una carpeta
llamada “datos” donde se encuentran los ficheros de datos. El fichero se puede descargar a
la carpeta de datos del proyecto con la siguiente expresión:
download.file("http://emilio.lcano.com/b/adr/datos/granjas.txt",
"datos/granjas.txt")

Preparación de los datos y espacio de trabajo

07
Se recomienda en primer lugar limpiar el espacio de trabajo eliminando todos los objetos
existentes:
rm(list = ls())

5-
Necesitaremos el paquete ca, luego vamos a cargarlo:

-0
library (ca)

La tabla con los datos de la aplicación se encuentra en el archivo de texto separado por

19
tabulaciones “granja.txt”. Obtendremos esta tabla utilizando la instrucción “read.table”, y
asignándolos al objeto data.frame “granjas”:
granjas <- read.table("datos/granjas.txt",
20
header = T, sep = "\t", dec = ",",
row.names = 1, fileEncoding = "latin1")

Las variables cualitativas o atributos (Humedad, Uso_Pasto, Uso_Abono, Utilización) son


or

recogidos, con la categoría que toman para cada caso o granja, en el data.frame “granjas”,
obteniéndose:
ad

granjas

## Humedad Uso_Pasto Uso_Abono Utilizacion


## Granja1 h1 u2 c4 es
rr

## Granja2 h1 u2 c2 bio
## Granja3 h2 u2 c4 es
Bo

## Granja4 h2 u2 c4 es
## Granja5 h1 u1 c2 re
## Granja6 h1 u2 c2 re
## Granja7 h1 u3 c3 re
## Granja8 h5 u3 c3 re
## Granja9 h4 u1 c1 re
## Granja10 h2 u1 c1 bio
## Granja11 h1 u3 c1 bio
## Granja12 h4 u2 c2 es
## Granja13 h5 u2 c3 es
## Granja14 h5 u3 c0 con
6.5. PRÁCTICAS 413

## Granja15 h5 u2 c0 con
## Granja16 h5 u3 c3 es

Análisis de correspondencias
A continuación se obtiene la solución, mediante la función “mjca” suponiendo una represen-
tación de las categorías de los atributos en dos dimensiones. La solución se guarda en un
objeto al que hemos llamado, por ejemplo, “b”:
b <- mjca(granjas, lambda = "Burt")

07
print(b)

##

5-
## Eigenvalues:
## 1 2 3 4 5 6 7

-0
## Value 0.498902 0.359584 0.205281 0.153415 0.109793 0.0429 0.01938
## Percentage 35.66% 25.7% 14.67% 10.96% 7.85% 3.07% 1.39%
## 8 9 10 11 12
##
##
##
Value 0.005709
Percentage 0.41% 0.25% 0.03%19
0.0035 0.000476 0.000226 0
0.02% 0%
20
##
## Columns:
## Humedad:h1 Humedad:h2 Humedad:h4 Humedad:h5 Uso_Pasto:u1
## Mass 0.093750 0.046875 0.031250 0.078125 0.046875
## ChiDist 0.797566 1.374369 1.551881 1.143095 1.408966
or

## Inertia 0.059635 0.088542 0.075260 0.102083 0.093056


## Dim. 1 -0.553488 -0.805941 -1.023277 1.557061 -1.346563
ad

## Dim. 2 0.389208 -1.465801 0.489030 0.216819 1.187550


## Uso_Pasto:u2 Uso_Pasto:u3 Uso_Abono:c0 Uso_Abono:c1 Uso_Abono:c2
## Mass 0.125000 0.078125 0.031250 0.046875 0.062500
## ChiDist 0.677003 0.987927 2.031010 1.463127 1.090680
rr

## Inertia 0.057292 0.076250 0.128906 0.100347 0.074349


## Dim. 1 -0.032579 0.860064 2.387924 -1.213855 -0.803223
Bo

## Dim. 2 -0.979444 0.854580 0.387311 1.233306 0.247002


## Uso_Abono:c3 Uso_Abono:c4 Utilizacion:bio Utilizacion:con
## Mass 0.062500 0.046875 0.046875 0.031250
## ChiDist 1.157404 1.471960 1.331944 2.031010
## Inertia 0.083724 0.101562 0.083160 0.128906
## Dim. 1 0.819926 -0.400365 -1.034143 2.387924
## Dim. 2 0.354457 -2.293458 0.736185 0.387311
## Utilizacion:es Utilizacion:re
## Mass 0.093750 0.078125
## ChiDist 0.905232 0.941630
## Inertia 0.076823 0.069271
414 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

## Dim. 1 0.023574 -0.362972


## Dim. 2 -1.380751 1.060266

Se obtienen unos resultados que indican que al seleccionar dos dimensiones se recoge el 61,3 %
de la Inercia Principal. Por lo tanto confirmamos que un número de dimensiones de 2 recoge
buena parte del comportamiento de las granjas estudiadas.

También se nos ofrecen las informaciones concernientes a los niveles de los factores o atribu-
tos (masas o porcentajes que cada categoría del factor representa con respecto al total de
individuos, las distancias chi-cuadrado correspondientes a cada categoría de cada factor con

07
respecto al centroide, las inercias de cada categoría de cada factor). Entre estas informaciones
destacan las coordenadas de cada nivel de cada atributo o factor.

Al final representamos cada nivel de cada factor en un diagrama de dos dimensiones:

5-
plot (b, mass = TRUE, main = "Análisis de Correspondencias Múltiple")

-0
Análisis de Correspondencias Múltiple

Uso_Abono:c1
Uso_Pasto:u1

19
Utilizacion:re
Uso_Pasto:u3
0.5

Utilizacion:bio
20
Humedad:h4
Humedad:h1 Uso_Abono:c3 Uso_Abono:c0
Utilizacion:con
Uso_Abono:c2 Humedad:h5
Dimension 2 (25.7%)

0.0

or
ad
−0.5

Uso_Pasto:u2

Utilizacion:es
rr

Humedad:h2
−1.0
Bo

Uso_Abono:c4

−1.0 −0.5 0.0 0.5 1.0 1.5

Dimension 1 (35.7%)

El argumento “mass” indica si los puntos tendrán un tamaño proporcional a las masas de
las categorías correspondientes. A partir de aquí, correspondería analizar el gráfico con el
conocimiento del problema concreto. Por ejemplo, se ve cómo se agrupan u3, c3, y h5.
6.5. PRÁCTICAS 415

Explora otras visualizaciones


Utiliza las funciones del paquete factoextra para realizar otras visualizaciones y análisis de
los resultados. Haz el análisis con el paquete FactoMineR y compara los resultados.

Práctica 6.4: Análisis de correspondencias múltiple con


los datos de la encuesta
En esta práctica no existe un guión tan estructurado como en el resto. Se trata de realizar

07
análisis de correspondencias simple sobre atributos de un conjunto de datos que tiene res-
puestas a un cuestionario. El fichero se puede descargar a la carpeta datos con la siguiente
expresión:

5-
download.file("http://emilio.lcano.com/b/adr/datos/encuesta_anonima_2018.RData",
"datos/encuesta_anonima_2018.RData")

-0
Se recomienda en primer lugar limpiar el espacio de trabajo eliminando todos los objetos
existentes:
rm(list = ls())
19
Los datos se encuentran almacenados como archivo de datos de R, “.RData”. Para cargarlos
20
en el espacio de trabajo, utilizamos la función load.
load("datos/encuesta_anonima_2018.RData")

A partir de aquí, realice análisis de correspondencias con algunos o todos los atributos de la
or

encuesta e interprete los resultados.


ad
rr
Bo
416 CAPÍTULO 6. ANÁLISIS DE CORRESPONDENCIAS CON R

07
5-
-0
19
20
or
ad
rr
Bo
07
5-
Parte III

-0
19
Extensiones del modelo lineal
20
or
ad
rr
Bo

417
Bo
rr
ad
or
20
19
-0
5-
07
419

El modelo lineal se queda corto en muchísimas situaciones reales. En los siguientes capítulos
se abordará cómo afrontar estas situaciones ajustando modelos adecuados con R, incluyendo
modelos lineales mixtos, modelos aditivos, modelos lineales generalizados (respuesta binaria
y de Poisson).

07
5-
-0
19
20
or
ad
rr
Bo
420

Bo
rr
ad
or
20
19
-0
5-
07
Capítulo 7

07
5-
Modelos lineales mixtos

-0
7.1. Introducción 19
20
Uno de los primeros problemas que se encuentra un analista es identificar qué modelo es
el adecuado para su problema. Primero, obviamente, ha debido definir el problema con
precisión, cuáles son los objetivos del análisis y la información que es capaz de recabar. En
or

los distintos apartados del capítulo se incluyen pistas para la identificación del modelo, más
uno o dos ejemplos de su aplicación.
ad
rr

7.2. Modelo de efectos fijos y aleatorios


Bo

7.3. Modelo de medidas repetidas

En ocasiones, la variable respuesta se observa en los individuos objeto de estudio en distintos


periodos de tiempo, que pueden ser intervalos regulares o no. En esta situación, la propia
correlación de las observaciones dentro de cada individuo hace que no se cumplan las hipótesis
del modelo lineal y haya que tratarlo de forma distinta. En la práctica, el individuo se
convierte en un efecto aleatorio cuyo efecto en promedio es cero, y cuya varianza se debe
analizar para establecer cómo afecta a la varianza de la respuesta.

421
422 CAPÍTULO 7. MODELOS LINEALES MIXTOS

7.3.1. Identificación del modelo


7.3.2. Ajuste del modelo
7.3.3. ANOVA
7.3.4. Estimación efectos
7.3.5. Predicción

7.4. Modelos de panel

07
En realidad, estos modelos son prácticamente iguales que los modelos de medidas repetidas.
No obstante, en aplicaciones de economía y empresa tiene algunas connotaciones por las que

5-
merece la pena tratarlas en un apartado distinto.

-0
7.5. Modelo de efectos aleatorios

7.6. Algunas consideraciones


19
20
Hay dos paquetes en R que sirven para ajustar modelos mixtos con muy pocas diferen-
cias: lmery lme4.
Una interesante curiosidad es que el paquete lme4 no reporta p-valores por cuestiones
or

filosóficas, según los autores. Es por esto que al utilizar este paquete se tienen que
obtener con otras funciones.
ad

7.6.1. Recursos
Guide to mixed models
rr

MIXED MODELS FOR REPEATED (LONGITUDINAL)DATA


Treatment of Missing Data–Part 1
Bo
Bo
rr
ad
or

423
20
19
-0
5-
07
424 CAPÍTULO 8. CAPÍTULOS EN PREPARACIÓN

Capítulo 8

07
Capítulos en preparación

5-
8.1. Visualización de datos avanzada

-0
8.2. Probabilidad e inferencia básicas
8.3. Modelos lineales 19
20
8.4. Series temporales
8.5. Extensiones del modelo lineal
or

8.6. Técnicas avanzadas de predicción


ad

8.7. Técnicas de clasificación


8.8. Diseño y análisis de experimentos
rr

8.9. Análisis de encuestas con R


Bo

8.10. Control estadístico de procesos


8.11. Análisis y visualización de datos espaciales
8.12. Análisis de datos Bayesiano
8.13. Técnicas de Investigación Operativa con R
8.14. Análisis matemático y álgebra con R
Apéndice A

07
Símbolos

5-
Este apéndice contiene una relación símbolos matemáticos y caligráficos utilizados en el libro

-0
como referencia para el lector no acostumbrado a la notación matemática.

A.1. Letras griegas


19
Letra Se lee
20
µ mu
Ω Omega∗
σ sigma
σ Sigma∗
or


Mayúsculas
ad

A.2. Símbolos
rr

Símbolo Se lee
Bo

∅ Conjunto vacío o suceso imposible


ℵ Aleph
℘ Probabilidad (como función)
: Tal que
P (ů) Probabilidad de ·
ů lo que sea (representa cualquier objeto matemático)
| Condicionado a

Sumatorio

n
Sumatorio desde i igual a uno hasta n
i=1
∀ Para todo

425
426 APÉNDICE A. SÍMBOLOS

Símbolo Se lee
∈ Pertenece/perteneciente
∃ Existe
=⇒ Implica/entonces
≃ Aproximadamente igual1

07
5-
-0
19
20
or
ad
rr
Bo

1
En este libro se usa sobre todo para indicar que se ha redondeado un número decimal
Apéndice B

07
Créditos

5-
Los gráficos y diagramas generados son creación y propiedad del autor, salvo que se indique

-0
lo contrario. Su licencia de uso es la misma que la del resto de la obra, véase el Prefacio.
Las imágenes de tipo clipart usadas en esta obra pertenecen al dominio público gracias
a openclipart.org.
19
Las capturas de pantalla de páginas web se han obtenido de sys respectivos sitios
on-line a fecha 2017-03-20
20
The R logo is (c) 2016 The R Foundation.
or
ad
rr
Bo

427
428 APÉNDICE B. CRÉDITOS

07
5-
-0
19
20
or
ad
rr
Bo
Bibliografía

07
Aldas, J. and Uriel, E. (2017). Análisis multivariante aplicado con R. Ediciones Paraninfo,
S.A.

5-
Allaire, J., Xie, Y., McPherson, J., Luraschi, J., Ushey, K., Atkins, A., Wickham, H., Cheng,
J., Chang, W., and Iannone, R. (2019). rmarkdown: Dynamic Documents for R. R package
version 1.12.

-0
Allen, T. T. (2010). Introduction to Engineering Statistics and Lean Six Sigma - Statistical
Quality Control and Design of Experiments and Systems. Springer.

19
Bendixen, M. T. (1995). Compositional perceptual mapping using chi‐squared trees analysis
and correspondence analysis. Journal of Marketing Management, 11(6):571–581.
20
Bryan, J. (2019). Happy Git and GitHub for the useR. On-line book.

Bryer, J. and Speerschneider, K. (2016). likert: Analysis and Visualization Likert Items. R
package version 1.3.5.
or

Cano, E. L., Moguerza, J. M., and Corcoba, M. P. (2015). Quality Control with R. An ISO
Standards Approach. Use R! Springer.
ad

Chang, W., Cheng, J., Allaire, J., Xie, Y., and McPherson, J. (2019). shiny: Web Application
Framework for R. R package version 1.3.2.
rr

Charrad, M., Ghazzali, N., Boiteau, V., and Niknafs, A. (2015). NbClust: Determining the
Best Number of Clusters in a Data Set. R package version 3.0.
Bo

Cheng, J., Karambelkar, B., and Xie, Y. (2018). leaflet: Create Interactive Web Maps with
the JavaScript ’Leaflet’ Library. R package version 2.0.2.

Everitt, B. and Hothorn, T. (2011). An introduction to applied multivariate analysis with R.


Springer Science & Business Media.

Faraway, J. (2016). Extending the Linear Model with R: Generalized Linear, Mixed Effects
and Nonparametric Regression Models. Chapman & Hall/CRC Texts in Statistical Science.
CRC Press.

Feys, J. (2016). Nonparametric tests for the interaction in two-way factorial designs using r.
The R Journal, 8(1):367–378.

429
430 BIBLIOGRAFÍA

Fraley, C., Raftery, A. E., and Scrucca, L. (2019). mclust: Gaussian Mixture Modelling for
Model-Based Clustering, Classification, and Density Estimation. R package version 5.4.3.

García Pérez, A. (2008). Estadística Aplicada con R. UNED.

Greenacre, M. and Nenadic, O. (2018). ca: Simple, Multiple and Joint Correspondence
Analysis. R package version 0.71.

Gross, J. and Ligges, U. (2015). nortest: Tests for Normality. R package version 1.0-4.

Hartigan, J. A. and Wong, M. A. (1979). Algorithm as 136: A k-means clustering algorithm.

07
Journal of the Royal Statistical Society. Series C (Applied Statistics), 28(1):100–108.

Henningsen, A. (2017). micEcon: Microeconomic Analysis and Modelling. R package version

5-
0.6-14.

Husson, F., Josse, J., Le, S., and Mazet, J. (2018). FactoMineR: Multivariate Exploratory

-0
Data Analysis and Data Mining. R package version 1.41.

Hyndman, R., Athanasopoulos, G., Bergmeir, C., Caceres, G., Chhay, L., O’Hara-Wild, M.,

19
Petropoulos, F., Razbash, S., Wang, E., and Yasmeen, F. (2019). forecast: Forecasting
Functions for Time Series and Linear Models. R package version 8.7.

ISO (2010). UNE-ISO 16269-4:2010 interpretación estadística de datos – parte 4: Detección


20
y tratamiento de valores atípicos. Norma Internacional.

Kassambara, A. and Mundt, F. (2017). factoextra: Extract and Visualize the Results of
Multivariate Data Analyses. R package version 1.0.5.
or

Knuth, D. E. (1984). Literate programming. The Computer Journal, 27(2):97–111.

Komsta, L. and Novomestky, F. (2015). moments: Moments, cumulants, skewness, kurtosis


ad

and related tests. R package version 0.14.

Kuhn, M. (2019). CRAN Task View: Reproducible Research. R Task View.


rr

Lawson, J. (2015). Design and Analysis of Experiments with R. Chapman & Hall/CRC
Texts in Statistical Science. CRC Press.
Bo

Leisch, F. (2002). Sweave: Dynamic generation of statistical reports using literate data
analysis. In Compstat, pages 575–580. Springer.

López Cano, E. (2018). Estadística económica y empresarial. Libro de apuntes con licencia
Creative Commons.

Maechler, M., Rousseeuw, P., Struyf, A., and Hubert, M. (2019). cluster: ”Finding Groups
in Data”: Cluster Analysis Extended Rousseeuw et al. R package version 2.0.9.

Moen, R., Nolan, T., and Provost, L. (2012). Quality Improvement Through Planned Expe-
rimentation 3/E. McGraw-Hill Education.
BIBLIOGRAFÍA 431

Ooms, J., James, D., DebRoy, S., Wickham, H., Horner, J., and RStudio (2018). RMySQL:
Database Interface and ’MySQL’ Driver for R. R package version 0.2-15.

R Core Team (2018). foreign: Read Data Stored by ’Minitab’, ’S’, ’SAS’, ’SPSS’, ’Stata’,
’Systat’, ’Weka’, ’dBase’, ... R package version 0.8-71.

R Core Team (2019). R: A Language and Environment for Statistical Computing. R Foun-
dation for Statistical Computing, Vienna, Austria.

R Special Interest Group on Databases (R-SIG-DB), Wickham, H., and Müller, K. (2018).

07
DBI: R Database Interface. R package version 1.0.0.

Revelle, W. (2019). psych: Procedures for Psychological, Psychometric, and Personality


Research. R package version 1.8.12.

5-
Ripley, B. and Lapsley, M. (2017). RODBC: ODBC Database Access. R package version
1.3-15.

-0
Schloerke, B., Crowley, J., Cook, D., Briatte, F., Marbach, M., Thoen, E., Elberg, A., and
Larmarange, J. (2018). GGally: Extension to ’ggplot2’. R package version 1.4.0.
19
Sievert, C., Parmer, C., Hocking, T., Chamberlain, S., Ram, K., Corvellec, M., and Despouy,
P. (2019). plotly: Create Interactive Web Graphics via ’plotly.js’. R package version 4.9.0.
20
Spinu, V., Grolemund, G., and Wickham, H. (2018). lubridate: Make Dealing with Dates a
Little Easier. R package version 1.7.4.

Tukey, J. (1977). Exploratory Data Analysis. Addison-Wesley series in behavioral science.


or

Addison-Wesley Publishing Company.

Vaidyanathan, R., Xie, Y., Allaire, J., Cheng, J., and Russell, K. (2018). htmlwidgets: HTML
ad

Widgets for R. R package version 1.3.

Venables, W. and Ripley, B. (2002). Modern applied statistics with S. Statistics and compu-
ting. Springer.
rr

Walker, A. (2018). openxlsx: Read, Write and Edit XLSX Files. R package version 4.1.0.
Bo

Warnes, G. R., Bolker, B., Bonebakker, L., Gentleman, R., Liaw, W. H. A., Lumley, T.,
Maechler, M., Magnusson, A., Moeller, S., Schwartz, M., and Venables, B. (2019). gplots:
Various R Programming Tools for Plotting Data. R package version 3.0.1.1.

Wei, T. and Simko, V. (2017). corrplot: Visualization of a Correlation Matrix. R package


version 0.84.

Wickham, H. (2015). Advanced R. Chapman & Hall/CRC The R Series. CRC Press.

Wickham, H. (2019). stringr: Simple, Consistent Wrappers for Common String Operations.
R package version 1.4.0.
432 BIBLIOGRAFÍA

Wickham, H. and Bryan, J. (2019). readxl: Read Excel Files. R package version 1.3.1.
Wickham, H., Chang, W., Henry, L., Pedersen, T. L., Takahashi, K., Wilke, C., and Woo,
K. (2019a). ggplot2: Create Elegant Data Visualisations Using the Grammar of Graphics.
R package version 3.1.1.
Wickham, H., François, R., Henry, L., and Müller, K. (2019b). dplyr: A Grammar of Data
Manipulation. R package version 0.8.0.1.
Wickham, H. and Grolemund, G. (2016). R for Data Science. O’Reilly Media.

07
Wickham, H. and Henry, L. (2019). tidyr: Easily Tidy Data with ’spread()’ and ’gather()’
Functions. R package version 0.8.3.
Wickham, H., Hester, J., and Francois, R. (2018). readr: Read Rectangular Text Data. R

5-
package version 1.3.1.
Wickham, H. and Miller, E. (2019). haven: Import and Export ’SPSS’, ’Stata’ and ’SAS’

-0
Files. R package version 2.1.0.
Wickham, H. and Pedersen, T. L. (2019). gtable: Arrange ’Grobs’ in Tables. R package
version 0.3.0.
19
Wikipedia (2018). Navaja de ockham — wikipedia, la enciclopedia libre. [Internet; descar-
20
gado 25-enero-2019].
Wikipedia (2019). Paradoja de simpson — wikipedia, la enciclopedia libre. [Internet; des-
cargado 25-enero-2019].
or

Xie, Y. (2016). bookdown: Authoring Books and Technical Documents with R Markdown.
Chapman & Hall/CRC The R Series. CRC Press.
ad

Xie, Y. (2018). bookdown: Authoring Books and Technical Documents with R Markdown. R
package version 0.9.
Xie, Y. (2019a). blogdown: Create Blogs and Websites with R Markdown. R package version
rr

0.12.
Xie, Y. (2019b). knitr: A General-Purpose Package for Dynamic Report Generation in R. R
Bo

package version 1.22.


Xie, Y. (2019c). xaringan: Presentation Ninja. R package version 0.9.
Xie, Y., Allaire, J., and Grolemund, G. (2018a). R Markdown: The Definitive Guide. Chap-
man & Hall/CRC the R. Taylor & Francis.
Xie, Y., Cheng, J., and Tan, X. (2018b). DT: A Wrapper of the JavaScript Library ’Data-
Tables’. R package version 0.5.
Xie, Y., Hill, A., and Thomas, A. (2017). blogdown: Creating Websites with R Markdown.
Chapman & Hall/CRC The R Series. CRC Press.

S-ar putea să vă placă și