introalg:taller07_6
Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anteriorRevisión previaPróxima revisión | Revisión previa | ||
introalg:taller07_6 [2007/06/12 00:36] – nicolasw | introalg:taller07_6 [2018/08/10 03:03] (actual) – editor externo 127.0.0.1 | ||
---|---|---|---|
Línea 1: | Línea 1: | ||
====== Frecuencia de Palabras ====== | ====== Frecuencia de Palabras ====== | ||
- | Nos proponemos hacer un programa funcional que **cuente la frecuencia de las ocurrencias de palabras**. | + | Nos proponemos hacer un programa funcional que **cuente la frecuencia de las ocurrencias de palabras** |
+ | El tipo de la función es el siguiente: | ||
< | < | ||
Línea 7: | Línea 8: | ||
</ | </ | ||
- | Main> frecuencia [" | + | Donde '' |
- | [(" | + | |
- | + | ||
- | Donde '' | + | |
< | < | ||
Línea 16: | Línea 14: | ||
</ | </ | ||
- | Esta función resulta de gran utilidad para **análisis estadístico de textos**, como el que se utiliza para comprimir archivos, dar importancia a las palabras en las búsquedas, detectar palabras significativas, | + | Y esperamos este tipo de comportamiento. |
+ | |||
+ | Main> frecuencia [" | ||
+ | [(" | ||
+ | |||
+ | Esta función resulta de gran utilidad para **análisis estadístico de textos**, como el que se utiliza para comprimir archivos, dar importancia a las palabras en las búsquedas | ||
+ | |||
===== División en Palabras ===== | ===== División en Palabras ===== | ||
- | Para hacer más fácil el uso de esta función tomamos de [[http:// | + | Para hacer más fácil el uso de esta función tomamos de [[http:// |
Veamos el código de " | Veamos el código de " | ||
Línea 39: | Línea 44: | ||
tomaPalabra :: String -> String | tomaPalabra :: String -> String | ||
tomaPalabra [] = [] | tomaPalabra [] = [] | ||
- | tomaPalabra (x: | + | tomaPalabra (x: |
- | | otherwise | + | | otherwise |
tiraPalabra :: String -> String | tiraPalabra :: String -> String | ||
tiraPalabra [] = [] | tiraPalabra [] = [] | ||
- | tiraPalabra (x: | + | tiraPalabra (x: |
- | | otherwise | + | | otherwise |
tiraEspacio :: String -> String | tiraEspacio :: String -> String | ||
tiraEspacio [] = [] | tiraEspacio [] = [] | ||
- | tiraEspacio (x: | + | tiraEspacio (x: |
- | | otherwise | + | | otherwise |
Línea 59: | Línea 62: | ||
espacio :: [Char] | espacio :: [Char] | ||
- | espacio = [' | + | espacio = [' |
</ | </ | ||
- | |||
- | |||
Línea 69: | Línea 70: | ||
* Definir la función politípica //elemento :: Eq a => a -> [a] -> Bool//, donde //elemento a xs// decide si //a// está en la lista //xs//. Ejemplo: //elemento ' | * Definir la función politípica //elemento :: Eq a => a -> [a] -> Bool//, donde //elemento a xs// decide si //a// está en la lista //xs//. Ejemplo: //elemento ' | ||
Casos de Test: '' | Casos de Test: '' | ||
- | * Usando la definición de esta función | + | * Habiendo definido // |
Casos de Test: | Casos de Test: | ||
< | < | ||
Línea 80: | Línea 81: | ||
... | ... | ||
</ | </ | ||
- | * Las funciones // | + | * Las funciones // |
* Defina la función // | * Defina la función // | ||
* Defina la función // | * Defina la función // | ||
- | * ?Como se llaman // | + | * ¿Cómo |
- | * Defina // | + | * Defina // |
- | + | ||
===== Lectura del Archivo ===== | ===== Lectura del Archivo ===== | ||
Línea 114: | Línea 113: | ||
((take 100).partePalabras.leeArchivo) " | ((take 100).partePalabras.leeArchivo) " | ||
[" | [" | ||
+ | |||
==== Ejercicios ==== | ==== Ejercicios ==== | ||
- | * Contar | + | * Contar |
* Obtener las palabras de "El Gaucho Martín Fierro" | * Obtener las palabras de "El Gaucho Martín Fierro" | ||
- | * Observar que hay problemas con // | + | * Observar que hay problemas con // |
Línea 138: | Línea 138: | ||
agregaOcurrencia :: Palabra -> [(Palabra, | agregaOcurrencia :: Palabra -> [(Palabra, | ||
</ | </ | ||
- | que procesa una palabra, la definición de // | + | que procesa una palabra, |
Línea 145: | Línea 146: | ||
==== Ejercicios ==== | ==== Ejercicios ==== | ||
- | * Definir la función // | + | * Definir la función // |
Casos de test: '' | Casos de test: '' | ||
* A partir de // | * A partir de // | ||
Caso de test: '' | Caso de test: '' | ||
* Componer // | * Componer // | ||
+ | |||
===== Ordenando por frecuencias ===== | ===== Ordenando por frecuencias ===== | ||
- | El esquema presentado hasta ahora ('' | + | El esquema presentado hasta ahora ('' |
* Compresión de texto: estas palabras se deben codificar " | * Compresión de texto: estas palabras se deben codificar " | ||
* Relevancia de palabras para búsquedas: a estas palabras no hay que darles peso. | * Relevancia de palabras para búsquedas: a estas palabras no hay que darles peso. | ||
- | * Detectar palabras | + | * Detectar palabras |
La lista que devuelve // | La lista que devuelve // | ||
Línea 177: | Línea 179: | ||
ordenaIns _ = [] | ordenaIns _ = [] | ||
</ | </ | ||
- | |||
- | |||
==== Ejercicios ==== | ==== Ejercicios ==== | ||
Línea 187: | Línea 187: | ||
* Agregar // | * Agregar // | ||
* Redefinir // | * Redefinir // | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
Línea 192: | Línea 198: | ||
===== Optimización del Cómputo ===== | ===== Optimización del Cómputo ===== | ||
- | El cálculo de la frecuencia resulta ineficiente, por cada palabra tenemos que recorrer toda la lista de frecuencias '' | + | El cálculo de la frecuencia resulta ineficiente. Por cada palabra tenemos que recorrer toda la lista de frecuencias '' |
- | De hecho para las aproximadamente 15000 palabras que contiene "El Gaucho Martín Fierro", | + | De hecho para las aproximadamente 15000 palabras que contiene "El Gaucho Martín Fierro", |
Una posible mejora sería mantener **ordenada por palabras** la lista de frecuencias, | Una posible mejora sería mantener **ordenada por palabras** la lista de frecuencias, | ||
Línea 203: | Línea 209: | ||
agregaOcurrenciaOrd palabra [] = [(palabra, | agregaOcurrenciaOrd palabra [] = [(palabra, | ||
agregaOcurrenciaOrd palabra ((p,n):xs) | p==palabra = (p,n+1) : xs | agregaOcurrenciaOrd palabra ((p,n):xs) | p==palabra = (p,n+1) : xs | ||
- | | p< | + | | p< |
| p> | | p> | ||
Línea 211: | Línea 217: | ||
</ | </ | ||
- | Activamos la llave que muestra la //cantidad de reducciones// | + | Activamos la llave que muestra la //cantidad de reducciones// |
Main> :set +s | Main> :set +s | ||
Línea 224: | Línea 230: | ||
(105556 reductions, 232333 cells) | (105556 reductions, 232333 cells) | ||
- | Ouch! | + | D'oh! |
Al parecer la idea no es buena, y se pone peor a medida que aumentamos la cantidad de palabras que tomamos en el '' | Al parecer la idea no es buena, y se pone peor a medida que aumentamos la cantidad de palabras que tomamos en el '' | ||
- | La idea que si nos puede salvar es cambiar de manera salvaje la **estructura de datos**, es decir cambiar la //lista de pares// por otra estructura que **mejore el tiempo de búsqueda de una palabra**. | + | Podemos intentar |
Una de las estructuras de datos más comunes que mejora de manera dramática el tiempo de búsqueda son los [[http:// | Una de las estructuras de datos más comunes que mejora de manera dramática el tiempo de búsqueda son los [[http:// | ||
Línea 235: | Línea 242: | ||
* Subárbol izquierdo | * Subárbol izquierdo | ||
* Subárbol derecho | * Subárbol derecho | ||
- | donde el dato que está en la **raíz** es mayor que todos los del subarbol | + | donde el dato que está en la **raíz** es mayor que todos los del subárbol |
Luego con esta forma de estructurar los datos, realizar una búsqueda es sencillo: | Luego con esta forma de estructurar los datos, realizar una búsqueda es sencillo: | ||
Línea 242: | Línea 249: | ||
* si el dato está en la raíz, listo. | * si el dato está en la raíz, listo. | ||
+ | Para definir estos árboles haremos uso de la **definición de tipos de datos** en Haskell '' | ||
+ | |||
+ | < | ||
+ | data ArbolFrec = Nodo (Palabra, | ||
+ | |||
+ | agregaOcurrenciaArbol :: Palabra -> ArbolFrec -> ArbolFrec | ||
+ | agregaOcurrenciaArbol palabra Nulo = Nodo (palabra,1) Nulo Nulo | ||
+ | agregaOcurrenciaArbol palabra (Nodo par@(p,n) izq der) | ||
+ | | p==palabra = Nodo (p,n+1) izq der | ||
+ | | p< | ||
+ | | p> | ||
+ | |||
+ | frecuencia'' | ||
+ | frecuencia'' | ||
+ | </ | ||
+ | |||
+ | Lo probamos para ver el resultado en las 100 primeras palabras y obtenemos: | ||
+ | |||
+ | Main> (frecuencia'' | ||
+ | ERROR - Cannot find " | ||
+ | *** Expression : (frecuencia'' | ||
+ | *** Of type : ArbolFrec | ||
+ | |||
+ | El problema se soluciona desactivando una llave de Hugs | ||
+ | |||
+ | Main> :set -u | ||
+ | Main> (frecuencia'' | ||
+ | ArbolFrec_Nodo (" | ||
+ | |||
+ | ... y esto no se entiende nada! | ||
+ | Entonces definimos una función que " | ||
+ | |||
+ | < | ||
+ | aplanaArbol :: ArbolFrec -> [(Palabra, | ||
+ | aplanaArbol Nulo = [] | ||
+ | aplanaArbol (Nodo par izq der) = par : (aplanaArbol izq ++ aplanaArbol der) | ||
+ | </ | ||
+ | |||
+ | Ahora si veamos como se comporta la versión ABB del problema: | ||
+ | |||
+ | Main> (aplanaArbol.frecuencia'' | ||
+ | [(" | ||
+ | (58403 reductions, 104322 cells) | ||
+ | |||
+ | |||
+ | Woohoo! | ||
+ | |||
+ | La siguiente tabla resume las reducciones en de las 3 versiones y para 3 cantidades de palabras: | ||
+ | |||
+ | ^ algoritmo\palabras ^100 ^1000 ^10000 ^ | ||
+ | | frecuencia' | ||
+ | | frecuencia | ||
+ | | frecuencia'' | ||
- | + | Notar que la mejora de // | |
introalg/taller07_6.1181608565.txt.gz · Última modificación: 2018/08/10 03:03 (editor externo)