Introducción

La gestión moderna de portafolios se fundamenta en la teoría de media-varianza de Markowitz, que establece la importancia de diversificar para reducir el riesgo específico y mantener únicamente el riesgo sistemático. Sin embargo, en mercados financieros, los activos suelen presentar correlaciones significativas, lo que dificulta identificar fuentes independientes de riesgo. El Análisis de Componentes Principales (PCA) ofrece una solución estadística robusta al descomponer la estructura de correlación en factores ortogonales, revelando patrones dominantes y contrastes entre activos. Aplicar PCA a los retornos de acciones tecnológicas como AMZN, AAPL y NVDA permite construir portafolios más eficientes, optimizando la relación riesgo-retorno mediante una mejor diversificación.

Cargar librerías

library(tidyquant)  
library(tidyverse)
library(lubridate)
library(factoextra) 
library(ggplot2)
library(scales)
library(gridExtra)
knitr::opts_chunk$set(echo = TRUE)

Descargar precios ajustados desde Yahoo

symbols <- c("AMZN", "AAPL", "NVDA")
end_date <- Sys.Date()
start_date <- end_date %m-% years(5)   # 5 años atrás

prices_raw <- tq_get(symbols,
                     get  = "stock.prices",
                     from = start_date,
                     to   = end_date,
                     complete_cases = FALSE)

Extraer Adjusted Close y pivotear a formato ancho (wide)

prices_adj_wide <- prices_raw %>%
  select(date, symbol, adjusted) %>%
  pivot_wider(names_from = symbol, values_from = adjusted) %>%
  arrange(date)

Usamos log returns:

  • \(r_t = ln(P_t/P_{t-1})\)
returns <- prices_adj_wide %>%
  arrange(date) %>%
  mutate(across(-date, ~ log(.x) - log(lag(.x)))) %>%
  slice(-1)  # eliminar primera fila con NA por diferencia

# Quitar filas con NA (por ejemplo, si faltan datos para un símbolo en una fecha)
returns_clean <- returns %>% drop_na()

# ver primeras fila
print(head(returns_clean))
## # A tibble: 6 × 4
##   date            AMZN      AAPL     NVDA
##   <date>         <dbl>     <dbl>    <dbl>
## 1 2020-10-06 -0.0315   -0.0291    0.00687
## 2 2020-10-07  0.0304    0.0168    0.0164 
## 3 2020-10-08 -0.00161  -0.000956 -0.00901
## 4 2020-10-09  0.0297    0.0172   -0.00551
## 5 2020-10-12  0.0465    0.0616    0.0331 
## 6 2020-10-13  0.000203 -0.0269    0.00156

Preparar matriz para PCA

# Extraer solo las columnas numéricas (retornos)
ret_mat <- returns_clean %>% select(-date) %>% as.matrix()

# Escalar (media 0, varianza 1) — recomendado para PCA de retornos
ret_mat_scaled <- scale(ret_mat, center = TRUE, scale = TRUE)

# Ejecutar PCA (prcomp)
pca_res <- prcomp(ret_mat_scaled, center = FALSE, scale. = FALSE) 

# Resumen y varianza explicada 
print(summary(pca_res))
## Importance of components:
##                           PC1    PC2    PC3
## Standard deviation     1.4547 0.6892 0.6393
## Proportion of Variance 0.7054 0.1583 0.1362
## Cumulative Proportion  0.7054 0.8638 1.0000

PC1 (70.54% de la varianza)

Este componente captura la tendencia común entre las tres acciones.

PC2 (15.83%)

Este componente refleja diferencias relativas entre las acciones.

PC3 (13.62%)

Explica la menor parte de la variaciones residuales.

Scree plot (proporción de varianza por PC)

# Extraer varianza (prop. de varianza)
eigvals <- (pca_res$sdev)^2
prop_var <- eigvals / sum(eigvals)
cum_var <- cumsum(prop_var)
var_table <- tibble(PC = paste0("PC", seq_along(eigvals)),
                    Eigenvalue = eigvals,
                    PropVar = prop_var,
                    CumVar = cum_var)

scree_df <- var_table %>% mutate(PCnum = row_number())

ggplot(scree_df, aes(x = PCnum, y = PropVar)) +
  geom_col() +
  geom_line(aes(y = CumVar), group = 1) +
  geom_point(aes(y = CumVar)) +
  scale_x_continuous(breaks = scree_df$PCnum, labels = scree_df$PC) +
  labs(title = "Scree plot / Proporción de varianza",
       x = "Componentes principales",
       y = "Proporción de varianza (barra) / Varianza acumulada (línea)") +
  theme_minimal()

  • PC1 explica la mayor parte de la variabilidad (≈70–75%), lo que indica que existe un patrón común muy fuerte entre las variables (en tu caso, AMZN, AAPL y NVDA). Este componente es el más importante y puede usarse como un índice sintético del comportamiento conjunto.

  • PC2 aporta alrededor del 15%, capturando diferencias relativas entre las acciones (rotación sectorial o divergencias).

  • PC3 explica cerca del 13%, representando variaciones idiosincráticas o ruido.

  • La línea acumulada muestra que con PC1 + PC2 se alcanza más del 85% de la varianza total, suficiente para reducir dimensionalidad sin perder demasiada información.

Biplot (factor scores + loadings)

# Usamos factoextra para biplot limpio
p_biplot <- fviz_pca_biplot(pca_res,
                            repel = TRUE,
                            col.var = "red",      # carga de variables
                            col.ind = "blue",     # observaciones
                            title = "Biplot PCA (retornos escalados)")
# Loadings (contribuciones) por PC
loadings <- as.data.frame(pca_res$rotation)
loadings$Symbol <- rownames(loadings)
loadings_long <- loadings %>%
  pivot_longer(cols = -Symbol, names_to = "PC", values_to = "Loading")

ggplot(loadings_long, aes(x = PC, y = Loading, fill = Symbol)) +
  geom_col(position = position_dodge(width = 0.9)) +
  labs(title = "Loadings (cargas) de cada símbolo por PC",
       y = "Loading",
       x = "Componente principal") +
  theme_minimal()

Para AMZN, AAPL y NVDA, el PC1 (70.5%; eigenvalue 2.116) captura el factor común del mercado tech: un fuerte co‑movimiento entre las tres acciones, típicamente impulsado por shocks macro, tasas, liquidez y sentimiento. Si las cargas de PC1 son del mismo signo y magnitud similar, PC1 funciona como un índice sintético del trío: cuando PC1 sube, en promedio suben las tres. Conservar solo PC1 resume gran parte de la estructura con una pérdida moderada (~29.5%). El PC2 (15.8%) representa diferencias relativas entre empresas (p. ej., NVDA vs AAPL/AMZN), útil para detectar rotación sectorial o “winners vs laggards”; el PC3 (13.6%) suele ser idiosincrático (eventos propios) o residual. En práctica, PC1+PC2 explican ~86.4% de la variación; para una lectura direccional, mira las cargas: sus signos/magnitudes dirán cuál acción domina el contraste en PC2 y si PC3 contiene un patrón residual significativo.

Conclusión:

En la teoría de portafolio, el modelo de media-varianza y el principio de diversificación son pilares fundamentales: no debemos concentrar todo el riesgo en un solo activo, sino combinar activos para reducir el riesgo específico, manteniendo únicamente el riesgo sistemático \(\beta\). La diversificación se logra seleccionando activos con baja covarianza entre sí. Aquí es donde el Análisis de Componentes Principales (PCA) aporta valor: el PC1 refleja el movimiento común del mercado, mientras que PC2 captura diferencias relativas entre empresas, útiles para identificar rotación sectorial o “winners vs laggards”. Apoyarse en PCA para estimar estas diferencias permite construir portafolios más diversificados, reduciendo riesgos idiosincráticos y mejorando la eficiencia del portafolio.