Rango Finito

fotoscódigoobservatorioshermanocerdo temas plots

python

Codility

Codility es una plataforma en línea para evaluar habilidades de programación. Ayer, una de las empresas a las que he enviado hojas de vida me envió allá a hacer un examen de aptitud. Todavía no me he animado a hacerlo, pero ayer mismo estuve probando la plataforma aprovechando que ofrecen algunos problemas de prueba. Son problemas típicos (y (a posteriori) sencillos) de diseño de algoritmos. Hice dos más o menos rápido. En el que quedaba me embolaté y me fui a dormir cansado y frustrado pero la ansiedad que determina el 98% de mi existencia me despertó a las cuatro de la mañana con una idea vaga de cómo escribirlo (y otros pensamientos menos agradables). Finalmente me levanté a las seis e hice el deber. Al final, después de varios intentos, logré soluciones satisfactorias a todas las preguntas. Como lenguaje elegí Python, que también está disponible como opción en la prueba que tengo que hacer. Algo bueno de Python es que me puedo desentender de problemas de desborde con números muy grandes (varios de los tests que hacían a las soluciones intentan romperlas así.) Aquí subí las soluciones sin mayor comentario. Espero que el código sea suficientemente claro.

20

Desde hace ocho días estoy dedicado en los ratos libres a hacer los ejercicios de este curso de algoritmos de bioinformática más que todo para practicar Python con problemas concretos. Aquí está el cuaderno de iPython en el que estoy trabajando. Algunas soluciones son mejores que otras. Algunas creo que sé cómo mejorarlas. Cuando tenga tiempo lo haré. A medida que resuelva más ejercicios lo iré actualizando.

Capicúas

Esta tarde escribí un cuaderno de iPython para jugar con números capicúas. La motivación fue este problema propuesto por Cédric Villani en su sección recién inaugurada de juegos matemáticos de Le Monde. (Loable el esfuerzo de Villani por promover personalmente la matemática entre la gente del común, por cierto. Y adorable su uso (francesísimo) de tablero y tiza para presentar y resolver los problemas. Cada vez me cae mejor.)

Saber y perder

La columna de hoy (o de ayer, no la veo en portada hoy domingo, pero se supone que salió hoy) se desprende de una revisión sencilla de los resultados por colegios de las pruebas Saber 11 de este año y el pasado jugando con herramientas elementales de estadística descriptiva disponibles en cualquier hoja de cálculo.

Como complemento, la observación que desencadenó la columna: en la página de la revista Dinero donde los resultados de este año están disponibles para descarga se lee:

Siglas: Dado que la mayor parte de los colegios son privados (no oficiales) solo se indica cuando son públicos (oficiales) mediante la sigla “(Of)”.

Como la anotación me intrigó, filtré los datos para mirar cuántos colegios tenían “(Of)” al final del nombre. El resultado, 8168 de 12615. Es decir, un 64%. de los colegios son oficiales; no precisamente una minoría. Al contar estudiantes (en lugar de colegios) se descubre que un 71.77% de las personas que presentan las pruebas Saber 11 estudia en un colegio oficial. Quedé con la duda de si los periodistas de Dinero se equivocaron o si de verdad piensan que la mayor parte de los colegios colombianos son privados y no se molestaron en contar. Como sea, la anotación ilustra bien la profundidad con la que los muchachos de Dinero estudiaron sus datos.

De paso: un análisis (pdf) de las ventajas de los colegios privados de acuerdo a las pruebas Pisa.

Sesgo en públicos 2012: 0.526599249105; Sesgo en privados 2012: 1.02662898427; Promedio en públicos 2012: 42.8033300686; Promedio en privados 2012: 46.0227293165; Mediana en públicos 2012: 42.7; Mediana en privados 2012: 44.65. Sesgo en públicos 2011: 0.207080369486; Sesgo en privados 2011: 0.673856432328; Promedio en públicos 2011: 42.2170533907; Promedio en privados 2011: 45.6859889984; Mediana en públicos 2011: 42.26; Mediana en privados 2011: 44.65 (Qué sencillo y agradable utilizar los cuadernos de iPython y la librería Pandas de análisis de datos para hacer estos cálculos, por cierto.)

I went through a sudden period where I couldn’t read

Llevo meses postergando este ejercicio. Hace un par de semanas le dediqué una tarde, pero con la muerte del computador perdí el trabajo (entre muchas otras cosas), así que ayer por la noche lo volví a hacer. El resultado final es más oscuro que iluminador pero qué más da. Su génesis se encuentra en el largo monólogo de Chris Fogle que ocupa el capítulo §22 de The Pale King, la (pseudo)novela póstuma de David Wallace:

[I]nstead of reading something I’d count the words in it, as though reading was the same as just counting the words. [En lugar de leer algo contaba sus palabras, como si leer fuera lo mismo que sólo contar palabras.]

The Pale King (en español El rey pálido, traducción de Javier Calvo) es el esqueleto escueto de una novela que, estimo, rondaría las 1500 páginas (i.e., apenas un tercio de la novela fue concluída). Está estructurada (al menos en su primera edición) en 50 capítulos que, tras la muerte de Wallace, fueron dispuestos en orden lineal por su editor (Wallace no dejó mayores directivas al respecto). Mi pregunta inicial, intencionalmente ingenua, era cómo automatizar ese trabajo o al menos facilitarlo mediante un procesamiento automático del texto que involucrara, cómo no, conteos de palabras.

Gráfico del logaritmo de la extensión en carácteres de cada uno de los capítulos de The Pale King

Con el tiempo, sin embargo, me decanté por un ejercicio alternativo más a mi alcance: (1) Calcular una distancia léxica entre los capítulos, y (2) Disponerlos como puntos en un plano de manera que respetaran (dentro de lo posible) la distancia propuesta. Mi teoría era que un gráfico de ese estilo sería una herramienta útil (un criterio más) para facilitar la organización del texto. Ya no estoy tan seguro.

*

El primer componente del ejercicio es la distancia. La aproximación más intuitiva al cálculo de distancias entre documentos (este artículo de Anna Huang ofrece un sobrevuelo por varios métodos) se basa en recolectar una lista de palabras presentes en los documentos (más detalles adelante) y utilizarlas como base de un espacio vectorial. Bajo este esquema, a cada documento le corresponde una combinación lineal de la base con escalares elegidos de acuerdo al número de apariciones (frecuencia) de la palabra en el documento. Así, si la lista de palabras es $\{v_i\colon 1 \leq i \leq M\}$, entonces un documento $d$ es representado por el vector $M$-dimensional $$\sum_{i=1}^M f_i(d) v_i,$$ donde $f_i(d)$ es igual al número de apariciones de la palabra $v_i$ en el documento $d$. Una vez representados de esta manera, calcular distancias entre documentos se reduce a aplicar el teorema de Pitágoras.

Una versión sólo un poco más sofisticada de lo anterior se basa en la siguiente observación: si una palabra $v_i$ es muy frecuente en un documento $d$ pero también está presente en la mayoría de los documentos disponibles (supongamos que tenemos $N$ documentos) entonces probablemente no sea tan representativa del documento $d$ como cabría esperar inicialmente. Para tomar en cuenta esto, reescribimos la representación vectorial del documento $d$ como $$\sum_{i=1}^M f_i(d) \log\left (\frac{N}{P_i}\right ) v_i,$$ donde $P_i$ es igual al número de documentos que contienen la palabra $v_i$. De esta manera, la frecuencia de la palabra $v_i$ en cada documento es penalizada multiplicándola por un número ($\log(\frac{N}{P_i})$) que se acerca a cero entre más documentos la mencionen.

Así, al final el problema del cálculo de distancias se reduce a decidir cuál debe ser la lista de palabras que se utilicen como base del espacio vectorial de documentos. Siguiendo (a mano alzada) el artículo de Huang, tras una serie de filtros sencillos que removieran diferencias innecesarias y contenido irrelevante busqué (usando NLTK, la navaja suiza del análisis automatizado de texto) todas las palabras que aparecieran más de siete veces en todo el libro. 2060 palabras (aproximadamente un décimo de las que contiene el libro) cumplían con esta condición. Esto en particular implica que los capítulos del libro son representados por puntos en un espacio de dos mil y tantas dimensiones. Calcular distancias entre ellos, ya lo dije, es sencillo. Verlos en un plano es otra historia.

*

Había sobrestimado seriamente la incomprensibilidad del texto. Un conteo burdo de nombres propios en páginas 12-21 ofrece 38, 28, 17, 28, 40, 32, 31, 31, 18, 22. Número medio por página, 28,2, desviación estándar de 6,9, 70% de los datos a s de la media. Número promedio de palabras por página basado en una muestra de 2, 302. O sea 9% de comprensibilidad. Alto.

— H. DeWitt, Ese oscuro objeto del deseo

*

No sé por qué pensaba que el problema de aplanar dimensiones debía estar completa y contundentemente resuelto desde hace décadas. Fue difícil dar por mi cuenta con soluciones convincentes. Finalmente, Juan Manuel me sugirió revisar los métodos de manifold learning implementados en scikit-learn. Para mi sorpresa, varios de los algoritmos disponibles son bastante recientes y provienen de laboratorios de ciencias cognitivas interesados en visión. El que elegí para mi ejercicio, Isomap, fue desarrollado por Josh Tenenbaum (y amigos) cuando trabajaba en Stanford.

La conexión entre visión y reducción de dimensiones se basa en el hecho, permítome ser burdo, de que el ojo cuenta con (muchísimos) sensores que registran el estímulo (imaginen cada sensor como un vector independiente) y luego el cerebro toma esas (combinaciones lineales de) señales y compone una imagen bidimensional (o tal vez un par). ¿Cómo lo hace? Ni idea. Los métodos de manifold analysis intentan simularlo. La idea es asumir que un conjunto de puntos en un espacio de dimensión alta yacen sobre una superficie (de ahí el término manifold) y luego aplanarla preservando en lo posible distancias locales. En el caso particular de Isomap primero se construye un grafo que captura, mediante la imposición de vértices, el sabor local de la colección de puntos, luego se define una distancia optimizada sobre el grafo y finalmente se soluciona un problema de optimización para encontrar los puntos de baja dimensión correspondientes (para el interesado en por qué y cómo funciona, aquí hay detalles y aquí todavía más detalles). Como es de esperarse, entre más puntos, mejor el resultado.

*

Tal vez cincuenta puntos no sean suficientes. (Aquí más grande.)

Este de arriba es el resultado de aplicar Isomap a una versión normalizada (para evitar desequilibrios por diferencias de extensión) de los 50 puntos 2060-dimensionales que representan, de acuerdo a la lista de palabras elegidas, los 50 capítulos de The Pale King. Así se ve. Con Javier discutimos una noche los posibles significados de varios gráficos similares a este pero no logramos decidir si se conectaban de alguna manera con la sustancia del libro, lo que quiera que eso signifique. La verdad, prefiero que sea así. El anticlímax tiene naturaleza de Buda.

*

Anoche, antes de acostarme, se me ocurrió un posible orden lineal que se desprendería de estos cálculos: organizar los capítulos de acuerdo a la distancia al centro de masa (Isomap lo clava en $(0,0)$). El orden sería: §20, §6, §9, §22, §2, §14, §13, §7, §15, §16, §35, §32, §21, §46, §31, §17, §43, §26, §29, §45, §4, §8, §42, §19, §39, §10, §38, §33, §24, §50, §36, §27, §44, §47, §49, §12, §34, §23, §5, §1, §18, §11, §28, §30, §41, §48, §37, §3, §40 y §25. Ya puestos, calculé directamente sobre los puntos originales (en el espacio de dimensión 2060) y en ese caso (cambia, obviamente) el orden es: §22, §24, §2, §27, §42, §30, §7, §19, §33, §9, §5, §14, §47, §6, §49, §16, §8, §46, §43, §15, §13, §23, §36, §32, §26, §45, §39, §3, §12, §18, §29, §20, §17, §48, §38, §37, §50, §21, §31, §4, §35, §44, §1, §11, §41, §40, §28, §34, §10 y §25. En ambos, el recorrido se cierra en ese capítulo neurótico a dos columnas (Devils are actually angels) que describe la tediosa cotidianidad diaria de la oficina de impuestos (casi todos los personajes son mencionados), y se inicia (o casi) con el soliloquio de Chris Fogle (§22) sobre, entre otras cosas, su tendencia a contar palabras en lugar de leer. También podrían organizarse en sentido inverso, como en una espiral hacia el origen. Tal vez eso tenga más sentido.