En R, las distribuciones de probabilidad tienen cuatro tipos de funciones:
d...):
Devuelven la densidad de probabilidad en un punto.p...): Devuelven la probabilidad acumulada hasta un
punto.q...):
Devuelven el valor de la variable aleatoria correspondiente a un cuantil
dado.r...): Se usan para generar números aleatorios.sample(c(0,1), prob = c(0.5, 0.5), size=1, replace = T)
## [1] 1
# Probabilidad de obtener exactamente 3 éxitos en 10 ensayos con p = 0.8
n <- 10
k <- 3
p <- 0.8
combinatorio_n_k <- factorial(n)/(factorial(k)*factorial(n-k) )
funcion_masa_en_k <- combinatorio_n_k * p**k * (1-p)**(n-k)
print(funcion_masa_en_k)
## [1] 0.000786432
print(dbinom(3, size = 10, prob = 0.8))
## [1] 0.000786432
# Probabilidad acumulada P(X <= 4) en una binomial (12, 0.2)
probaTotalAcumulada <- 0
for (i in c(0:4)){
probaTotalAcumulada <- probaTotalAcumulada + dbinom(i, size = 12, prob = 0.2)
}
print(probaTotalAcumulada)
## [1] 0.9274445
print(pbinom(4, size = 12, prob = 0.2))
## [1] 0.9274445
# Cuantil 80% de una binomial (10, 0.5)
qbinom(0.8, size = 10, prob = 0.5)
## [1] 6
# Probabilidad de obtener exactamente 4 eventos con media lambda = 2
dpois(4, lambda = 2)
## [1] 0.09022352
# Probabilidad acumulada P(X <= 4) en una Poisson con lambda = 2
ppois(4, lambda = 2)
## [1] 0.947347
# Cuantil 90% de una Poisson con lambda = 2
qpois(0.90, lambda = 2)
## [1] 4
# Densidad en x = 1 de una distribución exponencial con tasa lambda = 2
dexp(1, rate = 2)
## [1] 0.2706706
# Probabilidad acumulada P(X <= 1) en una exponencial con lambda = 2
pexp(1, rate = 2)
## [1] 0.8646647
# Cuantil 75% de una exponencial con lambda = 2
qexp(0.75, rate = 2)
## [1] 0.6931472
curve(dexp(x, rate = 2), from = 0, to = 3, lwd = 2, col = "steelblue",
ylab = "Densidad", xlab = "x", main = "PDF de la Exponencial (λ = 2)")
# Densidad de una normal estándar en x = 1
dnorm(1, mean = 0, sd = 1)
## [1] 0.2419707
# Probabilidad acumulada P(X <= 1) en una normal estándar
pnorm(1, mean = 0, sd = 1)
## [1] 0.8413447
# Cuantil 90 de una normal con media 2 y desviación estándar 3
qnorm(0.90, mean = 2, sd = 3)
## [1] 5.844655
# Probabilidad de que X esté entre -1 y 1 en una normal estándar
pnorm(1, mean = 0, sd = 1) - pnorm(-1, mean = 0, sd = 1)
## [1] 0.6826895
lambda <- 1
com <- -2
fin <- lambda+5
x <- com:fin
xnorm <- seq(com, fin, 0.01)
poisson_vals <- dpois(x, lambda)
normal_vals <- dnorm(xnorm, mean = lambda, sd = sqrt(lambda))
plot(x, poisson_vals, type = "h", col = "blue", lwd = 2,
main = "Poisson vs Normal",
ylab = "Densidad", xlab = "x")
lines(xnorm, normal_vals, col = "red", lwd = 2)
legend("topright", legend = c("Poisson", "Normal"), col = c("blue", "red"), lwd = 2)
### Ley de los grandes numeros
set.seed(123)
# Simular 600 lanzamientos de una moneda cargada (Bernoulli con p = 0.7)
n <- 600
x <- rbinom(n, size = 1, prob = 0.7)
# Calcular media acumulada
media_acumulada <- cumsum(x) / (1:n)
# Graficar
plot(media_acumulada, type = "l", col = "blue", lwd = 2,
main = "Ley de los Grandes Números (LGN)",
xlab = "Número de observaciones",
ylab = "Media acumulada")
abline(h = 0.7, col = "red", lty = 2) # Línea de la media teórica
legend("bottomright", legend = c("Media acumulada", "Media verdadera"),
col = c("blue", "red"), lwd = 2, lty = c(1, 2))
### Teorema central del limite
set.seed(220)
# Parámetros
n_muestras <- 100000 # cuántas muestras
tamaño_muestra <- 50 # tamaño de cada muestra
# Crear un vector para guardar las medias muestrales
medias <- numeric(n_muestras)
# Simular
for (i in 1:n_muestras) {
muestra <- rexp(tamaño_muestra, rate = 1) # Distribución exponencial (media = 1)
medias[i] <- mean(muestra)
}
# Graficar histograma de las medias
hist(medias, breaks = 50, probability = TRUE, col = "skyblue",
main = "Teorema Central del Límite (TCL)",
xlab = "Medias muestrales")
# Agregar curva normal teórica
curve(dnorm(x, mean = 1, sd = 1/sqrt(tamaño_muestra)), add = TRUE, col = "red", lwd = 2)
legend("topright", legend = c("Medias muestrales", "Normal teórica"),
col = c("skyblue", "red"), lwd = 2)
# Densidad de una t de Student con 10 grados de libertad en x = 2
dt(2, df = 10)
## [1] 0.06114577
# Probabilidad acumulada P(X <= 2) en una t de Student con 10 grados de libertad
pt(2, df = 10)
## [1] 0.963306
# Cuantil 95% de una t de Student con 10 grados de libertad
qt(0.95, df = 10)
## [1] 1.812461
library(shiny)
ui <- fluidPage(
titlePanel("Comparación: t de Student vs Normal estándar"),
sidebarLayout(
sidebarPanel(
sliderInput("df", "Grados de libertad (df):",
min = 1, max = 100, value = 1, step = 1)
),
mainPanel(
plotOutput("distPlot")
)
)
)
server <- function(input, output) {
output$distPlot <- renderPlot({
curve(dt(x, df = input$df), from = -5, to = 5, col = "blue", lwd = 2,
ylab = "Densidad", xlab = "x", main = paste("t de Student (df =", input$df, ") vs Normal"))
curve(dnorm(x), from = -5, to = 5, col = "red", lwd = 2, add = TRUE, lty = 2)
legend("topright", legend = c("t de Student", "Normal estándar"),
col = c("blue", "red"), lwd = 2, lty = c(1, 2))
})
}
shinyApp(ui = ui, server = server)
Casos de uso:
Pruebas de independencia (Chi-cuadrado)
Análisis de varianza (ANOVA)
Evaluación de bondad de ajuste
# Densidad en x = 5 de una chi-cuadrado con 4 grados de libertad
dchisq(5, df = 4)
## [1] 0.1026062
# Probabilidad acumulada P(X <= 5) en una chi-cuadrado con 4 grados de libertad
pchisq(5, df = 4)
## [1] 0.7127025
# Cuantil 99% de una chi-cuadrado con 4 grados de libertad
qchisq(0.99, df = 4)
## [1] 13.2767
curve(dchisq(x, df = 4), from = 0, to = 15, main = "Distribución Chi-cuadrado (grados de libertad = 4)")
curve(dchisq(x, df = 1), from = 0, to = 15, main = "Distribución Chi-cuadrado (grados de libertad = 1)")
curve(dchisq(x, df = 10), from = 0, to = 25, main = "Distribución Chi-cuadrado (grados de libertad = 10)")
Casos de uso:
Comparación de varianzas
ANOVA (prueba F)
y otros..
# Densidad en x = 3 de una F con 5 y 10 grados de libertad
df(3, df1 = 5, df2 = 10)
## [1] 0.05582673
# Probabilidad acumulada P(X <= 3) en una F con 5 y 10 grados de libertad
pf(3, df1 = 5, df2 = 10)
## [1] 0.9344424
# Cuantil 95% de una F con 5 y 10 grados de libertad
qf(0.95, df1 = 5, df2 = 10)
## [1] 3.325835
curve(df(x, df1 = 5, df2 = 10), from = 0, to = 5, main = "Distribución F (df1 = 5, df2 = 10)")
# Generación de muestras de distribuciones conocidas
muestra.unif1=runif(100) # genera una muestra uniforme en [0,1] de 100 datos
muestra.unif1 # devuelve la muestra generada
## [1] 0.74042917 0.06060387 0.44815931 0.70520033 0.14980901 0.70059005
## [7] 0.94331055 0.74753949 0.22538930 0.36657710 0.95306480 0.88135497
## [13] 0.35496980 0.63943374 0.31551702 0.95597580 0.75917776 0.78098909
## [19] 0.80101753 0.10331994 0.51770831 0.09899885 0.80992561 0.79399644
## [25] 0.71497625 0.56534870 0.90738863 0.83550352 0.76549823 0.91622815
## [31] 0.20957039 0.35387827 0.10562600 0.11721563 0.99949867 0.82183209
## [37] 0.66413885 0.30061668 0.90199878 0.63598207 0.70597580 0.74565152
## [43] 0.60814978 0.46730330 0.99394922 0.70940463 0.93478809 0.67125895
## [49] 0.45033733 0.69362545 0.37645711 0.01156165 0.84068528 0.20144150
## [55] 0.06921584 0.47401665 0.66515178 0.29031024 0.82305299 0.60091102
## [61] 0.30346513 0.40702847 0.34507134 0.28265412 0.43251592 0.10712020
## [67] 0.21825061 0.49005801 0.65876810 0.01475468 0.40777074 0.35895701
## [73] 0.02371050 0.20551534 0.98529712 0.94729525 0.66421386 0.59480097
## [79] 0.79294093 0.26875167 0.55978508 0.12098553 0.21304076 0.40670725
## [85] 0.68683903 0.98079129 0.78204748 0.11256118 0.64084680 0.05221190
## [91] 0.61670265 0.98870831 0.74087994 0.45713742 0.55398697 0.81226586
## [97] 0.59417271 0.65756812 0.89513997 0.95548542
muestra.unif2=runif(200,min=2,max=5) # genera una muestra uniforme en [2,5] de 200 datos
muestra.unif2 # devuelve la muestra generada
## [1] 3.579399 4.571081 3.265408 2.078373 2.096941 2.352739 4.090955 3.812831
## [9] 4.907075 4.308211 2.397673 2.247867 4.111123 4.012437 2.501061 4.221375
## [17] 2.260264 2.648805 3.513249 4.442773 2.976490 3.664838 2.228200 4.590831
## [25] 4.027013 3.195291 2.786817 3.675958 2.091530 4.905974 4.914610 2.115734
## [33] 3.511480 2.390844 4.682109 2.836080 2.623192 3.904162 3.651448 4.228731
## [41] 4.362340 2.820409 4.469565 3.205014 4.455499 2.293602 3.405958 3.918008
## [49] 3.440164 3.011023 2.939242 4.337266 4.552475 4.013619 4.558456 4.036880
## [57] 4.037275 4.086572 4.219177 3.227989 2.221861 3.728602 4.491770 2.119827
## [65] 3.467433 2.917282 2.733925 3.399535 4.692520 2.700122 4.457819 4.216531
## [73] 3.946205 2.995239 4.115602 4.880907 4.768666 3.500952 4.652364 3.305349
## [81] 2.306639 2.903662 2.973551 4.126877 4.770191 4.478155 2.384397 2.171593
## [89] 4.975327 4.746852 4.474165 4.677274 2.682309 4.827670 2.536487 2.812166
## [97] 4.960047 4.701242 4.301109 3.609146 4.878997 3.989081 3.922237 2.323821
## [105] 2.484757 4.943961 4.846238 4.948866 2.374402 4.725156 4.910773 2.286091
## [113] 4.378342 2.001660 2.861195 3.703988 2.442162 4.129757 3.109064 2.044757
## [121] 4.862710 2.127956 2.603903 3.059018 4.639620 3.407775 2.211968 4.514156
## [129] 2.569993 3.315739 4.839088 2.961710 2.935697 2.400757 2.489231 4.176028
## [137] 4.856867 4.516277 3.672435 4.962107 2.685461 3.401775 4.333779 3.915034
## [145] 4.836480 4.827346 3.628800 4.713197 2.355867 4.330170 2.617845 3.755121
## [153] 2.605704 3.031690 3.192901 2.374146 2.484289 2.819595 4.924016 2.603762
## [161] 4.242884 4.599244 2.105177 2.388055 4.779116 4.702227 4.229962 3.697644
## [169] 3.038434 4.219772 4.662290 4.343123 2.858557 4.758197 4.749133 4.576582
## [177] 2.451825 2.049822 2.359585 2.350898 4.883602 4.473896 4.587783 2.309450
## [185] 2.448921 2.604292 2.333888 4.525389 4.494202 3.634131 4.938330 2.457503
## [193] 4.851168 2.332125 3.077755 2.226452 3.117209 4.086925 4.914893 2.651436
muestra.norm.est=rnorm(30) # genera una muestra normal estándar de 30 datos
muestra.norm.est # devuelve la muestra generada
## [1] 0.37536456 0.61633444 -0.13207753 -0.84182534 0.64888415 -0.61988153
## [7] -1.02143842 0.36716569 1.02678185 -0.15137749 0.23015338 -1.82897245
## [13] -0.42454906 -1.33004840 0.23188712 0.67897920 0.82312409 0.48332637
## [19] -1.76470658 -1.10769332 -0.62258009 -1.84438392 0.86542091 -0.02442294
## [25] -0.42052439 -0.06218155 0.77566964 0.29861208 -0.83071892 1.38690656
muestra.norm=rnorm(50,mean=10,sd=3) # genera una muestra normal(10,3) de 50 datos
muestra.norm # devuelve la muestra generada
## [1] 9.948360 9.946225 12.820570 7.195618 11.057105 8.211103 8.126123
## [8] 7.743977 12.106622 8.840420 8.958294 8.807370 8.988964 9.903350
## [15] 8.824195 9.856798 11.389683 11.006917 10.378072 13.899570 10.279101
## [22] 11.166549 7.996514 9.505961 10.365770 15.329751 9.931408 15.028995
## [29] 7.106841 3.361811 8.579147 7.859542 8.373523 10.296328 15.084664
## [36] 7.196552 15.059271 6.354302 7.448454 7.073693 10.520295 4.045151
## [43] 11.565057 6.562143 8.430889 9.746364 10.109599 7.263787 5.115718
## [50] 12.093796
muestra.gamma=rgamma(40,rate=2, shape=3) # genera una muestra gamma(2,3) de 40 datos
muestra.gamma # devuelve la muestra generada
## [1] 2.8303459 2.4804876 1.1733628 1.0764862 0.2258607 0.8491683 0.1369941
## [8] 3.3555643 2.1491391 2.6943299 0.5356545 1.4416502 0.4680046 0.7211067
## [15] 0.4600094 1.2532749 0.8022449 1.3616378 0.7384643 1.0931889 1.4580672
## [22] 1.4579551 0.8705889 1.4999644 2.3970581 0.8079735 1.3974800 1.4320079
## [29] 1.7341655 1.0734878 0.4735892 1.3711478 2.8756068 0.9831509 1.4855759
## [36] 1.4510629 2.9130642 0.7599633 1.2037134 0.7635966
muestra.f=rf(80,df1=5,df2=6) # genera una muestra F de Snedekor(5,6) de 80 datos
muestra.f # devuelve la muestra generada
## [1] 0.7816374 2.4950283 0.1716568 0.2190316 0.4988687 1.3101435
## [7] 0.6565118 1.0771670 1.6822010 0.1920139 6.1105602 6.8638902
## [13] 1.1617624 2.1003740 2.0602778 0.2950320 0.2759087 1.3897829
## [19] 2.4187985 0.4134039 0.5422662 2.7060681 5.8710144 0.9432917
## [25] 1.3526495 0.9289754 2.6032814 1.1963459 0.9933244 1.1112781
## [31] 0.5810191 0.5145165 1.1613098 0.5914126 0.2689882 1.7165862
## [37] 2.6315728 0.1257322 0.4364502 1.7380113 18.2909699 0.5267842
## [43] 0.7869181 0.2556803 2.0241606 4.0774168 2.2275640 2.2957841
## [49] 0.8021862 13.9987361 2.5290191 0.5743604 0.4282625 1.1058253
## [55] 6.5111068 1.4877607 1.5672073 0.1241038 0.3096609 1.0945569
## [61] 0.1698885 2.0597161 0.4686950 0.8236358 0.9346092 8.6982744
## [67] 0.3518496 1.0714930 0.6771836 0.8441745 1.1207992 0.1145178
## [73] 0.7508293 0.5540607 1.3773911 1.7045334 0.7007199 0.9543451
## [79] 1.2799168 0.6700914
muestra.exp=rexp(90,2) # genera una muestra exponencial(2) de 90 datos
muestra.exp # devuelve la muestra generada
## [1] 0.146891257 0.041396276 0.089243189 0.193379929 0.461492539 0.139154651
## [7] 0.371848039 0.600838534 0.263642893 1.384352672 0.146588288 0.492269787
## [13] 0.462839721 0.963121605 0.547897488 0.239735272 0.142199038 0.123214886
## [19] 0.115045888 1.222349527 0.522918675 0.100731689 0.121986352 0.955774859
## [25] 0.551490530 0.091535015 1.176788542 0.369352909 0.546943967 0.039379181
## [31] 0.061558785 0.085643889 0.074742885 0.396892373 0.265599324 1.010948399
## [37] 0.120154399 0.033734369 0.025818836 1.010403250 0.281340827 0.062566719
## [43] 0.514405075 0.003428954 0.269583077 0.413284824 0.007962151 0.129664049
## [49] 0.085150389 0.021191897 0.207863645 0.857450373 0.341216152 0.798894148
## [55] 0.430740735 1.677423704 0.194771136 0.936760286 0.362510940 0.566323129
## [61] 1.049111219 0.446898828 0.188321537 0.185318798 0.371112982 0.097446594
## [67] 0.044770877 0.574032640 0.036808933 0.214853190 0.026602598 0.297118115
## [73] 0.852686072 0.909643375 0.005212244 0.085993649 1.602962557 0.470145563
## [79] 0.446734530 0.907775566 1.046979311 1.556020416 0.818563580 0.102257351
## [85] 0.580904884 0.279733178 0.008250367 0.153280553 0.410663530 0.529737980
muestra.chi=rchisq(70,df=4) # genera una muestra chi cuadrado con 4 grados de libertad de 70 datos
muestra.chi # devuelve la muestra generada
## [1] 3.5259103 2.8904494 3.4179077 1.5745689 0.5029640 2.4308665
## [7] 3.2153110 6.3409944 1.9995501 4.6299788 3.6576959 5.6087074
## [13] 1.4684165 3.1198414 4.9681251 1.6028103 4.9267733 3.7453270
## [19] 2.1521752 5.1412008 2.8693379 3.2127423 5.3215697 1.2952842
## [25] 6.0594948 0.2503803 2.5488674 1.1380526 6.7814683 4.9601378
## [31] 3.5519375 2.0753775 2.1237285 1.2998218 3.7910245 3.9142274
## [37] 4.2486886 3.0048135 1.6949628 3.2462716 4.5358589 5.1001843
## [43] 4.1737611 7.4697364 2.9543772 1.0485618 3.8750156 7.1395889
## [49] 1.7782713 4.7620021 7.9518480 2.3919892 2.1442662 3.3937487
## [55] 6.8857174 0.9055090 3.8099335 2.7275571 4.2068811 3.0387885
## [61] 1.2577280 6.7728146 7.5478957 1.0911562 4.9996565 3.2130827
## [67] 2.6594193 3.8881630 3.8843364 10.0697846
# Cargo la base:
PACIENTE<-1:30
EDAD<-c(7, 7, 8, 7, 7, 10,7 ,7, 7 ,9, 9, 11, 7, 9, 9, 11, 12, 7, 11, 6, 8, 8, 7, 10, 7, 8, 10, 7, 9, 10)
SEXO<-c("M", "M", "M", "F", "M", "M" ,"M", "M", "M", "M", "M", "F", "M" ,"M" ,"F" ,"M", "M" ,"M" ,"M" ,"F" ,"F" ,"F", "F","F", "M" ,"M" ,"F", "F" ,"F" ,"M")
PESO<-c(24.4, 23.6, 47.0, 24.0, 23.9, 41.0, 32.9, 22.4, 28.7, 31.4, 28.9, 51.2, 26.2, 58.5, 23.7, 25.5, 49.7, 39.6,42.5, 21.6, 38.0, 26.6, 20.4, 23.7, 21.4, 45.7, 51.3, 28.0, 26.9, 43.9)
TALLA<-c(1.2, 1.2, 1.4, 1.2, 1.2, 1.4, 1.3, 1.2, 1.3, 1.3, 1.3, 1.6, 1.3, 1.5, 1.3, 1.3, 1.7, 1.3, 1.5, 1.2, 1.3, 1.2, 1.2,1.3, 1.2, 1.4, 1.5, 1.3, 1.3, 1.5)
IMC<-c(16.94444, 16.38889, 23.97959, 16.66667, 16.59722, 20.91837, 19.46746, 15.55556, 16.98225, 18.57988,17.10059, 20.00000, 15.50296, 26.00000, 14.02367, 15.08876, 17.19723, 23.43195, 18.88889, 15.00000,22.48521, 18.47222, 14.16667, 14.02367, 14.86111, 23.31633, 22.80000, 16.56805, 15.91716, 19.51111)
PIMC<-c(7.97, 72.72, 97.08, 83.88, 45.85, 87.33, 96.57, 32.88, 80.77, 92.72, 55.54, 77.77, 70.70, 98.69, 3.25,2.07, 38.08, 98.75, 80.60, 39.97, 96.07, 71.06, 3.44, 2.02, 56.86, 98.99, 90.84, 57.50, 44.77, 84.89)
CC<-c(54, 52, 76, 63, 56, 78, 69, 52, 60, 69, 60, 75, 50, 88, 58, 73, 75, 76, 72, 52, 76, 54, 52, 56, 56, 78, 76, 57, 57, 76)
CatPeso<-c("N", "N", "OB", "N", "N", "SO", "OB", "N", "N", "SO", "N", "N", "N", "OB", "D", "D", "N", "OB","N" , "N", "OB", "N", "D", "D", "N", "OB", "SO", "N", "N", "N" )
IMCin<-data.frame(PACIENTE,EDAD,SEXO,PESO,TALLA,IMC,PIMC,CC,CatPeso)
#View(IMCin)
head(IMCin) # muestra las seis primeras filas de datos y los nombres de las columnas
## PACIENTE EDAD SEXO PESO TALLA IMC PIMC CC CatPeso
## 1 1 7 M 24.4 1.2 16.94444 7.97 54 N
## 2 2 7 M 23.6 1.2 16.38889 72.72 52 N
## 3 3 8 M 47.0 1.4 23.97959 97.08 76 OB
## 4 4 7 F 24.0 1.2 16.66667 83.88 63 N
## 5 5 7 M 23.9 1.2 16.59722 45.85 56 N
## 6 6 10 M 41.0 1.4 20.91837 87.33 78 SO
tail(IMCin)# muestra las seis últimas filas de datos y los nombres de las columnas
## PACIENTE EDAD SEXO PESO TALLA IMC PIMC CC CatPeso
## 25 25 7 M 21.4 1.2 14.86111 56.86 56 N
## 26 26 8 M 45.7 1.4 23.31633 98.99 78 OB
## 27 27 10 F 51.3 1.5 22.80000 90.84 76 SO
## 28 28 7 F 28.0 1.3 16.56805 57.50 57 N
## 29 29 9 F 26.9 1.3 15.91716 44.77 57 N
## 30 30 10 M 43.9 1.5 19.51111 84.89 76 N
dim(IMCin)#30 9
## [1] 30 9
rbind(head(IMCin),tail(IMCin))#une filas: las seis primeras filas con las seis últimas
## PACIENTE EDAD SEXO PESO TALLA IMC PIMC CC CatPeso
## 1 1 7 M 24.4 1.2 16.94444 7.97 54 N
## 2 2 7 M 23.6 1.2 16.38889 72.72 52 N
## 3 3 8 M 47.0 1.4 23.97959 97.08 76 OB
## 4 4 7 F 24.0 1.2 16.66667 83.88 63 N
## 5 5 7 M 23.9 1.2 16.59722 45.85 56 N
## 6 6 10 M 41.0 1.4 20.91837 87.33 78 SO
## 25 25 7 M 21.4 1.2 14.86111 56.86 56 N
## 26 26 8 M 45.7 1.4 23.31633 98.99 78 OB
## 27 27 10 F 51.3 1.5 22.80000 90.84 76 SO
## 28 28 7 F 28.0 1.3 16.56805 57.50 57 N
## 29 29 9 F 26.9 1.3 15.91716 44.77 57 N
## 30 30 10 M 43.9 1.5 19.51111 84.89 76 N
cbind(IMCin$SEXO[1:5],IMCin$PESO[1:5]) #cuidado!
## [,1] [,2]
## [1,] "M" "24.4"
## [2,] "M" "23.6"
## [3,] "M" "47"
## [4,] "F" "24"
## [5,] "M" "23.9"
data.frame(IMCin$SEXO[1:5],IMCin$PESO[1:5]) #une columnas con sus 5 primeros elementos
## IMCin.SEXO.1.5. IMCin.PESO.1.5.
## 1 M 24.4
## 2 M 23.6
## 3 M 47.0
## 4 F 24.0
## 5 M 23.9
table(IMCin$SEXO) # devuelve las frecuencias absolutas de las categorías de la variable
##
## F M
## 11 19
dist.conj=table(IMCin$CatPeso, IMCin$SEXO) # devuelve la distribución conjunta de las variables categoría de peso y sexo
Z= IMCin$TALLA*100 # guarda los datos de la talla en centímetros
mean(Z) # calcula la media
## [1] 133
median(Z) # calcula la mediana
## [1] 130
quantile(Z, 0.75) # calcula el cualtil 75
## 75%
## 140
quantile(Z, probs = seq(0, 1, 0.25)) # calcula los cuantiles 0, 25, 50, 75 y 100
## 0% 25% 50% 75% 100%
## 120 120 130 140 170
is.na(Z) # indica los valores que faltan
## [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [25] FALSE FALSE FALSE FALSE FALSE FALSE
W<-Z
W[1]<-NA # asigna un valor perdido en la primera componente del vector W
is.na(W)
## [1] TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [25] FALSE FALSE FALSE FALSE FALSE FALSE
mean(W) # devuelve NA
## [1] NA
mean(W,na.rm=T) # no considera los valores no disponibles
## [1] 133.4483
mean(na.omit(W)) # equivalente al anterior
## [1] 133.4483
median(W,na.rm=T) # otra funcion que requiere excluir los valores no disponibles
## [1] 130
sd(W,na.rm=T) # otra funcion que requiere excluir los valores no disponibles
## [1] 13.16811
Ejercicio 1 Calcular la media y mediana del vector x y el número de valores que están por debajo de la media y de la mediana, siendo x: x<-c(1,5,7,9,3,5,6,2,4,7,5,6,9,8,6,2,6,1,4).
Ejercicio 2 Escribir la función que calcula el módulo de un número real.
Ejercicio 3 Usar for para hallar el resultado de dividir de manera consecutiva el número 1111 por los siguientes divisores (en este orden): 2, 3, 4, 5, 6.
Ejercicio 4 Escribir una función que responda el signo del producto de dos factores dado, es decir “Positivo”, o “Negativo”, y en el caso que el producto sea 0 devuelva “Nulo”.
Ejercicio 5 Simular el lanzamiento de un dado.
Ejercicio 6 Simular el lanzamiento de cuatro dados o de un mismo dado cuatro veces.
Ejercicio 7 Supongamos una urna con 3 bolas blancas y 7 negras, simular la extracción de una bola (asignar, por ejemplo, el 1 a bola blanca y 0 a negra).
Ejercicio 8 Simular 8 extracciones con reemplazo de la urna del ejercicio 7.
Ejercicio 9 Simular una muestra aleatoria de tamaño 10 proveniente de una distribución normal con media 4 y desviación estándar 0.5.
Ejercicio 10 ¿Para qué valor de P se cumple que la probabilidad de que una variable aleatoria con distribución normal N(0, 2) esté entre -P y P es del 85%?
Ejercicio 11 ¿Cuál es el valor de la función de densidad de una normal estándar N(0,1) en el punto donde la acumulación de probabilidad alcanza el 60%?
Ejercicio 1
x <- c(1,5,7,9,3,5,6,2,4,7,5,6,9,8,6,2,6,1,4)
m <- mean(x)
M <- median(x)
valores_bajo_media <- sum(x < m)
valores_bajo_mediana <- sum(x < M)
Ejercicio 2
# Opción 1
modulo <- function(x) {
if (x >= 0) {
return(x)
} else {
return(-x)
}
}
# Opción 2
modu <- function(x) {
y <- abs(x)
return(y)
}
Ejercicio 3
cocientes <- numeric(5)
y <- 1111
for (i in 2:6) {
y <- y / i
cocientes[i - 1] <- y
}
print(cocientes)
## [1] 555.500000 185.166667 46.291667 9.258333 1.543056
Ejercicio 4
signo <- function(x, y) {
z <- x * y
res <- ifelse(z == 0, "Nulo", ifelse(z > 0, "Positivo", "Negativo"))
return(res)
}
signo(0, -2)
## [1] "Nulo"
Ejercicio 5
sample(1:6, size = 1)
## [1] 5
Ejercicio 6
sample(1:6, size = 4, replace = TRUE)
## [1] 3 2 1 1
Ejercicio 7
sample(c(1, 0), size = 1, prob = c(0.3, 0.7))
## [1] 0
Ejercicio 8
sample(c(1, 0), size = 8, replace = TRUE, prob = c(0.3, 0.7))
## [1] 0 0 0 1 0 1 0 0
Ejercicio 9
muestra <- rnorm(n = 10, mean = 4, sd = 0.5)
muestra
## [1] 4.997421 3.886136 3.425789 3.608067 4.969224 4.048778 4.042436 4.233697
## [9] 4.319687 4.251627
Ejercicio 10
# Como la distribución es simétrica, usamos la función qnorm para obtener el valor correspondiente a (1 - 0.15/2) = 0.925
P <- qnorm((1 - 0.15/2), mean = 0, sd = 2)
P
## [1] 2.879063
Ejercicio 11
# Primero encontramos el valor cuya probabilidad acumulada es 60%
x <- qnorm(0.60, mean = 0, sd = 1)
# Evaluamos la función de densidad en ese punto
densidad <- dnorm(x, mean = 0, sd = 1)
densidad
## [1] 0.3863425
Antes de aplicar cualquier tratamiento, examinamos la estructura y características de los datos. Creamos un dataset de ejemplo que contiene tanto valores perdidos como posibles outliers.
# Cargar librerías necesarias
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.5.3
## Warning: package 'readr' was built under R version 4.5.3
## Warning: package 'forcats' was built under R version 4.5.3
## Warning: package 'lubridate' was built under R version 4.5.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.2.0
## ✔ forcats 1.0.1 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.2 ✔ tibble 3.3.0
## ✔ lubridate 1.9.5 ✔ tidyr 1.3.1
## ✔ purrr 1.1.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(caret)
## Warning: package 'caret' was built under R version 4.5.3
## Cargando paquete requerido: lattice
##
## Adjuntando el paquete: 'caret'
##
## The following object is masked from 'package:purrr':
##
## lift
library(mice)
## Warning: package 'mice' was built under R version 4.5.3
##
## Adjuntando el paquete: 'mice'
##
## The following object is masked from 'package:stats':
##
## filter
##
## The following objects are masked from 'package:base':
##
## cbind, rbind
library(outliers) # Para test de Grubbs y Dixon
## Warning: package 'outliers' was built under R version 4.5.2
var1 <- c(rnorm(1000, mean = 30, sd = 10))
var2 <- c(rnorm(1000, mean = 0, sd = 10))
var2 <- var1*3 + var2
p_na <- 0.05 # 5% proba de NA
p_outlier <- 0.005 # 0.5% proba de outlier
introducir_anomalies <- function(x, p_na, p_outlier) {
for (i in seq_along(x)) {
rnd <- runif(1)
if (rnd < p_na) {
x[i] <- NA
} else if (rnd < p_na + p_outlier) {
x[i] <- 10000
}
}
return(x)
}
var1 <- introducir_anomalies(var1, p_na, p_outlier)
var2 <- introducir_anomalies(var2, p_na, p_outlier)
set.seed(123)
datos <- tibble(
id = 1:1000,
variable1 = var1,
variable2 = var2
)
# Mostrar resumen del conjunto de datos
summary(datos)
## id variable1 variable2
## Min. : 1.0 Min. : -3.873 Min. : -21.29
## 1st Qu.: 250.8 1st Qu.: 23.316 1st Qu.: 69.12
## Median : 500.5 Median : 29.866 Median : 91.07
## Mean : 500.5 Mean : 71.572 Mean : 111.85
## 3rd Qu.: 750.2 3rd Qu.: 37.132 3rd Qu.: 112.30
## Max. :1000.0 Max. :10000.000 Max. :10000.00
## NA's :36 NA's :44
Se observa que existen valores NA en ambas variables y algunos valores extremos (10000 en ambas variables).
Para detectar la presencia de valores nulos, utilizamos funciones de R tanto de base como del tidyverse.
# Contar valores perdidos en cada variable
datos %>% summarise(across(everything(), ~sum(is.na(.))))
## # A tibble: 1 × 3
## id variable1 variable2
## <int> <int> <int>
## 1 0 36 44
ggplot(datos, aes(x = variable1, y = variable2)) +
geom_point(color = "blue", alpha = 0.6) + # Scatter plot points
geom_smooth(method = "lm", color = "red", se = FALSE) + # Linear regression line
labs(
title = "Scatter Plot de Variable1 vs Variable2",
x = "Variable 1",
y = "Variable 2"
) +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 77 rows containing non-finite outside the scale range
## (`stat_smooth()`).
## Warning: Removed 77 rows containing missing values or values outside the scale range
## (`geom_point()`).
datos_filtered <- datos %>% drop_na()
lower_q1 <- quantile(datos_filtered$variable1, 0.02)
upper_q1 <- quantile(datos_filtered$variable1, 0.98)
lower_q2 <- quantile(datos_filtered$variable2, 0.02)
upper_q2 <- quantile(datos_filtered$variable2, 0.98)
datos_filtered <- datos_filtered %>%
filter(variable1 >= lower_q1, variable1 <= upper_q1,
variable2 >= lower_q2, variable2 <= upper_q2)
ggplot(datos_filtered, aes(x = variable1, y = variable2)) +
geom_point(color = "blue", alpha = 0.6) + # Scatter plot points
geom_smooth(method = "lm", color = "red", se = FALSE) + # Linear regression line
labs(
title = "Scatter Plot sacando 2% mas grande y chico",
x = "Variable 1",
y = "Variable 2"
) +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
Existen diversas técnicas para imputar valores nulos. A continuación se muestran varias, cada una con sus pros y contras.
Se eliminan las filas que contengan algún valor perdido.
datos_omit <- na.omit(datos)
dim(datos_omit)
## [1] 923 3
Sustituir los NA por la media (o mediana) de la variable.
# Imputación con la media para variable1
datos <- datos %>%
mutate(variable1_impute_mean = ifelse(is.na(variable1), mean(variable1, na.rm = TRUE), variable1))
# Imputación con la mediana para variable2
datos <- datos %>%
mutate(variable2_impute_median = ifelse(is.na(variable2), median(variable2, na.rm = TRUE), variable2))
Se imputan los valores perdidos seleccionando aleatoriamente un valor observado de la misma variable.
# Función para imputación hot-deck
imputacion_hotdeck <- function(x) {
missing <- is.na(x)
x[missing] <- sample(x[!missing], sum(missing), replace = TRUE)
return(x)
}
# Aplicar hot-deck a variable2
datos <- datos %>% mutate(variable2_impute_hotdeck = imputacion_hotdeck(variable2))
# Cargar librerías necesarias
library(tidyverse)
library(caret)
library(mice)
library(outliers) # Para test de Grubbs y Dixon
n <- 1000
# Generar variables iniciales
var1 <- rnorm(n, mean = 30, sd = 10)
var2 <- rnorm(n, mean = 0, sd = 10)
var2 <- var1 * 3 + var2
p_na <- 0.05 # 5% de probabilidad de NA
p_outlier <- 0.005 # 0.5% de probabilidad de outlier
# Función para introducir anomalías (NA y outliers)
introducir_anomalies <- function(x, p_na, p_outlier) {
for (i in seq_along(x)) {
rnd <- runif(1)
if (rnd < p_na) {
x[i] <- NA
} else if (rnd < p_na + p_outlier) {
x[i] <- 400
}
}
return(x)
}
var1 <- introducir_anomalies(var1, p_na, p_outlier)
var2 <- introducir_anomalies(var2, p_na, p_outlier)
set.seed(123)
datos <- tibble(
id = 1:n,
variable1 = var1,
variable2 = var2
)
# Imputación con la mediana
datos <- datos %>%
mutate(
variable1_mediana = if_else(is.na(variable1),
median(variable1, na.rm = TRUE),
variable1),
variable2_mediana = if_else(is.na(variable2),
median(variable2, na.rm = TRUE),
variable2)
)
# Imputación con la media
datos <- datos %>%
mutate(
variable1_media = if_else(is.na(variable1),
mean(variable1, na.rm = TRUE),
variable1),
variable2_media = if_else(is.na(variable2),
mean(variable2, na.rm = TRUE),
variable2)
)
# Suponiendo que 'datos_imputados' ya está creado y contiene las filas donde había NA
# Convertir a formato largo para cada método de imputación
original <- datos %>%
select(id, variable1, variable2) %>%
mutate(metodo = "Original")
mediana <- datos %>%
select(id, variable1_mediana, variable2_mediana) %>%
rename(variable1 = variable1_mediana,
variable2 = variable2_mediana) %>%
mutate(metodo = "Mediana")
media <- datos %>%
select(id, variable1_media, variable2_media) %>%
rename(variable1 = variable1_media,
variable2 = variable2_media) %>%
mutate(metodo = "Media")
# Unir todos los datasets en uno solo
datos_long <- bind_rows(original, mediana, media)
datos_long <- datos_long %>% filter(variable1<400, variable2<400 )
# Graficar solo los puntos con sus respectivos colores
ggplot(datos_long, aes(x = variable1, y = variable2, color = metodo)) +
geom_point(alpha = 1) +
labs(x = "Variable 1", y = "Variable 2", color = "Metodo de Imputacion") +
theme_minimal()
El boxplot es una herramienta gráfica clásica para identificar posibles outliers.
ggplot(datos, aes(y = variable1)) +
geom_boxplot(fill = "lightblue") +
labs(title = "Boxplot de variable1", y = "variable1") +
theme_minimal()
## Warning: Removed 58 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
Un QQ-Plot (Quantile-Quantile Plot) es una herramienta gráfica utilizada en estadística para comparar la distribución de una variable con una distribución teórica, generalmente una distribución normal. Es útil para verificar si los datos siguen una distribución específica y detectar posibles desviaciones, como colas pesadas, asimetría o valores atípicos.
Se parte de un conjunto de datos \(X = \{x_1, x_2, \dots, x_n\}\) con \(n\) observaciones.
Se asume que los datos siguen una distribución normal teórica con media \(\mu\) y desviación estándar \(\sigma\).
Se calcula el cuantil teórico esperado para cada observación \(x_{(i)}\). Para esto, se usa la posición de cada dato en la muestra: \[ p_i = \frac{i - 0.5}{n} \] donde \(p_i\) es el percentil estimado para cada dato.
Luego, se usa la función inversa de la distribución normal estándar \(\Phi^{-1}(p_i)\) para obtener los valores teóricos: \[ q_i = \Phi^{-1}(p_i) \] donde \(q_i\) representa los cuantiles teóricos de una distribución normal estándar \(N(0,1)\).
Supongamos que tenemos los siguientes datos:
\[ X = \{2.3, 2.9, 3.1, 3.8, 4.2, 4.8, 5.5\} \]
Ordenamos los datos:
\[
(2.3, 2.9, 3.1, 3.8, 4.2, 4.8, 5.5)
\]
Calculamos los cuantiles teóricos (con \(n=7\)) usando:
\[ p_i = \frac{i - 0.5}{n}, \quad i = 1,2,...,7 \]
Obtenemos los valores de \(p_i\):
\[ (0.07, 0.21, 0.36, 0.50, 0.64, 0.79, 0.93) \]
Luego, aplicamos la función inversa de la normal estándar \(\Phi^{-1}(p_i)\) para obtener:
\[ (-1.47, -0.81, -0.36, 0.00, 0.36, 0.81, 1.47) \]
Graficamos los puntos:
obtener_datos_qq_manual <- function(valores, a = 0.5) {
# Eliminar valores NA
valores <- na.omit(valores)
# Ordenar los valores observados
observados <- sort(valores)
# Tamaño de la muestra
n <- length(observados)
# Calcular manualmente los puntos de probabilidad
i <- 1:n
probabilidades <- (i - a) / (n + 1 - 2 * a)
# Cuantiles teóricos de una N(0, 1)
teoricos <- qnorm(probabilidades)
# Devolver como data frame
data.frame(teorico = teoricos, observado = observados)
}
# Histograma
ggplot(datos, aes(x = variable2)) +
geom_histogram(fill = "salmon", color = "black", bins = 20) +
labs(title = "Histograma de variable2", x = "variable2") +
theme_minimal()
## Warning: Removed 48 rows containing non-finite outside the scale range
## (`stat_bin()`).
# QQ-Plot
ggplot(datos, aes(sample = variable2)) +
stat_qq() +
stat_qq_line(color = "blue") +
labs(title = "QQ-Plot de variable2") +
theme_minimal()
## Warning: Removed 48 rows containing non-finite outside the scale range
## (`stat_qq()`).
## Warning: Removed 48 rows containing non-finite outside the scale range
## (`stat_qq_line()`).
Calculamos el z-score para identificar observaciones que se alejen más de 3 desviaciones estándar de la media.
datos <- datos %>% mutate(z_variable1 = abs(scale(variable1)))
outliers_z <- datos %>% filter(z_variable1 > 3)
## Warning: Using one column matrices in `filter()` was deprecated in dplyr 1.1.0.
## ℹ Please use one dimensional logical vectors instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
outliers_z
## # A tibble: 8 × 8
## id variable1 variable2 variable1_mediana variable2_mediana variable1_media
## <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 104 400 78.5 400 78.5 400
## 2 163 400 75.6 400 75.6 400
## 3 302 400 84.1 400 84.1 400
## 4 701 400 82.2 400 82.2 400
## 5 729 400 64.8 400 64.8 400
## 6 794 400 107. 400 107. 400
## 7 841 400 92.0 400 92.0 400
## 8 902 400 87.5 400 87.5 400
## # ℹ 2 more variables: variable2_media <dbl>, z_variable1 <dbl[,1]>
Se calculan el primer (Q1) y tercer cuartil (Q3) y se definen como outliers aquellos puntos que se encuentran fuera de \[Q1 - 1.5·IQR, Q3 + 1.5·IQR\].
# Calcular cuartiles e IQR para variable2
q1 <- quantile(datos$variable2, 0.25, na.rm = TRUE)
q3 <- quantile(datos$variable2, 0.75, na.rm = TRUE)
iqr <- q3 - q1
# Definir límites
limite_inferior <- q1 - 1.5 * iqr
limite_superior <- q3 + 1.5 * iqr
# Filtrar outliers
outliers_iqr <- datos %>% filter(variable2 < limite_inferior | variable2 > limite_superior)
outliers_iqr
## # A tibble: 8 × 8
## id variable1 variable2 variable1_mediana variable2_mediana variable1_media
## <int> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 14 -2.27 -9.35 -2.27 -9.35 -2.27
## 2 119 22.4 400 22.4 400 22.4
## 3 194 57.1 178. 57.1 178. 57.1
## 4 216 -3.11 -18.9 -3.11 -18.9 -3.11
## 5 604 -0.470 -3.85 -0.470 -3.85 -0.470
## 6 707 18.2 400 18.2 400 18.2
## 7 716 63.0 186. 63.0 186. 63.0
## 8 944 12.2 -1.58 12.2 -1.58 12.2
## # ℹ 2 more variables: variable2_media <dbl>, z_variable1 <dbl[,1]>
Identifica el valor extremo más alejado de la media en una distribución normal (se remueven NA).
El Test de Grubbs es una prueba estadística utilizada para detectar valores atípicos en un conjunto de datos que sigue una distribución normal. Su objetivo es identificar si el valor extremo más alejado de la media es significativamente diferente del resto de los datos.
La estadística del test se calcula como:
\[ G = \frac{\max |X_i - \bar{X}|}{s} \]
Donde: - \(X_i\) es el valor más alejado de la media (\(\bar{X}\)). - \(\bar{X}\) es la media de los datos. - \(s\) es la desviación estándar muestral.
El valor crítico de \(G\) se obtiene de una tabla de referencia o mediante software estadístico. Si \(G\) es mayor que el valor crítico para un nivel de significancia (\(\alpha\), típicamente 0.05), se rechaza \(H_0\) y se considera el dato como un valor atípico.
grubbs_result <- grubbs.test(na.omit(datos$variable1))
grubbs_result
##
## Grubbs test for one outlier
##
## data: na.omit(datos$variable1)
## G = 10.36318, U = 0.88575, p-value < 2.2e-16
## alternative hypothesis: highest value 400 is an outlier
El Test de Dixon es una prueba estadística diseñada para identificar valores atípicos en conjuntos de datos pequeños o medianos. Es especialmente útil cuando el tamaño de la muestra es menor o igual a 30.
El test de Dixon calcula una estadística basada en la distancia entre el valor más extremo y el resto de la distribución. Existen diferentes fórmulas dependiendo de si se considera el menor o el mayor valor como sospechoso de ser un outlier. La estadística general es:
\[ Q = \frac{x_{\text{extremo}} - x_{\text{más cercano}}}{x_{\text{máximo}} - x_{\text{mínimo}}} \]
Donde: - \(x_{\text{extremo}}\) es el valor sospechoso de ser un outlier (mínimo o máximo del conjunto de datos). - \(x_{\text{más cercano}}\) es el valor más cercano a \(x_{\text{extremo}}\). - \(x_{\text{máximo}}\) y \(x_{\text{mínimo}}\) son los valores máximos y mínimos del conjunto de datos.
El valor de \(Q\) se compara con valores críticos tabulados. Si \(Q\) es mayor que el valor crítico correspondiente al tamaño de la muestra y nivel de significancia (\(\alpha\), típicamente 0.05), se considera que el valor extremo es un outlier significativo.
El código en R implementa el test de Dixon de la siguiente manera:
# Instalar el paquete si no está instalado
install.packages("outliers")
## Warning: package 'outliers' is in use and will not be installed
# Cargar la librería
library(outliers)
# Contar la cantidad de datos no nulos (sin NA)
sample_size <- sum(!is.na(datos$variable1))
# Aplicar la prueba de Dixon solo si la muestra es <= 30
if (sample_size > 30) {
submuestra <- sample(na.omit(datos$variable1), 30) # Seleccionar una submuestra de 30 elementos
dixon_result <- dixon.test(submuestra) # Aplicar test de Dixon
print(dixon_result)
} else {
dixon_result <- dixon.test(na.omit(datos$variable1)) # Aplicar test directamente
print(dixon_result)
}
##
## Dixon test for outliers
##
## data: submuestra
## Q = 0.34044, p-value = 0.1769
## alternative hypothesis: lowest value -2.27322829767503 is an outlier
Una vez identificados los outliers, existen diversas estrategias para su tratamiento.
Se eliminan las observaciones detectadas.
datos_sin_outliers <- datos %>%
filter(!(variable2 < limite_inferior | variable2 > limite_superior))
dim(datos_sin_outliers)
## [1] 944 8
Consiste en reemplazar los valores extremos por los percentiles de corte (por ejemplo, al 5% y 95%).
winsorizacion <- function(x, lower = 0.05, upper = 0.95) {
quantiles <- quantile(x, probs = c(lower, upper), na.rm = TRUE)
x[x < quantiles[1]] <- quantiles[1]
x[x > quantiles[2]] <- quantiles[2]
return(x)
}
datos <- datos %>%
mutate(variable2_winsorizada = winsorizacion(variable2, 0.05, 0.95))
En el dataset airquality se introducen valores extremos en la variable Temp (simulando outliers) y se mantienen los valores NA presentes en variables como Ozone y Solar.R.
# Cargar las librerías necesarias
library(dplyr)
library(ggplot2)
# Cargar el dataset real
datos <- airquality
# Introducir outliers en 'Temp': se duplican el valor en el 5% de las observaciones
set.seed(123)
indices_extremos <- sample(1:nrow(datos), size = round(0.05 * nrow(datos)))
datos$Temp[indices_extremos] <- datos$Temp[indices_extremos] * 2
# Visualizar un resumen del dataset modificado
summary(datos)
## Ozone Solar.R Wind Temp
## Min. : 1.00 Min. : 7.0 Min. : 1.700 Min. : 56.00
## 1st Qu.: 18.00 1st Qu.:115.8 1st Qu.: 7.400 1st Qu.: 73.00
## Median : 31.50 Median :205.0 Median : 9.700 Median : 80.00
## Mean : 42.13 Mean :185.9 Mean : 9.958 Mean : 82.01
## 3rd Qu.: 63.25 3rd Qu.:258.8 3rd Qu.:11.500 3rd Qu.: 86.00
## Max. :168.00 Max. :334.0 Max. :20.700 Max. :184.00
## NA's :37 NA's :7
## Month Day
## Min. :5.000 Min. : 1.0
## 1st Qu.:6.000 1st Qu.: 8.0
## Median :7.000 Median :16.0
## Mean :6.993 Mean :15.8
## 3rd Qu.:8.000 3rd Qu.:23.0
## Max. :9.000 Max. :31.0
##
# Nota: El dataset 'datos' presenta NA en variables como Ozone y Solar.R, lo cual es útil para la práctica.
summarise y
is.na().# Calcular la proporción de NA en cada variable
proporcion_NA <- datos %>% summarise(across(everything(), ~mean(is.na(.))))
print(proporcion_NA)
## Ozone Solar.R Wind Temp Month Day
## 1 0.2418301 0.04575163 0 0 0 0
# (a) Imputación con la media en 'Ozone'
datos <- datos %>%
mutate(Ozone_impute_mean = ifelse(is.na(Ozone), mean(Ozone, na.rm = TRUE), Ozone))
# (b) Imputación hot-deck para 'Ozone'
imputacion_hotdeck <- function(x) {
missing <- is.na(x)
x[missing] <- sample(x[!missing], sum(missing), replace = TRUE)
return(x)
}
datos <- datos %>% mutate(Ozone_impute_hotdeck = imputacion_hotdeck(Ozone))
# Resumen estadístico y cálculo de la desviación estándar
cat("Imputación con la media:\n")
## Imputación con la media:
print(summary(datos$Ozone_impute_mean))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.00 21.00 42.13 42.13 46.00 168.00
cat("SD:", sd(datos$Ozone_impute_mean, na.rm = TRUE), "\n\n")
## SD: 28.69337
cat("Imputación hot-deck:\n")
## Imputación hot-deck:
print(summary(datos$Ozone_impute_hotdeck))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.00 19.00 31.00 41.75 61.00 168.00
cat("SD:", sd(datos$Ozone_impute_hotdeck, na.rm = TRUE), "\n\n")
## SD: 32.24037
# Comparación con la distribución original (solo casos sin NA)
datos_completos <- datos %>% filter(!is.na(Ozone))
cat("Datos originales (sin NA):\n")
## Datos originales (sin NA):
print(summary(datos_completos$Ozone))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.00 18.00 31.50 42.13 63.25 168.00
cat("SD:", sd(datos_completos$Ozone), "\n")
## SD: 32.98788
# Cálculo de cuartiles, IQR y límites para 'Temp'
q1 <- quantile(datos$Temp, 0.25, na.rm = TRUE)
q3 <- quantile(datos$Temp, 0.75, na.rm = TRUE)
iqr <- q3 - q1
limite_inferior <- q1 - 1.5 * iqr
limite_superior <- q3 + 1.5 * iqr
# Detectar outliers
outliers <- datos %>% filter(Temp < limite_inferior | Temp > limite_superior)
cat("Outliers en 'Temp':\n")
## Outliers en 'Temp':
print(outliers)
## Ozone Solar.R Wind Temp Month Day Ozone_impute_mean Ozone_impute_hotdeck
## 1 14 274 10.9 136 5 14 14.00000 14
## 2 NA 250 9.2 184 6 12 42.12931 73
## 3 12 120 11.5 146 6 19 12.00000 12
## 4 50 275 7.4 172 7 29 50.00000 50
## 5 64 253 7.4 166 7 30 64.00000 64
## 6 73 215 8.0 172 8 26 73.00000 73
## 7 14 191 14.3 150 9 28 14.00000 14
## 8 20 223 11.5 136 9 30 20.00000 20
# Crear un dataset sin outliers
datos_sin_outliers <- datos %>% filter(Temp >= limite_inferior & Temp <= limite_superior)
# Comparar media y desviación estándar
media_original <- mean(datos$Temp, na.rm = TRUE)
sd_original <- sd(datos$Temp, na.rm = TRUE)
media_sin <- mean(datos_sin_outliers$Temp, na.rm = TRUE)
sd_sin <- sd(datos_sin_outliers$Temp, na.rm = TRUE)
cat("Media y SD en 'Temp':\n")
## Media y SD en 'Temp':
print(c("Media original" = media_original, "SD original" = sd_original,
"Media sin outliers" = media_sin, "SD sin outliers" = sd_sin))
## Media original SD original Media sin outliers SD sin outliers
## 82.006536 20.482501 77.827586 9.513401
# Función para winsorización
winsorizacion <- function(x, lower, upper) {
qnt <- quantile(x, probs = c(lower, upper), na.rm = TRUE)
x[x < qnt[1]] <- qnt[1]
x[x > qnt[2]] <- qnt[2]
return(x)
}
# Aplicar winsorización en 'Temp'
datos <- datos %>% mutate(Temp_winsorizada = winsorizacion(Temp, 0.05, 0.95))
# Resúmenes estadísticos
cat("Resumen 'Temp' original:\n")
## Resumen 'Temp' original:
print(summary(datos$Temp))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 56.00 73.00 80.00 82.01 86.00 184.00
cat("\nResumen 'Temp' winsorizada:\n")
##
## Resumen 'Temp' winsorizada:
print(summary(datos$Temp_winsorizada))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 60.20 73.00 80.00 79.78 86.00 112.60
cat("\nResumen 'Temp' sin outliers (eliminación):\n")
##
## Resumen 'Temp' sin outliers (eliminación):
print(summary(datos_sin_outliers$Temp))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 56.00 72.00 79.00 77.83 84.00 97.00
# Comparación gráfica: gráficos de densidad
ggplot(datos, aes(x = Temp)) +
geom_density(fill = "gray", alpha = 0.5) +
labs(title = "Densidad de Temp - Original")
ggplot(datos, aes(x = Temp_winsorizada)) +
geom_density(fill = "blue", alpha = 0.5) +
labs(title = "Densidad de Temp - Winsorizada")
ggplot(datos_sin_outliers, aes(x = Temp)) +
geom_density(fill = "green", alpha = 0.5) +
labs(title = "Densidad de Temp - Sin Outliers")
Nota: Para estos tests es necesario el paquete outliers.
library(outliers)
# Test de Grubbs para 'Ozone'
grubbs_result <- grubbs.test(na.omit(datos$Ozone))
cat("Resultado del test de Grubbs en 'Ozone':\n")
## Resultado del test de Grubbs en 'Ozone':
print(grubbs_result)
##
## Grubbs test for one outlier
##
## data: na.omit(datos$Ozone)
## G = 3.8157, U = 0.8723, p-value = 0.004765
## alternative hypothesis: highest value 168 is an outlier
# Test de Dixon para 'Ozone'
sample_size <- sum(!is.na(datos$Ozone))
if (sample_size > 30) {
submuestra <- sample(na.omit(datos$Ozone), 30)
dixon_result <- dixon.test(submuestra)
cat("Resultado del test de Dixon (muestra de 30) en 'Ozone':\n")
print(dixon_result)
} else {
dixon_result <- dixon.test(na.omit(datos$Ozone))
cat("Resultado del test de Dixon en 'Ozone':\n")
print(dixon_result)
}
## Resultado del test de Dixon (muestra de 30) en 'Ozone':
##
## Dixon test for outliers
##
## data: submuestra
## Q = 0.47826, p-value = 0.0116
## alternative hypothesis: highest value 168 is an outlier
# Comentario: El test de Grubbs es adecuado para detectar un único outlier asumiendo normalidad,
# mientras que el test de Dixon es útil en muestras pequeñas o cuando se sospecha de múltiples extremos.
library(mice)
# Copiar el dataset mtcars
data("mtcars")
mtcars_mod <- mtcars
# Introducir NA aleatorios en 'mpg' (10% de las observaciones)
set.seed(123)
na_indices <- sample(1:nrow(mtcars_mod), size = round(0.1 * nrow(mtcars_mod)))
mtcars_mod$mpg[na_indices] <- NA
# Resumen de 'mpg' con NA
cat("Resumen de 'mpg' en mtcars_mod (con NA):\n")
## Resumen de 'mpg' en mtcars_mod (con NA):
print(summary(mtcars_mod$mpg))
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 10.40 15.80 19.20 20.24 22.80 33.90 3
# Aplicar imputación múltiple con mice para la variable 'mpg'
imputacion_mtcars <- mice(mtcars_mod, m = 5, maxit = 50, method = 'pmm', seed = 500)
##
## iter imp variable
## 1 1 mpg
## 1 2 mpg
## 1 3 mpg
## 1 4 mpg
## 1 5 mpg
## 2 1 mpg
## 2 2 mpg
## 2 3 mpg
## 2 4 mpg
## 2 5 mpg
## 3 1 mpg
## 3 2 mpg
## 3 3 mpg
## 3 4 mpg
## 3 5 mpg
## 4 1 mpg
## 4 2 mpg
## 4 3 mpg
## 4 4 mpg
## 4 5 mpg
## 5 1 mpg
## 5 2 mpg
## 5 3 mpg
## 5 4 mpg
## 5 5 mpg
## 6 1 mpg
## 6 2 mpg
## 6 3 mpg
## 6 4 mpg
## 6 5 mpg
## 7 1 mpg
## 7 2 mpg
## 7 3 mpg
## 7 4 mpg
## 7 5 mpg
## 8 1 mpg
## 8 2 mpg
## 8 3 mpg
## 8 4 mpg
## 8 5 mpg
## 9 1 mpg
## 9 2 mpg
## 9 3 mpg
## 9 4 mpg
## 9 5 mpg
## 10 1 mpg
## 10 2 mpg
## 10 3 mpg
## 10 4 mpg
## 10 5 mpg
## 11 1 mpg
## 11 2 mpg
## 11 3 mpg
## 11 4 mpg
## 11 5 mpg
## 12 1 mpg
## 12 2 mpg
## 12 3 mpg
## 12 4 mpg
## 12 5 mpg
## 13 1 mpg
## 13 2 mpg
## 13 3 mpg
## 13 4 mpg
## 13 5 mpg
## 14 1 mpg
## 14 2 mpg
## 14 3 mpg
## 14 4 mpg
## 14 5 mpg
## 15 1 mpg
## 15 2 mpg
## 15 3 mpg
## 15 4 mpg
## 15 5 mpg
## 16 1 mpg
## 16 2 mpg
## 16 3 mpg
## 16 4 mpg
## 16 5 mpg
## 17 1 mpg
## 17 2 mpg
## 17 3 mpg
## 17 4 mpg
## 17 5 mpg
## 18 1 mpg
## 18 2 mpg
## 18 3 mpg
## 18 4 mpg
## 18 5 mpg
## 19 1 mpg
## 19 2 mpg
## 19 3 mpg
## 19 4 mpg
## 19 5 mpg
## 20 1 mpg
## 20 2 mpg
## 20 3 mpg
## 20 4 mpg
## 20 5 mpg
## 21 1 mpg
## 21 2 mpg
## 21 3 mpg
## 21 4 mpg
## 21 5 mpg
## 22 1 mpg
## 22 2 mpg
## 22 3 mpg
## 22 4 mpg
## 22 5 mpg
## 23 1 mpg
## 23 2 mpg
## 23 3 mpg
## 23 4 mpg
## 23 5 mpg
## 24 1 mpg
## 24 2 mpg
## 24 3 mpg
## 24 4 mpg
## 24 5 mpg
## 25 1 mpg
## 25 2 mpg
## 25 3 mpg
## 25 4 mpg
## 25 5 mpg
## 26 1 mpg
## 26 2 mpg
## 26 3 mpg
## 26 4 mpg
## 26 5 mpg
## 27 1 mpg
## 27 2 mpg
## 27 3 mpg
## 27 4 mpg
## 27 5 mpg
## 28 1 mpg
## 28 2 mpg
## 28 3 mpg
## 28 4 mpg
## 28 5 mpg
## 29 1 mpg
## 29 2 mpg
## 29 3 mpg
## 29 4 mpg
## 29 5 mpg
## 30 1 mpg
## 30 2 mpg
## 30 3 mpg
## 30 4 mpg
## 30 5 mpg
## 31 1 mpg
## 31 2 mpg
## 31 3 mpg
## 31 4 mpg
## 31 5 mpg
## 32 1 mpg
## 32 2 mpg
## 32 3 mpg
## 32 4 mpg
## 32 5 mpg
## 33 1 mpg
## 33 2 mpg
## 33 3 mpg
## 33 4 mpg
## 33 5 mpg
## 34 1 mpg
## 34 2 mpg
## 34 3 mpg
## 34 4 mpg
## 34 5 mpg
## 35 1 mpg
## 35 2 mpg
## 35 3 mpg
## 35 4 mpg
## 35 5 mpg
## 36 1 mpg
## 36 2 mpg
## 36 3 mpg
## 36 4 mpg
## 36 5 mpg
## 37 1 mpg
## 37 2 mpg
## 37 3 mpg
## 37 4 mpg
## 37 5 mpg
## 38 1 mpg
## 38 2 mpg
## 38 3 mpg
## 38 4 mpg
## 38 5 mpg
## 39 1 mpg
## 39 2 mpg
## 39 3 mpg
## 39 4 mpg
## 39 5 mpg
## 40 1 mpg
## 40 2 mpg
## 40 3 mpg
## 40 4 mpg
## 40 5 mpg
## 41 1 mpg
## 41 2 mpg
## 41 3 mpg
## 41 4 mpg
## 41 5 mpg
## 42 1 mpg
## 42 2 mpg
## 42 3 mpg
## 42 4 mpg
## 42 5 mpg
## 43 1 mpg
## 43 2 mpg
## 43 3 mpg
## 43 4 mpg
## 43 5 mpg
## 44 1 mpg
## 44 2 mpg
## 44 3 mpg
## 44 4 mpg
## 44 5 mpg
## 45 1 mpg
## 45 2 mpg
## 45 3 mpg
## 45 4 mpg
## 45 5 mpg
## 46 1 mpg
## 46 2 mpg
## 46 3 mpg
## 46 4 mpg
## 46 5 mpg
## 47 1 mpg
## 47 2 mpg
## 47 3 mpg
## 47 4 mpg
## 47 5 mpg
## 48 1 mpg
## 48 2 mpg
## 48 3 mpg
## 48 4 mpg
## 48 5 mpg
## 49 1 mpg
## 49 2 mpg
## 49 3 mpg
## 49 4 mpg
## 49 5 mpg
## 50 1 mpg
## 50 2 mpg
## 50 3 mpg
## 50 4 mpg
## 50 5 mpg
# Completar los datos imputados (se elige la primera imputación)
mtcars_imputed <- complete(imputacion_mtcars, 1)
# Ver resumen de 'mpg' después de la imputación
cat("Resumen de 'mpg' en mtcars_imputed:\n")
## Resumen de 'mpg' en mtcars_imputed:
print(summary(mtcars_imputed$mpg))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 10.40 15.72 19.20 20.13 22.80 33.90
# Histogramas comparativos
par(mfrow = c(1,2))
hist(mtcars$mpg, main = "Histograma de mpg - Original", xlab = "mpg", col = "gray", breaks = 10)
hist(mtcars_imputed$mpg, main = "Histograma de mpg - Imputado", xlab = "mpg", col = "blue", breaks = 10)
par(mfrow = c(1,1))
Muchos algoritmos de aprendizaje automático (como regresión logística, SVM, KNN y PCA) son sensibles a la escala de las variables. Cuando las variables tienen escalas muy diferentes, aquellas con valores más altos pueden dominar el cálculo de distancias o la función objetivo. Normalizar o estandarizar ayuda a:
La normalización transforma los valores de una variable para que queden en el rango [0, 1] mediante la fórmula:
\[ x_{\text{norm}} = \frac{x - \min(x)}{\max(x) - \min(x)} \]
# Crear datos de ejemplo
set.seed(123)
datos <- data.frame(variable = rnorm(100, mean = 50, sd = 10))
# Normalización manual
datos$variable_norm <- (datos$variable - min(datos$variable)) / (max(datos$variable) - min(datos$variable))
summary(datos$variable_norm)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.0000 0.4037 0.5273 0.5337 0.6674 1.0000
caretlibrary(caret)
preProc_range <- preProcess(datos, method = c("range"))
datos_norm <- predict(preProc_range, datos)
head(datos_norm)
## variable variable_norm
## 1 0.3889008 0.3889008
## 2 0.4623575 0.4623575
## 3 0.8601969 0.8601969
## 4 0.5292286 0.5292286
## 5 0.5423008 0.5423008
## 6 0.8949699 0.8949699
La normalización es particularmente útil cuando se desea preservar la forma de la distribución, pero ajustando todos los valores a una escala común.
La estandarización reescala la variable para que tenga media 0 y desviación estándar 1, utilizando la fórmula:
\[ z = \frac{x - \mu}{\sigma} \]
# Estandarización manual utilizando scale()
datos$variable_std <- scale(datos$variable)
summary(datos$variable_std)
## V1
## Min. :-2.62876
## 1st Qu.:-0.64006
## Median :-0.03139
## Mean : 0.00000
## 3rd Qu.: 0.65885
## Max. : 2.29721
sd(datos$variable_std)
## [1] 1
caretpreProc_std <- preProcess(datos, method = c("center", "scale"))
datos_std_caret <- predict(preProc_std, datos)
head(datos_std_caret)
## variable variable_norm variable_std
## 1 -0.71304802 -0.71304802 -0.71304802
## 2 -0.35120270 -0.35120270 -0.35120270
## 3 1.60854170 1.60854170 1.60854170
## 4 -0.02179795 -0.02179795 -0.02179795
## 5 0.04259548 0.04259548 0.04259548
## 6 1.77983218 1.77983218 1.77983218
La estandarización es muy útil para algoritmos basados en distancias, ya que asegura que las unidades de medida no influyan en el análisis.
El escalamiento robusto se utiliza cuando la presencia de outliers puede distorsionar las medidas tradicionales (media y desviación estándar). Este método utiliza la mediana y el rango intercuartílico (IQR) para centrar y escalar los datos, según la fórmula:
\[ x_{\text{robust}} = \frac{x - \text{Mediana}(x)}{IQR(x)} \]
# Calcular el escalamiento robusto
mediana <- median(datos$variable, na.rm = TRUE)
iqr_val <- IQR(datos$variable, na.rm = TRUE)
datos$variable_robust <- (datos$variable - mediana) / iqr_val
summary(datos$variable_robust)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -1.99964 -0.46860 0.00000 0.02416 0.53140 1.79272
Utilizando la función sample, se extraen elementos al
azar:
# Seleccionar 100 valores al azar de 'variable' sin reemplazo
muestra_simple <- sample(datos$variable, size = 100, replace = FALSE)
head(muestra_simple)
## [1] 62.53815 43.72094 46.74068 67.86913 54.35181 63.68602
caretSi se cuenta con una variable categórica para estratificar, se puede
utilizar createDataPartition para asegurar que la
distribución de los estratos se mantenga en la partición de
entrenamiento y prueba.
# Supongamos que añadimos una variable categórica para estratificar
datos$grupo <- sample(c("A", "B", "C"), size = nrow(datos), replace = TRUE)
library(caret)
set.seed(123)
trainIndex <- createDataPartition(datos$grupo, p = 0.7, list = FALSE)
train <- datos[trainIndex, ]
test <- datos[-trainIndex, ]
# Revisar la distribución de 'grupo' en la población, entrenamiento y prueba
table(datos$grupo)
##
## A B C
## 38 32 30
table(train$grupo)
##
## A B C
## 27 23 21
table(test$grupo)
##
## A B C
## 11 9 9
El muestreo sistemático consiste en seleccionar cada k-ésima observación de la población, lo cual puede ser eficiente si se conoce la estructura subyacente.
# Calcular el intervalo k y seleccionar cada k-ésimo elemento
k <- 4
muestra_sistematico <- datos[seq(1, nrow(datos), by = k), ]
nrow(muestra_sistematico)
## [1] 25
nrow(datos)
## [1] 100
En este método, se dividen los datos en conglomerados (por ejemplo, grupos geográficos o categóricos) y se selecciona aleatoriamente uno o varios conglomerados completos.
# Suponiendo que 'grupo' representa conglomerados en el dataset:
# Asignar aleatoriamente grupos a los datos (si no existe esta variable)
datos$grupo <- sample(c("A", "B", "C", "D"), size = nrow(datos), replace = TRUE)
# Seleccionar aleatoriamente dos conglomerados
conglomerados_seleccionados <- sample(unique(datos$grupo), size = 2)
muestra_conglomerados <- datos[datos$grupo %in% conglomerados_seleccionados, ]
table(muestra_conglomerados$grupo)
##
## B D
## 30 25
El bootstrapping es una técnica de remuestreo utilizada en estadística para estimar la distribución de una estadística muestral sin necesidad de asumir una distribución teórica específica. Consiste en generar múltiples muestras de la misma población mediante remuestreo con reemplazo, permitiendo obtener una distribución empírica de la estadística de interés. Esto es útil para estimar errores estándar, intervalos de confianza y la variabilidad de estimadores.
Este método no hace suposiciones sobre la distribución de la población. Se basa en seleccionar repetidamente muestras con reemplazo de la muestra original y calcular la estadística de interés en cada una de ellas. Es ampliamente utilizado en situaciones en las que la distribución subyacente es desconocida o difícil de modelar.
A diferencia del enfoque no paramétrico, este método asume una distribución específica para los datos y genera muestras sintéticas a partir de parámetros estimados de la población. Se usa cuando se tiene información previa sobre la distribución de los datos y se desea modelar la variabilidad basándose en dicha distribución.
El bootstrapping es útil en diversas situaciones: - Cuando el tamaño de la muestra es pequeño y los métodos asintóticos no son confiables. - Cuando la distribución de la población no es conocida o es difícil de modelar. - Para estimar la varianza de una estadística y construir intervalos de confianza sin necesidad de supuestos fuertes. - Para validar modelos predictivos a través de técnicas como el bootstrap cross-validation.
Para ilustrar el uso del bootstrapping, utilizaremos el conjunto de
datos mtcars de R. En este ejemplo, estimaremos la media
del consumo de combustible (mpg) y su variabilidad usando
bootstrapping no paramétrico.
library(boot)
##
## Adjuntando el paquete: 'boot'
## The following object is masked from 'package:lattice':
##
## melanoma
# Cargar los datos
datos <- mtcars
densidad <- density(datos$mpg)
print(mean(datos$mpg))
## [1] 20.09062
# Graficar la densidad
plot(densidad, main="Gráfico de Densidad de MPG", xlab="Millas por galón (mpg)", col="blue", lwd=2)
polygon(densidad, col=rgb(0, 0, 1, 0.2), border="blue") # Relleno con transparencia
# Definir función para calcular la media del consumo de combustible
media_fn <- function(data, indices) {
return(mean(data[indices], na.rm = TRUE))
}
# Aplicar bootstrapping con 1000 replicaciones
set.seed(123)
boot_result <- boot(data = datos$mpg, statistic = media_fn, R = 1000)
print(boot_result)
##
## ORDINARY NONPARAMETRIC BOOTSTRAP
##
##
## Call:
## boot(data = datos$mpg, statistic = media_fn, R = 1000)
##
##
## Bootstrap Statistics :
## original bias std. error
## t1* 20.09062 0.048825 1.048114
plot(boot_result)
El resultado de la función boot() nos proporciona: -
Estadística original: La media muestral de
mpg. - Sesgo: Diferencia entre la media de
los valores bootstrapeados y la estadística original. - Error
estándar: Variabilidad estimada de la media.
Para obtener un intervalo de confianza del 95% basado en los percentiles de la distribución empírica obtenida:
boot.ci(boot_result, type = "perc")
## BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
## Based on 1000 bootstrap replicates
##
## CALL :
## boot.ci(boot.out = boot_result, type = "perc")
##
## Intervals :
## Level Percentile
## 95% (18.12, 22.21 )
## Calculations and Intervals on Original Scale
Este intervalo de confianza es útil para evaluar la incertidumbre de
la estimación de la media de mpg.
Para realizar un bootstrapping paramétrico, asumimos que
mpg sigue una distribución normal con media y desviación
estándar estimadas de la muestra original. Generamos nuevas muestras de
mpg basadas en esta distribución y aplicamos
bootstrapping:
param_bootstrap <- function(data, R) {
mu <- mean(data, na.rm = TRUE)
sigma <- sd(data, na.rm = TRUE)
boot_samples <- replicate(R, mean(rnorm(length(data), mean = mu, sd = sigma)))
return(boot_samples)
}
# Aplicamos el bootstrapping paramétrico
set.seed(123)
param_results <- param_bootstrap(datos$mpg, R = 1000)
# Estimamos el intervalo de confianza del 95%
quantile(param_results, probs = c(0.025, 0.975))
## 2.5% 97.5%
## 17.97379 21.98495
En este caso, generamos R=1000 muestras sintéticas de
mpg asumiendo una distribución normal. Luego, obtenemos el
intervalo de confianza basado en los percentiles de la distribución
generada.
Una parte esencial del análisis predictivo es dividir el conjunto de
datos en dos (o más) subconjuntos:
- Entrenamiento: Donde se ajusta el modelo.
- Validacion: Donde se evalúa el desempeño del modelo
en datos no vistos. - Test: Conjunto de datos sobre el
cual NO se toman decisiones y sirve para al finalizar reportar
metricas
Esta división ayuda a evitar el sobreajuste y proporciona una estimación realista de la capacidad predictiva.
caretEl paquete caret facilita la creación de particiones de
datos manteniendo la distribución de variables importantes
(especialmente en el caso de variables categóricas).
datos
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
## Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
## Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
## Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
## Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
## Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
## Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
## Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
## Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
## Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
## Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
## Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
## Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
## Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
## Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
## Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
## Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
## AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
## Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
## Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
## Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
## Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
## Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
## Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
## Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
## Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
## Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
# Supongamos que 'datos' es nuestro dataset y 'grupo' es una variable de estratificación
set.seed(123)
library(caret)
datos$grupo <- sample(c("A", "B", "C", "D"), size = nrow(datos), replace = TRUE)
trainIndex <- createDataPartition(datos$grupo, p = 0.7, list = FALSE)
train <- datos[trainIndex, ]
test <- datos[-trainIndex, ]
# Revisar la distribución de la variable estratificada en cada subconjunto
table(datos$grupo)
##
## A B C D
## 8 10 10 4
table(train$grupo)
##
## A B C D
## 6 7 7 3
table(test$grupo)
##
## A B C D
## 2 3 3 1
Se puede entrenar un modelo, por ejemplo, una regresión lineal, y evaluarlo en el conjunto de prueba.
# Ajustar un modelo de regresión lineal usando el conjunto de entrenamiento
modelo_lm <- lm(mpg ~ ., data = train)
# Predicción en el conjunto de prueba
prediccionesTest <- predict(modelo_lm, newdata = test)
prediccionesTrain <- predict(modelo_lm, newdata = train)
# Comparar las predicciones con los valores reales
resultados <- data.frame(Real = test$mpg, Predicho = prediccionesTest)
resultadosTrain <- data.frame(Real = train$mpg, Predicho = prediccionesTrain)
head(resultados)
## Real Predicho
## Hornet Sportabout 18.7 13.72877
## Merc 450SL 17.3 15.98009
## Merc 450SLC 15.2 16.47472
## Toyota Corolla 33.9 28.24974
## Dodge Challenger 15.5 15.61435
## AMC Javelin 15.2 18.38049
# Calcular error cuadrático medio (MSE) en test
mse <- mean((resultados$Real - resultados$Predicho)^2)
mseTrain <- mean((resultadosTrain$Real - resultadosTrain$Predicho)^2)
print(paste("MSE Test:", round(mse, 2)))
## [1] "MSE Test: 12.13"
print(paste("MSE Train:", round(mseTrain, 2)))
## [1] "MSE Train: 2.72"
La validación cruzada es una técnica que permite evaluar el rendimiento de un modelo de forma más robusta al dividir los datos en varios pliegues (folds) y promediar el desempeño en cada uno.
Una de las formas más comunes es la validación cruzada k-fold, en la que el conjunto de datos se divide en k partes iguales. Se entrena el modelo k veces, cada vez usando k-1 partes para entrenamiento y la parte restante para prueba.
# Definir un control de entrenamiento para validación cruzada k-fold (por ejemplo, k=10)
control_cv <- trainControl(method = "cv", number = 10)
# Entrenar el modelo utilizando validación cruzada
modelo_cv <- train(mpg ~ ., data = train, method = "lm", trControl = control_cv)
print(modelo_cv)
## Linear Regression
##
## 23 samples
## 11 predictors
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 20, 21, 21, 21, 20, 21, ...
## Resampling results:
##
## RMSE Rsquared MAE
## 4.619263 0.8849882 4.022908
##
## Tuning parameter 'intercept' was held constant at a value of TRUE
modelo_cv
## Linear Regression
##
## 23 samples
## 11 predictors
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 20, 21, 21, 21, 20, 21, ...
## Resampling results:
##
## RMSE Rsquared MAE
## 4.619263 0.8849882 4.022908
##
## Tuning parameter 'intercept' was held constant at a value of TRUE
El LOOCV es un caso especial de k-fold donde k es igual al número de observaciones. Esto puede ser computacionalmente costoso, pero es útil para conjuntos de datos pequeños.
# Configurar el control para LOOCV
control_loocv <- trainControl(method = "LOOCV")
# Entrenar el modelo utilizando LOOCV
modelo_loocv <- train(mpg ~ ., data = train, method = "lm", trControl = control_loocv)
print(modelo_loocv)
## Linear Regression
##
## 23 samples
## 11 predictors
##
## No pre-processing
## Resampling: Leave-One-Out Cross-Validation
## Summary of sample sizes: 22, 22, 22, 22, 22, 22, ...
## Resampling results:
##
## RMSE Rsquared MAE
## 4.903128 0.4894812 4.039779
##
## Tuning parameter 'intercept' was held constant at a value of TRUE
A continuación se presentan nuevos ejercicios utilizando datasets reales de R. Primero se exponen los enunciados de cada ejercicio y, posteriormente, se muestran sus resoluciones correspondientes.
Utiliza el dataset mtcars para dividirlo en un 70% de
entrenamiento y un 30% de prueba. Ajusta un modelo de regresión lineal
para predecir el consumo de combustible (mpg) en función de
la potencia (hp) y el peso (wt). Evalúa el
modelo en el conjunto de prueba calculando el error cuadrático medio
(MSE).
Con el conjunto de entrenamiento obtenido en el Ejercicio 1, realiza
una validación cruzada de 10 pliegues para evaluar el rendimiento de un
modelo de regresión lineal que prediga mpg a partir de
hp y wt. Reporta el RMSE promedio obtenido
durante la validación.
Utiliza el dataset airquality y enfócate en la variable
Ozone.
1. Elimina los valores faltantes de dicha variable.
2. Aplica dos técnicas de preprocesamiento:
- Normalización (Min-Max Scaling): transforma los datos
para que sus valores estén entre 0 y 1.
- Estandarización (Z-score Scaling): centra los datos
en 0 y los escala de acuerdo con su desviación estándar.
3. Visualiza, mediante histogramas, las distribuciones de la variable
original, la normalizada y la estandarizada. Comenta las diferencias
observadas.
data(mtcars)
set.seed(123)
indices <- sample(1:nrow(mtcars), size = 0.7 * nrow(mtcars))
train_ex1 <- mtcars[indices, ]
test_ex1 <- mtcars[-indices, ]
modelo_ex1 <- lm(mpg ~ hp + wt, data = train_ex1)
predicciones_ex1 <- predict(modelo_ex1, newdata = test_ex1)
mse_ex1 <- mean((test_ex1$mpg - predicciones_ex1)^2)
print(paste("MSE del modelo:", round(mse_ex1, 2)))
## [1] "MSE del modelo: 4.24"
library(caret)
set.seed(123)
control_ex2 <- trainControl(method = "cv", number = 10)
modelo_ex2 <- train(mpg ~ hp + wt, data = train_ex1, method = "lm", trControl = control_ex2)
## Warning in nominalTrainWorkflow(x = x, y = y, wts = weights, info = trainInfo,
## : There were missing values in resampled performance measures.
print(modelo_ex2)
## Linear Regression
##
## 22 samples
## 2 predictor
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 19, 20, 20, 20, 20, 20, ...
## Resampling results:
##
## RMSE Rsquared MAE
## 3.037779 0.9912946 2.510219
##
## Tuning parameter 'intercept' was held constant at a value of TRUE
library(ggplot2)
data(airquality)
datos_ex3 <- na.omit(airquality[, "Ozone", drop = FALSE])
datos_ex3$Ozone_norm <- (datos_ex3$Ozone - min(datos_ex3$Ozone)) /
(max(datos_ex3$Ozone) - min(datos_ex3$Ozone))
datos_ex3$Ozone_std <- scale(datos_ex3$Ozone)
p1 <- ggplot(datos_ex3, aes(x = Ozone)) +
geom_histogram(bins = 30, fill = "skyblue", color = "white") +
labs(title = "Distribucion Original de Ozone")
p2 <- ggplot(datos_ex3, aes(x = Ozone_norm)) +
geom_histogram(bins = 30, fill = "lightgreen", color = "white") +
labs(title = "Distribucion Normalizada (Min-Max)")
p3 <- ggplot(datos_ex3, aes(x = Ozone_std)) +
geom_histogram(bins = 30, fill = "salmon", color = "white") +
labs(title = "Distribucion Estandarizada (Z-score)")
print(p1)
print(p2)
print(p3)