TÉCNICAS ESTADÍSTICAS DE VISUALIZACIÓN Y VALIDEZ POBLACIONAL CON R MEDIANTE DATOS PRAGMÁTICOS Y FÓNICOS

Author
Affiliation

Adrián Cabedo Nebot

Universitat de València

Curso diseñado para el Servei de Formació Permanent de la Universitat de València.

Email: adrian.cabedo@uv.es

Celebrado los días: 20, 23, 27 y 30 de mayo de 2024

Copyright y derechos:

Curso estadística 2024 para el Servei de Formació Permanent by Adrián Cabedo Nebot is licensed under CC BY 4.0

1 Programa del curso

1.1 Resumen

El curso ofrece una inmersión completa en el análisis y aprovechamiento de bases de datos lingüísticas, superando las limitaciones de herramientas convencionales como Excel y Google Sheets. Los participantes adquirirán una sólida comprensión de R, un lenguaje de programación esencial en análisis de datos. Además, explorarán técnicas estadísticas avanzadas para visualizar y analizar datos lingüísticos y poblacionales. Aprenderán a crear visualizaciones descriptivas impactantes utilizando GGplot2, aplicarán Mosaicplot y pruebas de chi cuadrado para investigar relaciones categóricas, identificarán patrones en datos multidimensionales mediante análisis de correspondencias y componentes, utilizarán árboles de decisiones para tomar decisiones basadas en datos y explorarán relaciones no lineales, y generarán mapas de calor para visualizar correlaciones y tendencias en datos numéricos. Este curso proporciona una base para el análisis avanzado de datos lingüísticos y poblacionales.

1.2 Objetivos específicos

• Adquirir habilidades avanzadas en el manejo de bases de datos lingüísticas más allá de las hojas de cálculo tradicionales como Excel o Google Sheets.

• Familiarizarse con el programa R, aprendiendo los conceptos básicos de programación y análisis de datos en este entorno.

• Desarrollar la capacidad de representar datos de manera efectiva utilizando técnicas de visualización avanzadas, incluyendo barras, lolipops, diagramas de caja y líneas temporales utilizando GGplot2 en R.

• Adquirir habilidades avanzadas en el análisis de datos, utilizando diversas técnicas estadísticas y de visualización, como Mosaicplot y pruebas de chi cuadrado para explorar relaciones entre variables categóricas, análisis de correspondencias múltiples y análisis de componentes para identificar patrones en datos multidimensionales, la construcción de árboles de decisiones para tomar decisiones basadas en datos y la exploración de relaciones no lineales, así como la generación de mapas de calor para visualizar patrones de correlación y tendencias en datos numéricos.

1.3 Contenidos

  1. Análisis y explotación de una base de datos lingüística: más allá de Excel/Goole Sheets

  2. Introducción básica al manejo del programa R

  3. Técnicas estadísticas de visualización y contraste poblacional

    1. Visualización descriptiva (barras, lolipops, diagramas de caja, líneas temporales…) con GGplot2.
    2. Mosaicplot y chi cuadrado Análisis múltiple de correspondencias / Análisis de componentes
    3. Árboles de decisiones
    4. Mapas de calor

1.4 Conocimientos previos

Se recomienda a las personas interesadas en realizar el curso que tengan un conocimiento básico de programas de hojas de datos como, por ejemplo, Excel o, al menos, que conozcan su estructura general. También es recomendable que hayan realizado investigaciones previas con datos.

1.5 Requisitos técnicos

Se recomienda a quien acuda al curso que tenga previamente instalado R (https://cran.rediris.es/) y RStudio (https://posit.co/download/rstudio-desktop) en su propio ordenador portátil, independientemente de que la realización del curso pueda impartirse en algún aula con ordenadores. Ambos son programas gratuitos y pueden instalarse en Linux, Windows y Mac.

1.6 Sobre los datos de este curso

En este curso, utilizaremos datos lingüísticos, específicamente datos pragmáticos y fónicos, como ejemplos prácticos para aprender a trabajar con R y desarrollar habilidades estadísticas avanzadas. Sin embargo, es importante comprender que el enfoque principal de este curso va más allá de los datos lingüísticos en sí. Las técnicas y pruebas que aprenderán aquí son universales y se pueden aplicar a una amplia gama de datos en diferentes campos y disciplinas. Nuestro objetivo es capacitar a quienes asistan para que se conviertan en analistas de datos competentes y versátiles que puedan abordar y resolver problemas utilizando R y técnicas estadísticas, independientemente del tipo de datos con el que trabajen en el futuro.

1.7 Evaluación

Los contenidos se evaluarán a través de la asistencia y las prácticas realizadas en el aula, así como de la realización de un breve cuestionario online a la finalización del curso. En este cuestionario se preguntará sobre los ejemplos prácticos expuestos en clase.

1.8 Bibliografía recomendada

Referencias recomendas
  • Este mismo documento.

  • Cabedo Nebot, A. (2021). Fundamentos de estadística con R para lingüistas. Tirant Lo Blanch.

  • Gries, S. Th. (2021). Statistics for Linguistics with R: A Practical Introduction. De Gruyter. https://doi.org/10.1515/9783110718256

  • Levshina, N. (2015). How to do Linguistics with R: Data exploration and statistical analysis. John Benjamins Publishing Company.

  • Moore, D. S., & McCabe, G. P. (1999). Introduction to the practice of statistics. W.H. Freeman.

  • Navarro, D. (2015). Learning statistics with R: A tutorial for psychology students and other beginners. (. University of Adelaide. https://learningstatisticswithr.com/

1.9 ¿Dónde voy cuando me atasco?

2 Y hubo un principio…

2.1 ¿Qué hago en mi investigación?

Images created by an AI from OpenAI

2.2 ¿Por qué analizar datos?

Image created by an AI from OpenAI

2.3 ¿Cómo siente un lingüista la estadística?

Images created by an AI from OpenAI

3 Sobre R

Funcionalidades de R
  • Análisis Estadístico: Desde análisis descriptivos básicos hasta modelos estadísticos avanzados y pruebas de hipótesis.

  • Visualización de Datos: Creación de gráficos y mapas detallados para explorar y presentar datos de manera efectiva.

  • Manipulación de Datos: Transformación, limpieza y preparación de datos para análisis mediante paquetes como dplyr y tidyr.

  • Modelado Predictivo: Desarrollo de modelos de machine learning, incluyendo regresión, clasificación y clustering.

  • Generación de Informes: Automatización de informes y creación de documentos reproducibles con R Markdown.

  • Interfaz de Programación: Desarrollo de aplicaciones interactivas y dashboards usando Shiny para presentaciones dinámicas de datos.

4 Sobre R (II)

Vale, pero, ¿qué hace realmente R?

library(tidyverse)
library(gridExtra)

frase <- unlist(strsplit("la noche en la que suplico que no 
                         salga el sol", " "))

# Crear el data frame
datos <- data.frame(
  palabra = frase,  
  tiempo = seq(0, length(frase) - 1), 
  pitch = runif(length(frase), min=80, max=90),  
  intensidad = runif(length(frase), min=70, max=85)  
)

# Create the plot with labels
plot <- ggplot(datos) +
  geom_point(aes(x = tiempo, y = pitch, color = "Pitch")) +
  geom_smooth(aes(x = tiempo, y = pitch, color = "Pitch")) +
  geom_text(aes(x = tiempo, y = pitch, label = palabra), vjust = -1, 
            hjust = 0.5, size = 3.5, check_overlap = TRUE) +  
  geom_point(aes(x = tiempo, y = intensidad, color = "Intensidad")) +
  geom_smooth(aes(x = tiempo, y = intensidad, color = "Intensidad")) +
  labs(color = "Variable") + # Add text labels above points
  theme_minimal() 
plot

Figura extraída con GGplot2. Curva melódica y de intensidad del enunciado la noche en la que no salga el sol

5 ¿Qué más puedo hacer con R?

Más funcionalidades
  • Escribir documentos científicos mediante Rmarkdown o Quarto (este mismo documento ha sido escrito en R).

  • Exportar tus documentos a varios formatos: PDF, Word o Powerpoint.

  • Modificación de las plantillas. Ejemplo: revista Normas de la UV.

  • Programar scripts que realicen funciones de manera automática. Por ejemplo, abre todos los archivos de una carpeta e impórtalos.

  • Crear aplicaciones web para consultar datos. Ej.: Oralstats.

6 ¿Desde dónde instalo R y RStudio?

  • R
  • RStudio
  • Puedes usar también una versión gratuita online (con limitaciones de uso, pero suficiente para este curso y para un uso puntual): https://posit.cloud/

7 ¿Por qué RStudio?

Justificación de R
  • RStudio es un entorno de desarrollo integrado (IDE) para R.

  • RStudio simplifica la programación en R y mejora la productividad del usuario.

  • RStudio es gratuito y de código abierto.

  • RStudio es multiplataforma (Windows, Mac y Linux).

8 Uso de Excel o Google Sheets

Uso de Excel
  • Formato tabular. Filas y columnas.

  • Organización de datos.

  • Tablas dinámicas para estadística básica.

  • Limitaciones: no permite realizar análisis estadísticos avanzados.

8.1 Bases de datos

https://github.com/acabedo/abralin_1/blob/main/idiolectal.xlsx

https://github.com/acabedo/databases/blob/main/r-libro/fonocortesia.xlsx

8.2 Ejemplo de uso: Fonocortesía

https://lookerstudio.google.com/reporting/57f127e6-8e3b-4d63-8fc7-7e0226431e9c/page/9OMAB?s=iJDWulQ3Ees

https://adrin-cabedo.shinyapps.io/oralstats_v_1_3/

8.3 Métodos de exploración avanzada en Excel o Google Sheets

Sobre tablas dinámicas

Tablas dinámicas: “Una tabla dinámica es una herramienta avanzada para calcular, resumir y analizar datos que le permite ver comparaciones, patrones y tendencias en ellos. Las tablas dinámicas funcionan de forma un poco distinta dependiendo de la plataforma que use para ejecutar Excel.” (extraído de: https://support.microsoft.com/es-es/office/crear-una-tabla-din%C3%A1mica-para-analizar-datos-de-una-hoja-de-c%C3%A1lculo-a9a84538-bfe9-40a9-a8e9-f99134456576)

8.4 Ejercicio

Explora la base de datos Idiolectal en Excel o Google Sheets.

8.5 Definir la construcción de la base de datos (estructura)

flowchart LR
  A[Investigación] --> B(Base de datos)
  B --> C{Variables}
  C --> D[elemento de análisis]
  C --> E[F0 media]
  C --> F[Intensidad media]
  C --> G[Cortesía]
  C --> H[...]
flowchart LR
  A[Investigación] --> B(Base de datos)
  B --> C{Variables}
  C --> D[elemento de análisis]
  C --> E[F0 media]
  C --> F[Intensidad media]
  C --> G[Cortesía]
  C --> H[...]

Figura. Proceso de construcción de la base de datos.

9 Uso general de R

9.1 Instalar librerías

install.packages("tidyverse")
install.packages("FactoMineR")
install.packages("factoextra")
install.packages("partykit")
install.packages("randomForest")
install.packages("DataExplorer")
install.packages("heatmap.2")
install.packages("corrplot")
install.packages("ggwordcloud")

9.2 Cargar librerías

library(tidyverse)
library(corrplot)
library(FactoMineR)
library(factoextra)
library(partykit)
library(randomForest)
library(DataExplorer)
library(gplots)
library(ggwordcloud)

9.3 Importar datos

library(readxl)
fonocortesia <- read_xlsx("databases/corpus.xlsx")

9.4 Conoce la estructura de tus datos: str o summary

Ejemplo de str para las primeras cinco columnas:

str(fonocortesia[,c(1:5)])

Ejemplo de summary para las primeras cinco columnas:

summary(fonocortesia[,c(1:5)])
 Conversacion       Cortes_Descortes   Llama_Atencion     Mediodeexpresion  
 Length:282         Length:282         Length:282         Length:282        
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
                                                                            
   F0_Inicial   
 Min.   :  0.0  
 1st Qu.:161.8  
 Median :219.7  
 Mean   :212.7  
 3rd Qu.:252.2  
 Max.   :490.0  
 NA's   :42     

9.5 Citar R

citation()
To cite R in publications use:

  R Core Team (2024). _R: A Language and Environment for Statistical
  Computing_. R Foundation for Statistical Computing, Vienna, Austria.
  <https://www.R-project.org/>.

A BibTeX entry for LaTeX users is

  @Manual{,
    title = {R: A Language and Environment for Statistical Computing},
    author = {{R Core Team}},
    organization = {R Foundation for Statistical Computing},
    address = {Vienna, Austria},
    year = {2024},
    url = {https://www.R-project.org/},
  }

We have invested a lot of time and effort in creating R, please cite it
when using it for data analysis. See also 'citation("pkgname")' for
citing R packages.
citation("tidyverse")
To cite package 'tidyverse' in publications use:

  Wickham H, Averick M, Bryan J, Chang W, McGowan LD, François R,
  Grolemund G, Hayes A, Henry L, Hester J, Kuhn M, Pedersen TL, Miller
  E, Bache SM, Müller K, Ooms J, Robinson D, Seidel DP, Spinu V,
  Takahashi K, Vaughan D, Wilke C, Woo K, Yutani H (2019). "Welcome to
  the tidyverse." _Journal of Open Source Software_, *4*(43), 1686.
  doi:10.21105/joss.01686 <https://doi.org/10.21105/joss.01686>.

A BibTeX entry for LaTeX users is

  @Article{,
    title = {Welcome to the {tidyverse}},
    author = {Hadley Wickham and Mara Averick and Jennifer Bryan and Winston Chang and Lucy D'Agostino McGowan and Romain François and Garrett Grolemund and Alex Hayes and Lionel Henry and Jim Hester and Max Kuhn and Thomas Lin Pedersen and Evan Miller and Stephan Milton Bache and Kirill Müller and Jeroen Ooms and David Robinson and Dana Paige Seidel and Vitalie Spinu and Kohske Takahashi and Davis Vaughan and Claus Wilke and Kara Woo and Hiroaki Yutani},
    year = {2019},
    journal = {Journal of Open Source Software},
    volume = {4},
    number = {43},
    pages = {1686},
    doi = {10.21105/joss.01686},
  }

9.6 Data frames

Un data frame es una estructura de datos en R que se utiliza para almacenar datos en forma tabular. Es similar a una matriz, pero cada columna puede contener un tipo de datos diferente.

data.frame(
  cortesia = c("cortés", "descortés", "cortés"),
  f0_media = c(145, 187, 135),
  sexo = c("Hombre", "Mujer", "Hombre")
)
   cortesia f0_media   sexo
1    cortés      145 Hombre
2 descortés      187  Mujer
3    cortés      135 Hombre
Visualizar data frames

Los data frames se pueden visualizar en RStudio en la pestaña “Environment” o escribiendo el nombre del data frame en la consola. Para mejorar la visualización, puedes usar la función View().

10 Tareas de limpieza y manipulación de datos

  1. Revisión y corrección de valores faltantes:

    • Identificar y manejar los valores no disponicles (NA en R).

    • Decidir si imputar los valores faltantes con la media, mediana, moda, o algún otro método, o eliminar las filas/columnas con valores faltantes.

  2. Detección y manejo de valores atípicos:

    • Identificar valores atípicos o outliers que pueden distorsionar el análisis.

    • Decidir si eliminar, transformar o tratar de otra manera estos valores.

  3. Estandarización y normalización de datos:

    • Estandarizar unidades de medida para asegurarse de que sean consistentes.

    • Normalizar o estandarizar variables si es necesario para ciertos tipos de análisis.

  4. Conversión de tipos de datos:

    • Asegurarse de que los datos estén en los tipos adecuados (por ejemplo, convertir variables categóricas a factores en R).
  5. Revisión de la coherencia de los datos:

    • Verificar que no haya inconsistencias en los datos (por ejemplo, un valor de edad negativo).

    • Asegurar que los valores categóricos estén correctamente codificados y no haya variaciones como “Hombre” y “hombre”.

  6. Eliminación de duplicados:

    • Identificar y eliminar registros duplicados que puedan afectar el análisis.
  7. Corrección de errores tipográficos y de entrada de datos:

    • Revisar y corregir errores tipográficos o de entrada manual en los datos.
  8. Creación de variables derivadas:

    • Crear nuevas variables que puedan ser útiles para el análisis, como agregar una variable que represente la diferencia entre dos fechas (edad, duración, etc.).
  9. Filtrado de datos irrelevantes:

    • Eliminar columnas o filas que no sean relevantes para el análisis específico.

10.1 ¿Qué es Tidyverse?

https://www.tidyverse.org/

Note

Colección de paquetes de R diseñados para la ciencia de datos.

  • dplyr: manipulación de datos.

  • ggplot2: visualización de datos.

  • tidyr: limpieza de datos.

  • readr: importación de datos.

10.2 Filtrar datos

  1. Ver los datos (table)
  2. Filtrar datos (filter)
Notas importantes
  • El operador %>% se utiliza para encadenar funciones en R. Se lee de izquierda a derecha, lo que facilita la lectura del código.
  • El operador == se utiliza para comparar si dos valores son iguales.
  • EL operador != se utiliza para comparar si dos valores son diferentes.
  • El operador <- se utiliza para crear un nuevo objeto (variable, dataframe…) en R.
table(fonocortesia$Cortes_Descortes)

     cortés desconocido   descortés 
        135           1         146 
fonocortesia%>%filter(Cortes_Descortes=="desconocido")
# A tibble: 1 × 36
  Conversacion Cortes_Descortes Llama_Atencion Mediodeexpresion F0_Inicial
  <chr>        <chr>            <chr>          <chr>                 <dbl>
1 VALESCO 194A desconocido      entonación     desconocido             296
# ℹ 31 more variables: F0_Final <dbl>, F0_Media <dbl>, F0_Maxima <dbl>,
#   F0_Minima <dbl>, Intensidad_Maxima <dbl>, Intensidad_Minima <dbl>,
#   Intensidad_Primera <dbl>, Intensidad_Ultima <dbl>, Intensidad_Media <dbl>,
#   Silabas <dbl>, Duracion <dbl>, Duracion_Pausa_Anterior <dbl>,
#   Duracion_Pausa_Posterior <dbl>, Continuacion_Pausa <chr>,
#   Curva_Melodica <chr>, Otro_Curva_Melodica <chr>,
#   Inflexion_Local_Interna <chr>, Tonema <chr>, Unidad_Del_Discurso <chr>, …
table(fonocortesia$Cortes_Descortes)

     cortés desconocido   descortés 
        135           1         146 
fonocortesia_filt <- fonocortesia%>%filter(Cortes_Descortes!="desconocido")

10.3 Seleccionar columnas: select

fonocortesia_sel <- fonocortesia%>%select(Cortes_Descortes, F0_Media, 
                                          Intensidad_Media)

10.4 Ordenar datos: arrange

fonocortesia_ord <- fonocortesia%>%arrange(F0_Media)

10.5 Reordernar columnas:: relocate

fonocortesia_reord2 <- fonocortesia%>%relocate(Cortes_Descortes, 
                                               .after = Intensidad_Media)

10.6 Crear nuevas columnas: mutate

Ejemplo: convertir Hz a Semitono

fonocortesia_nueva <- fonocortesia%>%mutate(F0_media_norm = 
                                              12*log2(F0_Media/1))

10.6.1 Crear columnas usando varias columnas mediante suma de variables

fonocortesia_nueva2 <- fonocortesia%>%mutate(Nueva_columna = 
                                              F0_Media + Intensidad_Media)

10.6.2 Crear columnas usando varias columnas mediante media de variables

fonocortesia_nueva3 <- fonocortesia%>%mutate(Nueva_columna = 
                                              (F0_Media + Intensidad_Media)/2)

10.6.3 Crear columnas usando varias columnas usando rowwise

fonocortesia_nueva4 <- fonocortesia%>%rowwise()%>%
  mutate(Nueva_columna = mean(c(F0_Media, Intensidad_Media),na.rm=T))

10.6.4 Crear columnas usando varias columnas usando row_number

fonocortesia_nueva5 <- fonocortesia%>%mutate(id=row_number())

10.6.5 Crear columnas usando condiciones

fonocortesia_nueva3 <- fonocortesia%>%mutate(Medio_nuevo = 
                                              ifelse(Mediodeexpresion=="Intensificación",
                                                     "Intensificación",
                                                     "Atenuación"))

10.6.6 Crear columnas usando paste

fonocortesia_nueva4 <- fonocortesia%>%mutate(Nueva_columna = 
                                              paste(Cortes_Descortes, 
                                                    Mediodeexpresion, 
                                                    sep = "_"))

10.7 Agrupar datos: group_by

fonocortesia_agrup <- fonocortesia%>%group_by(Cortes_Descortes)%>%
  mutate(F0_media_mean = mean(F0_Media,na.rm = T), 
         Intensidad_media_mean = mean(Intensidad_Media,na.rm = T))

10.8 Resumir datos: summarise

fonocortesia_resumen <- fonocortesia%>%group_by(Cortes_Descortes)%>%
  summarise(F0_media_mean = mean(F0_Media,na.rm = T), 
            Intensidad_media_mean = mean(Intensidad_Media,na.rm = T))

11 Visualización de datos

En esta sección, aprenderemos a visualizar datos utilizando el paquete ggplot2 en R. GGplot2 es una librería de visualización de datos en R que permite crear gráficos de alta calidad de manera sencilla y flexible.

11.1 ¿Por qué visualizar datos?

Visualizar datos es una parte fundamental del análisis de datos. Las visualizaciones permiten explorar los datos, identificar patrones y tendencias, comunicar resultados y conclusiones, y tomar decisiones adecuadas y coherentes. Las visualizaciones efectivas pueden ayudar a resumir y presentar datos de manera clara y concisa; esto facilita la interpretación y comprensión de los datos.

Images created by an AI from OpenAI

11.2 ¿Qué es ggplot2?

GGplot2 es una librería de visualización de datos en R que permite crear gráficos de alta calidad de manera sencilla y flexible. GGplot2 se basa en la gramática de gráficos, un enfoque que descompone los gráficos en componentes básicos (datos, estética, geometría, estadísticas y facetas) y permite construir gráficos complejos combinando estos componentes de manera intuitiva.

11.3 Tipos de gráficos

Los gráficos más comunes que se pueden crear con ggplot2 incluyen: gráfico de barras, gráfico de líneas, gráfico de dispersión, gráfico de violín, gráfico de áreas, gráfico de burbujas, gráfico de donut, gráfico de lolipop, gráfico de mapa de calor, gráfico de densidad, gráfico de correlaciones, gráfico de árbol…

11.3.1 Gráficos de barras

11.3.1.1 Barras 1

ggplot(fonocortesia, aes(x=Cortes_Descortes)) + 
  geom_bar(stat="count")

11.3.1.2 Barras 2

fonocortesia%>% ggplot(aes(x=Cortes_Descortes, fill=Mediodeexpresion)) + 
  geom_bar(stat="count")

11.3.1.3 Barras 3

fonocortesia%>% ggplot(aes(x=Cortes_Descortes, fill=Tonema)) + 
  scale_x_discrete(guide = guide_axis(n.dodge=3))+  
  geom_bar(stat="count") + facet_wrap(~Tonema)

11.3.1.4 Barras 4

fonocortesia%>% ggplot(aes(x=Cortes_Descortes, fill=Mediodeexpresion)) + 
  geom_bar(stat="count") + coord_flip()

11.3.1.5 Barras 5

data <- fonocortesia%>%group_by(Cortes_Descortes,Mediodeexpresion)%>%
  summarise(Total = sum(n())) %>%
  mutate(Percentage = Total / sum(Total) * 100)

ggplot(data, aes(x=Cortes_Descortes,y=Percentage, 
                 fill=Mediodeexpresion))+
  geom_bar(stat="identity") + geom_text(
    aes(label = paste(Total, "(", sprintf("%.1f%%", Percentage), ")", 
                      sep = "")),
    position = position_stack(vjust = 0.5), 
    size = 2  # Adjust text size
  ) + coord_flip() 

ggplot(data%>%filter(Mediodeexpresion%in%
                       c("Atenuación","Intensificación","desconocido")), aes(x=Cortes_Descortes,y=Percentage, fill=Mediodeexpresion))+
  geom_bar(stat="identity") + geom_text(
    aes(label = paste(Total, "(", sprintf("%.1f%%", 
                                          Percentage), ")", sep = "")),
    position = position_stack(vjust = 0.5), 
    size = 2  # Adjust text size
  ) + coord_flip() 

11.3.2 Diagramas de caja

ggplot(fonocortesia, aes(y=F0_Media,fill=Cortes_Descortes)) + 
  geom_boxplot()

11.3.3 Gráfico de correlaciones

library(corrplot)
datosnum <- fonocortesia%>%select_if(is.numeric)
correlaciones <- cor(datosnum,use = "complete.obs")
corrplot(correlaciones, method = "color",tl.col = "black",tl.cex = 0.7)

11.3.4 Gráficos de líneas

ggplot(fonocortesia%>%mutate(id=row_number()), 
       aes(x=id,y=F0_Media,
      fill=Cortes_Descortes, 
color = Cortes_Descortes)) + geom_line() + geom_point()

11.3.5 Gráficos de dispersión

ggplot(fonocortesia%>%filter(between(Intensidad_Media,60,90), 
F0_Media<300), aes(x=F0_Media, y=Intensidad_Media))  +
  geom_point() + geom_smooth(method = "lm", se = FALSE, color = "blue")

11.3.6 Gráficos de burbujas

ggplot(fonocortesia, aes(x=Duracion, y=Intensidad_Media, 
size=F0_Media, fill = Cortes_Descortes, color=Cortes_Descortes)) + 
  geom_point()

11.3.7 Gráficos de áreas

ggplot(fonocortesia%>%mutate(id=row_number())%>%
filter(Cortes_Descortes!="desconocido"), 
aes(x=id, y=F0_Media, fill=Cortes_Descortes)) + 
  geom_area() + facet_wrap(~Cortes_Descortes)

11.3.8 Gráficos de violín

El gráfico de violín es una combinación de un diagrama de caja y un gráfico de densidad. Muestra la distribución de los datos en función de una variable categórica.

ggplot(fonocortesia, aes(x=Cortes_Descortes, y=F0_Media, 
color=Cortes_Descortes, fill=Cortes_Descortes)) + 
  geom_violin() + coord_flip()

11.3.9 Gráficos de densidad

La densidad de un conjunto de datos es una estimación de la distribución de probabilidad subyacente de los datos. Los gráficos de densidad muestran la distribución de los datos en forma de una curva suave.

ggplot(fonocortesia, aes(x=F0_Media)) + 
  geom_density()

11.3.10 Gráficos de lolipop

lolipop <- fonocortesia%>%group_by(Cortes_Descortes)%>%
  summarise(f0_mean=mean(F0_Media,na.rm = T))

ggplot(lolipop, aes(x=Cortes_Descortes, y=f0_mean, 
                    fill = Cortes_Descortes, color =Cortes_Descortes)) +
  geom_point(aes(size = f0_mean), alpha = 0.6) +  
  geom_segment(aes(x=Cortes_Descortes, xend=Cortes_Descortes, 
                   y=0, yend=f0_mean)) +coord_flip()

11.3.11 Gráficos de donut

data <- fonocortesia%>%group_by(Cortes_Descortes)%>%
  summarise(count=n())%>%na.omit()%>%
  rename(category=Cortes_Descortes, count=count)

data$fraction <- data$count / sum(data$count)

data$ymax <- cumsum(data$fraction)

data$ymin <- c(0, head(data$ymax, n=-1))

data$labelPosition <- (data$ymax + data$ymin) / 2

data$label <- paste0(data$category, "\n value: ", data$count)

ggplot(data, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=category)) +
  geom_rect() +
  geom_label( x=3.5, aes(y=labelPosition, label=label), size=3) +
  scale_fill_brewer(palette=3) +
  coord_polar(theta="y") +
  xlim(c(2, 4)) +
  theme_void() +
  theme(legend.position = "none")

11.3.12 Gráficos de mapa de calor

library(gplots)
png(filename='heatmap.png', width=2400, height=1550, res=300)


p <- fonocortesia %>%
  group_by(Cortes_Descortes) %>%
  summarise_all(mean, na.rm = TRUE) %>%
  column_to_rownames(var="Cortes_Descortes") %>%
  select_if(is.numeric) %>%
  select(F0_Media, Duracion, Intensidad_Media)

heatmap.2(as.matrix(p), na.rm = TRUE, 
          scale="column", cexCol = 0.8, cexRow = 0.8)

11.3.13 Nube de palabras

library(ggwordcloud)

df_words <- fonocortesia %>%select(Cortes_Descortes,
                                   Elemento_Analizado)%>%
  mutate(word = str_split(Elemento_Analizado, " "),
         cortesia=Cortes_Descortes) %>%  # Dividir el texto en palabras
  unnest(word) %>%  group_by(cortesia,word) %>%  
  summarise(frecuencia = n())%>%
  mutate(word2 = gsub("[^a-zA-Z]","",word))%>%filter(frecuencia>2) 


ggplot(df_words%>%filter(!word%in%c("A:","B:","C:","L:","M:","(...)")), 
       aes(label = word2, size = frecuencia,color=cortesia)) +
  geom_text_wordcloud(area_corr = TRUE) +
  scale_size_area(max_size = 20) +
  theme_minimal()

12 Ejercicios

  1. Importa los datos del archivo idiolectal.xlsx y explora su estructura.
library(readxl)
idiolectal <- read_excel("databases/idiolectal.xlsx")
str(idiolectal)
tibble [1,218 × 27] (S3: tbl_df/tbl/data.frame)
 $ ...1                : chr [1:1218] "1" "2" "3" "4" ...
 $ filename            : chr [1:1218] "5pangelreal" "5pangelreal" "5pangelreal" "5pangelreal" ...
 $ spk                 : chr [1:1218] "angelreal" "angelreal" "angelreal" "angelreal" ...
 $ phon                : chr [1:1218] "i*" "e*" "e*" "e*" ...
 $ word                : chr [1:1218] "intrusismo" "momento" "ser" "ser" ...
 $ ip                  : chr [1:1218] "claro a lo mejor ahí sí que se podría considerar intrusismo" "en aquel momento" "puede ser" "puede ser" ...
 $ ip_dur              : num [1:1218] 2441 716 456 378 1567 ...
 $ tmin                : num [1:1218] 1982616 1983404 1984151 1985149 1986698 ...
 $ tmax                : num [1:1218] 1982703 1983443 1984254 1985221 1986789 ...
 $ words               : num [1:1218] 11 3 2 2 8 1 3 3 9 8 ...
 $ dur                 : num [1:1218] 87 39 103 72 91 35 130 118 57 71 ...
 $ toneme              : chr [1:1218] "yes" "yes" "yes" "yes" ...
 $ desplazamiento      : chr [1:1218] "no" "no" "no" "no" ...
 $ dur_first           : num [1:1218] 31 84 26 20 27 60 130 118 168 37 ...
 $ word_first          : chr [1:1218] "claro" "aquel" "puede" "puede" ...
 $ desplazamiento_first: chr [1:1218] NA NA NA NA ...
 $ phon_preanac        : chr [1:1218] NA "e" NA NA ...
 $ word_preanac        : chr [1:1218] NA "en" NA NA ...
 $ dur_preanac         : num [1:1218] NA 34 NA NA 69 NA NA 174 152 51 ...
 $ tonemeMAS           : num [1:1218] NA -1.31 NA NA 4.11 ...
 $ circunflejo         : chr [1:1218] "no" "no" "no" NA ...
 $ MAStag              : chr [1:1218] NA "PV" NA NA ...
 $ body                : num [1:1218] NA 26.4 NA NA NA ...
 $ spk2                : chr [1:1218] "5pangelreal" "5pangelreal" "5pangelreal" "5pangelreal" ...
 $ spk3                : chr [1:1218] "5pangelrealangelreal" "5pangelrealangelreal" "5pangelrealangelreal" "5pangelrealangelreal" ...
 $ genre               : chr [1:1218] "5p" "5p" "5p" "5p" ...
 $ tonemes             : chr [1:1218] NA "suspendido" NA NA ...
  1. Haz dos dataframes según la variable genre. Cada uno de ellos debe contener los datos solo de un género.
table(idiolectal$genre)

 5p pod 
609 609 
idiolectal_5p <- idiolectal%>%filter(genre=="5p")
idiolectal_pod <- idiolectal%>%filter(genre=="pod")
  1. Crea un dataframe llamado “piquito_relocado” y ubica la variable tonemes delante de genre
piquito_relocado <- idiolectal%>%relocate(tonemes, .before = genre)
  1. Visualiza en un gráfico de líneas en el dataframe “idiolectal” la evolución de los tonemas solo en el archivo 5pangelreal.
library(tidyverse)
idiolectal%>%filter(filename=="5pangelreal")%>%
  ggplot(aes(x=tmin,y=tonemeMAS, color=spk, fill=spk)) + 
  geom_line() + geom_point()

  1. Crea un dataframe llamado “piquito_filtrado” en el que filtre todos los datos que no sean NA en la variable tonemeMAS.
piquito_filtrado <- idiolectal%>%filter(!is.na(tonemeMAS))
  1. Crea un diagrama de caja de la variable dur en el dataframe “idiolectal”. ¿Sabrías crearlos por hablante en un mismo gráfico? Hay varias maneras de hacerlo.
ggplot(idiolectal, aes(x=spk, y=dur, fill=spk)) + geom_boxplot()

ggplot(idiolectal, aes(x=spk, y=dur, fill=spk)) + 
  scale_x_discrete(guide = guide_axis(n.dodge=5))+ 
  geom_boxplot() + facet_wrap(~spk,ncol = 5)

  1. ¿Cuántos tonemas hay en el dataframe “idiolectal”? Visualízalo en una tabla y en un gráfico de barras usando la base de datos “piquito_filtrado”
table(piquito_filtrado$MAStag)

other    PI   PII  PIII   PIX    PV  PVIa  PVIb  PVII PVIII   PXa   PXI PXIIa 
  289   234     8     3     9   151    35    13     3    29     1     5    64 
ggplot(piquito_filtrado, aes(x=MAStag)) + geom_bar()

  1. Correlaciona en el dataframe “idiolectal” las variables numéricas de este estudio.
library(corrplot)
correlaciones <- cor(idiolectal%>%
                       select_if(is.numeric),use = "complete.obs")
corrplot(correlaciones, method = "color",
         tl.col = "black",tl.cex = 0.7)

  1. Haz una tabla de frecuencias de cada hablante en el dataframe “idiolectal” y saca la media de tonemeMAS, de dur y de body
idiolectal%>%group_by(spk)%>%summarise(
  tonemeMAS_mean = mean(tonemeMAS,na.rm = T), 
  dur_mean = mean(dur,na.rm = T), 
  body_mean = mean(body,na.rm = T))
# A tibble: 5 × 4
  spk         tonemeMAS_mean dur_mean body_mean
  <chr>                <dbl>    <dbl>     <dbl>
1 angelreal            1.02      93.7      5.88
2 dufort               2.75     106.       4.38
3 estepa               0.240    130.      -4.50
4 pzorro              11.0       99.8      7.28
5 rcastellano          1.10      87.0     15.4 
  1. Visualiza la información anterior en un mapa de calor.
library(gplots)
mapacalor <- idiolectal%>%group_by(spk)%>%summarise(
tonemeMAS_mean = mean(tonemeMAS,na.rm = T), 
dur_mean = mean(dur,na.rm = T), 
body_mean = mean(body,na.rm = T))%>%
  column_to_rownames(var="spk")
heatmap.2(as.matrix(mapacalor), na.rm = TRUE, 
scale="column", cexRow = 0.5, cexCol = 0.5)

13 Estadística descriptiva

Cuando hablamos de estadística descriptiva normalmente nos estamos refiriendo a un conjunto de operaciones básicas como la media, la mediana, la moda, la desviación típica, etc. También entraría dentro de la estadística descriptiva el estudio de las distribuciones de las variables de nuestras bases de datos.

13.1 Precaución

Correlaciones espúreas (ápud Levshina, 2015)

https://www.tylervigen.com/spurious-correlations

13.2 Tratamiento previo

Antes de empezar este apartado sobre estadística descriptiva crearemos una modificación de la base de datos corpus que hemos utilizado en el tema anterior. En esta nueva base de datos, que llamaremos corpusren, hemos renombrado las variables para que sean más comprensibles y hemos eliminado los casos en los que la variable Cortes_Descortes tiene el valor desconocido. También hemos eliminado los casos en los que la variable Tonema tiene el valor desconocido. La base de datos corpusren es la que utilizaremos en este tema.

library(kableExtra)
library(tidyverse)
library(corrplot)
library(psych)
library(flextable)
library(FactoMineR)
library(factoextra)
library(partykit)
library(readxl)
library(randomForest)
library(DataExplorer)
library(gplots)
library(ggwordcloud)
corpus <- read_excel("databases/corpus.xlsx")
corpusren <- corpus %>% rename(
  

  
  conv = Conversacion,  cort = Cortes_Descortes, 
  Llam = Llama_Atencion,  med = Mediodeexpresion,  
  F0I = F0_Inicial,  F0F = F0_Final,  
  F0M = F0_Media,  F0X = F0_Maxima,  F0N = F0_Minima,  
  IU = Intensidad_Ultima,  IM = Intensidad_Media,  
  IN = Intensidad_Minima,  IX = Intensidad_Maxima,  
  IP = Intensidad_Primera,  Sil = Silabas,  
  dur = Duracion,  DPA = Duracion_Pausa_Anterior,  
  DPP = Duracion_Pausa_Posterior,  CP = Continuacion_Pausa,  
  Cur = Curva_Melodica,  OCur = Otro_Curva_Melodica,  
  ILI = Inflexion_Local_Interna,  To = Tonema,  
  Disc = Unidad_Del_Discurso,  Vmod = Valormodal,  
  OVmod = Otro_Valor_Modal,  Fton = Fenomeno_Tonal, 
  Fdur = Fenomeno_Duracion,  Fpau = Fenomeno_Pausas,  
  Fve = Fenomeno_Velocidad,  Fam = Fenomeno_Amplitud, 
  UF = Unidad_Fonica,  EPra = Estrategia_Pragmatica,  
  Efec = Efecto_Pragmatico_Asociado,  EA = Elemento_Analizado,  
  Fr = Fragmento)%>%filter(cort!="desconocido", To != "desconocido")

options(scipen = 1, digits = 2)

13.3 Tablas simples o tablas de contingencia

Tablas de contingencia
  • Procedimiento table
  • Procedimiento flextable de la librería flextable.
table(corpusren$cort)

   cortés descortés 
      131       145 

Ejemplo con table

set_flextable_defaults(
  font.family = "Times", 
  font.size = 11,
  padding = 0,
  font.color = "black",
  table.layout = "autofit",
  digits = 1,
  theme_fun = "theme_box"
  )

p <- as.data.frame(table(corpusren$cort))
flextable(p)

Var1

Freq

cortés

131

descortés

145

Con la variable tonema:

flextable(corpusren%>%group_by(To)%>%
            summarise(cantidad=n())%>%arrange(cantidad))

To

cantidad

circunflejo

27

suspendido

67

ascendente

84

descendente

98

Tabla resumen de las frecuencias de la variable Tonema

Procedimiento prop.table de la librería base. Sirve para calcular las proporciones de las tablas de contingencia.

Proporción por fila:

prop.table(table(corpusren$To,corpusren$cort),margin = 1)
             
              cortés descortés
  ascendente    0.27      0.73
  circunflejo   0.44      0.56
  descendente   0.51      0.49
  suspendido    0.69      0.31

Proporción por columna:

prop.table(table(corpusren$To,corpusren$cort),margin = 2)
             
              cortés descortés
  ascendente   0.176     0.421
  circunflejo  0.092     0.103
  descendente  0.382     0.331
  suspendido   0.351     0.145

Propoción del total:

prop.table(table(corpusren$To,corpusren$cort))
             
              cortés descortés
  ascendente   0.083     0.221
  circunflejo  0.043     0.054
  descendente  0.181     0.174
  suspendido   0.167     0.076

Debemos recordar, no obstante, que nos encontramos en este caso en una fase de descripción y que, por tanto, sin la aplicación de pruebas estadísticas inferenciales no podemos controlar de manera precisa la repercusión de estos datos, que pertenecen a nuestra muestra, en relación con la población general de potenciales enunciados corteses o descorteses del español hablado.

La librería flextable permite realizar las mismas dos operaciones que hemos realizado anteriormente, la de observar las proporciones por columnas y por filas, en una misma tabla.

proc_freq(corpusren, "cort","To",)%>%fontsize(size = 10,part="all")

cort

To

ascendente

circunflejo

descendente

suspendido

Total

cortés

Count

23 (8.3%)

12 (4.3%)

50 (18.1%)

46 (16.7%)

131 (47.5%)

Mar. pct (1)

27.4% ; 17.6%

44.4% ; 9.2%

51.0% ; 38.2%

68.7% ; 35.1%

descortés

Count

61 (22.1%)

15 (5.4%)

48 (17.4%)

21 (7.6%)

145 (52.5%)

Mar. pct

72.6% ; 42.1%

55.6% ; 10.3%

49.0% ; 33.1%

31.3% ; 14.5%

Total

Count

84 (30.4%)

27 (9.8%)

98 (35.5%)

67 (24.3%)

276 (100.0%)

(1) Columns and rows percentages

13.4 Resumen estadístico

Los resúmenes estadísticos permiten explorar de manera inicial una base de datos. Por defecto, el comando general para efectuar esa operación de resumen es summary. Con este comando, R ofrecerá una pantalla con una muestra de las frecuencias más pobladas de las variables categóricas y datos de estadística descriptiva como la media, la mediana, los valores mínimos y máximos, los valores vacíos, el primer y el tercer cuartil.

Con finalidad de ejemplificación, podemos observar valores de algunas variables de la base de datos Fonocortesía:

kable(summary(corpusren[,c(2,23,5:7)]))
cort To F0I F0F F0M
Length:276 Length:276 Min. : 0 Min. : 0 Min. : 0
Class :character Class :character 1st Qu.:166 1st Qu.:146 1st Qu.:180
Mode :character Mode :character Median :220 Median :211 Median :221
NA NA Mean :214 Mean :212 Mean :216
NA NA 3rd Qu.:252 3rd Qu.:267 3rd Qu.:251
NA NA Max. :490 Max. :519 Max. :420
NA NA NA’s :41 NA’s :41 NA

Observar equilibrio en los datos. ¿Se han recogido un número similar de casos de cada conversación?

Si quisiéramos conocer, por ejemplo, el total de recuento por conversación podríamos ejecutar el comando table. En el siguiente ejemplo, se combina table, con la propiedad arrange de la librería dplyr que permite ordenar los datos:

flextable(table(corpusren$conv) %>% 
            as.data.frame() %>% arrange(desc(Freq)))

Var1

Freq

VALESCO 025A

45

VALESCO 130A

39

VALESCO 171A

24

VALESCO 114A

23

VALESCO 183A

22

VALESCO 37B

21

VALESCO 84A

20

VALESCO 140A

19

VALESCO 80A

11

VALESCO 129B

10

VALESCO 69A

10

VALESCO 162A

9

VALESCO 194A

8

VALESCO 126A

7

VALESCO 165A

3

VALESCO 179B

3

VALESCO 193A

1

VALESCO 279b

1

En general, hay una distribución más o menos constante por conversación, de 10 a 20 casos de media, aunque la 25A y la 130A, como decíamos anteriormente, recogen el mayor número de enunciados corteses o descorteses recogidos.

13.4.1 Valores estadísticos generales de una variable

También puede darse la situación de que estemos interesados en una variable en particular. Por ejemplo, si queremos recoger valores estadísticos para la variable F0_Media (F0M), podemos usar el comando describe de la librería psych. Los valores concretos que se recogerán serán los siguientes:

describe(corpusren$F0M)
   vars   n mean sd median trimmed mad min max range skew kurtosis  se
X1    1 276  216 61    221     217  52   0 420   420 -0.3        1 3.7

Podemos describir cada uno de estos valores estadísticos:

  1. Vars. Número de variables analizadas. En este caso hemos tomado los valores únicamente de la variable F0_media.
  2. n. Cantidad de elementos: 276
  3. Mean. Media de la variable, que serían 216 Hz.
  4. Sd. Desviación típica, es decir, los datos se desvían 61 Hz de media por encima o por debajo, precisamente, de la media de 216 Hz que se indicaba previamente.
  5. Median. Valor central de la variable, por encima y por debajo del cual se sitúan la mitad superior e inferior de los datos. Es un valor robusto que no se ve afectado por la presencia de datos extremos positivos o negativos. En este caso, sería algo superior a la media: 221 Hz.
  6. Trimmed. Se trata de la media con valores extremos eliminados. Serían 216.6 Hz
  7. mad. Desviación típica de la mediana. 52 Hz.
  8. min Valor mínimo recogido para esta variable. En el caso de la F0_media, se recoge 0 porque hay algún dato vacío.
  9. max. Valor máximo de la variable. Esta opción sirve para detectar casos extremos. Para la F0_media sería 420 Hz, que seguramente sea un error de alguna muestra de audio o, también, puede tratarse de un enunciado afectado por fenómenos paralingüísticos como las risas o por algún ruido medioambiental (golpes, por ejemplo).
  10. range. Se trata del rango de valores entre el valor mínimo y el valor máximo.
  11. skew. Es el grado de asimetría. Si se acerca a 0, como es el caso, significa que la distribución de la variable está ciertamente normalizada y que los valores se distribuyen de manera equilibrada alrededor de la media y la mediana y se distribuyen en forma positiva o negativa a los lados siguiendo la regla expuesta anteriormente del 68 %, 95 % y 99.8 %.
  12. kurtosis. La kurtosis es la forma de la curva de la distribución. Un valor de 1.01 indica que la curva refleja una concentración de valores algo más elevada de lo normal en el centro, es decir, hay más valores cercanos a la media, aunque no es un valor desproporcionado. De hecho, asimetría y kurtosis están relacionados.
  13. se. Es el error estándar de la media. En el caso de F0_Media indica que la media de nuestra muestra, 216 Hz, se encuentra seguramente a una distancia máxima de 3.7 desviaciones típica de la presunta media de toda la población. En general, valores pequeños de este valor indican que nuestra muestra es bastante adecuada. Al mismo tiempo, si obtuviéramos más datos, el valor se iría reduciendo de manera exponencial.

13.4.2 Valores estadísticos por grupos

Todos los valores que hemos tomado para la variable en conjunto pueden especificarse por una variable de grupo; por ejemplo, podemos observar los valors de estadística descriptiva para F0_Media según los grupos establecidos en la variable Cortes_Descortes; en la librería psych puede realizarse mediante el comando describeBy:

p <- describeBy(x=corpusren$F0M,group = corpusren$cort)
p

 Descriptive statistics by group 
group: cortés
   vars   n mean sd median trimmed mad min max range skew kurtosis  se
X1    1 131  198 66    200     200  71   0 333   333 -0.4     0.27 5.8
------------------------------------------------------------ 
group: descortés
   vars   n mean sd median trimmed mad min max range skew kurtosis  se
X1    1 145  232 52    228     230  41  92 420   327 0.43     0.94 4.3

13.5 Valores del resumen estadístico

En caso de querer acceder a un valor concreto del resumen estadístico, podemos obtenerlos mediante los siguientes comandos:

mean(x = corpus$F0_Media)
median(x = corpus$F0_Media)
max(x = corpus$F0_Media)
min(x = corpus$F0_Media)
range(x = corpus$F0_Media)
quantile(x = corpus$F0_Media)
IQR(x = corpus$F0_Media)
var(x = corpus$F0_Media)
sd(x = corpus$F0_Media)
skew(x = corpus$F0_Media)
skew(x = corpus$Duracion)
kurtosi(x = corpus$F0_Media)

13.6 Informe con DataExplorer

La librería DataExplorer permite crear un informe general en forma de gráficos sobre todas las variables de nuestras bases de datos, sean estas numérica o categóricas. Toda la información que aporta esta librería se podría computar también manualmente realizando gráficos de barra, por ejemplo, de cada variable nominal de la base de datos; no obstante, es interesante poder registrar toda la información con una sola instrucción.

Esta librería no solo va a informar sobre la estructura de las variables, frecuencia de las categorías, por ejemplo, sino que también va a indicar cuántos datos están omitidos, tanto variables como variantes.

Más allá de la visualización descriptiva, DataExplorer también puede ejecutar un análisis de componentes principales que, aunque no lo tratamos en el contexto de este libro, sirve para reducir el nivel de variabilidad de los datos; también puede realizarse un análisis de correlaciones entre las variables.

Es conveniente que estas últimas dos opciones, correlaciones y análisis de componentes principales, las desactivemos en el código de ejecución de DataExplorer, dado que una base de datos de Humanidades suele incorporar gran número de variantes en sus variables y, por esta razón, el consumo de recursos de la librería sería innecesariamente alta, más si cabe cuando seguramente nuestro objetivo principal será observar de modo general los datos.

library(DataExplorer)
DataExplorer::create_report(corpusren, 
config = configure_report(add_plot_density = FALSE, 
                          
                          add_plot_qq = FALSE, 
                          add_plot_correlation = FALSE,
                          add_plot_prcomp = FALSE,
                          plot_bar_args = list(maxcat=60)))

Dado que el informe resultante de la librería se configura en formato de HTML, ofrecemos en las siguientes imágenes capturas de pantalla de ese informe. En primer lugar, en la siguiente imagen podemos observar cómo DataExplorer genera gráficos de histograma para cada variables numérica de la base de datos.

En segundo lugar, la siguiente captura de pantalla incorpora la representación en gráficos de barra de todas las variables categóricas.

De entrada, en la anterior imagen podemos ver las variables que tienen una gran cantidad de categorías en su interior, como es el caso de la conversación, de Llama la atención, de Medio de expresión, etc.

14 Relaciones, agrupaciones y visualización

Son muchas las pruebas estadísticas o técnicas de visualización que pueden realizarse mediante R. Sin embargo, en esta sección vamos a centrarnos específicamente en cuatro: la prueba de chi cuadrado, la prueba T Test (o ANOVA, para más de dos categorías), el análisis múltiple de correspondencias, el árbol de decisiones y la prueba de Random Forest.

14.1 Chi cuadrado

En palabras de Moore (2005: 620): “el estadístico Ji cuadrado es una medida de la diferencia entre los recuentos observados y los recuentos esperados en una tabla de contingencia”.

La chi cuadrado puede utilizarse de dos maneras distintas. En la primera, puede que nos interese conocer si hay alguna frecuencia categorial que sea distinta de la esperada bajo unas condiciones de proporcionalidad que pueden ser de equilibrio (misma proporción esperada para cada categoría inicialmente) o de un desajuste ya esperado (por ejemplo, imaginemos que conocemos que proporcionalmente siempre va a haber más casos de cortesía que descortesía en la conversación espontánea, con una proporción ya conocida de 70 % de cortesía y 30 % de descortesía). Esta primera manera de aplicar la chi-cuadrado toma una única variable y contrapone las frecuencias de sus categorías entre sí. Es el modo que se conoce como bondad de ajuste.

En la segunda manera de aplicar la chi cuadrado, la que suele ser más habitual, dos variables categóricas se cruzan a modo de tabla de contingencia. En este cruce, se pretende observar si hay alguna relación de dependencia entre las dos variables categóricas; esto es, si una categoría de una variable concreta (hombre de la variable sexo, por ejemplo) está relacionada con la categoría o categorías de otra variable (descortesía de la variable Cortes_Descortes). Si está relación es llamativa o significativa, seguramente encontraremos una cantidad de casos muy amplia para este cruce de variables.

Según Moore (2013: 621):

Interpreta el estadístico Ji cuadrado, X2, como una medida de la distancia entre los recuentos observados y los recuentos esperados. Como cualquier distancia, su valor siempre es cero o positivo. Es cero sólo cuando los recuentos observados son exactamente iguales a los recuentos esperados. Los valores de X2 grandes constituyen una evidencia en contra de H0, ya que indican que los recuentos observados están lejos de lo que esperaríamos si H0 fuera cierta. Aunque la hipótesis alternativa Ha es de muchas colas, la prueba Ji cuadrado es de una cola, ya que cualquier violación de H0 tiende a producir un valor de X2 grande. Los valores pequeños de X2 no constituyen ninguna evidencia en contra de H0.

La prueba de chi cuadrado, por lo tanto, indica cuál es la posible relación entre las variables, pero no establece de inicio qué categorías están signficativamente relacionadas. Para ello, hay que usar un valor derivado calculado por la prueba conocido como residuo estandarizado. Aquellos residuos que tengan unos valores superiores o inferiores a 1.96 se considera que están excesivamente muy o poco representados en nuestra base de datos en el supuesto de que no hubiera relación entre las variables. Dicho de otro modo, en un mundo hipotético en el que estuviéramos seguros de que no hay relación entre las variables, las frecuencias que encontramos para el cruce de esas dos variables serían muy extraños o anómalos.

Como es difícil que esto sea así, se acepta que hay una alta probabilidad de que H0 no sea cierta y, dándole la vuelta, quiere decir que sí se observa una relación entre ambas variables. Hay, además, otro concepto que debe tenerse en cuenta: la fuerza de la relación. Esta no la establece ni el valor de la prueba ni siquiera el valor p (que no mide esto), sino que queda señalada por otros valores como la V de Krámer (todo lo superior a 60-70 % indica una relación fuerte).

En general, el resultado de la prueba de la chi-cuadrado arrojará varios datos que pasamos a describir:

  1. Datos observados. Se trata del recuento por categoría o por cruces de categorías.
  2. Datos esperados. Es la frecuencia de datos que se hubiera esperado encontrar bajo un supuesto de no relación específica entre las variables.
  3. Grado de libertad. A nivel técnico, los grados de libertad establecen parámetros para poder interpretar bien las relaciones inferenciales entre las categorías que se cruzan. En general, va a estar relacionado con la cantidad de datos que podemos asignar de manera arbitraria, con anterioridad a que un valor sea tomado automáticamente. En la prueba chi cuadrado los grados de libertad son número de filas menos uno por número de columnas menos uno. Por ejemplo, una tabla de 2 x 2 tiene un solo grado de libertad, mientras que una columna de 2 x 3 tiene dos grados de libertad.
  4. Valor del estadístico. En estadística inferencial el valor de la prueba estadística vendrá dado por defecto. Valores altos suponen un buen argumento para rechazar H0, mientras que valores bajos suponen lo contrario.
  5. Valor p. Este es el valor en el que realmente nos centraremos. Si es inferior a 0.05 indicará que hay una relación significativa entre las variables para un nivel de significación del 95 %, que es de los más habituales en estudios que siguen el método científico basado en datos. Lo que no sabremos es en qué medida; para ello necesitaremos los residuos, que se exponen más abajo.
  6. Residuos. Los residuos estandarizados de Pearson son una medida general que relaciona la diferencia entre los datos observados y esperados y los proyecta sobre el eje de una estandarización normalizada. De esta manera, todo cruce de categorías que incluya un valor superior o inferior a 1.96 indicará de manera llamativa que ese cruce está muy por encima o muy por debajo de lo que esperaríamos encontrar bajo un supuesto de no relación entre las variables.

14.1.1 Bondad de ajuste

corpusren %>%group_by(cort)%>%summarise(cantidad=n())%>%
  arrange(desc(cantidad))%>%flextable()

cort

cantidad

descortés

145

cortés

131

Tabla de frecuencias absolutas de la variable combinación fonética

Valores de la prueba chi cuadrado

table <- table(corpusren%>%select(cort))
chi <- chisq.test(table,p = c(1/2,1/2))
chi

    Chi-squared test for given probabilities

data:  table
X-squared = 0.7, df = 1, p-value = 0.4

Valores de los residuos estandarizados

chi$residuals
cort
   cortés descortés 
     -0.6       0.6 

14.1.2 Chi cuadrado entre dos variables

La prueba de chi-cuadrado es una de las más conocidas en disciplina humanística para observar la relación entre dos variables categóricas. En esta sección vamos a analizar relaciones de variables de las dos bases de datos de este estudio. En primer lugar, observaremos la relación entre el tipo de combinación fonética y género para transmitir atenuación; en segundo lugar, analizaremos la relación entre la variable Cortes_Descortes y los tonemas.

14.1.2.1 Relación entre cortesía y tonemas

En el siguiente ejemplo, presentamos la relación entre dos variables de la base de datos Fonocortesía: la variable Cortes_Descortes y la variable tonema. El interés en este caso reside en conocer si la parte final de los enunciados tiene un comportamiento melódico distinto en relación con la categoría cortés o descortés.

En primer lugar, por tanto, recogemos el código de la chi cuadrado en una variable llamada pruebachi; esta no es una operación necesaria, pero realmente simplifica el acceso a otras opciones como los valores observados, esperados y los residuos. En esta sección, además, utilizaremos el comando assocstats de la librería vcd que aporta datos relevantes como la V de Crámer, que sirve para medir la fuerza de la relación entre dos variables.

Para acceder al valor de la prueba de la chi cuadrado y a los datos desarrollados con assocstats puede usarse el siguiente código:

library(broom)
pruebachi <- chisq.test(table(corpusren$cort,corpusren$To))
pruebachi

    Pearson's Chi-squared test

data:  table(corpusren$cort, corpusren$To)
X-squared = 26, df = 3, p-value = 8e-06
assocstats(table(corpusren$cort,corpusren$To))
                    X^2 df   P(> X^2)
Likelihood Ratio 27.053  3 5.7384e-06
Pearson          26.250  3 8.4528e-06

Phi-Coefficient   : NA 
Contingency Coeff.: 0.29 
Cramer's V        : 0.31 
  • Likelihood ratio test y Pearson’s Chi-squared test son una pruebas de bondad de ajuste que se utiliza para comparar un modelo nulo con un modelo alternativo.

  • Phi-coefficient, Contingency coefficient y Cramer’s V son medidas de la fuerza de la relación entre dos variables categóricas. Sus valores se sitúan entre 0 y 1, siendo 0 la ausencia de relación y 1 la relación perfecta. La relación entre cortesía y tonemas es de 0.29 o 0.31, lo que indica que no todas las categorías están igualmente emparentadas.

En este caso Phi_Coefficient es NA porque solo se puede calcular para variables que tengan solo dos categorías.

Para acceder a los valores observados, esperados y residuos, el código es el que sigue:

pruebachi$observed
           
            ascendente circunflejo descendente suspendido
  cortés            23          12          50         46
  descortés         61          15          48         21

Valores observados

pruebachi$expected
           
            ascendente circunflejo descendente suspendido
  cortés            40          13          47         32
  descortés         44          14          51         35

Valores esperados

pruebachi$residuals
           
            ascendente circunflejo descendente suspendido
  cortés         -2.67       -0.23        0.51       2.52
  descortés       2.54        0.22       -0.49      -2.39

Valores de los residuos

Los residuos estandarizados establecen una relación significativa entre el tonema suspendido y la categoría cortés, por una parte, y la categoría descortés y el tonema ascendente, por otra parte. Desde un punto de vista epistemológico, estos datos son importantes, ya que sugieren un comportamiento distinto a los comunes aceptados en el marco de la comunidad científica. Según este conocimiento compartido, los valores de cortesía estarían vinculados a subidas tonales, si bien no parece ser el caso de nuestra muestra, en la que se encuentra lo contrario.

Los datos de los residuos pueden proyectarse, para una mejor claridad, en un gráfico llamado mosaicplot, como se expone a continuación:

  mosaicplot(table(corpusren$cort,corpusren$To), 
             
main =" Mosaicplot cortesía vs Tonema", shade = TRUE,cex.axis = 0.5,las = 1)

Mosaicplot de Cortes_Descortes y Tonema

14.1.3 Ejercicios

Práctica
  1. En la base de datos Idiolectal, realizar una prueba de bondad de ajuste para la variable tonemes. ¿Hay alguna categoría que se desvíe de la proporción esperada (igualdad de proporción)?
table <- table(idiolectal%>%select(tonemes)%>%na.omit())
chi <- chisq.test(table,p = c(1/4,1/4,1/4,1/4))
chi

    Chi-squared test for given probabilities

data:  table
X-squared = 222, df = 3, p-value <2e-16
  1. En la base de datos Idiolectal, realizar una prueba de chi cuadrado para la relación entre la variable tonemes y la variable genre. ¿Hay alguna relación significativa entre ambas variables?
table <- table(idiolectal%>%select(tonemes,genre)%>%na.omit())
chi <- chisq.test(table)
chi

    Pearson's Chi-squared test

data:  table
X-squared = 7, df = 3, p-value = 0.08
  1. Realiza un mosaicplot para la relación entre la variable tonemes y la variable genre en la base de datos Idiolectal.
mosaicplot(table(idiolectal%>%select(tonemes,genre)%>%
na.omit()),shade=T,main="Mosaicplot de tonemes y género")

14.2 T test y ANOVA

Las pruebas T test (o t de Student) y ANOVA (analysis of variance) son pruebas usadas para observar la diferencia entre grupos ya creados a partir de una variable numérica. En el caso de la prueba T test se trata de un máximo de dos grupos, mientras que para la ANOVA se parte de más de dos. Un ejemplo concreto sería observar si en la base de datos Fonocortesía hay diferencia entre los registros de cortesía y los de descortesía en función de cualquiera de las variables numéricas de las base de datos: duración, F0_Media, Intensidad_Media…

14.2.1 Ejemplo de T. Test: F0 Media según (des)cortesía

En este caso analizamos como variable independiente la variables Cortes_Descortes y, por tanto, intentamos averiguar si existe una diferencia notable entre los valores medios de la F0 para los enunciados corteses y para los enunciados descorteses.

t.test(corpusren$F0M~corpusren$cort)

    Welch Two Sample t-test

data:  corpusren$F0M by corpusren$cort
t = -5, df = 245, p-value = 6e-06
alternative hypothesis: true difference in means between group cortés and group descortés is not equal to 0
95 percent confidence interval:
 -47 -19
sample estimates:
   mean in group cortés mean in group descortés 
                    198                     232 

Las medias de los enunciados corteses son significativamente inferiores, con 198 Hz, frente a los 232 Hz de los enunciados descorteses. La prueba T de Student con un valor de -5, 245 grados de libertad y un valor p de 6e-06 indica que la diferencia es por tanto significativa y que, en esta situación, nos permite contemplar la presencia de dos grupos distintos. En otras palabras, los enunciados descorteses destacan por una F0 superior a los enunciados corteses.

Las pruebas estadísticas relacionadas con medias suelen acompañarse de algún tipo de gráfico para la visualización de estas. En concreto, podemos acompañar esta prueba de un diagrama de caja que, aunque permite visualizar el valor de la mediana y no la media, es un dato de tendencia central de los datos y, a no ser que haya outliers muy marcados, permite fácilmente detectar la diferencia entre grupos:

ggplot(corpusren, aes(x=cort, y=F0M, fill = cort)) + 
  geom_boxplot() + theme_minimal() + 
  labs(title="Diagrama de caja de la relación 
       entre F0 Media y Cortes_Descortes", 
       x="Cortes_Descortes", y="F0 Media")

Diagrama de caha de la relación entre F0 Media y Cortes_Descortes

14.2.2 Ejemplos ANOVA: Variables fónicas según medio de expresión

Esta sección nos servirá para introducir la prueba ANOVA (analysis of variance), que es una extensión de la prueba T de Student para más de dos grupos. Se usa para comparar las medias de dos o más grupos y determinar si al menos uno de los grupos es significativamente diferente de los demás. Para ello, se completa con una prueba post hoc, como la de Tukey (HSDTukey), que permite comparar los grupos dos a dos. Como la variable Medio de expresión tiene muchas categorías, vamos a simplificarla en tres: Atenuación, Intensificación y Otro valor. Para ello, usaremos el siguiente código:

corpusren <- corpusren%>%mutate(med2 = ifelse(
  
  med == "Atenuación", "Atenuación",
  ifelse(
    med == "Intensificación", "Intensificación",
    "Otro_valor"
  )
    
  )
  
)

Para aplicar la prueba ANOVA y la de diferenciación de grupos (Tukey), vamos a analizar si hay diferencias significativas entre los tres categorías de la variable Medio de expresión en relación con las variables F0M, dur e IM.

14.2.2.1 F0 Media

En primer lugar, observamos la variable F0M:

TukeyHSD(aov(F0M~med2, data= corpusren))
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = F0M ~ med2, data = corpusren)

$med2
                           diff lwr upr p adj
Intensificación-Atenuación   32  11  53  0.00
Otro_valor-Atenuación        -4 -30  22  0.93
Otro_valor-Intensificación  -36 -57 -14  0.00

Los datos que se observan indican que hay diferencias significativas entre dos grupos, con valores inferiores a 0.05. En concreto, Intensificación y Atenuación se diferencian entre sí, al igual que Otro valor de Intensificación, pero no Atenuación de Otro valor. El diagrama de caja que se presenta a continuación muestra la diferencia entre los tres grupos:

Diagrama de caja

ggplot(corpusren, aes(x=med2, y=F0M, fill = med2)) + 
  geom_boxplot() + theme_minimal() + 
  labs(title="Diagrama de caja de la variable F0M
       por género discursivo",
       x="Género discursivo", y="F0 Media")

Diagrama de caja de la variable rango tonal por género discursivo

Descripción por grupos

library(psych)
describeBy(x= corpusren$F0M, group = corpusren$med2)

 Descriptive statistics by group 
group: Atenuación
   vars  n mean sd median trimmed mad min max range skew kurtosis  se
X1    1 61  199 53    200     197  49  91 315   224 0.18    -0.66 6.8
------------------------------------------------------------ 
group: Intensificación
   vars   n mean sd median trimmed mad min max range  skew kurtosis  se
X1    1 157  230 58    231     231  46   0 420   420 -0.28      1.6 4.6
------------------------------------------------------------ 
group: Otro_valor
   vars  n mean sd median trimmed mad min max range  skew kurtosis  se
X1    1 58  195 67    200     197  65   0 333   333 -0.52     0.69 8.8

14.2.2.2 Duración

En cuanto a la duración, los valores de la prueba ANOVA y el contraste post HOC Tukey son los siguientes:

TukeyHSD(aov(dur~med2, data= corpusren))
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = dur ~ med2, data = corpusren)

$med2
                            diff   lwr  upr p adj
Intensificación-Atenuación -0.11 -0.95 0.72  0.95
Otro_valor-Atenuación       0.29 -0.73 1.30  0.79
Otro_valor-Intensificación  0.40 -0.45 1.25  0.51

En el caso de la velocidad de habla no hay diferencias significativas entre los tres grupos. El diagrama de caja señala esa falta de diferencia:

ggplot(corpusren%>%filter(dur<20), aes(x=med2, 
 y=dur, fill = med2)) + geom_boxplot() + 
  theme_minimal() + labs(title="Diagrama de caja de 
  la variable duración por género discursivo", 
  x="Género discursivo", y="Duración")

Diagrama de caja de la variable velocidad por género discursivo

14.2.2.3 Intensidad media

Finalmente, la variable de intensidad media tampoco presenta diferencias significativas entre grupos:

TukeyHSD(aov(IM~med2, data= corpusren))
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = IM ~ med2, data = corpusren)

$med2
                           diff   lwr upr p adj
Intensificación-Atenuación -1.7  -7.4 4.0  0.76
Otro_valor-Atenuación      -3.8 -10.8 3.1  0.40
Otro_valor-Intensificación -2.1  -8.0 3.7  0.67

Descripción por grupos

describeBy(x= corpusren$IM, group = corpusren$med2)

 Descriptive statistics by group 
group: Atenuación
   vars  n mean sd median trimmed mad min max range skew kurtosis  se
X1    1 61   79 15     83      81 5.9   0  90    90   -3       12 1.9
------------------------------------------------------------ 
group: Intensificación
   vars   n mean sd median trimmed mad min max range skew kurtosis se
X1    1 157   77 13     82      78 8.9  50 143    93 0.21      3.1  1
------------------------------------------------------------ 
group: Otro_valor
   vars  n mean sd median trimmed mad min max range skew kurtosis  se
X1    1 58   75 24     76      73  17  48 222   174  3.9       22 3.1

Diagrama de caja

ggplot(corpusren, aes(x=med2, y=IM, fill = med2)) + 
  geom_boxplot() + theme_minimal() + 
  labs(title="Diagrama de caja de la variable 
       intensidad por género discursivo", 
       x="Género discursivo", y="Intensidad Media")

Diagrama de caja de la variable intensidad por género discursivo

14.2.3 Ejercicios

Práctica
  1. En la base de datos Idiolectal, realizar una prueba ANOVA para la variable tonemeMAS según la variable genre. ¿Hay alguna diferencia significativa entre los grupos?
TukeyHSD(aov(tonemeMAS~genre, data= idiolectal))
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = tonemeMAS ~ genre, data = idiolectal)

$genre
        diff  lwr upr p adj
pod-5p 0.022 -5.8 5.9  0.99
  1. En la base de datos Idiolectal, realizar una prueba T.Test para la variable dur según la variable genre. ¿Hay alguna diferencia significativa entre los grupos?
t.test(idiolectal$dur~idiolectal$genre)

    Welch Two Sample t-test

data:  idiolectal$dur by idiolectal$genre
t = -2, df = 1215, p-value = 0.01
alternative hypothesis: true difference in means between group 5p and group pod is not equal to 0
95 percent confidence interval:
 -15.6  -1.7
sample estimates:
 mean in group 5p mean in group pod 
               98               107 
  1. En la base de datos Idiolectal, realiza un boxplot con los datos anteriores.
ggplot(idiolectal, aes(x=genre, y=dur, fill = genre)) + 
  geom_boxplot() + theme_minimal() + 
  labs(title="Diagrama de caja de la variable duración por género", 
       x="Género", y="Duración")

14.3 Análisis múltiple de correspondencias

El análisis múltiple de correspondencia es una técnica exploratoria para visualizar la relación de más de dos variables de tipo categórico. Convencionalmente, puede realizarse la misma técnica con solo dos variables, aunque en este caso el nombre de la prueba cambia a análisis de correspondencias.

Existen diferentes opciones para realizar el AMC en R, aunque nuestra recomendación es la librería FactoMineR, que se puede acompañar además de dos librerías adicionales, elaboradas por los mismos autores, cuyos nombres son FactoInvestigate y FactoShiny. FactoInvestigate realizará un informe automático de las relaciones entre las variables que incluyamos en el análisis y aportará gráficos y tendencias de grupo. Por su parte, FactoShiny permite realizar la misma operación, pero en un entorno dinámico, es decir, de manera interactiva podremos ir añadiendo o quitando variables y viendo cómo, al modificarlo, los gráficos y los cómputos se modifican también.

Aunque el análisis de clúster es una técnica clásica de agrupación tanto de individuos como de grupos, en este caso veremos su utilidad en la creación de grupos que pueden derivarse del análisis múltiple de correspondencias.

Anteriormente, en la sección destinada a los mapas de calor, hemos visto de qué manera los análisis de clúster creaban agrupaciones en forma de líneas que se unían con otras para agrupar a elementos (registros o variables). En relación con el análisis múltiple de correspondencias, los clústeres son una herramienta útil para crear grupos de elementos que se hayan establecido previamente.

Otro de los aspectos claves sobre la prueba del análisis múltiple de correspondencias es que no necesita una variable independiente; es decir, esta prueba parte de la presuposición de que hay un conjunto de categorías que pertenecen a un conjunto de variables y se pretende ver, en ese caso, qué coocurrencias existen.

14.3.1 Referencias para ampliar

Citamos a continuación algunas referencias bibliográficas que pueden ser interesantes para ampliar nociones y contenidos sobre el análisis múltiple de correspondencias:

  • http://factominer.free.fr/
  • François Husson, canal de Youtube: https://www.youtube.com/channel/UCyz4M1pwJBNfjMFaUCHCNUQ
  • Husson F., Lê S., Pagès J. (2017). Exploratory Multivariate Analysis by Example Using R. 2nd edition. Chapman & Hall/CRC.
  • Greenacre, M.J.. (2007). Correspondence analysis in practice. Chapman & Hall/CRC.
  • Greenacre, M.J. and Blasius, J. (2006). Multiple correspondence analysis and related methods. Chapman & Hall/CRC.

14.3.2 Condiciones de la prueba

Las condiciones del análisis múltiple de correspondencias no son especialmente restrictivas. Se necesita sobre todo que las variables categóricas sean variables de factor en R. Como precacución para la interpretación de los resultados, cabe tener en cuenta que en el análisis de correspondencias, si se introducen muchas variables y muchas variantes, puede conllevar la no visibilidad del gráfico generado por la librería FactoMineR.

Para observar cuál es el papel de cada categoría por dimensión generada, se recomienda utilizar el proceso dimdesc que aporta los datos de las tres primera dimensiones. Ante un número amplio de variables, las dos primeras dimensiones, que son además las más relevantes según los autores de FactoMineR, no tendrán un alto porcentaje de variabilidad explicado, posiblemente entre un 15 o 20 %. Ello no significa que no sea un buen método; debe considerarse que este se trata de un proceso de visualización y que posteriores pruebas de validación, como la chi-cuadrado, establecerán la relación entre variables de manera significativa.

En palabras de Greenacre (2007:88):

CA is performed with the objective of accounting for a maximum amount of inertia along the first axis. The second axis accounts for a maximum of the remaining inertia, and so on. Thus the total inertia is also decomposed into components along principal axes, i.e., the principal inertias.

Al mismo tiempo, un 20 % o menos en la inercia explicada (cantidad de variación explicada) debe entenderse como un núcleo de agrupación, es decir, los elementos o registros que se engloban en estas dos primera dimensiones comparten unas características muy definidas de variación. Por otro lado, FactoMineR permite realizar un dendograma (gráfico del análisis de clúster) con el AMC realizado; de esta manera, pueden observarse todavía mejor los clústeres o agrupaciones creadas con las primeras dimensiones del AMC.

14.3.3 Ejemplo de AMC

En principio, podríamos utilizar todas las variables categóricas que deseemos de la base de datos Fonocortesía, a excepción de las columnas referenciales o de ejemplo, como Elemento_analizado o Fragmento. En el caso del presente ejemplo, vamos a utilizar solo 4 con la intención de no sobresaturar el gráfico resultante. Las variables utilizadas serán Cortes_Descortes, Llama_Atencion, Tonema y Mediodeexpresion.

La primera operación es computar el mapa de dimensiones en el que se van a proyectar las cercanías entre las categorías estudiadas. Hay diferentes gráficos que pueden generarse, aunque nos centraremos inicialmente en dos: el gráfico de relación entre los individuos y el gráfico de relación entre las variantes. El primero de ello se observa en el siguiente gráfico:

library(FactoMineR)
mcacortesia <- MCA(corpusren[c(2,3,4,23)], 
                   graph =FALSE,level.ventil = 0.05)
fviz_mca_biplot(mcacortesia, invisible=c("var"))

Gráficos extraídos de la prueba ACM

En el gráfico anterior, observamos que las dos primeras dimensiones generadas, habitualmente las más importantes en la explicación de la variación existente (Greenacre 2007), explican un 35 % de la variación de la base de datos. Como se comentó anteriormente, los valores de explicación de la variación no son especialmente altos en esta prueba, por lo que explicar más de un tercio de la variación de una base de datos lingüística, donde va a existir, como hemos visto, gran cantidad de variables y de categorías, es un dato muy importante y, por ende, positivo.

Debemos deternos en este punto e intentar explicar algo más el concepto de dimensión. Una dimensión pretende reducir el espacio de variación entre los datos, es un concepto similar al creado en la técnica análisis de componentes principales, que no tratamos en este libro y que también pretende reducir en bloque la variación de una base de datos.

En general, puede sistematizarse como un espacio virtual, de ahí la generación posterior de un gráfico, donde las cercanías y lejanías se transforman en una puntuación sobre un eje de ordenadas y de abscisas. Como veremos más adelante, la relación entre la categoría atenuación o cortesía se podrá detectar porque ambos elementos van a puntuar de una forma determinada en cada una de las dos dimensiones generadas.

En las dimensiones del AMC, por tanto, los registros y las categorías obtendrán una puntuación en estas coordenadas según las cercanías o lejanías entre ellos; habrá además datos y categorías que puntuarán alto en ambas dimensiones. Las dimensiones no tienen una explicación semántica sencilla; para poder empezar con su interpretación, como veremos más adelante, hay que utilizar el comando dimdesc para poder visualizar qué variables y categorías puntúan de forma más elevada en cada una de las dos principales dimensiones generadas. Según cuáles sean las que tengan mayor puntuación, podremos darle una etiqueta identificativa y semántica a cada dimensión: dimensión de la cortesía, dimensión de la prosodia, etc.

Si seguimos con la interpretación de los gráficos, podemos ver la cercanía entre las categorías. Evidentemente, cada categoría sirve como representación de un conjunto determinado de individuos, los que aparecían en el gráfico anterior, y que comparten una característica de agrupación.

fviz_mca_biplot(mcacortesia, invisible=c("ind"))

Mapa sobre la relación entre las categorías de algunas variables de la base de datos Fonocortesía

En el gráfico anterior, por lo tanto, se observan fenómenos llamativos que, posteriormente, una prueba chi cuadrado podrá confirmar o no. En principio, vemos que en la primera dimensión hay una puntuación alta para la categoría cortés y esta se acompaña, con una puntuación alta en la segunda dimensión y todavía más en la primera, de la categoría Atenuación. Al mismo tiempo, en la primera dimensión se observa una puntuación alta de la categoría entonativa suspendido. De este modo, hay un pequeño grupo visual que se caracteriza por compartir estas características: son enunciados corteses, mayoritariamente con atenuación pragmática y con entonación suspendida.

Por su parte, la categoría descortés está en el polo opuesto de la primera dimensión, la que podríamos llamar precisamente de cortesía. A su vez, se vincula con categorías como intensificación y tonema ascendente. Así pues, como señalábamos en el anterior párrafo, se observa un grupo caracterizado por incluir enunciados descorteses, intensificados y con entonación ascendente.

El resto de categorías que se proyectan sobre el gráfico aluden sobre todo a cuestiones entonativas en la segunda dimensión, sobre todo a las categorías que reflejan datos de la variable Llama la atención y que señalan los fenómenos fónicos que, en un determinado momento, despertaron el interés de los investigadores y condicionaron la catalogación de un enunciado como cortés o descortés.

Si queremos profundizar un poco más y observar cuál es la importancia de cada categoría en cada una de las tres primeras dimensiones, podemos usar el siguiente código:

dimdesc(mcacortesia,axes = c(1:2))

Representación de los eigenvalues. Los eigenvalues son una medida de la importancia de cada dimensión en el análisis. En general, se considera que una dimensión es importante si su eigenvalue es superior a 1. En este caso, las dos primeras dimensiones son las más importantes, con valores de 0.25 y 0.15, respectivamente.

  fviz_eig(mcacortesia, )

Gráfico sobre la importancia de las categorías en las primeras dos dimensiones:

fviz_contrib(mcacortesia, choice = "var", axes = 1:2, top = 10)

En el resultado que se extrae del comando dimdesc podemos observar muchas de las valoraciones de análisis realizadas previamente. En primer lugar, se ofrece la puntuación en la dimensión de las variables acompañadas de un valor p que indica significatividad. Posteriormente, para cada dimensión, se puntúan también las categorías, que aparecen acompañadas también de un valor p.

En la primera dimensión, por ejemplo, puntúan de manera muy elevada los valores que hemos comentado anteriormente: enunciados corteses, atenuados, donde llama la atención la entonación y se acompañan de un tonema suspendido. En el polo inverso de esta dimensión, aparecen los enunciados descorteses, intensificados, donde el acento y la entonación llaman la atención del investigador y donde, además, se vincula un tonema ascendente. En la segunda dimensión, por su parte, aparecen otros factores que aluden más a cuestiones fonéticas y a un medio de expresión en concreto, como es la atenuación, que aparece más relacionado con el tonema circunflejo y otros factores fónicos (acento, duración…).

14.3.3.1 Análisis de clúster derivado

El análisis múltiple de correspondencias puede completarse con la librería FactoMiner mediante el uso del análisis de clúster que, al mismo tiempo, generará un conjunto de grupos que integran además características identitarias. La exploración de los resultados del análisis múltiple de correspondencias hace suponer que realmente hay dos grandes grupos; para no forzar completamente esta agrupación, hemos optado por indicar la creación de 3 grupos, aunque podríamos haber sugerido la creación de más grupos. Esta última opción no tendría demasiado sentido si tomamos en consideración todo lo visto anteriormente.

cluster <- HCPC(mcacortesia, nb.clust = 3, graph = FALSE)
fviz_cluster(cluster, geom = "point", palette = 
 c("#00AFBB", "#E7B800", "#FC4E07"), ggtheme = theme_minimal())

Gráfico del análisis de clúster generado a partir de los resultados del AMC

Los grupos generados se han coloreado con tres colores distintos. De todos modos, con el siguiente código podemos ver cuántos registros constituyen cada grupo y, además, cuáles son las características de cada uno de ellos.

table(cluster$data.clust$clust)
cluster$desc.var

14.3.3.2 Informe generado por FactoInvestigate

Otra opción interesante es utilizar la librería FactoInvestigate, que permite realizar un informe general a partir de los datos incluidos en el análisis. El código para poder utilizar esta librería sería el que sigue:

library(FactoInvestigate)
Investigate(mcacortesia)
mcacortesia2 <- MCA(corpus[c(2,3,4,18,19,22,24,31)], graph =TRUE)
Investigate(mcacortesia2)

Al igual que sucedía con el informe creado por DataExplorer, el informe que genera FactoInvestigate se realiza en formato HTML. Para poder visualizar adecuadamente el tipo de documento que se genera, aportamos las siguientes dos capturas de pantalla.

En esta primera captura de pantalla, se observa un gráfico y una descripción sobre la inercia de nuestra base de datos. Las dimensiones creadas explican un total de variabilidad de los datos. A partir de ese gráfico, puede determinarse que las dos primeras dimensiones, que son siempre las más significativas, explican un 36.86 % de los datos.

Finalmente, en la anterior captura de pantalla, se presenta la sección de clasificación del informe, es decir, todo el apartado generado por el análisis de clúster, Sección @ref(cluster). Como puede observarse, los cinco grupos creados se distribuyen en un gráfico en distinto color, mientras que más abajo se ofrece una descripción de cada uno de ellos, según el conjunto de categorías más frecuentes que los integran.

14.4 Descripción de categorías con FactoMineR

La librería Factominer permite realizar una exploración de los datos relacionada parcialmente con el análisis múltiple de correspondencias . El procedimiento se llama catdes y permite observar en qué medida las variantes de una variable se correlacionan de modo significativo con categorías o medias numéricas de otras variables. De esta manera, las asociaciones generadas se utilizan para explicar cada una de las categorías de la variable de entrada.

Los elementos que hay que conocer para poder entender la prueba son los siguientes:

  1. Cla/mod. Se trata del porcentaje de casos de la categoría analizada dentro de la variable que aparece en el resultado.
  2. Mod/Cla. Se trata del porcentaje de casos de la variable del resultado dentro de la variable de entrada.
  3. Global. Se trata del porcentaje de casos que representa el cruce de categorías sobre el total.
  4. p.value. Valor de significación estadística.
  5. V.test. Si es superior a 0 indica que el valor es superior a la media o frecuencia general esperada; si es inferior a 0 indica que el valor es inferior.

Para entender algo mejor conceptos de esta prueba, como v.test, puede acudirse a Le, Josse y Husson (2008).

14.4.1 Desviaciones fónicas y atenuación

corpusselect <- corpusren%>%select(cort, To, med2)

catedes <- catdes(corpusselect,num.var = 1,proba = 0.01)
catedes

Link between the cluster variable and the categorical variables (chi-square test)
=================================================================================
     p.value df
med2 1.6e-16  2
To   8.5e-06  3

Description of each cluster by the categories
=============================================
$cortés
                     Cla/Mod Mod/Cla Global p.value v.test
med2=Atenuación           92      43     22 2.2e-16    8.2
To=suspendido             69      35     24 6.9e-05    4.0
To=ascendente             27      18     30 8.8e-06   -4.4
med2=Intensificación      28      34     57 6.4e-14   -7.5

$descortés
                     Cla/Mod Mod/Cla Global p.value v.test
med2=Intensificación    72.0    77.9     57 6.4e-14    7.5
To=ascendente           72.6    42.1     30 8.8e-06    4.4
To=suspendido           31.3    14.5     24 6.9e-05   -4.0
med2=Atenuación          8.2     3.4     22 2.2e-16   -8.2
plot.catdes(catedes, show= "quali", cex.names = 1.2, 
            col.upper = "blue",col.lower = "red")

Gráfico para representar la descripción de categorías en FactoMineR

En el anterior gráfico, el color azul señala los casos de sobrepoblación, mientras que el color rojo indica casos de categorías poco pobladas. No es, por tanto, un mapa de calor convencional, ya que en este gráfico solo se representan las categorías o valores que han resultado ser significativamente distintos.

14.4.2 Ejercicios

Práctica
  1. En la base de datos Idiolectal, realiza una descripción de categorías para la variable genre en función de las variables tonemes, spk, spk2, MAStag y circunflejo.
idiolectalselect <- idiolectal%>%select(genre,tonemes,spk,spk2,MAStag,circunflejo)

catedes2 <- catdes(idiolectalselect,num.var = 1,proba = 0.01)

catedes2

Link between the cluster variable and the categorical variables (chi-square test)
=================================================================================
      p.value df
spk2 1.6e-256  9
spk   4.6e-15  4

Description of each cluster by the categories
=============================================
$`5p`
                    Cla/Mod Mod/Cla Global  p.value v.test
spk2=5ppzorro           100    46.6   23.3 3.4e-105   21.8
spk2=5pangelreal        100    16.9    8.5  8.8e-34   12.1
spk2=5prcastellano      100    15.9    8.0  9.9e-32   11.7
spk2=5pestepa           100    13.6    6.8  5.2e-27   10.8
spk2=5pdufort           100     6.9    3.4  1.1e-13    7.4
spk=angelreal            71    16.9   12.0  9.3e-08    5.3
spk=rcastellano          63    15.9   12.6  5.6e-04    3.5
spk=dufort               26     6.9   13.3  2.5e-11   -6.7
spk2=podangelreal         0     0.0    3.5  5.3e-14   -7.5
spk2=podrcastellano       0     0.0    4.7  1.8e-18   -8.8
spk2=podestepa            0     0.0    7.1  5.1e-28  -11.0
spk2=poddufort            0     0.0    9.9  1.1e-39  -13.2
spk2=podpzorro            0     0.0   24.9 4.7e-114  -22.7

$pod
                    Cla/Mod Mod/Cla Global  p.value v.test
spk2=podpzorro          100    49.8   24.9 4.7e-114   22.7
spk2=poddufort          100    19.7    9.9  1.1e-39   13.2
spk2=podestepa          100    14.1    7.1  5.1e-28   11.0
spk2=podrcastellano     100     9.4    4.7  1.8e-18    8.8
spk2=podangelreal       100     7.1    3.5  5.3e-14    7.5
spk=dufort               74    19.7   13.3  2.5e-11    6.7
spk=rcastellano          37     9.4   12.6  5.6e-04   -3.5
spk=angelreal            29     7.1   12.0  9.3e-08   -5.3
spk2=5pdufort             0     0.0    3.4  1.1e-13   -7.4
spk2=5pestepa             0     0.0    6.8  5.2e-27  -10.8
spk2=5prcastellano        0     0.0    8.0  9.9e-32  -11.7
spk2=5pangelreal          0     0.0    8.5  8.8e-34  -12.1
spk2=5ppzorro             0     0.0   23.3 3.4e-105  -21.8
  1. En la base de datos Idiolectal, realiza un gráfico con los resultados obtenidos.
plot.catdes(catedes2, show= "quali", cex.names = 1.2, 
            col.upper = "blue",col.lower = "red")

  1. En la base de datos Idiolectal, realiza una análisis múltiple de correspondencias con las variables genre, tonemes, spk, spk2, MAStag y circunflejo.
library(FactoMineR)
library(factoextra)
idiolectalselect2 <- idiolectal%>%select(genre,tonemes,spk,spk2,MAStag,circunflejo)

mcaidiolectal <- MCA(idiolectalselect2, 
                   graph =FALSE,level.ventil = 0.05)

fviz_mca_biplot(mcaidiolectal, invisible=c("var"))

  1. En la base de datos Idiolectal, realiza un análisis de clúster con los resultados obtenidos.
clusteridiolectal <- HCPC(mcaidiolectal, nb.clust = 3, graph = FALSE)

fviz_cluster(clusteridiolectal, geom = "point", palette = 
 c("#00AFBB", "#E7B800", "#FC4E07"), ggtheme = theme_minimal())

  1. En la base de datos Idiolectal, realiza un gráfico con los resultados obtenidos en el análisis múltiple de correspondencias.
fviz_contrib(mcaidiolectal, choice = "var", axes = 1:2, top = 10)

fviz_mca_biplot(mcaidiolectal, invisible=c("ind"))

14.5 Árbol de decisiones y Random Foerst

El árbol de decisiones es una técnica de visualización y de reducción de la variabilidad de uso extendido en la actualidad que permite clasificar las categorías de una variable independiente a partir de un conjunto de variables explicativas. Tanto la primera como las segundas pueden ser indistintamente cuantitativas o nominales. Por su parte, la técnica Random Forest toma como base una simulación de datos que se basa, precisamente, en la generación de múltiples árboles de decisiones. Mientras el árbol de decisiones descansa sus procesos estadísticos en la base de datos concreta que sirve de entrada, RandomForest simula información y, en tal sentido, va un poco más allá. En general, se trata de dos técnicas de clasificación.

Un procedimiento habitual en estudio estadístico es desglosar nuestra base de datos en dos partes (un 20-80 o un 40-60 o similar), calcular la clasificación sobre el porcentaje menor y, posteriormente, aplicarla sobre la porción restante de la base de datos. No obstante, si nuestros datos no son muchos, por ejemplo 200-300 registros, puede operarse simplemente con toda la base de datos y observar cuáles son las reglas de clasificación establecidas o, al menos, descubrir qué variables son las más relevantes para clasificar un determinado fenómeno.

Estas dos técnicas son muy robustas y dependen mucho de la manera en la que hemos configurado nuestra base de datos. Por ello, hay que ser bastante cuidadoso tanto a la hora de definir la variable independiente como, sobre todo, al introducir variables dependientes. En este último caso, es especialmente importante no utilizar variables que solapen información porque, si lo hacemos, el cálculo de la prueba va a intentar siempre explicar de la manera más sencilla y directa las categorías o valores de la variable independiente.

Por ejemplo, si en una base de datos almacenamos información de variables temporales e incluimos además variables como número de sílabas o número de palabras, porque luego pueden ser útiles para calcular factores como la velocidad de habla, es posible que en el árbol de decisiones esa información sea redundante y se solape; en este sentido, la variable duración y valores elevados en ella corresponderán casi ineludiblemente con esas variables de sílabas y palabras y valores también altos en ellas. No tiene por qué ser una relación directa, pero hay que contemplar este tipo de factores para evitar influencias de variables ocultas.

Por otro lado, cabe incidir en el hecho de que las clasificaciones de las categorías o valores de la variable independiente no resultará en un 100 % de óptima clasificación; es decir, en el marco de bases de datos siempre hay un espacio para la variación y, en tal medida, no podemos esperar que elementos que pertenezcan a determinadas categorías queden independizados todos unos de otros.

Por lo tanto, el árbol de decisiones, al igual que sucedía con el análisis de clúster, propone secuencias de etiquetado o clasificación según la influencia de un grupo de parámetros de diferentes variables, pero habrá zonas de intersección entre las categorías. Podremos verlo más detenidamente en los ejemplos de las siguientes secciones.

14.5.1 Referencias para ampliar

Hay en la actualidad diferentes referencias que han introducido los árboles de decisiones o Random Forest en general y también en su aplicación al estudio concreto de elementos lingüísticos.

Librerías utilizadas:

  • Partykit
  • randomForest

Lecturas:

14.5.2 Condiciones de la prueba

Tanto el árbol de decisiones como RandomForest solo necesitan una variable independiente, numérica o nominal, y un conjunto de variables independientes, numéricas o nominales. Las variables nominales deben ser variables de factor. Hay que intentar que las variables numéricas no incluyan valores vacíos, comúnmente llamados NA en R.

14.5.3 Árbol con variable independiente numérica

En Levinson y Torreira (2015) se aplica tanto la técnica del árbol de decisiones como la del RandomForest para caracterizar los valores temporales de FTO (Floor Transfer Offest). Por tanto, en ese caso concreto hay una variable independiente de tipo numérico, los valores del intervalo temporal que transcurre entre la finalización de un enunciado por parte de un hablante y el principio de otro enunciado por parte de otro interlocutor. En su caracterización, entran en juego valores fónicos (descenso tonal, duración del grupo entonativo…), pero también categóricos (acto de habla, por ejemplo).

Tomando ese ejemplo de Levinson y Torreira (2015) como ejemplo, analizaremos en esta sección la variable FM0, que mide la media de tono en un enunciado. En este caso, la variable independiente es numérica y, por tanto, se trata de un árbol de decisiones clásico.

En primer lugar, utilizaremos solo los casos de la variable independiente que no tengan valores perdidos o iguales a 0. Los árboles de decisiones no permiten que haya valores ausentes en su cómputo y tampoco favorece que haya valores iguales a 0 porque simplifica significa que no se han podido registrar valores tonales para ese enunciado concreto y que, por ello mismo, tampoco ha sido posible computar el rango tonal. Al mismo tiempo, usaremos la librería partykit, en la que participan autore de la librería partykit y que ofrece algunas configuraciones que parecen muy interesarantes, sobre todo, para la configuración de los gráficos (evitar solapamientos en las categorías que aparecen dispuestas en los gráfico, por ejemplo):

corpusarbol <- corpusren%>%filter(F0M>0)
corpusarbol[sapply(corpusarbol, is.character)] <- 
  lapply(corpusarbol[sapply(corpusarbol, is.character)],as.factor)


library(partykit)

A continuación, realizamos el primer árbol de decisiones y lo convertimos en gráfico. Si se desea, puede accederse a los datos numéricos y a las clasificaciones que la librería produce. Para ello, únicamente hay que almacenar el cómputo del árbol de decisiones en una variables y, posteriormente, invocarlo desde el terminal. Por ejemplo, en nuestro caso práctico vamos a almacenar el análisis en una variable/objeto que se llama corpustree y que podemos introducir directamente en el terminal.

Posteriormente, podemos usar la función plot para convertir el árbol de decisiones en un gráfico interpretable. En esta comando, se adjunta una especificación ep_args = list(justmin = 15) que se utiliza para que si hay nodos con muchas categorías no se solapen unas con otras.

library(dplyr)
corpustree <- partykit::ctree(F0M~cort+IM+To+med2+Vmod, 
data= corpusarbol, control = ctree_control(maxdepth = 3))
plot(corpustree, ep_args = list(justmin = 15), 
     gp = gpar(fontsize = 8))

Árbol de decisiones de la variable rango tonal en general

14.5.4 Árbol con variable independiente categórica

Posiblemente, en análisis que cruza fonética y pragmática es mucho más frecuente que exista una variable independiente formada por grupos previos. En el caso de la investigación sobre género discursivo y atenuación, existen variables categóricas que podrían ser utilizadas como variable independiente: el género discursivo, la combinatoria fónica, la atenuación pragmática o no y el hablante. De todas ellas, en esta sección ejemplificaremos la clasificación realiada sobre el género discursivo y sobre la atenuación pragmática.

Al igual que ocurría en la anterior sección, en este caso filtramos primero la base de datos por casos desviados fónicamente que pueden estar señalados como “sí”, en el sentido de que transmite atenuación pragmática, o como “no”, es decir, pueden ser superiores o inferiores a la media de las variables fónicas estudiadas de modo significativo, pero no sirven para indicar atenuación pragmática o al menos, no han sido evaluados positivamente de esta manera. Posteriormente, ejecutamos el gráfico del árbol de decisiones correspondiente.

library(dplyr)
corpustree <- partykit::ctree(cort~F0M+IM+To+med2+Vmod, 
        data= corpusarbol, control = ctree_control(maxdepth = 3))
plot(corpustree, ep_args = list(justmin = 15),
     gp = gpar(fontsize = 8))

Árbol de decisiones de la variable rango tonal en general

14.5.5 Random Forest

La prueba de Random Forest es una prueba que genera una simulación de un número determinado de árboles de decisiones para poder determinar con qué variables se clasifican mejor los datos de una variable independiente, bien sea esta numérica o categórica. Se trata, por tanto, de una técnica de reducción de las variables en aras de explicar una determinada variable de entrada.

Para ejemplificar el caso de Random Forest utilizaremos en este caso la base de datos Fonocortesía y tomaremos precisamente como variable independiente de entrada la variable Cortes_Descortes. Como variables explicativas utilizaremos todas aquellas que no tengan un número de factores superior a 20 niveles y también las numéricas que son consideradas más interesantes; cabe recordar que si queremos conocer la tipología de las variables y la cantidad de factores, podemos utilizar el comando str. El procedimiento o comando utilizado en R para crear un RandomForest es muy parecido al observado en el árbol de decisiones, únicamente cambiamos el comando ctree por randomForest.

corpusren$cort <- gsub("cortés","cor",corpusren$cort)
corpusren$cort <- gsub("descor","des",corpusren$cort)
corpusren$cort <- as.factor(corpusren$cort)
cortesia_cforest<- randomForest(cort~Llam+med+
F0M+IM+Sil+dur+DPA+DPP+CP+Cur+ILI+To+Vmod, data=corpusren%>%
  mutate_if(is.character,as.factor), na.action = na.roughfix)
print(cortesia_cforest)

Call:
 randomForest(formula = cort ~ Llam + med + F0M + IM + Sil + dur +      DPA + DPP + CP + Cur + ILI + To + Vmod, data = corpusren %>%      mutate_if(is.character, as.factor), na.action = na.roughfix) 
               Type of random forest: classification
                     Number of trees: 500
No. of variables tried at each split: 3

        OOB estimate of  error rate: 17%
Confusion matrix:
    cor des class.error
cor 106  25        0.19
des  21 124        0.14

Inicialmente y sin más información, RandomForest genera un grupo de 500 árboles simulados, en los que cambia cada vez un dato de algunas de las variables empleadas. Porsteriormente, en el resultado principal de la prueba, observamos un porcentaje de clasificación adecuada de los grupos de la variable independiente. En general, hay un porcentaje de error del 18 %; los casos descorteses se clasifican bien en un 85 % (23 casos se han incluido como corteses), mientras que los de cortesía se clasifican algo peor, con un 79 % (28 casos se han considerado descorteses). Por tanto, la clasificación es en cierto modo interesante.

Podemos acceder a la contribución de cada variable en el proceso de clasificación. Se utiliza en este caso el código importance:

importance(cortesia_cforest)
     MeanDecreaseGini
Llam             12.8
med              29.5
F0M              16.8
IM               13.4
Sil               8.5
dur               9.3
DPA               5.0
DPP               5.4
CP                5.9
Cur               7.7
ILI               5.4
To                6.7
Vmod             10.1

Además, RandomForest permite visualizar las contribuciones de las variables en forma de gráfico, como el que se incluye a continuación:

varImpPlot(cortesia_cforest)

Importancia de las variables en Random Forest

En el gráfico anterior, se observa que hay una variable mucho más importante que el resto; se trata de med, que es el medio de expresión de la cortesía o descortesía. En general, como hemos visto en secciones anteriores, se trata generalmente de valores como atenuación o intensificación. Después, las otras cuatros variables que puntúan de manera alta serían la F0 y la intensidad medias, la variable llama la atención y la variable Valor modal.

RandomForest es complejo de interpretar en muchas ocasiones porque no produce un gráfico de clasificación como sucede con la prueba del árbol de decisiones tradicional. No obstante, podemos acceder a los valores de la base de datos con la predicción sugerido por el análisis de la prueba. En los siguientes ejemplos, vemos una muestra de los primeros ocho casos de la base de datos y la predicción que se ha generado basada en el resultado de la prueba:

head(cortesia_cforest$predicted, n= 8)
  1   2   3   4   5   6   7   8 
des cor des des des des cor des 
Levels: cor des

Podemos acceder a la puntuación que ha recibido cada uno de esos registros. De esta manera, podemos comparar las predicciones realizadas con el valor real.

head(margin(cortesia_cforest), n=8)
  des   des   des   des   des   cor   cor   des 
 0.59 -0.63  0.76  0.79  0.77 -0.58  0.65  0.91 

Podemos observar que los registros que no se han clasificado bien porque han puntuado de manera negativa han sido el 2 y el 6. El resto se ha clasificaco adecuadamente, aunque con porcentajes de seguridad medio altos.

14.5.6 Ejercicios

Práctica
  1. En la base de datos Idiolectal, realiza un análisis de Random Forest con la variable genre como variable independiente y las variables tonemes, tonemeMAS, dur, spk, spk2, MAStag y circunflejo como variables explicativas.
library(randomForest)
idiolectal <- idiolectal%>%select(genre,tonemes,
tonemeMAS,dur,spk,spk2,MAStag,circunflejo)%>%
  mutate_if(is.character,as.factor)

idiolectal_cforest<- 
randomForest(genre~tonemes+tonemeMAS+dur+spk+spk2+MAStag+circunflejo,
             
             data=idiolectal, na.action = na.roughfix)

print(idiolectal_cforest)

Call:
 randomForest(formula = genre ~ tonemes + tonemeMAS + dur + spk +      spk2 + MAStag + circunflejo, data = idiolectal, na.action = na.roughfix) 
               Type of random forest: classification
                     Number of trees: 500
No. of variables tried at each split: 2

        OOB estimate of  error rate: 0%
Confusion matrix:
     5p pod class.error
5p  609   0           0
pod   0 609           0
  1. En la base de datos Idiolectal, realiza un gráfico con los resultados obtenidos.
varImpPlot(idiolectal_cforest)

  1. Realiza un árbol de decisiones con la variable genre como variable independiente y las variables tonemes, tonemeMAS, dur, spk, MAStag y circunflejo como variables explicativas. Excluye a “pzorro” de la variable spk.
library(partykit)
idiolectal_tree<- partykit::ctree(genre~tonemes+
tonemeMAS+dur+spk+MAStag+circunflejo, 
        data= idiolectal%>%filter(spk!="pzorro")%>%select(genre,tonemes,tonemeMAS,dur,spk,MAStag,circunflejo)%>%mutate_if(is.character,as.factor), control = ctree_control(maxdepth = 3))

plot(idiolectal_tree, ep_args = list(justmin = 15))

  1. Si eliminamos genre y lo cambiamos por spk2, ¿cómo cambian los resultados?
idiolectal_cforest2<- 
  randomForest(spk2~tonemes+tonemeMAS+dur+MAStag+circunflejo, 
               data=idiolectal, na.action = na.roughfix)

print(idiolectal_cforest2)

Call:
 randomForest(formula = spk2 ~ tonemes + tonemeMAS + dur + MAStag +      circunflejo, data = idiolectal, na.action = na.roughfix) 
               Type of random forest: classification
                     Number of trees: 500
No. of variables tried at each split: 2

        OOB estimate of  error rate: 75%
Confusion matrix:
               5pangelreal 5pdufort 5pestepa 5ppzorro 5prcastellano
5pangelreal              0        0        1       49             1
5pdufort                 0        0        3       25             0
5pestepa                 1        1        2       36             0
5ppzorro                 3        2        7      103             2
5prcastellano            0        0        0       42            12
podangelreal             0        0        1       17             0
poddufort                0        0        2       51             3
podestepa                0        0        3       30             2
podpzorro                0        0        4      112             3
podrcastellano           0        0        0       20             0
               podangelreal poddufort podestepa podpzorro podrcastellano
5pangelreal               0         2         1        49              0
5pdufort                  0         1         2        11              0
5pestepa                  0         5         3        35              0
5ppzorro                  3         7         3       154              0
5prcastellano             1         2         2        38              0
podangelreal              2         1         0        22              0
poddufort                 2        10         2        50              0
podestepa                 1         5         2        43              0
podpzorro                 1         1         3       179              0
podrcastellano            0         1         1        35              0
               class.error
5pangelreal           1.00
5pdufort              1.00
5pestepa              0.98
5ppzorro              0.64
5prcastellano         0.88
podangelreal          0.95
poddufort             0.92
podestepa             0.98
podpzorro             0.41
podrcastellano        1.00
  1. Realiza un árbol de decisiones con la variable spk2 como variable independiente y las variables tonemes, tonemeMAS, dur, MAStag y circunflejo como variables explicativas.
idiolectal_tree2<- partykit::ctree(spk2~tonemes+tonemeMAS+dur+
                                     MAStag+circunflejo, 
        data= idiolectal, control = ctree_control(maxdepth = 3))

plot(idiolectal_tree2, ep_args = list(justmin = 15), 
     gp = gpar(fontsize = 8))

15 Ejercicios finales sobre el curso (usando la base de datos Idiolectal)

  • Renombra la variable ip y llámala intonational_phrase.
library(tidyverse)
library(readxl)
idiolectal <- read_xlsx("databases/idiolectal.xlsx",sheet = 1)
idiolectal <- idiolectal%>%dplyr::rename(intonational_phrase = ip)
  • Crea una variable llamada id2 en la que se recoja el número de fila para cada grupo de la variable filename.
idiolectal <- idiolectal%>%group_by(filename)%>%
  mutate(id2 = row_number())
  • Crea un dataframe llamado idiolectal_pod que recoja solo las variables spk, phon, tonemes, words de la categoría “pod” en genre. Este dataframe no debe tener valores vacíos en ninguna variable.
idiolectal_pod <- idiolectal%>%filter(genre == "pod")%>%
  select(spk,phon,tonemes,words)%>%
  na.omit()
  • Crea un diagrama de caja con la variable dur según las categorías de la variable genre.
library(ggplot2)
ggplot(idiolectal, aes(x = genre, y = dur)) + 
  geom_boxplot()

  • Construye un gráfico de líneas para el filename “poddufort” en el que tmin sea la línea de tiempo, tonemeMAS sea el eje de las ordenadas y spk sea el color de las líneas.
idiolectal%>%filter(filename == "poddufort")%>%
  ggplot(aes(x = tmin, y = tonemeMAS, color = spk)) + 
  geom_line()

  • Haz un mapa de calor de los hablantes en el genre “pod” con todas las variables numéricas que no sean tmin o tmax.
library(gplots)
idiolectal_pod2 <- idiolectal%>%filter(genre == "pod")%>%
  select(-tmin,-tmax)%>%na.omit()%>%
  group_by(spk)%>%
  summarise_all(mean,na.rm=T)%>%column_to_rownames(var="spk")%>%
  select(ip_dur,dur,words,dur_first,dur_preanac,tonemeMAS,body)

heatmap.2(as.matrix(idiolectal_pod2), scale = "column",
          cexRow = 0.8, cexCol = 0.8)

  • Realiza un análisis de correspondencias múltiples con las variables tonemes, spk2,phon, MAStag y circunflejo. Visualiza un mapa con las categorías más relacionadas.
library(FactoMineR)
library(factoextra)

idiolectal_mca <- MCA(idiolectal%>%select(tonemes,spk2,
                      phon,MAStag,circunflejo), 
                      graph =FALSE,level.ventil = 0.05)

fviz_mca_biplot(idiolectal_mca, invisible=c("ind"))

  • Computa una variable que recoja la velocidad de habla. Recomendación: fíjate en la variable dur y en la variable words.
idiolectal <- idiolectal%>%mutate(velocidad = words/dur)
  • Realiza un Wordcloud con la variable word, pero usa solo las 50 palabras más frecuentes.
library(ggwordcloud)
library(dplyr)

idiolectal%>%count(word)%>%top_n(50)%>%
  ggplot(aes(label = word, size = n)) + 
  geom_text_wordcloud()

  • Transforma la variable genre en una variable de factor y realiza un análisis randomForest con las variables tonemes, tonemeMAS, dur, spk, MAStag y circunflejo (las variables de carácter también debes transformarlas a factor). La variable independiente será genre.
idiolectal2 <- idiolectal%>%
  mutate(genre = as.factor(genre),tonemes = as.factor(tonemes),
         spk = as.factor(spk),MAStag = as.factor(MAStag),
         circunflejo = as.factor(circunflejo))
idiolectal_cforest3<- 
  randomForest(genre~tonemes+tonemeMAS+dur+spk+MAStag+circunflejo, 
               data=idiolectal2, na.action = na.roughfix)

print(idiolectal_cforest3)

Call:
 randomForest(formula = genre ~ tonemes + tonemeMAS + dur + spk +      MAStag + circunflejo, data = idiolectal2, na.action = na.roughfix) 
               Type of random forest: classification
                     Number of trees: 500
No. of variables tried at each split: 2

        OOB estimate of  error rate: 42%
Confusion matrix:
     5p pod class.error
5p  337 272        0.45
pod 236 373        0.39
  • Realiza un análisis de clúster con las variables genre, tonemes, spk2, MAStag y circunflejo.
library(FactoMineR)
library(factoextra)

idiolectal_mca <- MCA(idiolectal%>%select(genre,tonemes,spk2,
                                          MAStag,circunflejo), 
                      graph =FALSE,level.ventil = 0.05)

idiolectal_cluster <- HCPC(idiolectal_mca, nb.clust = 3, graph = FALSE)

fviz_cluster(idiolectal_cluster, geom = "point", palette = 
               c("#00AFBB", "#E7B800", "#FC4E07"), 
             ggtheme = theme_minimal())

  • Haz un árbol de decisiones con la variable spk como variable independiente y las variables tonemes, tonemeMAS, dur, MAStag y circunflejo como variables explicativas. Debes filtrar previamente la categoría “pzorro” de la variable spk.
library(stringr)
idiolectal3 <- idiolectal%>%filter(spk != "pzorro")

idiolectal_tree3<- partykit::ctree(spk~tonemes+tonemeMAS+dur
+MAStag+circunflejo, 
data= idiolectal3%>%mutate(spk = str_trunc(spk, 4,ellipsis = ""))%>%
  mutate_if(is.character,as.factor), 
control = ctree_control(maxdepth = 3))

plot(idiolectal_tree3)

  • Haz un árbol de decisiones con la variable dur como variable independiente y las variables tonemes, tonemeMAS, genre,spk, MAStag y circunflejo como variables explicativas.
idiolectal_tree4 <- partykit::ctree(dur~tonemeMAS+tonemes
+genre+spk+circunflejo,
data= idiolectal%>%mutate_if(is.character,as.factor),
control = ctree_control(maxdepth = 3))

plot(idiolectal_tree4)

  • Haz una prueba ANOVA para la variable spk como independiente y la variable dur como dependiente.
Tuk <- TukeyHSD(aov(dur~spk, data = idiolectal%>%
mutate(spk = as.factor(spk))))

Tuk
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = dur ~ spk, data = idiolectal %>% mutate(spk = as.factor(spk)))

$spk
                       diff    lwr  upr p adj
pzorro-angelreal        6.1  -9.32 21.5  0.82
rcastellano-angelreal  -6.7 -25.95 12.6  0.88
dufort-angelreal       12.5  -6.58 31.5  0.38
estepa-angelreal       36.1  17.28 55.0  0.00
rcastellano-pzorro    -12.8 -27.88  2.3  0.14
dufort-pzorro           6.4  -8.46 21.2  0.77
estepa-pzorro          30.0  15.47 44.6  0.00
dufort-rcastellano     19.1   0.35 37.9  0.04
estepa-rcastellano     42.8  24.22 61.4  0.00
estepa-dufort          23.7   5.33 42.0  0.00
  • Realiza una prueba chi cuadrado (bondad de ajuste) con la hipótesis de igualdad de proporciones en la variable tonemes.
table <- table(idiolectal%>%select(tonemes))
bondad <- chisq.test(table, p = c(1/4,1/4,1/4,1/4))
bondad$residuals
               tonemes
filename        enfático enunciativo interrogativo suspendido
  5pangelreal     -0.537       1.209        -0.416     -0.829
  5pcastellano     0.850       0.500        -0.103     -1.127
  5pdufort         1.004      -0.305        -1.118     -0.126
  5pestepa        -0.222       0.051        -1.221      0.391
  podangelreal    -0.896      -0.078        -1.196      1.007
  poddufort       -0.270       0.151         2.838     -0.638
  podestepa        1.885      -0.835        -1.262     -0.148
  poscastellano   -1.958      -0.736         2.747      1.553
  • Realiza una prueba chi cuadrado que observe a relación entre spk y tonemes. Analiza los residuos estandarizados en un mosaicplot.
table2 <- table(idiolectal$spk,idiolectal$tonemes)

bondad2 <- chisq.test(table2)


bondad2$residuals
             
              enfático enunciativo interrogativo suspendido
  angelreal     -1.731       1.330        -0.138     -0.170
  dufort         0.426       0.696         1.163     -1.333
  estepa         0.764       0.298        -1.454     -0.528
  pzorro         0.035      -1.310         0.323      1.320
  rcastellano    0.139       0.290         0.076     -0.431
mosaicplot(table2, shade = TRUE)

  • Realiza una prueba de correlación de Pearson entre las variables tonemesMAS, dur_first,dur_preanac,body y dur y visualízalo en un gráfico.
correlacion <- cor(idiolectal%>%select(tonemeMAS,dur_first,
    dur_preanac,body,dur)%>%na.omit(), method = "pearson")

library(corrplot)

corrplot(correlacion,addCoef.col = 'black',cl.pos = "n",
         tl.pos = 'd', col = COL2('PiYG'),tl.cex = 0.8)

16 Librerías citadas

  • Breiman, L., Cutler, A., Liaw, A., & Wiener, M. (2022). randomForest: Breiman and Cutler’s Random Forests for Classification and Regression. https://www.stat.berkeley.edu/~breiman/RandomForests/

  • Cui, B. (2024). DataExplorer: Automate Data Exploration and Treatment. http://boxuancui.github.io/DataExplorer/

  • Gohel, D., & Skintzos, P. (2024). flextable: Functions for Tabular Reporting. https://ardata-fr.github.io/flextable-book/

  • Hothorn, T., Hornik, K., & Zeileis, A. (2006). Unbiased Recursive Partitioning: A Conditional Inference Framework. Journal of Computational and Graphical Statistics, 15(3), 651-674. https://doi.org/10.1198/106186006X133933

  • Hothorn, T., & Zeileis, A. (2015). partykit: A Modular Toolkit for Recursive Partytioning in R. Journal of Machine Learning Research, 16, 3905-3909.

  • Hothorn, T., & Zeileis, A. (2023). partykit: A Toolkit for Recursive Partytioning. http://partykit.r-forge.r-project.org/partykit/

  • Husson, F., Josse, J., Le, S., & Mazet, J. (2024). FactoMineR: Multivariate Exploratory Data Analysis and Data Mining. http://factominer.free.fr

  • Kassambara, A., & Mundt, F. (2020). factoextra: Extract and Visualize the Results of Multivariate Data Analyses. http://www.sthda.com/english/rpkgs/factoextra

  • Lê, S., Josse, J., & Husson, F. (2008). FactoMineR: A Package for Multivariate Analysis. Journal of Statistical Software, 25(1), 1-18. https://doi.org/10.18637/jss.v025.i01

  • Liaw, A., & Wiener, M. (2002). Classification and Regression by randomForest. R News, 2(3), 18-22.

  • Pennec, E. L., & Slowikowski, K. (2023). ggwordcloud: A Word Cloud Geom for ggplot2. https://github.com/lepennec/ggwordcloud

  • R Core Team (2024). R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing, Vienna, Austria. https://www.R-project.org/.

  • Revelle, W. (2024). psych: Procedures for Psychological, Psychometric, and Personality Research. https://personality-project.org/r/psych/     https://personality-project.org/r/psych-manual.pdf

  • Warnes, G. R., Bolker, B., Bonebakker, L., Gentleman, R., Huber, W., Liaw, A., Lumley, T., Maechler, M., Magnusson, A., Moeller, S., Schwartz, M., & Venables, B. (2024). gplots: Various R Programming Tools for Plotting Data. https://github.com/talgalili/gplots

  • Wei, T., & Simko, V. (2021a). corrplot: Visualization of a Correlation Matrix. https://github.com/taiyun/corrplot

  • Wei, T., & Simko, V. (2021b). R package «corrplot»: Visualization of a Correlation Matrix. https://github.com/taiyun/corrplot

  • Wickham, H. (2023). tidyverse: Easily Install and Load the Tidyverse. https://tidyverse.tidyverse.org

  • Wickham, H., Averick, M., Bryan, J., Chang, W., McGowan, L. D., François, R., Grolemund, G., Hayes, A., Henry, L., Hester, J., Kuhn, M., Pedersen, T. L., Miller, E., Bache, S. M., Müller, K., Ooms, J., Robinson, D., Seidel, D. P., Spinu, V., … Yutani, H. (2019). Welcome to the tidyverse. Journal of Open Source Software, 4(43), 1686. https://doi.org/10.21105/joss.01686

  • Wickham, H., & Bryan, J. (2023). readxl: Read Excel Files. https://readxl.tidyverse.org

  • Zeileis, A., Hothorn, T., & Hornik, K. (2008). Model-Based Recursive Partitioning. Journal of Computational and Graphical Statistics, 17(2), 492-514. https://doi.org/10.1198/106186008X319331

  • Zhu, H. (2024). kableExtra: Construct Complex Table with kable and Pipe Syntax. http://haozhu233.github.io/kableExtra/