|
Archivo
Archivo para la categoría ‘r’
La semana que viene y con el lema
The Web 1.0 was readable, the Web 2.0 was social, now the web is programmable through application programming interfaces (aka APIs)
se celebrará en Madrid APIdays Mediterranea, un encuentro de entusiastas de las APIs.

Y dentro del programa, el sábado día 1, a la una menos cuarto —una hora compatible con mis poco matutinos hábitos—, tengo asignado el taller Rapidays: Quick introduction to R & APIs al que están, por supuesto, invitados los lectores de estas páginas (y para los que podría llegar a tener descuentos para el evento completo y entradas gratuitas para mi taller en particular).
Acabo de subir a mi servidor las diapositivas de la charla describiendo un lematizador desambiguado que anuncié el otro día. Gracias a Carlos Ortega y Pedro Concejero, el vídeo de la charla está disponible en Vímeo. Por su parte, las transparencias pueden descargarse aquí.
Quiero agradecer a los asistentes a la charla su interés y, muy particularmente, su participación en el debate que se abrió al final de la sesión. Fue muy enriquecedor.
El jueves 16 de mayo hablaré en el Grupo de Interés Local de Madrid de R sobre lematizadores probabilísticos.
Hablaré sobre el proceso de lematizacion y trataré de mostrar su importancia dentro del mundo del llamado procesamiento del lenguaje natural (NLP). La lematización es un proceso humilde dentro del NLP del que apenas nadie habla: su ejercicio solo ha hecho famoso a Martin Porter. Lo eclipsan otras aplicaciones más vistosas, como el siempre sobrevalorado análisis del sentimiento. Sin embargo, es una pieza fundamental que subyace (o debería subyacer) en cualquier aplicación seria que analice textos.
En la charla repasaré las tres grandes familias de soluciones para el problema de la lematización:
- las basadas en reglas duras,
- las basadas en diccionarios y, finalmente,
- las más interesantes, las probabilísticas.
Y, en particular, describiré con cierto detalle —aunque tratando de obviar los aspectos técnicos más áridos— un algoritmo que combina oportunísticamente diccionarios y modelos ocultos de Markov y que debería ver la luz en producción dentro del conjunto de APIs lingüísticas de Molino de Ideas.
Sigo con mi lacónica serie sobre data.table.
La protagonista:
frases[sample(1:nrow(frases), 3),]
#pos.es pos.en length.es length.en en es frase tfe qjilm num
#1: 15 43 72 72 i de 2632 4.881416e-02 0.01369863 6.686871e-04
#2: 33 48 46 48 X países 5321 2.726146e-06 0.02040816 5.563563e-08
#3: 2 35 53 66 in preguntar 4582 2.424379e-08 0.01492537 3.618476e-10
dim(frases)
#[1] 6340091 10
El tiempo:
system.time({
setkey(frases, "frase", "es")
denominadores <- frases[, sum(num), by = key(frases)]
setnames(denominadores, c("frase", "es", "den") )
frases <- merge(frases, denominadores)
frases$delta <- frases$num / frases$den
})
#user system elapsed
#5.628 0.208 5.841
En particular,
system.time( denominadores <- frases[, sum(num), by = key(frases)] )
#user system elapsed
#0.228 0.000 0.228
Increíble, ¿no?
El otro día tropecé con un problema de rendimiento con R y al utilizar Rprof() encontré muchas llamadas a funciones que yo no hacía directamente.
La principal sospechosa era la función daply (del paquete plyr) que parecía depender de bastantes otras. Uno puede navegar el código de las funciones para identificar esas dependencias, pero, mirad qué maravilla:
genera

Ahí se ve la dependencia de daply con respecto a laply. Y uno adquiere, además, una visión panorámica del paquete plyr.
La función foodweb tiene argumentos adicionales (prune es uno de los más útiles) que los interesados podrán encontrar en ?foodweb.
Motivado por los experimentos de Gregorio Serrano con shiny e ilustrado por la charla que dio en el Grupo de Usuarios de R de Madrid, decidí colgar el otro día un entretenimiento que ocupó la mañana de un domingo —y las mañanas de mis domingos son proverbialmente breves— en la red.
Se trata de una aplicación que distingue el idioma en que está escrito un texto dentro de una selección de ellos: español, italiano, latín, francés, portugués y catalán.

¡Invitados quedáis a probarlo!
(Nota: esta aplicación me fue sugerida, en forma de reto, por Elena Álvarez de Molino de Ideas).
(Coda: cualquier día, por chinchar, hago uno que distinga entre catalán, valenciano y mallorquín.)
Continuamos hoy nuestra serie sobre la llamada ley de Benford discutiendo la distribución de la parte fraccionaria de las muestras de una distribución.
La parte fraccionaria de un número es, para entendernos, lo que va detrás de la coma. Técnicamente, x - floor(x). ¿Le sorprendería a alguien la parte fraccionaria de una secuencia aleatoria de números no tenga una distribución uniforme sobre [0,1)?
Obviamente, si los números son enteros no. ¿Pero si siguen la distribución normal? Se puede probar, de hecho, que si la serie sigue una distribución de probabilidad que sea
- regular, es decir, que no tenga picos extraños y, más en concreto, cuya función de densidad crezca hasta cierto punto y decrezca de él en adelante y
- extendida, es decir, que cubra un rango amplio de valores (p.e., la recta real entera),
entonces la distribución de la parte fraccionaria de sus muestras serán aproximadamente uniformes. Y lo serán tanto más cuanto menor sea el máximo de la función de distribución. La referencia, el artículo Pourquoi la loi de Benford n’est pas mystérieuse de Nicolas Gauvrit y Jean-Paul Delahaye.
Esto se verifica fácilmente en ciertos casos. Por ejemplo,
que produce

En la siguiente entrega analizaremos qué tiene que ver esto con la ley de Benford.
Los protagonistas (tres tablas grandecitas):
dim(qjilm)
# [1] 3218575 5
dim(tf)
# [1] 6340091 7
dim(tfe)
#[1] 1493772 3
head(qjilm, 2)
#pos.es length.en length.es pos.en qjilm
#1 1 2 1 1 0.8890203
#2 1 2 1 2 0.1109797
head(tf, 2)
#frase es pos.es length.es en pos.en length.en
#1 996 ! 42 42 ! 43 44
#2 1231 ! 37 37 ! 37 38
head(tfe, 2)
#en es tfe
#1 ! ! 4.364360e-01
#2 ! !" 4.945229e-24
El objetivo (cruzarlas por los campos comunes):
El tiempo (usando merge):
res <- merge(merge(tf, tfe), qjilm)
#user system elapsed
#442.991 2.496 446.832
dim(res)
#[1] 6340091 9
Y con data.table:
library(data.table)
system.time({
res.dt <- merge(data.table( tf, key = c("en", "es")),
data.table( tfe, key = c("en", "es")) )
res.dt <- merge( setkeyv(res.dt, cols = c("pos.es", "pos.en", "length.es", "length.en")),
data.table(qjilm, key = c("pos.es", "pos.en", "length.es", "length.en") )
)
})
#user system elapsed
#32.070 0.012 32.118
dim(res.dt)
#[1] 6340091 9
Y, finalmente, suponiendo que los data.tables ya tienen asociado un índice de antemano:
Resumen:
- Había hecho unas pruebas con data.table previamente que no resultaron del todo satisfactorias.
- Anoche,
data.table me sacó de un apuro muy serio.
- Ahora soy fan.
- Gracias a
data.table, el límite de tamaño de los conjuntos de datos con los que soy capaz de trabajar razonablemente con R ha crecido en todo un orden de magnitud: ya no me asusta que me hablen de millones.
Las circunstancias —frente a las que soy dócil como el que más— me conducen a escribir de nuevo sobre la Ley de Benford. En concreto, voy a traer a la atención de mis lectores una condición suficiente para que se cumpla. Y de ella extraeremos conclusiones tal vez sorprendentes en sucesivas entradas de la serie que con esta inicio.
Dado un número (p.e., 1234), lo podemos descomponer en dos: una potencia de 10 y otro entre 0 y 10:
n <- 1234 # por ejemplo
suelo <- floor(log10(n))
parte.decimal <- log10(n) - suelo
10^suelo # una potencia de 10
10^parte.decimal # entre 0 y 10
Si lo que llamamos parte.decimal tiene una distribución uniforme en el intervalo (0,1), entonces la probabilidad de que un número comience por, por ejemplo, 3, será

o bien

que no es otra cosa que , el valor que corresponde a la definición estándar de la ley en cuestión.
Así que, en resumen:
Una condición suficiente para que se verifique la Ley de Benford para una serie de valores es que la parte decimal de los valores tenga una distribución uniforme sobre el intervalo (0,1).
(Nota: estoy obviando los signos).
Me sorprendió hace un tiempo averiguar que en la península ibérica hubiese tantos terremotos (aunque mis amigos chilenos los llamarían de otra manera).
En esta entrada voy a mostrar el siguiente mapa de actividad sísmica durante los últimos años,

que he construido con el siguiente código en R:
library(ggmap)
url <- "http://comcat.cr.usgs.gov/earthquakes/feed/search.php?maxEventLatitude=45&minEventLatitude=35&minEventLongitude=-10&maxEventLongitude=5&minEventTime=953683200000&maxEventTime=1364688000000&minEventMagnitude=-1.0&maxEventMagnitude=10&minEventDepth=0.0&maxEventDepth=800.0&format=csv"
terremotos <- read.csv(url)
# obtengo un mapa
pen.iber <- get_map( location = c(-9.5, 36, 3.5, 44),
color = "color",
maptype = "roadmap")
# le añado puntos
ggmap(pen.iber) +
geom_point(aes(x = Longitude, y = Latitude,
size = Magnitude),
data = terremotos, colour = 'red',
alpha = 0.2)
|