5  Regresión

La regresión es una técnica estadística y de machine learning utilizada para modelar y analizar relaciones entre variables. Su objetivo principal es entender cómo cambia una variable dependiente en función de una o más variables independientes. La regresión puede ser utilizada tanto para predecir valores futuros como para entender relaciones subyacentes en los datos.

En el contexto de la detección de cuentas falsas de Instagram, la regresión es una herramienta muy útil. Entrenamos y evaluamos el modelo con conjuntos de datos de entrenamiento y prueba, utilizando métricas para asegurar su efectividad. Gracias a que tenemos dos DataSets, train y test, podemos probar nuestro modelo con datos nuevos. Finalmente, interpretamos los resultados para identificar las variables más influyentes y ajustamos el modelo para mejorar su precisión, intentando crear una herramienta fiable de detección de cuentas falsas.

Ahora vamos a comenzar con

library(readr) 
library(dplyr)

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
library(ggplot2)
datos <- read_csv("Data/train.csv") 
Rows: 576 Columns: 12
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
dbl (12): profile pic, nums/length username, fullname words, nums/length ful...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
datosTest <- read_csv("Data/test.csv") 
Rows: 120 Columns: 12
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
dbl (12): profile pic, nums/length username, fullname words, nums/length ful...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.


Antes de intentar modelo de regresión, se debe explorar cuales son las correlaciones entre las variables numéricas.

cor(datos[c("nums/length username","fullname words","description length","#posts","#followers","#follows")])
                     nums/length username fullname words description length
nums/length username           1.00000000    -0.22547213       -0.321170271
fullname words                -0.22547213     1.00000000        0.272522165
description length            -0.32117027     0.27252216        1.000000000
#posts                        -0.15744211     0.07335018        0.144823702
#followers                    -0.06278509     0.03322460        0.005929455
#follows                      -0.17241327     0.09485496        0.226561422
                          #posts   #followers    #follows
nums/length username -0.15744211 -0.062785090 -0.17241327
fullname words        0.07335018  0.033224604  0.09485496
description length    0.14482370  0.005929455  0.22656142
#posts                1.00000000  0.321385480  0.09822504
#followers            0.32138548  1.000000000 -0.01106599
#follows              0.09822504 -0.011065994  1.00000000

Vamos a ordenar las correlaciones de mayor a menor y destacar las más significativas:

  1. description length y nums/length username: -0.32117027

  2. #followers y #posts: 0.32138548

  3. description length y fullname words: 0.272522165

  4. description length y #follows: 0.226561422

  5. nums/length username y fullname words: -0.22547213

  6. nums/length username y #follows: -0.17241327

  7. fullname words y description length: 0.272522165

  8. fullname words y nums/length username: -0.22547213

Estos valores nos indican las variables que tienen más relación entre sí. Es decir, las correlaciones altas señalan que cuando una variable cambia, la otra tiende a cambiar en la misma dirección o en dirección opuesta.

Vamos a emplear la librería psych para visualizar estas correlaciones de manera más intuitiva.

La parte superior de la visualización corresponde a la matriz de correlación. La diagonal muestra histogramas y además añade óvalos indicando la fuerza de correlación. Cuanto más se estire la elipse, más fuerte será la correlación. Cuanto más redondo el óvalo, más débil la correlación.

library(psych)
Warning: package 'psych' was built under R version 4.3.3

Attaching package: 'psych'
The following objects are masked from 'package:ggplot2':

    %+%, alpha
pairs.panels(datos[c("nums/length username","fullname words","description length","#posts","#followers","#follows")])

Ciertamente podemos ver que donde hay mayor elipse es en description length y nums/length username y en followers y #posts. Por lo tanto, las tendremos mas presentes para nuestro futuro modelo de regresión.

5.1 Construcción del modelo

Vamos a construir un primer modelo, donde vamos a enfrentar el atributo fake a todas las demás variables. Aunque seguramente no sea el mejor modelo, nos dará una primera idea de cómo podemos ir mejorándolo.

modelo1 <- lm(fake ~., data = datos)
summary(modelo1)

Call:
lm(formula = fake ~ ., data = datos)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.73096 -0.23729 -0.06653  0.24048  1.01052 

Coefficients:
                         Estimate Std. Error t value Pr(>|t|)    
(Intercept)             7.931e-01  3.798e-02  20.880  < 2e-16 ***
`profile pic`          -4.380e-01  3.345e-02 -13.094  < 2e-16 ***
`nums/length username`  8.062e-01  7.522e-02  10.718  < 2e-16 ***
`fullname words`       -3.354e-02  1.333e-02  -2.516 0.012142 *  
`nums/length fullname` -2.775e-02  1.212e-01  -0.229 0.818988    
`name==username`        2.241e-01  7.641e-02   2.933 0.003498 ** 
`description length`   -1.510e-03  4.342e-04  -3.478 0.000544 ***
`external URL`         -1.542e-01  4.800e-02  -3.213 0.001390 ** 
private                -9.459e-03  2.843e-02  -0.333 0.739459    
`#posts`               -9.094e-05  3.570e-05  -2.547 0.011120 *  
`#followers`           -9.960e-09  1.539e-08  -0.647 0.517743    
`#follows`             -1.850e-05  1.499e-05  -1.235 0.217530    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.3166 on 564 degrees of freedom
Multiple R-squared:  0.6074,    Adjusted R-squared:  0.5998 
F-statistic: 79.33 on 11 and 564 DF,  p-value: < 2.2e-16

Vemos que obtenemos un modelo que no tiene un mal valor de R-squared, pero sigue siendo bajo. Además, ya podemos visualizar variables que se podrían eliminar. Esto se deduce de ver que su p-value es alto, como por ejemplo en el atributo private. Además de tener un residuo alto.

Vamos a ver gráficas sobre el modelo, donde podemos ver los residuos intuitivamente:

plot(modelo1)

Podemos utilizar la gráfica de Residuals vs Leverage para ver la influencia de los puntos en nuestro modelo. Con esta información, observamos que en general no hay muchos puntos que afecten al modelo, los llamados “outliers”; solo podemos distinguir el 45, 25 y 41, los cuales pueden ser eliminados para mejorar el modelo.

Podemos visualizar la distribución de los residuos para evaluar si estos se comportan de manera aproximadamente normal, un supuesto común en muchos modelos estadísticos.

 plot(density(resid(modelo1)))

La forma de la gráfica sugiere que los residuos del modelo no se distribuyen de forma normal y que podría haber problemas con el modelo.

Por último, vamos a ver el modelo prediciendo gráficamente. Podemos utilizar los datos de prueba que nos proporciona nuestro dataset.

modelo1_predic <- predict(modelo1, newdata = datosTest)

datosTest1 <- datosTest %>% mutate(pred = modelo1_predic)

# Rojos -> Reales, verdes -> Predichos
ggplot(datosTest1, aes(x = pred, y = fake)) +
  geom_point(color = "red") +              
  geom_point(aes(x = pred, y = pred),      
             color = "green", shape = 1) +
  labs(title = "Comparación de valores reales y predichos",
       x = "Valores Predichos",
       y = "Valores Reales") +
  theme_minimal()                        

Vemos que ciertamente, al usar una regresión “lineal”, los valores se disponen en una linea recta, la que corresponde a la ecuación obtenida gracias a lm.

coef(modelo1)
           (Intercept)          `profile pic` `nums/length username` 
          7.930850e-01          -4.380333e-01           8.062047e-01 
      `fullname words` `nums/length fullname`       `name==username` 
         -3.354355e-02          -2.775272e-02           2.240837e-01 
  `description length`         `external URL`                private 
         -1.510047e-03          -1.542026e-01          -9.459373e-03 
              `#posts`           `#followers`             `#follows` 
         -9.094368e-05          -9.960487e-09          -1.850049e-05 

Una vez visto que nuestro modelo inicial, con todas las variables, no es del todo bueno, vamos a eliminar variables con p-values altos, outliers, … e intentar mejorarlo.

5.2 Mejorando el modelo

5.2.1 Eliminando Outliers

Vamos a eliminar los valores que están muy separados y que pueden afectar al modelo.

datos <- datos[-c(45,25,41),]
datos <- datos[-c(440,412,396),]
datos <- datos[-c(351,364,174),]
datos <- datos[-c(140,446,449),]

Hay que hacerlo con moderación ya que si eliminamos muchos valores que realmente no son “outliers” estamos obteniendo mejores modelos pero que realmente no son así.

5.3 Eliminar variables no significativas

modelo2 <- lm(fake ~
                `profile pic`+
                `nums/length username`+
                `fullname words`+
                `name==username`+
                `description length`+
                `external URL`+
                `#posts`    , data = datos)
summary(modelo2)

Call:
lm(formula = fake ~ `profile pic` + `nums/length username` + 
    `fullname words` + `name==username` + `description length` + 
    `external URL` + `#posts`, data = datos)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.74205 -0.22951 -0.06475  0.22687  0.83615 

Coefficients:
                         Estimate Std. Error t value Pr(>|t|)    
(Intercept)             8.144e-01  3.594e-02  22.656  < 2e-16 ***
`profile pic`          -4.297e-01  3.140e-02 -13.685  < 2e-16 ***
`nums/length username`  7.921e-01  6.561e-02  12.072  < 2e-16 ***
`fullname words`       -5.062e-02  1.573e-02  -3.218  0.00136 ** 
`name==username`        1.471e-01  7.287e-02   2.019  0.04397 *  
`description length`   -2.251e-03  4.363e-04  -5.160 3.45e-07 ***
`external URL`         -5.622e-02  4.740e-02  -1.186  0.23609    
`#posts`               -3.114e-04  7.568e-05  -4.115 4.46e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.3003 on 556 degrees of freedom
Multiple R-squared:  0.6443,    Adjusted R-squared:  0.6399 
F-statistic: 143.9 on 7 and 556 DF,  p-value: < 2.2e-16

Hemos obtenido un modelo un poco mejor y con menos residuos, ahora vamos a intentar mejorar este modelo usando variables no lineales.

modelo3 <- lm(fake ~ 
                `profile pic` +
                `nums/length username` +
                `fullname words` +
                `name==username` +
                `description length` +
                `external URL` +
                `#posts` +
                I(`nums/length username`^2)+
                I(`description length`^2)+
                I(`#posts`^2),
              data = datos)

summary(modelo3)

Call:
lm(formula = fake ~ `profile pic` + `nums/length username` + 
    `fullname words` + `name==username` + `description length` + 
    `external URL` + `#posts` + I(`nums/length username`^2) + 
    I(`description length`^2) + I(`#posts`^2), data = datos)

Residuals:
    Min      1Q  Median      3Q     Max 
-0.7340 -0.1915 -0.0474  0.2155  0.8442 

Coefficients:
                              Estimate Std. Error t value Pr(>|t|)    
(Intercept)                  7.954e-01  3.627e-02  21.933  < 2e-16 ***
`profile pic`               -3.725e-01  3.123e-02 -11.925  < 2e-16 ***
`nums/length username`       1.281e+00  1.547e-01   8.283 9.11e-16 ***
`fullname words`            -4.750e-02  1.510e-02  -3.145  0.00175 ** 
`name==username`             1.168e-01  7.019e-02   1.664  0.09663 .  
`description length`        -6.116e-03  1.099e-03  -5.568 4.03e-08 ***
`external URL`              -3.135e-02  4.616e-02  -0.679  0.49739    
`#posts`                    -8.571e-04  1.760e-04  -4.871 1.45e-06 ***
I(`nums/length username`^2) -8.867e-01  2.235e-01  -3.967 8.23e-05 ***
I(`description length`^2)    3.476e-05  8.677e-06   4.006 7.03e-05 ***
I(`#posts`^2)                6.033e-07  1.666e-07   3.621  0.00032 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.288 on 553 degrees of freedom
Multiple R-squared:  0.6747,    Adjusted R-squared:  0.6688 
F-statistic: 114.7 on 10 and 553 DF,  p-value: < 2.2e-16

Vemos, que nuestro modelo ha mejorado un poco y tenemos menos residuos, que es lo que estamos buscando.

plot(modelo3)

 plot(density(resid(modelo3)))

Seguimos teniendo una distribución de residuos asimétrica y no normal.

Vamos a visualizar como predice este nuevo modelo:

modelo3_predic <- predict(modelo3, newdata = datosTest)

datosTest3 <- datosTest %>% mutate(pred = modelo3_predic)

# Rojos -> Reales, verdes -> Predichos
ggplot(datosTest3, aes(x = pred, y = fake)) +
  geom_point(color = "red") +              
  geom_point(aes(x = pred, y = pred),      
             color = "green", shape = 1) +
  labs(title = "Comparación de valores reales y predichos",
       x = "Valores Predichos",
       y = "Valores Reales") +
  theme_minimal()           

Sin embargo, este gráfico, al ser los valores entre 0 y 1 es un poco confuso, vamos a ver el porcentaje de acierto mejor:

datosTest3 <- datosTest3 %>% mutate(pred = ifelse(modelo3_predic < 0.5, 0, 1))
# Calcular el porcentaje de aciertos
accuracy <- mean(datosTest3$pred == datosTest3$fake) * 100
accuracy
[1] 87.5

Vemos que ha acertado un 87.5% de las veces, un dato bastante bueno.

5.3.1 Exportar el modelo

Para poder utilizar el modelo en futuras aplicaciones, podemos guardarlo de la forma:

save(modelo3, file = "modelo3.rds")

5.4 Interacciones entre variables

Al incluir términos de interacción en el modelo de regresión, permitimos que el efecto de una variable sobre la otra varíe según los niveles de otras variables incluidas en la interacción.

Esto puede ser importante para capturar relaciones más complejas entre las variables.

modelo_interact <- lm(fake ~ `profile pic` * `nums/length username` +
                                       `fullname words` * `description length` +
                                       `name==username` * `external URL` +
                                       `#posts`, data = datos)
summary(modelo_interact)

Call:
lm(formula = fake ~ `profile pic` * `nums/length username` + 
    `fullname words` * `description length` + `name==username` * 
    `external URL` + `#posts`, data = datos)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.96028 -0.15321  0.00288  0.06898  0.93053 

Coefficients:
                                        Estimate Std. Error t value Pr(>|t|)
(Intercept)                            1.032e+00  4.025e-02  25.644  < 2e-16
`profile pic`                         -7.191e-01  4.077e-02 -17.637  < 2e-16
`nums/length username`                 4.660e-02  9.326e-02   0.500 0.617496
`fullname words`                      -5.708e-02  1.795e-02  -3.180 0.001555
`description length`                  -2.705e-03  7.093e-04  -3.814 0.000152
`name==username`                       1.487e-01  6.866e-02   2.166 0.030756
`external URL`                        -3.287e-02  4.372e-02  -0.752 0.452397
`#posts`                              -2.603e-04  6.964e-05  -3.738 0.000204
`profile pic`:`nums/length username`   1.250e+00  1.214e-01  10.297  < 2e-16
`fullname words`:`description length`  4.841e-04  3.308e-04   1.463 0.143985
`name==username`:`external URL`       -1.903e-01  2.866e-01  -0.664 0.507019
                                         
(Intercept)                           ***
`profile pic`                         ***
`nums/length username`                   
`fullname words`                      ** 
`description length`                  ***
`name==username`                      *  
`external URL`                           
`#posts`                              ***
`profile pic`:`nums/length username`  ***
`fullname words`:`description length`    
`name==username`:`external URL`          
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.2749 on 553 degrees of freedom
Multiple R-squared:  0.7037,    Adjusted R-squared:  0.6984 
F-statistic: 131.3 on 10 and 553 DF,  p-value: < 2.2e-16
# Guardar el modelo en un archivo
saveRDS(modelo_interact, file = "modelo_interact.rds")

Este modelo vemos que ha mejorado frente a todos loa anteriores, por lo que tenemos que tenerlo en cuenta para nuestro modelo final.

5.5 Ingeniería de variables

La ingeniería de variables implica crear nuevas variables o transformar las existentes para mejorar el rendimiento de un modelo predictivo. Esto incluye crear características nuevas, transformar las existentes, entre otras técnicas.

Vamos a probarlo en nuestro modelo.

modelo_nuevasVar <- lm(fake ~ `profile pic`+
                                    `nums/length username` +
                                    log(`description length` + 1) +
                                    `name==username` +
                                    log(`#posts`+1), data = datos)
summary(modelo_nuevasVar)

Call:
lm(formula = fake ~ `profile pic` + `nums/length username` + 
    log(`description length` + 1) + `name==username` + log(`#posts` + 
    1), data = datos)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.66063 -0.18128 -0.01962  0.16008  0.96220 

Coefficients:
                               Estimate Std. Error t value Pr(>|t|)    
(Intercept)                    0.839917   0.028606  29.362  < 2e-16 ***
`profile pic`                 -0.248421   0.033391  -7.440 3.83e-13 ***
`nums/length username`         0.659306   0.061590  10.705  < 2e-16 ***
log(`description length` + 1) -0.050486   0.007843  -6.437 2.62e-10 ***
`name==username`               0.107825   0.066988   1.610    0.108    
log(`#posts` + 1)             -0.080978   0.007900 -10.251  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.2757 on 558 degrees of freedom
Multiple R-squared:  0.6992,    Adjusted R-squared:  0.6965 
F-statistic: 259.4 on 5 and 558 DF,  p-value: < 2.2e-16
# Guardar el modelo en un archivo
saveRDS(modelo_nuevasVar, file = "modelo_nuevasVar.rds")

De nuevo, este modelo ha sido mejor que todos los anteriores simplemente añadiendo el logaritmo de unas variables.

5.6 Modelo final

Vamos a combinar todos los métodos anteriores para encontrar el mejor modelo posible. Aplicaremos tanto variables no lineales como ingeniería de variables e interacción entre variables.

modelo_final <- lm(fake ~ `profile pic` * `nums/length username` +
                                log(`description length` + 1) +
                                `name==username` +
                                log(`#posts`+1)+
                                `#followers` +
                                I(`nums/length username`^2)+
                                I(`description length`^2)+
                                I(`#posts`^2),
                         data = datos)

summary(modelo_final)

Call:
lm(formula = fake ~ `profile pic` * `nums/length username` + 
    log(`description length` + 1) + `name==username` + log(`#posts` + 
    1) + `#followers` + I(`nums/length username`^2) + I(`description length`^2) + 
    I(`#posts`^2), data = datos)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.70351 -0.11215 -0.00771  0.08622  1.01284 

Coefficients:
                                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)                           9.732e-01  3.395e-02  28.666  < 2e-16 ***
`profile pic`                        -5.097e-01  4.432e-02 -11.500  < 2e-16 ***
`nums/length username`                4.255e-01  1.583e-01   2.687  0.00742 ** 
log(`description length` + 1)        -4.738e-02  9.109e-03  -5.201 2.79e-07 ***
`name==username`                      9.404e-02  6.232e-02   1.509  0.13188    
log(`#posts` + 1)                    -6.765e-02  8.414e-03  -8.041 5.44e-15 ***
`#followers`                          1.126e-09  2.733e-08   0.041  0.96716    
I(`nums/length username`^2)          -5.574e-01  2.000e-01  -2.788  0.00549 ** 
I(`description length`^2)             2.373e-06  3.410e-06   0.696  0.48676    
I(`#posts`^2)                         8.394e-08  6.657e-08   1.261  0.20789    
`profile pic`:`nums/length username`  1.024e+00  1.158e-01   8.847  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.2557 on 553 degrees of freedom
Multiple R-squared:  0.7435,    Adjusted R-squared:  0.7389 
F-statistic: 160.3 on 10 and 553 DF,  p-value: < 2.2e-16

Vemos que el mejor modelo que hemos conseguido obtener ha mejorado bastante respecto al primer modelo obtenido, teniendo un mejor R cuadrado y menos residuos. Vamos a ver las demás métricas utilizadas anteriormente.

plot(modelo_final)

Vamos a generar predicciones con el dataSet de test.

# Generar predicciones
modeloFinal_predic <- predict(modelo_final, newdata = datosTest)


datosTestFinal <- datosTest %>% mutate(pred = ifelse(modeloFinal_predic < 0.5, 0, 1))
# Calcular el porcentaje de aciertos
accuracy <- mean(datosTestFinal$pred == datosTestFinal$fake) * 100
accuracy
[1] 87.5

Por último, vemos que obtenemos un buen porcentaje de acierto con nuestro dataSet de prueba,

5.7 Otros modelos de regresión

Vamos a explorar otros modelos de regresión diferentes al clásico modelo de regeresion lineal que hemos estado trabajando hasta ahora. Puede ser que para nuestra investigación, un modelo diferente al lineal sea mas conveniente y nos pudiera ayudar mas.

5.7.1 Random Forest

Random Forest es un algoritmo de aprendizaje automático que se basa en la idea de crear múltiples árboles de decisión durante el proceso de entrenamiento y luego combinar sus predicciones para obtener una predicción más robusta y precisa.

library(randomForest)
Warning: package 'randomForest' was built under R version 4.3.3
randomForest 4.7-1.1
Type rfNews() to see new features/changes/bug fixes.

Attaching package: 'randomForest'
The following object is masked from 'package:psych':

    outlier
The following object is masked from 'package:ggplot2':

    margin
The following object is masked from 'package:dplyr':

    combine
datosdf <- data.frame(datos)
# Crea el modelo de Random Forest
modelo_rf <- randomForest(fake ~ .,ntree=4, data = datosdf)
Warning in randomForest.default(m, y, ...): The response has five or fewer
unique values.  Are you sure you want to do regression?
# Resumen del modelo
print(modelo_rf)

Call:
 randomForest(formula = fake ~ ., data = datosdf, ntree = 4) 
               Type of random forest: regression
                     Number of trees: 4
No. of variables tried at each split: 3

          Mean of squared residuals: 0.08285584
                    % Var explained: 66.86
5.7.1.0.1 Importancia de las variables
importance(modelo_rf)
                     IncNodePurity
profile.pic           9.915185e+00
nums.length.username  3.282218e+01
fullname.words        2.443014e+00
nums.length.fullname  9.283660e-03
name..username        1.110223e-16
description.length    3.598971e+00
external.URL          4.737802e-01
private               4.920463e-01
X.posts               1.211513e+01
X.followers           5.861250e+01
X.follows             1.457846e+01
modeloRF_predic <- predict(modelo_rf, newdata = data.frame(datosTest))


modeloRF_predic <- datosTest %>% mutate(pred = ifelse(modeloRF_predic < 0.5, 0, 1))
# Calcular el porcentaje de aciertos
accuracy <- mean(modeloRF_predic$pred == modeloRF_predic$fake) * 100
accuracy
[1] 91.66667

5.7.2 Generalized Additive Model

Un GAM es un tipo de modelo estadístico que generaliza los modelos lineales al permitir relaciones no lineales entre las variables predictoras y la variable de respuesta.

En lugar de suponer una relación lineal entre las variables, los GAM permiten que cada variable explicativa tenga una relación suave con la variable de respuesta, modelada a través de funciones suaves.

library(mgcv)
Warning: package 'mgcv' was built under R version 4.3.3
Loading required package: nlme
Warning: package 'nlme' was built under R version 4.3.3

Attaching package: 'nlme'
The following object is masked from 'package:dplyr':

    collapse
This is mgcv 1.9-1. For overview type 'help("mgcv-package")'.
modelo_gam = gam(fake ~ profile.pic +
               nums.length.username +
               fullname.words +
               nums.length.fullname +
               name..username +
               description.length +
               external.URL +
               private +
               X.posts +
               X.followers +
               X.follows, 
             data = datosdf)

summary(modelo_gam)

Family: gaussian 
Link function: identity 

Formula:
fake ~ profile.pic + nums.length.username + fullname.words + 
    nums.length.fullname + name..username + description.length + 
    external.URL + private + X.posts + X.followers + X.follows

Parametric coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)           8.190e-01  3.828e-02  21.397  < 2e-16 ***
profile.pic          -4.272e-01  3.221e-02 -13.264  < 2e-16 ***
nums.length.username  7.855e-01  7.193e-02  10.921  < 2e-16 ***
fullname.words       -5.088e-02  1.587e-02  -3.205 0.001427 ** 
nums.length.fullname  1.413e-02  1.160e-01   0.122 0.903121    
name..username        1.461e-01  7.724e-02   1.891 0.059126 .  
description.length   -2.262e-03  4.422e-04  -5.115 4.33e-07 ***
external.URL         -5.643e-02  4.800e-02  -1.176 0.240246    
private              -8.206e-03  2.738e-02  -0.300 0.764497    
X.posts              -3.042e-04  7.783e-05  -3.908 0.000105 ***
X.followers          -1.982e-08  3.227e-08  -0.614 0.539287    
X.follows            -3.659e-06  1.456e-05  -0.251 0.801712    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1


R-sq.(adj) =  0.638   Deviance explained = 64.5%
GCV = 0.092734  Scale est. = 0.090761  n = 564
modeloGam_predic <- predict(modelo_gam, newdata = data.frame(datosTest))


modeloGam_predic <- datosTest %>% mutate(pred = ifelse(modeloGam_predic < 0.5, 0, 1))
# Calcular el porcentaje de aciertos
accuracy <- mean(modeloGam_predic$pred == modeloGam_predic$fake) * 100
accuracy
[1] 89.16667

5.8 Conclusiones

Hemos explorado tanto los tradicionales modelos lineales como también nuevos enfoques de regresión. Durante este proceso, hemos descubierto modelos interesantes que muestran un potencial considerable para generar predicciones precisas en contextos del mundo real. Al aplicar estos modelos a conjuntos de datos reales, estamos equipados para abordar problemas complejos y tenemos la herramientas para realizar predicciones certeras sobre datos reales, pudiendo servir de verdadera ayuda en el mundo real.