I1M2017: Estadística descriptiva (y functores aplicativos) en Haskell
En la segunda parte de la clase de hoy de Informática de 1º del Grado en Matemáticas hemos comentado las soluciones a los ejercicios de la relación 21 sobre estadística descriptiva.
Los ejercicios y su solución se muestran a continuación
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
-- --------------------------------------------------------------------- -- Introducción -- -- --------------------------------------------------------------------- -- El objetivo de esta relación es definir las principales medidas -- estadísticas de centralización (medias, mediana y modas) y de -- dispersión (rango, desviación media, varianza y desviación típica) -- que se estudian en 3º de ESO (como en http://bit.ly/2FbXOQm ). -- -- En las soluciones de los ejercicios se pueden usar las siguientes -- funciones de la librería Data.List fromIntegral, genericLength, sort, -- y group (cuya descripción se puede consultar en el "Manual de -- funciones básicas de Haskell" http://bit.ly/1PqHagT ). -- --------------------------------------------------------------------- -- Librerías auxiliares -- -- --------------------------------------------------------------------- import Data.List import Test.QuickCheck import Graphics.Gnuplot.Simple -- --------------------------------------------------------------------- -- Medidas de centralización -- -- --------------------------------------------------------------------- -- --------------------------------------------------------------------- -- Ejercicio 1. Definir la función -- media :: Floating a => [a] -> a -- tal que (media xs) es la media aritmética de los números de la lista -- xs. Por ejemplo, -- media [4,8,4,5,9] == 6.0 -- --------------------------------------------------------------------- -- 1ª definición media :: Floating a => [a] -> a media xs = sum xs / genericLength xs -- 2ª definición media2 :: Floating a => [a] -> a media2 = (/) <$> sum <*> genericLength -- --------------------------------------------------------------------- -- Ejercicio 2. La mediana de una lista de valores es el valor de -- la lista que ocupa el lugar central de los valores ordenados de menor -- a mayor. Si el número de datos es impar se toma como valor de la -- mediana el valor central. Si el número de datos es par se toma como -- valor de la mediana la media aritmética de los dos valores -- centrales. -- -- Definir la función -- mediana :: (Floating a, Ord a) => [a] -> a -- tal que (mediana xs) es la mediana de la lista xs. Por ejemplo, -- mediana [2,3,6,8,9] == 6.0 -- mediana [2,3,4,6,8,9] == 5.0 -- mediana [9,6,8,4,3,2] == 5.0 -- --------------------------------------------------------------------- mediana :: (Floating a, Ord a) => [a] -> a mediana xs | odd n = ys !! i | otherwise = media [ys !! (i-1), ys !! i] where ys = sort xs n = length xs i = n `div` 2 -- --------------------------------------------------------------------- -- Ejercicio 3. Comprobar con QuickCheck que para cualquier lista no -- vacía xs el número de elementos de xs menores que su mediana es menor -- o igual que la mitad de los elementos de xs y lo mismo pasa con los -- mayores o iguales que la mediana. -- --------------------------------------------------------------------- -- La propiedad es prop_mediana :: (Floating a, Ord a) => [a] -> Property prop_mediana xs = not (null xs) ==> genericLength [x | x <- xs, x < m] <= n/2 && genericLength [x | x <- xs, x > m] <= n/2 where m = mediana xs n = genericLength xs -- La comprobación es -- ghci> quickCheck prop_mediana -- +++ OK, passed 100 tests. -- --------------------------------------------------------------------- -- Ejercicio 4. Definir la función -- frecuencias :: Ord a => [a] -> [(a,Int)] -- tal que (frecuencias xs) es la lista formada por los elementos de xs -- junto con el número de veces que aparecen en xs. Por ejemplo, -- frecuencias "sosos" == [('o',2),('s',3)] -- -- Nota: El orden de los pares no importa -- --------------------------------------------------------------------- -- 1ª solución frecuencias :: Ord a => [a] -> [(a,Int)] frecuencias xs = [(y,ocurrencias y xs) | y <- sort (nub xs)] where ocurrencias y zs = length [1 | x <- zs, x == y] -- 2ª solución frecuencias2 :: Ord a => [a] -> [(a,Int)] frecuencias2 xs = [(y,1 + length ys) | (y:ys) <- group (sort xs)] -- 3ª solución frecuencias3 :: Ord a => [a] -> [(a,Int)] frecuencias3 = map (\ys@(y:_) -> (y,length ys)) . group . sort -- --------------------------------------------------------------------- -- Ejercicio 5. Las modas de una lista son los elementos de la lista -- que más se repiten. -- -- Definir la función -- modas :: Ord a => [a] -> [a] -- tal que (modas xs) es la lista ordenada de las modas de xs. Por -- ejemplo -- modas [7,3,7,5,3,1,6,9,6] == [3,6,7] -- --------------------------------------------------------------------- modas :: Ord a => [a] -> [a] modas xs = [y | (y,n) <- ys, n == m] where ys = frecuencias xs m = maximum (map snd ys) -- --------------------------------------------------------------------- -- Ejercicio 6. La media geométrica de una lista de n números es la -- raíz n-ésima del producto de todos los números. -- -- Definir la función -- mediaGeometrica :: Floating a => [a] -> a -- tal que (mediaGeometrica xs) es la media geométrica de xs. Por -- ejemplo, -- mediaGeometrica [2,18] == 6.0 -- mediaGeometrica [3,1,9] == 3.0 -- --------------------------------------------------------------------- -- 1ª solución mediaGeometrica :: Floating a => [a] -> a mediaGeometrica xs = product xs ** (1 / genericLength xs) -- 2ª solución mediaGeometrica2 :: Floating a => [a] -> a mediaGeometrica2 = (**) <$> product <*> ((1/) . genericLength) -- --------------------------------------------------------------------- -- Ejercicio 7. Comprobar con QuickCheck que la media geométrica de -- cualquier lista no vacía de números no negativos es siempre menor o -- igual que la media aritmética. -- --------------------------------------------------------------------- -- La propiedad es prop_mediaGeometrica :: (Floating a, Ord a) => [a] -> Property prop_mediaGeometrica xs = not (null xs) ==> mediaGeometrica ys <= media ys where ys = map abs xs -- La comprobación es -- ghci> quickCheck prop_mediaGeometrica -- +++ OK, passed 100 tests. -- --------------------------------------------------------------------- -- Medidas de dispersión -- -- --------------------------------------------------------------------- -- --------------------------------------------------------------------- -- Ejercicio 8. El recorrido (o rango) de una lista de valores es la -- diferencia entre el mayor y el menor. -- -- Definir la función -- rango :: (Num a, Ord a) => [a] -> a -- tal que (rango xs) es el rango de xs. Por ejemplo, -- rango [4,2,4,7,3] == 5 -- --------------------------------------------------------------------- -- 1ª solución rango :: (Num a, Ord a) => [a] -> a rango xs = maximum xs - minimum xs -- 2ª solución rango2 :: (Num a, Ord a) => [a] -> a rango2 = (-) <$> maximum <*> minimum -- 3ª solución rango3 :: (Num a, Ord a) => [a] -> a rango3 xs = maximo - minimo where (y:ys) = xs (minimo,maximo) = aux ys (y,y) aux [] (a,b) = (a,b) aux (z:zs) (a,b) = aux zs (min a z, max z b) -- --------------------------------------------------------------------- -- Ejercicio 9. La desviación media de una lista de datos xs es la -- media de las distancias de los datos a la media xs, donde la -- distancia entre dos elementos es el valor absoluto de su -- diferencia. Por ejemplo, la desviación media de [4,8,4,5,9] es 2 ya -- que la media de [4,8,4,5,9] es 6 y -- (|4-6| + |8-6| + |4-6| + |5-6| + |9-6|) / 5 -- = (2 + 2 + 2 + 1 + 3) / 5 -- = 2 -- -- Definir la función -- desviacionMedia :: Floating a => [a] -> a -- tal que (desviacionMedia xs) es la desviación media de xs. Por -- ejemplo, -- desviacionMedia [4,8,4,5,9] == 2.0 -- desviacionMedia (replicate 10 3) == 0.0 -- --------------------------------------------------------------------- desviacionMedia :: Floating a => [a] -> a desviacionMedia xs = media [abs (x - m) | x <- xs] where m = media xs -- --------------------------------------------------------------------- -- Ejercicio 10. La varianza de una lista datos es la media de los -- cuadrados de las distancias de los datos a la media. Por ejemplo, la -- varianza de [4,8,4,5,9] es 4.4 ya que la media de [4,8,4,5,9] es 6 y -- ((4-6)^2 + (8-6)^2 + (4-6)^2 + (5-6)^2 + (9-6)^2) / 5 -- = (4 + 4 + 4 + 1 + 9) / 5 -- = 4.4 -- -- Definir la función -- varianza :: Floating a => [a] -> a -- tal que (desviacionMedia xs) es la varianza de xs. Por ejemplo, -- varianza [4,8,4,5,9] == 4.4 -- varianza (replicate 10 3) == 0.0 -- --------------------------------------------------------------------- varianza :: Floating a => [a] -> a varianza xs = media [(x-m)^2 | x <- xs] where m = media xs -- --------------------------------------------------------------------- -- Ejercicio 11. La desviación típica de una lista de datos es la raíz -- cuadrada de su varianza. -- -- Definir la función -- desviacionTipica :: Floating a => [a] -> a -- tal que (desviacionTipica xs) es la desviación típica de xs. Por -- ejemplo, -- desviacionTipica [4,8,4,5,9] == 2.0976176963403033 -- desviacionTipica (replicate 10 3) == 0.0 -- --------------------------------------------------------------------- -- 1ª definición desviacionTipica :: Floating a => [a] -> a desviacionTipica xs = sqrt (varianza xs) -- 2ª definición desviacionTipica2 :: Floating a => [a] -> a desviacionTipica2 = sqrt . varianza -- --------------------------------------------------------------------- -- Regresión lineal -- -- --------------------------------------------------------------------- -- --------------------------------------------------------------------- -- Ejercicio 12. Dadas dos listas de valores -- xs = [x(1), x(2), ..., x(n)] -- ys = [y(1), y(2), ..., y(n)] -- la ecuación de la recta de regresión de ys sobre xs es y = a+bx, -- donde -- b = (nΣx(i)y(i) - Σx(i)Σy(i)) / (nΣx(i)² - (Σx(i))²) -- a = (Σy(i) - bΣx(i)) / n -- -- Definir la función -- regresionLineal :: [Double] -> [Double] -> (Double,Double) -- tal que (regresionLineal xs ys) es el par (a,b) de los coeficientes -- de la recta de regresión de ys sobre xs. Por ejemplo, para los -- valores -- ejX, ejY :: [Double] -- ejX = [5, 7, 10, 12, 16, 20, 23, 27, 19, 14] -- ejY = [9, 11, 15, 16, 20, 24, 27, 29, 22, 20] -- se tiene -- λ> regresionLineal ejX ejY -- (5.195045748716805,0.9218924347243919) -- --------------------------------------------------------------------- ejX, ejY :: [Double] ejX = [5, 7, 10, 12, 16, 20, 23, 27, 19, 14] ejY = [9, 11, 15, 16, 20, 24, 27, 29, 22, 20] regresionLineal :: [Double] -> [Double] -> (Double,Double) regresionLineal xs ys = (a,b) where n = genericLength xs sumX = sum xs sumY = sum ys sumX2 = sum (zipWith (*) xs xs) sumXY = sum (zipWith (*) xs ys) b = (n*sumXY - sumX*sumY) / (n*sumX2 - sumX^2) a = (sumY - b*sumX) / n -- --------------------------------------------------------------------- -- Ejercicio 13. Definir el procedimiento -- grafica :: [Double] -> [Double] -> IO () -- tal que (grafica xs ys) pinte los puntos correspondientes a las -- listas de valores xs e ys y su recta de regresión. Por ejemplo, -- con (grafica ejX ejY) se obtiene el dibujo de la Figura 1. -- --------------------------------------------------------------------- grafica :: [Double] -> [Double] -> IO () grafica xs ys = plotPathsStyle [YRange (0,10+mY)] [(defaultStyle {plotType = Points, lineSpec = CustomStyle [LineTitle "Datos", PointType 2, PointSize 2.5]}, zip xs ys), (defaultStyle {plotType = Lines, lineSpec = CustomStyle [LineTitle "Ajuste", LineWidth 2]}, [(x,a+b*x) | x <- [0..mX]])] where (a,b) = regresionLineal xs ys mX = maximum xs mY = maximum ys |
Varias de las soluciones están escritas usando functores aplicativos, lo que ha motivado su explicación usando las dos primeras secciones del capítulo 11 (Funtores, funtores aplicativos y monoides) del libro ¡Aprende Haskell por el bien de todos!: