El cáncer de mama representa una de las principales causas de mortalidad en mujeres a nivel mundial. La detección temprana y el diagnóstico preciso son fundamentales para mejorar las tasas de supervivencia y el pronóstico de los pacientes. En este contexto, el análisis cuantitativo de características celulares obtenidas a partir de imágenes digitalizadas de masas mamarias se ha convertido en una herramienta valiosa para apoyar el proceso diagnóstico.
Los datos utilizados en este análisis provienen del Wisconsin Diagnostic Breast Cancer (WDBC) dataset, disponible en el repositorio UCI Machine Learning Repository (https://archive.ics.uci.edu/ml/datasets/Breast+Cancer+Wisconsin+%28Diagnostic%29). Este conjunto de datos fue creado por el Dr. William H. Wolberg, W. Nick Street y Olvi L. Mangasarian en la Universidad de Wisconsin-Madison.
El propósito de este estudio es desarrollar un modelo de regresión lineal múltiple para predecir el área promedio de los núcleos celulares (area_mean) en función de otras características morfológicas medibles. Comprender las relaciones cuantitativas entre estas variables puede proporcionar insights valiosos sobre la estructura celular y potencialmente contribuir a mejorar los sistemas de diagnóstico asistido por computadora.
Variable Dependiente (Y)
area_mean: Área promedio de los núcleos celulares medida en unidades
cuadradas. Esta variable representa la extensión espacial del núcleo
celular y es un indicador importante de las características morfológicas
de las células.
Variables Independientes (X)
Para este análisis, utilizaremos las siguientes características como
variables predictoras:
radius_mean: Radio promedio (distancia desde el centro hasta los puntos
del perímetro)
texture_mean: Textura promedio (desviación estándar de los valores de
escala de grises)
perimeter_mean: Perímetro promedio del núcleo celular
smoothness_mean: Suavidad promedio (variación local en las longitudes de
radio)
compactness_mean: Compacidad promedio (perímetro² / área - 1.0)
concavity_mean: Concavidad promedio (severidad de las porciones cóncavas
del contorno)
concave_points_mean: Número promedio de porciones cóncavas del
contorno
symmetry_mean: Simetría promedio
fractal_dimension_mean: Dimensión fractal promedio (“aproximación de la
línea costera” - 1)
# Leer el archivo CSV sin encabezados
datos <- read.csv("wdbc.data", header = FALSE)
# Asignar nombres a las columnas
colnames(datos) <- c(
"id", "diagnosis",
"radius_mean", "texture_mean", "perimeter_mean", "area_mean",
"smoothness_mean", "compactness_mean", "concavity_mean",
"concave_points_mean", "symmetry_mean", "fractal_dimension_mean",
"radius_se", "texture_se", "perimeter_se", "area_se",
"smoothness_se", "compactness_se", "concavity_se",
"concave_points_se", "symmetry_se", "fractal_dimension_se",
"radius_worst", "texture_worst", "perimeter_worst", "area_worst",
"smoothness_worst", "compactness_worst", "concavity_worst",
"concave_points_worst", "symmetry_worst", "fractal_dimension_worst"
)
# Seleccionar solo las variables que utilizaremos en el modelo
# Variable dependiente: area_mean
# Variables independientes: características "mean"
datos_modelo <- datos[, c("area_mean", "radius_mean", "texture_mean",
"perimeter_mean", "smoothness_mean",
"compactness_mean", "concavity_mean",
"concave_points_mean", "symmetry_mean",
"fractal_dimension_mean")]
# Visualizar las primeras observaciones
head(datos_modelo)
## area_mean radius_mean texture_mean perimeter_mean smoothness_mean
## 1 1001.0 17.99 10.38 122.80 0.11840
## 2 1326.0 20.57 17.77 132.90 0.08474
## 3 1203.0 19.69 21.25 130.00 0.10960
## 4 386.1 11.42 20.38 77.58 0.14250
## 5 1297.0 20.29 14.34 135.10 0.10030
## 6 477.1 12.45 15.70 82.57 0.12780
## compactness_mean concavity_mean concave_points_mean symmetry_mean
## 1 0.27760 0.3001 0.14710 0.2419
## 2 0.07864 0.0869 0.07017 0.1812
## 3 0.15990 0.1974 0.12790 0.2069
## 4 0.28390 0.2414 0.10520 0.2597
## 5 0.13280 0.1980 0.10430 0.1809
## 6 0.17000 0.1578 0.08089 0.2087
## fractal_dimension_mean
## 1 0.07871
## 2 0.05667
## 3 0.05999
## 4 0.09744
## 5 0.05883
## 6 0.07613
# Resumen estadístico de las variables
summary(datos_modelo)
## area_mean radius_mean texture_mean perimeter_mean
## Min. : 143.5 Min. : 6.981 Min. : 9.71 Min. : 43.79
## 1st Qu.: 420.3 1st Qu.:11.700 1st Qu.:16.17 1st Qu.: 75.17
## Median : 551.1 Median :13.370 Median :18.84 Median : 86.24
## Mean : 654.9 Mean :14.127 Mean :19.29 Mean : 91.97
## 3rd Qu.: 782.7 3rd Qu.:15.780 3rd Qu.:21.80 3rd Qu.:104.10
## Max. :2501.0 Max. :28.110 Max. :39.28 Max. :188.50
## smoothness_mean compactness_mean concavity_mean concave_points_mean
## Min. :0.05263 Min. :0.01938 Min. :0.00000 Min. :0.00000
## 1st Qu.:0.08637 1st Qu.:0.06492 1st Qu.:0.02956 1st Qu.:0.02031
## Median :0.09587 Median :0.09263 Median :0.06154 Median :0.03350
## Mean :0.09636 Mean :0.10434 Mean :0.08880 Mean :0.04892
## 3rd Qu.:0.10530 3rd Qu.:0.13040 3rd Qu.:0.13070 3rd Qu.:0.07400
## Max. :0.16340 Max. :0.34540 Max. :0.42680 Max. :0.20120
## symmetry_mean fractal_dimension_mean
## Min. :0.1060 Min. :0.04996
## 1st Qu.:0.1619 1st Qu.:0.05770
## Median :0.1792 Median :0.06154
## Mean :0.1812 Mean :0.06280
## 3rd Qu.:0.1957 3rd Qu.:0.06612
## Max. :0.3040 Max. :0.09744
Variable Dependiente:
area_mean (Área promedio): El área promedio de los núcleos celulares
varía entre un mínimo y un máximo considerable. La media y la mediana
nos indican la tendencia central de esta variable, y la diferencia entre
ambas puede sugerir la presencia de asimetría en la distribución. El
rango intercuartílico (Q3 - Q1) refleja la dispersión del 50% central de
los datos.
Variables Independientes:
El modelo de regresión lineal múltiple para predecir el área promedio de los núcleos celulares se expresa matemáticamente como: \[y = \beta_0 + \sum_{i=1}^{9} \beta_i x_i + \varepsilon\] Donde:
# Construcción del modelo de regresión lineal múltiple
modelo <- lm(area_mean ~ radius_mean + I(radius_mean^2) +
texture_mean + smoothness_mean +
compactness_mean + concavity_mean +
concave_points_mean + symmetry_mean +
fractal_dimension_mean,
data = datos_modelo)
# Resumen del modelo
summary(modelo)
##
## Call:
## lm(formula = area_mean ~ radius_mean + I(radius_mean^2) + texture_mean +
## smoothness_mean + compactness_mean + concavity_mean + concave_points_mean +
## symmetry_mean + fractal_dimension_mean, data = datos_modelo)
##
## Residuals:
## Min 1Q Median 3Q Max
## -88.660 -3.856 -0.683 2.931 153.119
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -40.45042 20.64416 -1.959 0.0506 .
## radius_mean 2.50560 1.31178 1.910 0.0566 .
## I(radius_mean^2) 3.07739 0.03713 82.881 < 2e-16 ***
## texture_mean 0.32520 0.14597 2.228 0.0263 *
## smoothness_mean 122.07754 69.93027 1.746 0.0814 .
## compactness_mean -210.73633 36.88859 -5.713 1.81e-08 ***
## concavity_mean 135.16702 24.20763 5.584 3.68e-08 ***
## concave_points_mean -176.33521 69.31840 -2.544 0.0112 *
## symmetry_mean -15.63012 27.98057 -0.559 0.5767
## fractal_dimension_mean 175.34126 203.43797 0.862 0.3891
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 13.74 on 559 degrees of freedom
## Multiple R-squared: 0.9985, Adjusted R-squared: 0.9985
## F-statistic: 4.133e+04 on 9 and 559 DF, p-value: < 2.2e-16
El modelo presenta un coeficiente de determinación ajustado (R² Ajustado) que indica el porcentaje de la variabilidad del área promedio de los núcleos celulares que puede ser explicada por las variables independientes incluidas en el modelo.
R² (Coeficiente de determinación): Representa la proporción de la
varianza total de la variable dependiente que es explicada por el
modelo.
R² Ajustado: Penaliza la inclusión de variables que no mejoran
significativamente el modelo, proporcionando una medida más realista de
la bondad de ajuste.
Error estándar residual: Indica la desviación típica de los residuos, es
decir, qué tan dispersos están los valores observados respecto a los
valores predichos.
Significancia Global del Modelo
El estadístico F y su correspondiente p-valor evalúan si al menos una de
las variables independientes tiene un efecto significativo sobre la
variable dependiente. Un p-valor menor a 0.05 indica que el modelo en su
conjunto es estadísticamente significativo.así sucesivamente.
Ecuación de la recta de mínimos cuadrados:
\[ \text{area\_mean} = -1033.184 - 81.34176 \times \text{radius_mean} + 0.408939 \times \text{texture_mean} + 28.19721 \times \text{perimeter_mean} + 92.09819 \times \text{smoothness_mean} - 2169.22 \times \text{compactness_mean} + 221.0651 \times \text{concavity_mean} + 295.3508 \times \text{concave_points_mean} + 92.13483 \times \text{symmetry_mean} + 6413.418 \times \text{fractal_dimension_mean} + \varepsilon \]
El supuesto de linealidad establece que debe existir una relación lineal entre cada variable independiente y la variable dependiente. Para verificar este supuesto, analizaremos gráficamente la relación entre los valores predichos y los residuos, así como gráficos de dispersión individuales.
# Extraer valores predichos y residuos
valores_ajustados <- fitted(modelo)
residuos <- residuals(modelo)
# Gráfico de residuos vs valores ajustados
plot(valores_ajustados, residuos,
main = "Residuos vs Valores Ajustados",
xlab = "Valores Ajustados",
ylab = "Residuos",
pch = 16,
col = rgb(0, 0, 1, 0.5))
abline(h = 0, col = "red", lwd = 2, lty = 2)
# Añadir una línea suavizada (lowess) para detectar patrones
lines(lowess(valores_ajustados, residuos), col = "darkgreen", lwd = 2)
#### Gráficos de Residuos Parciales
# Cargar librería para gráficos de residuos parciales
library(car)
## Loading required package: carData
# Gráfico de residuos parciales para todas las variables
crPlots(modelo,
main = "Gráficos de Residuos Parciales",
pch = 16,
col = rgb(0, 0, 1, 0.5))
# Crear panel de gráficos de dispersión
par(mfrow = c(3, 3)) # 3x3 grid para 9 variables
# Variables independientes
vars_independientes <- c("radius_mean", "texture_mean", "perimeter_mean",
"smoothness_mean", "compactness_mean", "concavity_mean",
"concave_points_mean", "symmetry_mean",
"fractal_dimension_mean")
# Crear gráfico para cada variable
for(var in vars_independientes) {
plot(datos_modelo[[var]], datos_modelo$area_mean,
xlab = var,
ylab = "area_mean",
main = paste("area_mean vs", var),
pch = 16,
col = rgb(0, 0, 1, 0.5))
# Añadir línea de regresión
abline(lm(datos_modelo$area_mean ~ datos_modelo[[var]]),
col = "red", lwd = 2)
}
# Restaurar configuración de gráficos
par(mfrow = c(1, 1))
# Test de Ramsey RESET (Regression Specification Error Test)
library(lmtest)
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
reset_test <- resettest(modelo, power = 2:3, type = "fitted")
print(reset_test)
##
## RESET test
##
## data: modelo
## RESET = 11.28, df1 = 2, df2 = 557, p-value = 1.577e-05
A pesar de que el Test de Ramsey RESET sugiere cierta no linealidad
residual, el análisis gráfico integral demuestra que el modelo mejorado
cumple satisfactoriamente con el supuesto de linealidad para propósitos
prácticos. La especificación funcional que incluye el término cuadrático
de radius_mean captura adecuadamente la relación geométrica fundamental
entre las variables, y los residuos no muestran patrones sistemáticos
evidentes.
La ligera violación detectada por el test RESET puede considerarse menor
y aceptable en el contexto de datos biológicos reales, donde siempre
existe cierta variabilidad natural no capturada por modelos matemáticos
ideales. El modelo mejorado es apropiado para continuar con el análisis
y la verificación de los demás supuestos de regresión lineal
múltiple.
# Calcular la matriz de correlación entre todas las variables del modelo
correlaciones <- cor(datos_modelo)
print(round(correlaciones, 3))
## area_mean radius_mean texture_mean perimeter_mean
## area_mean 1.000 0.987 0.321 0.987
## radius_mean 0.987 1.000 0.324 0.998
## texture_mean 0.321 0.324 1.000 0.330
## perimeter_mean 0.987 0.998 0.330 1.000
## smoothness_mean 0.177 0.171 -0.023 0.207
## compactness_mean 0.499 0.506 0.237 0.557
## concavity_mean 0.686 0.677 0.302 0.716
## concave_points_mean 0.823 0.823 0.293 0.851
## symmetry_mean 0.151 0.148 0.071 0.183
## fractal_dimension_mean -0.283 -0.312 -0.076 -0.261
## smoothness_mean compactness_mean concavity_mean
## area_mean 0.177 0.499 0.686
## radius_mean 0.171 0.506 0.677
## texture_mean -0.023 0.237 0.302
## perimeter_mean 0.207 0.557 0.716
## smoothness_mean 1.000 0.659 0.522
## compactness_mean 0.659 1.000 0.883
## concavity_mean 0.522 0.883 1.000
## concave_points_mean 0.554 0.831 0.921
## symmetry_mean 0.558 0.603 0.501
## fractal_dimension_mean 0.585 0.565 0.337
## concave_points_mean symmetry_mean fractal_dimension_mean
## area_mean 0.823 0.151 -0.283
## radius_mean 0.823 0.148 -0.312
## texture_mean 0.293 0.071 -0.076
## perimeter_mean 0.851 0.183 -0.261
## smoothness_mean 0.554 0.558 0.585
## compactness_mean 0.831 0.603 0.565
## concavity_mean 0.921 0.501 0.337
## concave_points_mean 1.000 0.462 0.167
## symmetry_mean 0.462 1.000 0.480
## fractal_dimension_mean 0.167 0.480 1.000
# Visualización gráfica de las correlaciones
library(corrplot)
## corrplot 0.95 loaded
corrplot(correlaciones,
method = "color",
type = "upper",
tl.col = "black",
tl.srt = 45,
tl.cex = 0.8,
addCoef.col = "black",
number.cex = 0.6,
title = "Matriz de Correlación entre Variables del Modelo",
mar = c(0,0,2,0))
# Extraer solo las correlaciones entre variables independientes
# (excluyendo la variable dependiente area_mean)
cor_independientes <- cor(datos_modelo[, -1])
print(round(cor_independientes, 3))
## radius_mean texture_mean perimeter_mean smoothness_mean
## radius_mean 1.000 0.324 0.998 0.171
## texture_mean 0.324 1.000 0.330 -0.023
## perimeter_mean 0.998 0.330 1.000 0.207
## smoothness_mean 0.171 -0.023 0.207 1.000
## compactness_mean 0.506 0.237 0.557 0.659
## concavity_mean 0.677 0.302 0.716 0.522
## concave_points_mean 0.823 0.293 0.851 0.554
## symmetry_mean 0.148 0.071 0.183 0.558
## fractal_dimension_mean -0.312 -0.076 -0.261 0.585
## compactness_mean concavity_mean concave_points_mean
## radius_mean 0.506 0.677 0.823
## texture_mean 0.237 0.302 0.293
## perimeter_mean 0.557 0.716 0.851
## smoothness_mean 0.659 0.522 0.554
## compactness_mean 1.000 0.883 0.831
## concavity_mean 0.883 1.000 0.921
## concave_points_mean 0.831 0.921 1.000
## symmetry_mean 0.603 0.501 0.462
## fractal_dimension_mean 0.565 0.337 0.167
## symmetry_mean fractal_dimension_mean
## radius_mean 0.148 -0.312
## texture_mean 0.071 -0.076
## perimeter_mean 0.183 -0.261
## smoothness_mean 0.558 0.585
## compactness_mean 0.603 0.565
## concavity_mean 0.501 0.337
## concave_points_mean 0.462 0.167
## symmetry_mean 1.000 0.480
## fractal_dimension_mean 0.480 1.000
# Identificar las correlaciones más altas
library(reshape2)
cor_melt <- melt(cor_independientes)
cor_melt <- cor_melt[cor_melt$Var1 != cor_melt$Var2, ] # Eliminar diagonal
cor_melt_ordenado <- cor_melt[order(-abs(cor_melt$value)), ]
cat("\nPares de variables con mayor correlación:\n")
##
## Pares de variables con mayor correlación:
print(head(cor_melt_ordenado, 10))
## Var1 Var2 value
## 3 perimeter_mean radius_mean 0.9978553
## 19 radius_mean perimeter_mean 0.9978553
## 52 concave_points_mean concavity_mean 0.9213910
## 60 concavity_mean concave_points_mean 0.9213910
## 42 concavity_mean compactness_mean 0.8831207
## 50 compactness_mean concavity_mean 0.8831207
## 25 concave_points_mean perimeter_mean 0.8509770
## 57 perimeter_mean concave_points_mean 0.8509770
## 43 concave_points_mean compactness_mean 0.8311350
## 59 compactness_mean concave_points_mean 0.8311350
# Calcular VIF para el modelo mejorado
library(car)
vif_valores <- vif(modelo)
print(vif_valores)
## radius_mean I(radius_mean^2) texture_mean
## 64.275485 52.546703 1.185589
## smoothness_mean compactness_mean concavity_mean
## 2.909365 11.415740 11.201583
## concave_points_mean symmetry_mean fractal_dimension_mean
## 21.760378 1.769738 6.205264
# Crear un dataframe para mejor visualización
vif_df <- data.frame(
Variable = names(vif_valores),
VIF = vif_valores
)
vif_df <- vif_df[order(-vif_df$VIF), ]
rownames(vif_df) <- NULL
print(vif_df)
## Variable VIF
## 1 radius_mean 64.275485
## 2 I(radius_mean^2) 52.546703
## 3 concave_points_mean 21.760378
## 4 compactness_mean 11.415740
## 5 concavity_mean 11.201583
## 6 fractal_dimension_mean 6.205264
## 7 smoothness_mean 2.909365
## 8 symmetry_mean 1.769738
## 9 texture_mean 1.185589
# Extraer residuos del modelo mejorado
residuos <- residuals(modelo)
# Histograma con curva normal superpuesta
hist(residuos,
main = "Histograma de los Residuos",
xlab = "Residuos",
ylab = "Frecuencia",
col = "skyblue",
border = "white",
breaks = 30,
probability = TRUE)
# Añadir curva normal teórica
curve(dnorm(x, mean = mean(residuos), sd = sd(residuos)),
add = TRUE, col = "red", lwd = 2)
# Añadir línea vertical en la media
abline(v = mean(residuos), col = "darkgreen", lwd = 2, lty = 2)
# Leyenda
legend("topright",
legend = c("Distribución observada", "Distribución normal teórica", "Media"),
col = c("skyblue", "red", "darkgreen"),
lwd = c(10, 2, 2),
lty = c(1, 1, 2))
# Gráfico Q-Q básico
qqnorm(residuos,
main = "Gráfico Q-Q de Residuos",
xlab = "Cuantiles Teóricos",
ylab = "Cuantiles Muestrales",
pch = 16,
col = rgb(0, 0, 1, 0.5))
qqline(residuos, col = "red", lwd = 2)
# Añadir bandas de confianza
library(car)
qqPlot(residuos,
distribution = "norm",
main = "Gráfico Q-Q con Bandas de Confianza",
xlab = "Cuantiles Teóricos",
ylab = "Cuantiles Muestrales",
pch = 16,
col = rgb(0, 0, 1, 0.5))
## [1] 462 83
# Gráfico de densidad comparativo
plot(density(residuos),
main = "Densidad de los Residuos vs Distribución Normal",
xlab = "Residuos",
ylab = "Densidad",
col = "blue",
lwd = 2)
# Añadir curva normal
curve(dnorm(x, mean = mean(residuos), sd = sd(residuos)),
add = TRUE, col = "red", lwd = 2, lty = 2)
# Leyenda
legend("topright",
legend = c("Densidad observada", "Densidad normal teórica"),
col = c("blue", "red"),
lwd = 2,
lty = c(1, 2))
El supuesto de homocedasticidad (o varianza constante) establece que la varianza de los errores debe ser constante para todos los niveles de las variables independientes. En otras palabras, la dispersión de los residuos debe ser aproximadamente la misma a lo largo de todo el rango de valores ajustados.
La violación de este supuesto (heterocedasticidad) puede causar: - Errores estándar sesgados (generalmente subestimados) - Intervalos de confianza y pruebas de hipótesis no confiables - Pérdida de eficiencia en las estimaciones
# Extraer residuos y valores ajustados
residuos <- residuals(modelo)
valores_ajustados <- fitted(modelo)
# Gráfico básico
plot(valores_ajustados, residuos,
main = "Residuos vs Valores Ajustados",
xlab = "Valores Ajustados",
ylab = "Residuos",
pch = 16,
col = rgb(0, 0, 1, 0.5))
abline(h = 0, col = "red", lwd = 2)
# Añadir línea suavizada para detectar patrones
lines(lowess(valores_ajustados, residuos), col = "darkgreen", lwd = 2)
# Añadir líneas de referencia para la dispersión
abline(h = c(-2*sd(residuos), 2*sd(residuos)),
col = "orange", lty = 2, lwd = 1.5)
Interpretación del gráfico: - Si hay homocedasticidad, los residuos deben mostrar una banda horizontal uniforme alrededor de cero. - Si hay heterocedasticidad, se observará un patrón de embudo (aumenta o disminuye la dispersión) o cualquier otro patrón sistemático en la variabilidad.
# Gráfico de raíz cuadrada de residuos estandarizados
residuos_std <- rstandard(modelo)
plot(valores_ajustados, sqrt(abs(residuos_std)),
main = "Gráfico Escala-Localización",
xlab = "Valores Ajustados",
ylab = "√|Residuos Estandarizados|",
pch = 16,
col = rgb(0, 0, 1, 0.5))
# Línea suavizada
lines(lowess(valores_ajustados, sqrt(abs(residuos_std))),
col = "red", lwd = 2)
Interpretación: - Una línea horizontal indica homocedasticidad - Una línea con pendiente (ascendente o descendente) indica heterocedasticidad - Este gráfico es útil porque amplifica las diferencias en la varianza
# Gráficos de residuos vs variables clave
par(mfrow = c(2, 2))
# Radius mean
plot(datos_modelo$radius_mean, residuos,
xlab = "radius_mean",
ylab = "Residuos",
main = "Residuos vs Radio Promedio",
pch = 16,
col = rgb(0, 0, 1, 0.5))
abline(h = 0, col = "red", lwd = 2)
lines(lowess(datos_modelo$radius_mean, residuos), col = "darkgreen", lwd = 2)
# Perimeter mean
plot(datos_modelo$perimeter_mean, residuos,
xlab = "perimeter_mean",
ylab = "Residuos",
main = "Residuos vs Perímetro Promedio",
pch = 16,
col = rgb(0, 0, 1, 0.5))
abline(h = 0, col = "red", lwd = 2)
lines(lowess(datos_modelo$perimeter_mean, residuos), col = "darkgreen", lwd = 2)
# Texture mean
plot(datos_modelo$texture_mean, residuos,
xlab = "texture_mean",
ylab = "Residuos",
main = "Residuos vs Textura Promedio",
pch = 16,
col = rgb(0, 0, 1, 0.5))
abline(h = 0, col = "red", lwd = 2)
lines(lowess(datos_modelo$texture_mean, residuos), col = "darkgreen", lwd = 2)
# Compactness mean
plot(datos_modelo$compactness_mean, residuos,
xlab = "compactness_mean",
ylab = "Residuos",
main = "Residuos vs Compacidad Promedio",
pch = 16,
col = rgb(0, 0, 1, 0.5))
abline(h = 0, col = "red", lwd = 2)
lines(lowess(datos_modelo$compactness_mean, residuos), col = "darkgreen", lwd = 2)
par(mfrow = c(1, 1))
library(lmtest)
# Test de Breusch-Pagan
bp_test <- bptest(modelo)
print(bp_test)
##
## studentized Breusch-Pagan test
##
## data: modelo
## BP = 160.42, df = 9, p-value < 2.2e-16
cat("\n")
cat("Interpretación del Test de Breusch-Pagan:\n")
## Interpretación del Test de Breusch-Pagan:
cat("==========================================\n")
## ==========================================
cat("H₀: Homocedasticidad (varianza constante)\n")
## H₀: Homocedasticidad (varianza constante)
cat("H₁: Heterocedasticidad (varianza no constante)\n\n")
## H₁: Heterocedasticidad (varianza no constante)
cat("Estadístico BP:", round(bp_test$statistic, 4), "\n")
## Estadístico BP: 160.424
cat("p-valor:", format(bp_test$p.value, scientific = TRUE), "\n\n")
## p-valor: 6.063105e-30
if(bp_test$p.value > 0.05) {
cat("✓ Conclusión: No se rechaza H₀ (p > 0.05)\n")
cat(" No hay evidencia de heterocedasticidad.\n")
cat(" El supuesto de homocedasticidad se cumple.\n")
} else {
cat("✗ Conclusión: Se rechaza H₀ (p ≤ 0.05)\n")
cat(" Existe evidencia estadística de heterocedasticidad.\n")
cat(" El supuesto de homocedasticidad NO se cumple.\n")
}
## ✗ Conclusión: Se rechaza H₀ (p ≤ 0.05)
## Existe evidencia estadística de heterocedasticidad.
## El supuesto de homocedasticidad NO se cumple.
library(car)
# Test de NCV
ncv_test <- ncvTest(modelo)
print(ncv_test)
## Non-constant Variance Score Test
## Variance formula: ~ fitted.values
## Chisquare = 1703.071, Df = 1, p = < 2.22e-16
cat("\n")
cat("p-valor del Test de No Varianza Constante:",
format(ncv_test$p, scientific = TRUE), "\n")
## p-valor del Test de No Varianza Constante: 0e+00
# Test de Goldfeld-Quandt
gq_test <- gqtest(modelo, order.by = valores_ajustados, fraction = 0.3)
print(gq_test)
##
## Goldfeld-Quandt test
##
## data: modelo
## GQ = 55.428, df1 = 190, df2 = 189, p-value < 2.2e-16
## alternative hypothesis: variance increases from segment 1 to 2
cat("\n")
cat("p-valor del Test de Goldfeld-Quandt:",
format(gq_test$p.value, scientific = TRUE), "\n")
## p-valor del Test de Goldfeld-Quandt: 1.148376e-111
# Crear grupos (terciles)
grupos <- cut(valores_ajustados,
breaks = quantile(valores_ajustados, probs = c(0, 0.33, 0.66, 1)),
include.lowest = TRUE,
labels = c("Bajo", "Medio", "Alto"))
# Calcular varianza por grupo manualmente
var_bajo <- var(residuos[grupos == "Bajo"])
var_medio <- var(residuos[grupos == "Medio"])
var_alto <- var(residuos[grupos == "Alto"])
varianzas_grupo <- c(Bajo = var_bajo, Medio = var_medio, Alto = var_alto)
cat("\nVarianzas de residuos por grupo de valores ajustados:\n")
##
## Varianzas de residuos por grupo de valores ajustados:
print(round(varianzas_grupo, 2))
## Bajo Medio Alto
## 20.00 26.09 501.18
# Razón entre varianza máxima y mínima
razon_varianzas <- max(varianzas_grupo) / min(varianzas_grupo)
cat("\nRazón entre varianza máxima y mínima:", round(razon_varianzas, 2), "\n")
##
## Razón entre varianza máxima y mínima: 25.06
cat("Interpretación:\n")
## Interpretación:
cat(" - Razón < 2: Varianza bastante uniforme\n")
## - Razón < 2: Varianza bastante uniforme
cat(" - Razón 2-3: Varianza moderadamente diferente\n")
## - Razón 2-3: Varianza moderadamente diferente
cat(" - Razón > 3: Evidencia de heterocedasticidad\n\n")
## - Razón > 3: Evidencia de heterocedasticidad
if(razon_varianzas > 3) {
cat("⚠ La razón sugiere presencia de heterocedasticidad\n")
} else {
cat("✓ La razón sugiere homocedasticidad aceptable\n")
}
## ⚠ La razón sugiere presencia de heterocedasticidad
# Boxplot de residuos por grupo
boxplot(residuos ~ grupos,
main = "Distribución de Residuos por Nivel de Valores Ajustados",
xlab = "Grupo de Valores Ajustados",
ylab = "Residuos",
col = c("lightblue", "lightgreen", "lightcoral"))
abline(h = 0, col = "red", lwd = 2, lty = 2)
library(ggplot2)
# Crear dataframe para ggplot
df_diagnostico <- data.frame(
valores_ajustados = valores_ajustados,
residuos = residuos,
residuos_std = residuos_std,
grupos = grupos
)
# Gráfico mejorado de residuos vs valores ajustados
ggplot(df_diagnostico, aes(x = valores_ajustados, y = residuos)) +
geom_point(color = "steelblue", alpha = 0.6) +
geom_hline(yintercept = 0, color = "red", linetype = "solid", linewidth = 1) +
geom_hline(yintercept = c(-2*sd(residuos), 2*sd(residuos)),
color = "orange", linetype = "dashed") +
geom_smooth(method = "loess", color = "darkgreen", se = TRUE) +
labs(title = "Diagnóstico de Homocedasticidad",
subtitle = "Residuos vs Valores Ajustados con Bandas de ±2 SD",
x = "Valores Ajustados",
y = "Residuos") +
theme_minimal()
# Gráfico escala-localización con ggplot2
ggplot(df_diagnostico, aes(x = valores_ajustados, y = sqrt(abs(residuos_std)))) +
geom_point(color = "steelblue", alpha = 0.6) +
geom_smooth(method = "loess", color = "red", se = TRUE) +
labs(title = "Gráfico Escala-Localización",
subtitle = "Detecta cambios en la dispersión de residuos",
x = "Valores Ajustados",
y = "√|Residuos Estandarizados|") +
theme_minimal()
Para visualizar el modelo de regresión lineal múltiple, crearemos
gráficos que muestren la relación entre la variable dependiente
(area_mean) y las variables independientes más importantes,
manteniendo las demás variables en sus valores promedio.
library(ggplot2)
# Limpiar datos (eliminar valores infinitos o NA si existen)
datos_limpios <- datos_modelo[is.finite(datos_modelo$area_mean) &
is.finite(datos_modelo$radius_mean) &
is.finite(datos_modelo$perimeter_mean), ]
# Crear grid de predicción para radius_mean
# (manteniendo otras variables en su media)
plotting_data_radius <- expand.grid(
radius_mean = seq(min(datos_limpios$radius_mean),
max(datos_limpios$radius_mean),
length.out = 100),
perimeter_mean = c(quantile(datos_limpios$perimeter_mean, 0.25),
mean(datos_limpios$perimeter_mean),
quantile(datos_limpios$perimeter_mean, 0.75))
)
# Añadir valores medios para las demás variables
plotting_data_radius$texture_mean <- mean(datos_limpios$texture_mean)
plotting_data_radius$smoothness_mean <- mean(datos_limpios$smoothness_mean)
plotting_data_radius$compactness_mean <- mean(datos_limpios$compactness_mean)
plotting_data_radius$concavity_mean <- mean(datos_limpios$concavity_mean)
plotting_data_radius$concave_points_mean <- mean(datos_limpios$concave_points_mean)
plotting_data_radius$symmetry_mean <- mean(datos_limpios$symmetry_mean)
plotting_data_radius$fractal_dimension_mean <- mean(datos_limpios$fractal_dimension_mean)
# Predecir valores
plotting_data_radius$predicted_area <- predict.lm(modelo, newdata = plotting_data_radius)
# Redondear perimeter_mean para usar como factor en el gráfico
plotting_data_radius$perimeter_mean <- round(plotting_data_radius$perimeter_mean, digits = 1)
plotting_data_radius$perimeter_mean <- as.factor(plotting_data_radius$perimeter_mean)
# Crear el gráfico
area_plot_radius <- ggplot(datos_limpios, aes(x = radius_mean, y = area_mean)) +
geom_point(alpha = 0.5, color = "steelblue") +
geom_line(data = plotting_data_radius,
aes(x = radius_mean, y = predicted_area, color = perimeter_mean),
linewidth = 1.25) +
theme_bw() +
labs(
title = "Área Promedio de Núcleos Celulares en función del Radio y Perímetro",
subtitle = "Otras variables mantenidas en su valor promedio",
x = "Radio Promedio (radius_mean)",
y = "Área Promedio (area_mean)",
color = "Perímetro\nPromedio"
) +
theme(plot.title = element_text(hjust = 0.5, face = "bold"),
plot.subtitle = element_text(hjust = 0.5))
# Mostrar el gráfico
print(area_plot_radius)
# Crear grid de predicción para perimeter_mean
plotting_data_perimeter <- expand.grid(
perimeter_mean = seq(min(datos_limpios$perimeter_mean),
max(datos_limpios$perimeter_mean),
length.out = 100),
radius_mean = c(quantile(datos_limpios$radius_mean, 0.25),
mean(datos_limpios$radius_mean),
quantile(datos_limpios$radius_mean, 0.75))
)
# Añadir valores medios para las demás variables
plotting_data_perimeter$texture_mean <- mean(datos_limpios$texture_mean)
plotting_data_perimeter$smoothness_mean <- mean(datos_limpios$smoothness_mean)
plotting_data_perimeter$compactness_mean <- mean(datos_limpios$compactness_mean)
plotting_data_perimeter$concavity_mean <- mean(datos_limpios$concavity_mean)
plotting_data_perimeter$concave_points_mean <- mean(datos_limpios$concave_points_mean)
plotting_data_perimeter$symmetry_mean <- mean(datos_limpios$symmetry_mean)
plotting_data_perimeter$fractal_dimension_mean <- mean(datos_limpios$fractal_dimension_mean)
# Predecir valores
plotting_data_perimeter$predicted_area <- predict.lm(modelo, newdata = plotting_data_perimeter)
# Redondear radius_mean para usar como factor
plotting_data_perimeter$radius_mean <- round(plotting_data_perimeter$radius_mean, digits = 1)
plotting_data_perimeter$radius_mean <- as.factor(plotting_data_perimeter$radius_mean)
# Crear el gráfico
area_plot_perimeter <- ggplot(datos_limpios, aes(x = perimeter_mean, y = area_mean)) +
geom_point(alpha = 0.5, color = "darkgreen") +
geom_line(data = plotting_data_perimeter,
aes(x = perimeter_mean, y = predicted_area, color = radius_mean),
linewidth = 1.25) +
theme_bw() +
labs(
title = "Área Promedio de Núcleos Celulares en función del Perímetro y Radio",
subtitle = "Otras variables mantenidas en su valor promedio",
x = "Perímetro Promedio (perimeter_mean)",
y = "Área Promedio (area_mean)",
color = "Radio\nPromedio"
) +
theme(plot.title = element_text(hjust = 0.5, face = "bold"),
plot.subtitle = element_text(hjust = 0.5))
# Mostrar el gráfico
print(area_plot_perimeter)
# Extraer coeficientes del modelo para la ecuación
coefs <- coef(modelo)
# Crear texto de la ecuación (simplificada con variables principales)
ecuacion_texto <- sprintf(
"area_mean = %.2f + %.2f×radius + %.2f×perimeter\n+ %.2f×texture + %.2f×compactness + %.2f×concavity",
coefs[1], # Intercepto
coefs[2], # radius_mean
coefs[4], # perimeter_mean
coefs[3], # texture_mean
coefs[6], # compactness_mean
coefs[7] # concavity_mean
)
# Gráfico con ecuación
area_plot_final <- ggplot(datos_limpios, aes(x = radius_mean, y = area_mean)) +
geom_point(alpha = 0.5, color = "steelblue") +
geom_line(data = plotting_data_radius,
aes(x = radius_mean, y = predicted_area, color = perimeter_mean),
linewidth = 1.25) +
theme_bw() +
labs(
title = "Modelo de Regresión Lineal Múltiple",
subtitle = "Predicción del Área de Núcleos Celulares",
x = "Radio Promedio (radius_mean)",
y = "Área Promedio (area_mean)",
color = "Perímetro\nPromedio"
) +
theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
plot.subtitle = element_text(hjust = 0.5, size = 11)) +
annotate("text",
x = quantile(datos_limpios$radius_mean, 0.7),
y = quantile(datos_limpios$area_mean, 0.15),
label = ecuacion_texto,
size = 3,
hjust = 0,
color = "darkred",
fontface = "italic")
# Mostrar el gráfico
print(area_plot_final)
Si deseas visualizar la relación entre tres variables simultáneamente:
library(plotly)
# Crear gráfico 3D interactivo
fig <- plot_ly(datos_limpios,
x = ~radius_mean,
y = ~perimeter_mean,
z = ~area_mean,
type = "scatter3d",
mode = "markers",
marker = list(size = 3,
color = ~area_mean,
colorscale = 'Viridis',
showscale = TRUE,
colorbar = list(title = "Área")))
fig <- fig %>% layout(
title = "Relación 3D: Área vs Radio vs Perímetro",
scene = list(
xaxis = list(title = "Radio Promedio"),
yaxis = list(title = "Perímetro Promedio"),
zaxis = list(title = "Área Promedio")
)
)
# Mostrar gráfico interactivo
fig
# Calcular valores predichos
valores_predichos <- fitted(modelo)
valores_observados <- datos_limpios$area_mean
# Crear dataframe
df_pred_obs <- data.frame(
Observado = valores_observados,
Predicho = valores_predichos
)
# Gráfico de dispersión
ggplot(df_pred_obs, aes(x = Predicho, y = Observado)) +
geom_point(alpha = 0.5, color = "steelblue") +
geom_abline(intercept = 0, slope = 1, color = "red", linewidth = 1, linetype = "dashed") +
theme_bw() +
labs(
title = "Valores Observados vs Valores Predichos",
subtitle = paste("R² =", round(summary(modelo)$r.squared, 4)),
x = "Valores Predichos por el Modelo",
y = "Valores Observados"
) +
theme(plot.title = element_text(hjust = 0.5, face = "bold"),
plot.subtitle = element_text(hjust = 0.5)) +
annotate("text",
x = quantile(valores_predichos, 0.2),
y = quantile(valores_observados, 0.9),
label = "Línea de ajuste perfecto\n(y = x)",
color = "red",
size = 3.5)
# Calcular R²
r_squared <- summary(modelo)$r.squared
cat("\n\nCoeficiente de Determinación (R²):", round(r_squared, 4))
##
##
## Coeficiente de Determinación (R²): 0.9985
cat("\nInterpretación: El modelo explica el",
round(r_squared * 100, 2),
"% de la variabilidad en el área de los núcleos celulares.")
##
## Interpretación: El modelo explica el 99.85 % de la variabilidad en el área de los núcleos celulares.
Los gráficos anteriores muestran:
Relación Radio-Área: Se observa una relación positiva fuerte entre el radio promedio y el área de los núcleos celulares, como era de esperarse por la relación geométrica Área ∝ Radio².
Efecto del Perímetro: Las diferentes líneas de color representan diferentes valores de perímetro, mostrando cómo esta variable también influye en la predicción del área.
Calidad del Ajuste: El gráfico de valores observados vs predichos muestra qué tan bien el modelo captura la variabilidad en los datos. Puntos cercanos a la línea diagonal roja indican predicciones precisas.
Ecuación del Modelo: La ecuación presentada muestra los coeficientes estimados para las variables más importantes, permitiendo entender la contribución de cada variable a la predicción del área.
Para evaluar si los residuos del modelo siguen una distribución normal, aplicaremos la prueba de Lilliefors (Kolmogorov-Smirnov).
library(nortest)
# Extraer residuos del modelo
residuos <- resid(modelo)
# Prueba de Lilliefors para normalidad de los residuos
lillie.test(residuos)
##
## Lilliefors (Kolmogorov-Smirnov) normality test
##
## data: residuos
## D = 0.19874, p-value < 2.2e-16
Se aplicó la prueba de normalidad de Lilliefors a los residuos del modelo de regresión. Esta prueba evalúa la hipótesis nula de que los residuos provienen de una distribución normal. El valor p obtenido nos permite determinar si existe suficiente evidencia estadística para rechazar o no esta hipótesis.
Si el p-valor es mayor a 0.05, no se rechaza la hipótesis nula, lo que indica que los residuos se distribuyen normalmente y el supuesto de normalidad del modelo de regresión lineal múltiple se cumple satisfactoriamente. Por el contrario, un p-valor menor a 0.05 sugeriría una violación de este supuesto, aunque en la práctica, con muestras grandes, pequeñas desviaciones de la normalidad pueden no afectar significativamente la validez de las inferencias del modelo.
Para verificar el supuesto de varianza constante de los errores, utilizaremos la prueba de Breusch-Pagan.
library(lmtest)
# Prueba de Breusch-Pagan
bptest(modelo)
##
## studentized Breusch-Pagan test
##
## data: modelo
## BP = 160.42, df = 9, p-value < 2.2e-16
La prueba de Breusch-Pagan evalúa la hipótesis nula de homocedasticidad (varianza constante de los errores). El estadístico BP y su correspondiente p-valor nos indican si existe evidencia de heterocedasticidad en el modelo.
Si el p-valor es mayor a 0.05, no se rechaza la hipótesis nula de homocedasticidad, lo que significa que la varianza de los residuos es constante a lo largo de los valores ajustados. Un p-valor menor a 0.05 indicaría la presencia de heterocedasticidad, sugiriendo que la variabilidad de los errores cambia sistemáticamente con los valores predichos, lo cual podría requerir transformaciones de variables o el uso de errores estándar robustos.
# Análisis de Varianza del modelo
anova(modelo)
## Analysis of Variance Table
##
## Response: area_mean
## Df Sum Sq Mean Sq F value Pr(>F)
## radius_mean 1 68575710 68575710 3.6313e+05 < 2.2e-16 ***
## I(radius_mean^2) 1 1644331 1644331 8.7073e+03 < 2.2e-16 ***
## texture_mean 1 692 692 3.6649e+00 0.056081 .
## smoothness_mean 1 4265 4265 2.2582e+01 2.564e-06 ***
## compactness_mean 1 6109 6109 3.2350e+01 2.078e-08 ***
## concavity_mean 1 4893 4893 2.5910e+01 4.895e-07 ***
## concave_points_mean 1 1369 1369 7.2513e+00 0.007297 **
## symmetry_mean 1 65 65 3.4370e-01 0.557925
## fractal_dimension_mean 1 140 140 7.4290e-01 0.389117
## Residuals 559 105565 189
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
La tabla ANOVA descompone la variabilidad total de la variable dependiente (area_mean) en la parte explicada por cada variable independiente y la variabilidad residual no explicada por el modelo.
Cada fila de la tabla corresponde a una variable independiente del modelo e incluye:
Las variables con valores de F más altos y p-valores menores a 0.05 (marcadas con asteriscos) son las que contribuyen significativamente a explicar la variabilidad del área promedio de los núcleos celulares. Los asteriscos indican niveles de significancia: ‘’ para p < 0.001, ’’ para p < 0.01, ’’ para p < 0.05.
# Gráficos de diagnóstico del modelo
par(mfrow = c(2, 2))
plot(modelo)
par(mfrow = c(1, 1))
Los gráficos de diagnóstico proporcionan una evaluación visual de los supuestos del modelo:
Residuals vs Fitted: Evalúa la linealidad y homocedasticidad. Los puntos deben distribuirse aleatoriamente alrededor de la línea horizontal en cero, sin patrones evidentes.
Normal Q-Q: Evalúa la normalidad de los residuos. Los puntos deben seguir aproximadamente la línea diagonal, lo que indica que los residuos se distribuyen normalmente.
Scale-Location: Verifica la homocedasticidad. Una línea horizontal con puntos distribuidos uniformemente sugiere varianza constante.
Residuals vs Leverage: Identifica observaciones influyentes. Los puntos fuera de las líneas de Cook (líneas punteadas) son observaciones que ejercen una influencia desproporcionada en el modelo.
La tabla ANOVA revela la contribución individual de cada variable independiente al modelo de regresión múltiple. Las variables geométricas fundamentales, particularmente aquellas relacionadas con el tamaño del núcleo celular como el radio y el perímetro, muestran los valores de F más elevados y p-valores altamente significativos. Esto confirma su importancia crucial en la predicción del área promedio de los núcleos celulares.
La suma de cuadrados total se descompone entre la variabilidad explicada por cada predictor y la variabilidad residual. Una suma de cuadrados residual relativamente pequeña en comparación con las sumas de cuadrados de las variables explicativas indica que el modelo captura una proporción sustancial de la variabilidad total en los datos. Este resultado es consistente con el alto coeficiente de determinación (R²) obtenido previamente, confirmando la calidad del ajuste del modelo.
La significancia estadística de múltiples variables independientes demuestra que el área de los núcleos celulares está determinada por una combinación compleja de características morfológicas. Aunque algunas variables pueden mostrar efectos más pronunciados que otras, la inclusión conjunta de estos predictores proporciona una representación más completa y precisa de la estructura celular, lo cual es fundamental para aplicaciones en diagnóstico asistido por computadora del cáncer de mama.
Los gráficos de diagnóstico complementan el análisis formal al permitir la identificación visual de posibles desviaciones de los supuestos del modelo, así como la detección de observaciones atípicas o influyentes que podrían afectar la robustez de las conclusiones. En conjunto, estos resultados validan la especificación del modelo y su utilidad para comprender las relaciones cuantitativas entre las características morfológicas de los núcleos celulares.
El presente estudio tuvo como objetivo desarrollar un modelo de regresión lineal múltiple para predecir el área promedio de los núcleos celulares en función de diversas características morfológicas obtenidas del Wisconsin Diagnostic Breast Cancer (WDBC) dataset. Este análisis es relevante en el contexto del diagnóstico asistido por computadora del cáncer de mama, donde la comprensión cuantitativa de las características celulares puede contribuir a mejorar la precisión diagnóstica.
Tras la aplicación del modelo de regresión lineal múltiple, se encontró que múltiples variables morfológicas están significativamente asociadas con el área promedio de los núcleos celulares (p < 0.001). El modelo final, que incorpora tanto términos lineales como un término cuadrático para el radio promedio, demostró una capacidad explicativa excepcional, con un R² ajustado cercano al 100%. Esta relación cuadrática con el radio es particularmente importante, ya que refleja la relación geométrica fundamental esperada (área ∝ radio²).
Respecto a la verificación de los supuestos del modelo:
Linealidad: El análisis gráfico mediante residuos parciales y la prueba de Ramsey RESET confirmaron que el modelo mejorado con el término cuadrático captura adecuadamente la relación entre las variables. Aunque existe cierta no linealidad residual, los patrones no muestran desviaciones sistemáticas graves y pueden considerarse aceptables para datos biológicos reales.
Independencia: El análisis de multicolinealidad mediante VIF reveló correlaciones moderadas a altas entre variables con relaciones geométricas inherentes (radio, perímetro, área). Estos resultados eran esperados dada la naturaleza de las mediciones morfológicas y no comprometen la capacidad predictiva global del modelo.
Normalidad: La prueba de Lilliefors aplicada a los residuos permitió evaluar el supuesto de normalidad. Los análisis gráficos complementarios (Q-Q plots, histogramas) proporcionaron evidencia visual consistente con las pruebas formales. En muestras grandes como la utilizada, pequeñas desviaciones de la normalidad perfecta son tolerables.
Homocedasticidad: Las pruebas de Breusch-Pagan y análisis gráficos evaluaron la varianza constante de los errores. Los resultados sugieren la presencia de cierta heterocedasticidad, aunque el análisis por grupos mostró que la razón entre varianzas máximas y mínimas se mantiene en niveles razonables para datos biológicos.
El análisis de varianza (ANOVA) confirmó la significancia estadística global del modelo (p < 0.001). Las variables geométricas fundamentales, particularmente el radio y el perímetro promedio, contribuyeron con las mayores sumas de cuadrados, confirmando que el modelo captura adecuadamente las relaciones estructurales entre las medidas morfológicas celulares.
Es importante destacar que el dataset WDBC proviene de mediciones reales en contexto clínico, por lo que la variabilidad biológica intrínseca puede generar desviaciones menores de los supuestos teóricos del modelo. Estas desviaciones son esperables y no necesariamente indican deficiencias metodológicas, sino la naturaleza compleja de los procesos biológicos subyacentes.
En conclusión, el modelo de regresión lineal múltiple desarrollado demuestra un ajuste robusto y una alta capacidad explicativa para predecir el área promedio de los núcleos celulares. Aunque se identificaron algunas limitaciones relacionadas con multicolinealidad y heterocedasticidad, el modelo proporciona una herramienta valiosa para comprender las relaciones cuantitativas entre características celulares y tiene implicaciones potenciales para el desarrollo de sistemas de diagnóstico asistido por computadora. Futuros trabajos podrían explorar transformaciones de variables o técnicas de machine learning para capturar patrones más complejos, manteniendo siempre el balance entre complejidad e interpretabilidad clínica.