--- title: "IA para Científicos Sociales" subtitle: "Sesión 3.3: Laboratorio 5 - Clustering y PCA" author: - name: Danilo Freire orcid: 0000-0002-4712-6810 email: danilofreire@gmail.com affiliations: "Department of Data and Decision Sciences
Emory University" format: clean-revealjs: self-contained: true footer: "[Sesión 3.3](https://danilofreire.github.io/introduccion-ia-ucu/clases/dia-03/11-laboratorio-05.html)" transition: slide transition-speed: default scrollable: true revealjs-plugins: - multimodal engine: knitr editor: render-on-save: true lang: es --- ```{r setup, include=FALSE} options(htmltools.dir.version = FALSE) library(knitr) opts_chunk$set( prompt = T, fig.align = "center", dpi = 300, cache = T, engine.opts = list(bash = "-l") ) knit_hooks$set( prompt = function(before, options, envir) { options( prompt = if (options$engine %in% c("sh", "bash", "zsh")) "$ " else "R> ", continue = if (options$engine %in% c("sh", "bash", "zsh")) "$ " else "+ " ) } ) options(repos = c(CRAN = "https://cran.rstudio.com/")) if (!require("fontawesome", character.only = TRUE)) { install.packages("fontawesome", dependencies = TRUE) library(fontawesome, character.only = TRUE) } ``` # Laboratorio 5: Clustering y PCA {background-color="#2d4563"} ## Objetivos del laboratorio :::{style="margin-top: 30px; font-size: 26px;"} :::{.columns} :::{.column width=50%} **Lo que vamos a hacer:** 1. Explorar 8 indicadores de 18 países 2. Aplicar K-means y evaluar clusters 3. Usar el método del codo y silueta 4. Ejecutar PCA e interpretar componentes 5. Visualizar con biplot ::: :::{.column width=50%} **Lo que queremos descubrir:** - ¿Qué países se parecen entre sí? - ¿Cuántos grupos distintos hay? - ¿Qué dimensiones ocultas resumen las 8 variables? - ¿Es el [desarrollo]{.alert} una sola cosa o varias? ::: :::
[Trabajen en sus computadoras. Intenten resolver los ejercicios antes de mirar la solución. Clustering jerárquico y ejercicios adicionales están en los apéndices]{.alert} ::: # Parte 1: Exploración de datos {background-color="#2d4563"} ## Cargar paquetes :::{style="margin-top: 30px; font-size: 24px;"} ```{r} #| label: cargar-paquetes #| echo: true #| eval: true #| message: false #| warning: false # Instala los que falten y los carga paquetes <- c( "tidyverse", "tidymodels", # recipe(), step_normalize() "cluster", # silhouette() "factoextra", # fviz_cluster(), fviz_nbclust(), fviz_pca(), ... "corrplot" # matriz de correlación ) for (pkg in paquetes) { if (!require(pkg, character.only = TRUE)) { install.packages(pkg, dependencies = TRUE) library(pkg, character.only = TRUE) } } set.seed(2026) ``` ::: ## Cargar y explorar los datos :::{style="margin-top: 30px; font-size: 24px;"} ```{r} #| label: cargar-datos #| echo: true #| eval: true # Cargar indicadores por país paises <- read_csv("datos/indicadores_paises.csv") # Lean el archivo directo desde la web: # paises <- read_csv("https://raw.githubusercontent.com/danilofreire/introduccion-ia-ucu/main/clases/dia-03/datos/indicadores_paises.csv") # Vista general glimpse(paises) ``` ::: ## Variables del dataset :::{style="margin-top: 30px; font-size: 26px;"} | Variable | Descripción | |----------|-------------| | `pib_per_capita` | PIB per cápita en USD | | `esperanza_vida` | Esperanza de vida al nacer (años) | | `anios_educacion` | Años promedio de escolaridad | | `acceso_internet` | % de población con acceso a internet | | `gasto_salud_pib` | Gasto en salud como % del PIB | | `indice_gini` | Índice de Gini (desigualdad, 0-100) | | `urbanizacion` | % de población urbana | | `indice_democracia` | Índice de democracia (0-10) | :::{style="text-align: center;"} [Todas las variables son numéricas. Ideal para clustering y PCA]{.alert} ::: ::: ## Estadísticas descriptivas :::{style="margin-top: 30px; font-size: 24px;"} ```{r} #| label: estadisticas #| echo: true #| eval: true # Resumen de cada variable paises |> select(-pais) |> summary() ``` Las variables tienen [escalas muy diferentes]{.alert} (PIB en miles vs. índices de 0-10). Es necesario escalar antes de aplicar K-means o PCA ::: ## Matriz de correlación :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: correlacion #| echo: true #| eval: true #| fig-width: 6.5 #| fig-height: 4.5 # Calcular correlaciones cor_matrix <- paises |> select(-pais) |> cor() # Visualizar corrplot(cor_matrix, method = "color", type = "upper", addCoef.col = "black", number.cex = 0.7, tl.col = "black", tl.srt = 45, col = colorRampPalette(c("#E74C3C", "white", "#2d4563"))(200)) ``` ::: ## Interpretación de correlaciones :::{style="margin-top: 30px; font-size: 24px;"} :::{.columns} :::{.column width=50%} **Correlaciones positivas fuertes:** - Internet ↔ urbanización: **0.86** - Esperanza de vida ↔ democracia: **0.77** - PIB ↔ democracia: **0.76** - PIB ↔ esperanza de vida: **0.74** - PIB ↔ internet: **0.73** - Internet ↔ educación: **0.67** Estas variables "van juntas": los países con mayor PIB tienen mejor educación, salud, democracia e internet ::: :::{.column width=50%} **Correlaciones negativas:** - Gini ↔ urbanización: **-0.41** - Gini ↔ internet: **-0.26** - Gini ↔ PIB: **-0.15** Los países más desiguales tienden a ser menos urbanos y con menor acceso a internet. La correlación Gini ↔ democracia es **-0.12**, casi nula
[Varias variables "apuntan en la misma dirección": el PCA las resumirá en un "eje de desarrollo"]{.alert} ::: ::: ::: ## Ejercicio rápido: dos países {#sec:ejercicio-paises} :::{style="margin-top: 30px; font-size: 24px;"} Elijan dos países del dataset que les interesen (por ejemplo, Uruguay vs. Honduras, Chile vs. Bolivia, o Argentina vs. Venezuela). Comparen sus valores en las 8 variables. **Preguntas:** - ¿Cuál parece más [desarrollado]{.alert}? - ¿En qué variable es mayor la diferencia? - ¿Hay alguna variable en la que el "menos desarrollado" supere al otro? *Pista:* usen `paises |> filter(pais %in% c("...", "..."))` y `select()` con las variables que quieran comparar. [Tómense 3 minutos para experimentar]{.alert} [[Apéndice: Solución]{.button}](#sec:sol-paises) ::: ## Preparar datos para clustering :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: preparar-datos #| echo: true #| eval: true # Escalar con una receta (media = 0, sd = 1), como en el Día 2 receta_paises <- recipe(~ ., data = paises) |> update_role(pais, new_role = "id") |> step_normalize(all_numeric_predictors()) datos_scaled <- receta_paises |> prep() |> juice() |> column_to_rownames("pais") head(datos_scaled, 5) ``` [`step_normalize()`]{.alert} hace lo mismo que `scale()` y es la sintaxis que ya usamos en los laboratorios del Día 2. La receta [no tiene variable objetivo]{.alert} (empieza con `~`) y `update_role()` marca a `pais` como identificador, no como variable a normalizar [`column_to_rownames("pais")`]{.alert} mueve la columna `pais` a los nombres de fila, así los nombres de países se preservan automáticamente en todos los plots posteriores (clusters, dendrograma, biplot) ::: # Parte 2: K-means y evaluación {background-color="#2d4563"} ## ¿Qué buscamos con el clustering? :::{style="margin-top: 30px; font-size: 26px;"} La [hipótesis]{.alert}: los 18 países latinoamericanos no son todos iguales en desarrollo. K-means los dividirá en grupos "parecidos entre sí". **Preguntas que queremos responder:** - ¿Cuántos grupos realmente distintos hay? (¿2, 3, 4?) - ¿Qué países entran en cada grupo? - ¿Los grupos corresponden a niveles de desarrollo, o a otra dimensión? - ¿El resultado es estable o sensible al número K elegido? [Métrica de éxito:]{.alert} que los grupos tengan sentido sustantivo (países parecidos juntos) y que lo confirmen métricas como la [silueta]{.alert} y el [método del codo]{.alert} ::: ## Ejecutar K-means con K=2 :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: kmeans-basico #| echo: true #| eval: true # K-means con 2 clusters km2 <- kmeans(datos_scaled, centers = 2, nstart = 25) # Ver resultados km2$cluster # Agregar al dataframe original paises$cluster_km2 <- factor(km2$cluster) ``` ::: ## Visualizar los clusters :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: viz-kmeans #| echo: true #| eval: true #| fig-width: 8 #| fig-height: 5 # Visualización con factoextra (usa PCA automáticamente) fviz_cluster(km2, data = datos_scaled, palette = c("#2d4563", "#e63946"), geom = "point", ellipse.type = "convex", ggtheme = theme_minimal()) + geom_text(aes(label = rownames(datos_scaled)), vjust = -1, size = 3) + labs(title = "K-means con K=2") ``` ::: ## ¿Qué países están en cada cluster? :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: paises-cluster #| echo: true #| eval: true # Listar países por cluster paises |> group_by(cluster_km2) |> summarise(paises = paste(pais, collapse = ", ")) ``` ::: ## Perfil de cada cluster :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: perfil-cluster #| echo: true #| eval: true # Medias por cluster (datos originales, no escalados) paises |> group_by(cluster_km2) |> summarise( n = n(), pib_mean = round(mean(pib_per_capita)), vida_mean = round(mean(esperanza_vida), 1), educ_mean = round(mean(anios_educacion), 1), inet_mean = round(mean(acceso_internet), 1), gini_mean = round(mean(indice_gini), 1), demo_mean = round(mean(indice_democracia), 1) ) ``` ¿Los dos clusters corresponden a "más desarrollados" vs. "menos desarrollados"? ¿En qué variable se diferencian más? ::: ## Método del codo :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: metodo-codo #| echo: true #| eval: true #| fig-width: 6.5 #| fig-height: 4 # Calcular WSS para K=1 a K=8 fviz_nbclust(datos_scaled, kmeans, method = "wss", k.max = 8, nstart = 25) + labs(title = "Método del codo", subtitle = "¿Dónde se 'aplana' la curva?") + theme_minimal() ``` [La mayor caída va de K=1 a K=2. Después la curva se aplana: K=2 es el codo]{.alert} ::: ## Método de la silueta :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: metodo-silueta #| echo: true #| eval: true #| fig-width: 6.5 #| fig-height: 4 # Calcular silueta promedio para K=2 a K=8 fviz_nbclust(datos_scaled, kmeans, method = "silhouette", k.max = 8, nstart = 25) + labs(title = "Método de la silueta", subtitle = "K óptimo maximiza la silueta promedio") + theme_minimal() ``` [El pico está en K=2. Codo y silueta coinciden: dos grupos es la solución más defendible]{.alert} ::: ## Interpretación de la silueta :::{style="margin-top: 30px; font-size: 24px;"} :::{.columns} :::{.column width=50%} **Silueta promedio:** ```{r} #| label: silueta-promedio #| echo: true #| eval: true # Calcular silueta para cada observación sil <- silhouette(km2$cluster, dist(datos_scaled)) mean(sil[, 3]) ``` Un valor de ~0.29 indica estructura [débil pero visible]{.alert} **Observaciones con silueta negativa:** Están mal clasificadas (más cerca del otro cluster) ::: :::{.column width=50%} **Regla de interpretación:** :::{style="text-align: center;"} | Valor | Significado | |-------|-------------| | 0.71 - 1.00 | Fuerte | | 0.51 - 0.70 | Razonable | | 0.26 - 0.50 | Débil | | < 0.25 | Sin estructura | :::
[Con solo 18 países, es difícil obtener siluetas muy altas]{.alert} ::: ::: ::: ## Ejercicio rápido: ¿y si probamos K=3? {#sec:ejercicio-k3} :::{style="margin-top: 30px; font-size: 22px;"} Codo y silueta apuntan a K=2, pero K=3 está muy cerca. Prueben dividir los países en 3 grupos y comparen. **Instrucciones:** 1. Ejecuten `kmeans(datos_scaled, centers = 3, nstart = 25)` y guárdenlo en `km3` 2. Calculen la silueta promedio con `silhouette(km3$cluster, dist(datos_scaled))` 3. Comparen con la silueta de K=2 (≈ 0.29) **Preguntas:** - ¿La silueta sube o baja al pasar de K=2 a K=3? - ¿Qué países quedan en el cluster "intermedio"? - ¿Tiene sentido ese cluster como "desarrollo medio"? [Tómense 3 minutos para experimentar]{.alert} [[Apéndice: Solución]{.button}](#sec:sol-k3) ::: # Parte 3: PCA e interpretación {background-color="#2d4563"} ## ¿Qué buscamos con el PCA? :::{style="margin-top: 30px; font-size: 26px;"} Tenemos 8 variables. PCA las [comprime]{.alert} en pocas dimensiones sin perder mucha información. **Preguntas que queremos responder:** - ¿Cuántas dimensiones bastan para resumir las 8 variables? - ¿Qué [significa]{.alert} cada dimensión? (¿"desarrollo"? ¿"desigualdad"? ¿otra cosa?) - ¿Qué países están en los extremos de cada eje? - ¿Los clusters de K-means se separan cuando los vemos en PC1 y PC2? [Métrica de éxito:]{.alert} que con 2 o 3 componentes expliquemos >70% de la varianza, y que los ejes tengan una interpretación sustantiva clara ::: ## Ejecutar PCA :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: pca-basico #| echo: true #| eval: true # PCA sobre datos escalados pca <- prcomp(datos_scaled) # Resumen de varianza explicada summary(pca) ``` [PC1 explica el 52% de la varianza y PC2 el 20%. Entre los dos resumimos el 72% de la información de las 8 variables originales]{.alert} ::: ## Scree plot :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: scree-plot #| echo: true #| eval: true #| fig-width: 6.5 #| fig-height: 4 # Varianza explicada por componente fviz_eig(pca, addlabels = TRUE, barfill = "#2d4563", barcolor = "#2d4563") + labs(title = "Scree plot: varianza explicada por componente") + theme_minimal() ``` ::: ## Loadings: ¿qué mide cada componente? :::{style="margin-top: 30px; font-size: 20px;"} ```{r} #| label: loadings #| echo: true #| eval: true # Loadings de los primeros 3 componentes loadings <- pca$rotation[, 1:3] |> as.data.frame() |> rownames_to_column("variable") |> arrange(desc(abs(PC1))) loadings ``` ::: ## Interpretación de PC1 y PC2 :::{style="margin-top: 30px; font-size: 22px;"} :::{.columns} :::{.column width=50%} **PC1 (52% varianza):** Cargas altas (todas negativas) en: - PIB (-0.44), internet (-0.44) - Democracia (-0.40), urbanización (-0.38) - Esperanza de vida (-0.37), educación (-0.32) → [Eje de desarrollo general]{.alert} Todas estas variables cargan en la misma dirección (negativa): un país con PC1 muy negativo tiene más PIB, democracia e internet. El signo es arbitrario; lo que importa es que van juntas ::: :::{.column width=50%} **PC2 (20% varianza):** Cargas altas en: - Índice de Gini (0.51) - Esperanza de vida (0.43) - Gasto en salud (0.40) Cargas negativas en: - Urbanización (-0.39), educación (-0.32) → [Contraste desigualdad / urbanización]{.alert} Separa países desiguales pero con buena salud de países más urbanos y educados ::: ::: ::: ## Ejercicio rápido: ¿qué país está en los extremos? {#sec:ejercicio-pc1} :::{style="margin-top: 30px; font-size: 22px;"} Ordenen los países por su valor en PC1 para identificar los más "desarrollados" y los menos, según esta medida resumen. **Instrucciones:** 1. Extraigan las coordenadas PC1 y PC2 desde `pca$x[, 1:2]` 2. Conviertan a `data.frame` y agreguen los nombres de países con `rownames_to_column("pais")` 3. Ordenen por PC1 con `arrange(PC1)` **Preguntas:** - ¿Coincide el ranking con su intuición sobre el desarrollo latinoamericano? - ¿Qué país les sorprende más (arriba o abajo)? - ¿Qué países están cerca de PC1 = 0, en el "medio"? [Tómense 3 minutos para experimentar]{.alert} [[Apéndice: Solución]{.button}](#sec:sol-pc1) ::: ## Biplot :::{style="margin-top: 30px; font-size: 20px;"} ```{r} #| label: biplot #| echo: true #| eval: true #| fig-width: 8 #| fig-height: 5.5 # Biplot con factoextra fviz_pca_biplot(pca, repel = TRUE, # Evita solapamiento de etiquetas col.var = "#e63946", col.ind = "#2d4563", label = "all") + labs(title = "Biplot: países y variables") + theme_minimal() ``` ::: ## Resumen del laboratorio :::{style="margin-top: 30px; font-size: 24px;"} :::{.columns} :::{.column width=50%} **Lo que practicamos:** - Exploración y escalado de datos - K-means con evaluación (codo, silueta) - PCA con interpretación de loadings - Biplot para visualizar países y variables ::: :::{.column width=50%} **Funciones clave:** - `step_normalize()`: normalizar datos - `kmeans()`: clustering - `silhouette()`: evaluar clusters - `prcomp()`: PCA - `fviz_*()`: visualizaciones ::: :::
[En el próximo laboratorio aplicaremos análisis de texto. En los apéndices: clustering jerárquico y ejercicios adicionales]{.alert} ::: # Apéndice: Soluciones de ejercicios rápidos {background-color="#2d4563"} ## Solución: dos países {#sec:sol-paises} :::{style="margin-top: 20px; font-size: 20px;"} ```{r} #| label: sol-dos-paises #| echo: true #| eval: true paises |> filter(pais %in% c("Uruguay", "Honduras")) |> select(pais, pib = pib_per_capita, internet = acceso_internet, democracia = indice_democracia, urban = urbanizacion, gini = indice_gini) ``` - Uruguay tiene PIB per cápita [más de seis veces mayor]{.alert} que Honduras (17 185 vs. 2 658) - Uruguay supera a Honduras en internet (88% vs. 39%), democracia (8.7 vs. 5.4) y urbanización (95% vs. 59%) - Pero Honduras tiene Gini [más alto]{.alert} (52.3 vs. 38.9): es más desigual - El "desarrollo" no es una sola cosa: hay variables que van en distintas direcciones [[Volver al ejercicio]{.button}](#sec:ejercicio-paises) ::: ## Solución: ¿y si probamos K=3? {#sec:sol-k3} :::{style="margin-top: 20px; font-size: 20px;"} ```{r} #| label: sol-k3 #| echo: true #| eval: true km3 <- kmeans(datos_scaled, centers = 3, nstart = 25) sil3 <- silhouette(km3$cluster, dist(datos_scaled)) mean(sil3[, 3]) # ¿Qué países quedan en cada cluster? data.frame(pais = rownames(datos_scaled), cluster = km3$cluster) |> arrange(cluster) ``` - Silueta con K=3: [≈ 0.27]{.alert} (con K=2 era ≈ 0.29, así que baja un poco) - El cluster "intermedio" suele contener países como Bolivia, Ecuador, México, Perú, Paraguay y República Dominicana: desarrollo medio - El cluster "bajo" queda como Guatemala, Honduras y Nicaragua: los más pobres - [Lección:]{.alert} K=3 tiene sentido sustantivo aunque la silueta sea levemente peor [[Volver al ejercicio]{.button}](#sec:ejercicio-k3) ::: ## Solución: ¿qué país está en los extremos? {#sec:sol-pc1} :::{style="margin-top: 20px; font-size: 18px;"} ```{r} #| label: sol-extremos-pc1 #| echo: true #| eval: true pca$x[, 1:2] |> as.data.frame() |> rownames_to_column("pais") |> arrange(PC1) |> mutate(PC1 = round(PC1, 2), PC2 = round(PC2, 2)) ``` - Los valores más negativos de PC1 (Uruguay, Chile, Argentina, Costa Rica, Panamá) son los países más "desarrollados" en este conjunto - Los valores más positivos (Honduras, Nicaragua, Guatemala) son los menos desarrollados - [Sorpresas posibles:]{.alert} Venezuela tiene el PC2 más bajo (-2.99): combina alta urbanización y educación con el menor gasto en salud y la democracia más baja; México sorprende por estar cerca del medio pese a su PIB [[Volver al ejercicio]{.button}](#sec:ejercicio-pc1) ::: # Apéndice 1: Clustering jerárquico {background-color="#2d4563"} ## Calcular distancias y dendrograma :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: hclust-basico #| echo: true #| eval: true #| fig-width: 9 #| fig-height: 5 # Matriz de distancias euclidianas d <- dist(datos_scaled, method = "euclidean") # Clustering jerárquico con método Ward hc <- hclust(d, method = "ward.D2") # Dendrograma con rectángulos para K=2 plot(hc, hang = -1, cex = 0.9, main = "Dendrograma: Países latinoamericanos", xlab = "País", ylab = "Altura") rect.hclust(hc, k = 2, border = c("#2d4563", "#e63946")) ``` ::: ## Cortar y comparar con K-means :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: cortar-dendrograma #| echo: true #| eval: true # Cortar para obtener K=2 clusters grupos_hc <- cutree(hc, k = 2) # Comparar con K-means table(K_means = km2$cluster, Jerarquico = grupos_hc) ``` Los números de cluster son arbitrarios (cluster 1 en K-means puede ser cluster 2 en jerárquico). Lo importante es si los grupos de países coinciden ::: # Apéndice 2: PCA avanzado {background-color="#2d4563"} ## PCA coloreado por cluster K-means :::{style="margin-top: 30px; font-size: 20px;"} ```{r} #| label: pca-cluster #| echo: true #| eval: true #| fig-width: 8 #| fig-height: 5 pca_coords <- pca$x[, 1:2] |> as.data.frame() |> rownames_to_column("pais") |> mutate(cluster = paises$cluster_km2) ggplot(pca_coords, aes(x = PC1, y = PC2, color = cluster, label = pais)) + geom_point(size = 3) + geom_text(vjust = -0.8, size = 3, show.legend = FALSE) + scale_color_manual(values = c("#2d4563", "#e63946")) + labs(title = "PCA coloreado por cluster K-means", x = paste0("PC1 (", round(summary(pca)$importance[2,1]*100, 1), "%)"), y = paste0("PC2 (", round(summary(pca)$importance[2,2]*100, 1), "%)")) + theme_minimal() ``` ::: ## Contribución de variables a cada componente :::{style="margin-top: 30px; font-size: 22px;"} ```{r} #| label: contrib-var #| echo: true #| eval: true #| fig-width: 8 #| fig-height: 4 fviz_contrib(pca, choice = "var", axes = 1, fill = "#2d4563") + labs(title = "Contribución de variables a PC1") + theme_minimal() ``` ::: # Apéndice 3: Ejercicios adicionales {background-color="#2d4563"} ## Ejercicio: Probar K=4 :::{style="margin-top: 30px; font-size: 22px;"} **Instrucciones:** 1. Ejecutar K-means con K=4 2. Visualizar los clusters 3. Calcular la silueta 4. ¿Mejora respecto a K=2? ```{r} #| label: ejercicio-1 #| echo: true #| eval: true #| fig-width: 8 #| fig-height: 5 km4 <- kmeans(datos_scaled, centers = 4, nstart = 25) # Silueta promedio sil4 <- silhouette(km4$cluster, dist(datos_scaled)) mean(sil4[, 3]) # Visualizar fviz_cluster(km4, data = datos_scaled, palette = c("#2d4563", "#e63946", "#457b9d", "#f4a261"), ggtheme = theme_minimal()) + labs(title = "K-means con K=4") ``` ::: ## Ejercicio: PCA con 3 componentes :::{style="margin-top: 30px; font-size: 22px;"} **Instrucciones:** 1. Extraer los primeros 3 componentes 2. Comparar PC1-PC2 vs. PC1-PC3 3. ¿El tercer componente agrega información útil? ```{r} #| label: ejercicio-pca3 #| echo: true #| eval: true #| fig-width: 8 #| fig-height: 5 pca_3d <- pca$x[, 1:3] |> as.data.frame() |> rownames_to_column("pais") |> mutate(cluster = paises$cluster_km2) ggplot(pca_3d, aes(x = PC1, y = PC3, color = cluster, label = pais)) + geom_point(size = 3) + geom_text(vjust = -0.8, size = 3, show.legend = FALSE) + scale_color_manual(values = c("#2d4563", "#e63946")) + labs(title = "PC1 vs PC3") + theme_minimal() ``` ::: # Continuar con el laboratorio de texto {background-color="#2d4563"}