Se cargó la base de datos.

datos <- read.csv("mental_health_social_media_dataset.csv", header= T)

library(tidyverse)
datos <- datos %>% 
  mutate(date = as.Date(date,format="%m/%d/%Y")) %>%
  arrange(date)  

Se utlizó skim() para tener una mejor visión de la base de datos.

library(skimr)
skimr::skim(datos)
Data summary
Name datos
Number of rows 5000
Number of columns 15
_______________________
Column type frequency:
character 4
Date 1
numeric 10
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
person_name 0 1 7 17 0 891 0
gender 0 1 4 6 0 3 0
platform 0 1 6 9 0 7 0
mental_state 0 1 7 8 0 3 0

Variable type: Date

skim_variable n_missing complete_rate min max median n_unique
date 0 1 2024-01-01 2025-11-16 2024-12-09 686

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
age 0 1 29.95 12.28 13.0 21.0 27.0 35.25 69.0 ▇▆▃▁▁
daily_screen_time_min 0 1 373.06 106.00 140.0 310.0 388.0 461.00 520.0 ▃▃▃▅▇
social_media_time_min 0 1 175.33 71.21 35.0 118.0 170.0 231.00 338.0 ▃▇▇▅▃
negative_interactions_count 0 1 0.86 0.56 0.0 1.0 1.0 1.00 2.0 ▃▁▇▁▁
positive_interactions_count 0 1 1.84 0.94 0.0 1.0 2.0 2.00 4.0 ▁▇▆▃▁
sleep_hours 0 1 7.13 0.53 6.4 6.7 7.1 7.45 8.3 ▇▆▅▃▃
physical_activity_min 0 1 22.69 10.60 8.0 14.0 21.0 29.00 46.0 ▇▆▃▃▃
anxiety_level 0 1 2.51 0.79 1.0 2.0 3.0 3.00 4.0 ▂▇▁▇▂
stress_level 0 1 7.11 1.06 5.0 6.0 7.0 8.00 9.0 ▂▅▇▇▂
mood_level 0 1 5.63 0.76 4.0 5.0 6.0 6.00 7.0 ▁▆▁▇▂

La base de datos contiene 15 columnas y 5,000 filas. También se puede ver que el n_missing de cada columna tiene una cantidad de cero, lo cual significa que no hay datos faltantes. A continuación, se hizo una gráfica para tener certeza.

# NA por columna
library(naniar)
gg_miss_var(datos)

Ahora estariamos escalando las variables. La variable de stress_level, al ser la dependiente, no se escala. Escalamos todas las variables numéricas, y convertimos las categóricas a factor.

library(scales)
datos_esc <- datos %>%
  mutate(
    across(where(is.numeric) & !c(stress_level), rescale),  
    gender   = as.factor(gender),
    platform = as.factor(platform),
    mental_state = as.factor(mental_state)
  )
# Variables categóricas
datos_esc$gender       <- relevel(datos_esc$gender, ref = "Male")
datos_esc$mental_state <- relevel(datos_esc$mental_state, ref = "Healthy")

Regresión lineal simple

Para empezar, se decidió en hacer una regresión lineal simple (RLS). Nuestra variable dependiente (y) es el stress_level, mientras nuestra variable independiente es social_media_time_min. Escogimos estas 2 inicialmente para ver su correlación, y también considerando que son las variables que queremos investigar más.

# Correlación 
cor(datos_esc$social_media_time_min, datos_esc$stress_level)
## [1] 0.8828733

Un valor de correlación de 0.8829 es una relación fuerte y postiva entre el nivel de estrés y el tiempo en redes sociales en minutos.

Modelo de regresión lineal simple

lm <- lm(stress_level ~ social_media_time_min, data = datos_esc)
summary(lm)
## 
## Call:
## lm(formula = stress_level ~ social_media_time_min, data = datos_esc)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.97047 -0.39301 -0.01312  0.38412  1.05483 
## 
## Coefficients:
##                       Estimate Std. Error t value Pr(>|t|)    
## (Intercept)            5.25920    0.01559   337.2   <2e-16 ***
## social_media_time_min  3.99102    0.03003   132.9   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.499 on 4998 degrees of freedom
## Multiple R-squared:  0.7795, Adjusted R-squared:  0.7794 
## F-statistic: 1.767e+04 on 1 and 4998 DF,  p-value: < 2.2e-16

En el modelo de regresión lineal simple se analizó la relación entre el nivel de estrés y el tiempo en redes sociales en minutos, obteniendo un intercepto de 5.26, lo que indica que cuando el tiempo en redes sociales es cero, el nivel de estrés promedio es de 5.26 unidades. El coeficiente de la variable fue de 3.99, lo que sugiere que por cada unidad adicional en el tiempo dedicado a redes sociales (en escala estandarizada), el nivel de estrés aumenta en promedio 3.99 unidades, manteniendo constante el resto del contexto. Este efecto fue altamente significativo, con un p-value menor a 2e-16, lo que indica una relación confiable. Además, el modelo presentó un R² ajustado de 0.779, lo que significa que el tiempo en redes sociales explica aproximadamente el 77.9% de la variación en el nivel de estrés. Estos hallazgos sugieren que el tiempo en redes sociales es un predictor fuerte del estrés percibido, y sirven como punto de partida sólido para desarrollar modelos más complejos en las siguientes etapas del proyecto.

Regresión lineal múltiple

El método siguiente a utilizarse es el de la regresión lineal múltiple (RLM). Ya vimos la relación entre las variables de stress_level y social_media_time_min, pero ahora se añadiran variables adicionales para ir más al detalle con la investigación.

1. Ajuste del modelo:

Se va a evaluar que modelo vamos a escoger entre: el modelo por subconjuntos y el modelo paso a paso.

A. Modelo por subconjuntos:

Se calculó el modelo saturado, en donde se encuentran todas las variables que utilizaremos.

saturado <- stress_level ~ age + gender + platform +
  negative_interactions_count + positive_interactions_count +
  sleep_hours + physical_activity_min + anxiety_level + mood_level +
  social_media_time_min + daily_screen_time_min + mental_state

reg <- lm(saturado, data = datos_esc)

summary(reg)
## 
## Call:
## lm(formula = saturado, data = datos_esc)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.70481 -0.11100  0.00745  0.11117  0.63137 
## 
## Coefficients:
##                              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                  7.904920   0.433933  18.217  < 2e-16 ***
## age                         -0.325658   0.026896 -12.108  < 2e-16 ***
## genderFemale                -0.007434   0.005700  -1.304 0.192216    
## genderOther                 -0.017063   0.020460  -0.834 0.404335    
## platformInstagram            0.001181   0.019190   0.062 0.950945    
## platformSnapchat            -0.039973   0.022586  -1.770 0.076820 .  
## platformTikTok              -0.070660   0.031822  -2.220 0.026432 *  
## platformTwitter              0.072790   0.012353   5.893 4.05e-09 ***
## platformWhatsApp             0.022665   0.014812   1.530 0.126032    
## platformYouTube             -0.082463   0.027258  -3.025 0.002497 ** 
## negative_interactions_count  0.322541   0.022045  14.631  < 2e-16 ***
## positive_interactions_count -0.010834   0.039325  -0.276 0.782938    
## sleep_hours                 -0.016344   0.187918  -0.087 0.930697    
## physical_activity_min       -1.247074   0.371993  -3.352 0.000807 ***
## anxiety_level                0.724819   0.034020  21.306  < 2e-16 ***
## mood_level                  -1.590849   0.030426 -52.285  < 2e-16 ***
## social_media_time_min        0.542346   0.084197   6.441 1.30e-10 ***
## daily_screen_time_min       -0.245255   0.435250  -0.563 0.573132    
## mental_stateAt_Risk         -0.260604   0.028820  -9.042  < 2e-16 ***
## mental_stateStressed         0.079276   0.016919   4.686 2.87e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1992 on 4980 degrees of freedom
## Multiple R-squared:  0.965,  Adjusted R-squared:  0.9648 
## F-statistic:  7221 on 19 and 4980 DF,  p-value: < 2.2e-16

Selección de modelo por subconjunto:

library(leaps)

ajuste <- regsubsets(
  saturado,
  data = datos_esc,
  nvmax = 7,              
  method = "exhaustive")

s <- summary(ajuste)

names(s)
## [1] "which"  "rsq"    "rss"    "adjr2"  "cp"     "bic"    "outmat" "obj"

Se identificó el mejor modelo entre BIC y R^2 ajustado.

best_bic <- which.min(s$bic)
best_r2  <- which.max(s$adjr2)

# Visualización comparativa
par(mfrow = c(1,2))

plot(s$bic, type="b", col="red", pch=19,
     xlab="Número de predictores", ylab="BIC",
     main="Criterio BIC")
points(best_bic, s$bic[best_bic], pch=19, cex=1.5, col="blue")

plot(s$adjr2, type="b", col="darkgreen", pch=19,
     xlab="Número de predictores", ylab="R^2-ajustado",
     main="Criterio R^2-ajustado")
points(best_r2, s$adjr2[best_r2], pch=19, cex=1.5, col="blue")

El modelo saturado mostró un R2 ajustado de 0.9648, indicando que tiene una capacidad alta de explicar las variables. Aparte de esto, se aplicó la selección de variables por subconjunto, estos siendo el BIC y el R2 ajustado. Ambos criterios coincidieron en la selección de 7 predictores, lo que sugiere un equilibrio entre ajuste y parsimonia. El resultado nos asegura que el nivel de estrés si esta determinado por varias de estas variables; tales como: el estado mental, las interacciones negativas en las redes, la actividad física, entre otros.

B. Modelo paso a paso:

Se utlizó el mismo modelo saturado del ajuste de modelo de subconjuntos, y se calculó el modelo nulo.

saturado <- stress_level ~ age + gender + platform +
  negative_interactions_count + positive_interactions_count +
  sleep_hours + physical_activity_min + anxiety_level + mood_level +
  social_media_time_min + daily_screen_time_min + mental_state

reg <- lm(saturado, data = datos_esc)
nulo <- lm(stress_level ~ 1, data = datos_esc)

Forward stepwise selection:

step_forward <- step(nulo,
                     scope = list(lower = ~1, upper = formula(reg)),
                     direction = "forward",
                     k = log(nrow(datos)),
                     trace = FALSE) 

Backward stepwise selection:

step_backward <- step(reg,
                      direction = "backward",
                      k = log(nrow(datos)),
                      trace = FALSE)

Hybrid:

step_both <- step(nulo,
                  scope = list(lower = ~1, upper = formula(reg)),
                  direction = "both",
                  k = log(nrow(datos)),
                  trace = FALSE)

2. Modelo final (Hybrid):

modelo1 <- step_both
summary(modelo1)
## 
## Call:
## lm(formula = stress_level ~ mood_level + physical_activity_min + 
##     anxiety_level + negative_interactions_count + age + platform + 
##     mental_state + social_media_time_min, data = datos_esc)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.70032 -0.10999  0.00737  0.11198  0.63574 
## 
## Coefficients:
##                              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                  7.661344   0.057998 132.097  < 2e-16 ***
## mood_level                  -1.592604   0.030387 -52.411  < 2e-16 ***
## physical_activity_min       -1.023652   0.048893 -20.936  < 2e-16 ***
## anxiety_level                0.721797   0.033331  21.656  < 2e-16 ***
## negative_interactions_count  0.323722   0.021722  14.903  < 2e-16 ***
## age                         -0.325112   0.026757 -12.150  < 2e-16 ***
## platformInstagram            0.001334   0.018450   0.072  0.94239    
## platformSnapchat            -0.037440   0.022209  -1.686  0.09190 .  
## platformTikTok              -0.066949   0.031363  -2.135  0.03284 *  
## platformTwitter              0.073232   0.012328   5.940 3.04e-09 ***
## platformWhatsApp             0.021752   0.014688   1.481  0.13868    
## platformYouTube             -0.082002   0.026233  -3.126  0.00178 ** 
## mental_stateAt_Risk         -0.260603   0.028617  -9.107  < 2e-16 ***
## mental_stateStressed         0.079192   0.016869   4.695 2.74e-06 ***
## social_media_time_min        0.525983   0.075281   6.987 3.18e-12 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1992 on 4985 degrees of freedom
## Multiple R-squared:  0.965,  Adjusted R-squared:  0.9649 
## F-statistic:  9805 on 14 and 4985 DF,  p-value: < 2.2e-16

En el modelo final se obtuvo un intercepto de 7.66, lo que indica que el nivel esperado de estrés es de 7.66 unidades cuando todas las variables explicativas son cero y las categorías base de las variables categóricas están presentes.

mood_level: es de −1.59, lo que sugiere que, por cada unidad adicional en el nivel de estado de ánimo, el nivel de estrés disminuye en promedio 1.59 unidades, manteniendo constantes las demás variables.

physical_activity_min es de −1.02, indicando que un aumento en el tiempo dedicado a actividad física se asocia con una reducción promedio de 1.02 unidades en el nivel de estrés.

anxiety_level: de 0.72, lo que implica que por cada unidad adicional de ansiedad, el nivel de estrés aumenta en promedio 0.72 unidades, manteniendo constantes las demás variables.

negative_interaction_counts: el número de interacciones negativas en redes sociales muestra una relación positiva, ya que por cada interacción negativa adicional, el estrés aumenta en promedio 0.32 unidades.

age: es de (−0.33), lo que indica que, a mayor edad, el nivel de estrés tiende a disminuir, manteniendo constantes las demás variables.

social_media_time_min: es de 0.53, lo que sugiere que un mayor tiempo de uso está asociado con un aumento del nivel de estrés.

platform: se observa que el uso de Twitter se asocia con un nivel de estrés significativamente mayor en comparación con la plataforma base, mientras que YouTube y TikTok presentan coeficientes negativos, indicando menores niveles de estrés promedio.

mental_state: los individuos clasificados como At Risk o Stressed presentan niveles de estrés significativamente más altos que aquellos en la categoría base, manteniendo constantes las demás variables.

El modelo final presenta un R² ajustado de 0.9649, lo cual indica que explica aproximadamente el 96.49% de la variación en el nivel de estrés. Además, el error estándar residual es cercano a 0.20, lo que sugiere que, en promedio, las predicciones del modelo difieren del nivel real de estrés en aproximadamente 0.20 unidades.

3. Evaluación de los supuestos:

a. Normalidad

library(ggplot2)
library(broom)


df  <- data.frame(
 yhat = fitted.values(modelo1),
 res  = rstandard(modelo1))

ggplot(df, aes(sample = res)) +
  stat_qq(color = "blue") +
  stat_qq_line(linewidth = 1) +  
  labs(x = "Cuantiles teóricos", y = "Cuantiles muestrales") +
  theme_minimal(base_size = 14)

Prueba Shapiro-Wilk:

shapiro.test(df$res)
## 
##  Shapiro-Wilk normality test
## 
## data:  df$res
## W = 0.98294, p-value < 2.2e-16

Cuando analizamos el supuesto de normalidad por medio de la gráfica Q–Q, podemos observar que la mayoría de los puntos se encuentran cerca de la línea del modelo, especialmente en la parte central, aunque existen algunas desviaciones en los extremos. Esto sugiere que los residuos del modelo se distribuyen de forma aproximadamente normal. Si tomamos en consideración la Prueba de Shapiro–Wilk, se obtuvo un p-value menor a 0.05, por lo que se rechaza la H0 de normalidad. No obstante, debido al tamaño de la muestra y a que las desviaciones observadas en la gráfica no son severas, se puede concluir que el supuesto de normalidad se cumple de manera aproximada para fines del análisis del modelo.

b. Varianza constante

ggplot(df, aes(x = yhat, y = res)) +
  geom_point(alpha = 0.6, color = "blue") +
  geom_hline(yintercept = 0, linetype = "dashed", color = "grey40") +
  labs(x = "Valores ajustados", y = "Residuales estandarizados") +
  theme_minimal(base_size = 14)

Prueba Breusch-Pagan:

library(lmtest)
bptest(modelo1)
## 
##  studentized Breusch-Pagan test
## 
## data:  modelo1
## BP = 1747.2, df = 14, p-value < 2.2e-16

Para que se cumpla el supuesto de varianza constante por el gráfico, la nube de puntos debe permanecer aproximadamente constante alrededor del cero, sin presentar patrones definidos. En este caso, aunque los residuos se distribuyen alrededor del cero, se observa que la dispersión no es completamente uniforme basado en las líneas que aparecen, lo que sugiere posibles variaciones en la varianza a lo largo de los valores ajustados. Para complementar el análisis gráfico, se utilizó la Prueba de Breusch–Pagan, considerando como H0= la varianza es constante y H1= la varianza no es constante. Dado que el p-value obtenido es menor a 0.05, se rechaza la hipótesis nula, por lo que el modelo no cumple completamente con el supuesto de varianza constante.

c. Independencia

library(ggplot2)
library(tidyverse)

df1 <- data.frame(
  res   =  rstandard(modelo1)) %>%
  mutate(orden = 1:length(res))   
  

ggplot(df1, aes(x = orden, y = res)) +
  geom_point(alpha = 0.6, color = "blue") +
  geom_hline(yintercept = 0, linetype = "dashed", color = "grey40") +
  labs(x = "Orden/tiempo", y = "Residuales estandarizados") +
  theme_minimal(base_size = 14)

Prueba Durbin-Watson:

dwtest(modelo1)
## 
##  Durbin-Watson test
## 
## data:  modelo1
## DW = 2.0064, p-value = 0.5939
## alternative hypothesis: true autocorrelation is greater than 0

Para que se cumpla el supuesto de independencia por el gráfico, la nube de puntos debe distribuirse de forma aleatoria alrededor del cero, sin mostrar patrones sistemáticos ni tendencias. En este caso, los residuos se mantienen alrededor del cero y no presentan una estructura clara, lo que respalda gráficamente el cumplimiento del supuesto de independencia. Para reforzar, se aplicó la Prueba de Durbin–Watson, tomando como H0= la independencia de los errores y como H1= la dependencia/autocorrelación. El resultado arrojó un p-value mayor a 0.05, por lo que no se rechaza la hipótesis nula y se concluye que el modelo cumple con el supuesto de independencia.

Conclusión:

En este proyecto se analizó la relación entre el nivel de estrés y el uso de las redes sociales mediante modelos de refresión lineal simple y múltiple. El modelo de regresión lineal simple mostró que el tiempo dedicado a las redes sociales es un predictor significativo del nivel de estrés. Este resultado nos sirvió como base para el desarrollo de modelo más complejos.

Anteriormente, se habia estimado un modelo de regresión múltiple que incorporó variables demográficas, conductuales y psicológicas. Mediante distintos procesos de selección de variables (modelos por subconjunto y paso a paso), se pudo identificar que el modelo híbrido ofrecía coeficientes significativos alto y un R^2 ajustado elevado. Se terminó cumpliendo con los supuestos de normalidad e independencia, pero no se pudo cumplir el de varianza.

En conjunto, los resultados sugieren que el nivel de estrés esta influenciado no solo por el tiempo en las redes sociales, sino tambien por factores psicológicos, las experiencias negativas en las redes y hábitos de bienestar como la actividad física. Estos hallazgos resaltan la importancia de considerar varias variables al analizar el estrés que es percibido.