Archivo de la categoría: Consultoría

Gráficos de calendarios con series temporales

Cuando se realizan gráficos de series temporales se emplean gráficos de líneas donde el eje X contiene la fecha y el eje Y contiene el valor a representar. Hoy quiero traer al blog otra forma de representar series temporales, los gráficos de calendario y su realización con R. Para ilustrar el ejemplo vamos a emplear las cotizaciones históricas del índice bursatil IBEX35:

require(quantmod)
require(ggplot2)
require(reshape2)
require(dplyr)
library(lubridate)

# Obtenemos las cotizaciones del IBEX 35 desde 2010
getSymbols('^IBEX', from = '2010-01-01')

# data frame de trabajo
df<-data.frame(date=index(IBEX),IBEX)

Mediante quantmod extraemos las cotizaciones del IBEX desde 2010 y creamos un data frame de trabajo que llamamos df. Vamos a realizar dos tipos de gráficos, un mapa de calor por años, meses, semanas y días y un calendario de un año puntual.

Calendario como mapa de calor por

Este es un gráfico basado en un trabajo anterior (¡de 2012!) y es una forma imaginativa de representar el cierre del IBEX 35 desde 2010 en una sola imagen. El primer paso será crear las variables a representar en el mapa de calor, el mes, el día de la semana y la semana dentro del mes:

df <- df %>% mutate(año=year(date),
                    mes=factor(month(date),levels=(1:12),
                               labels = c("ENE","FEB","MAR","ABR","MAY","JUN","JUL",
                                              "AGO","SEP","OCT","NOV","DIC"),ordered = T),
                    dia=factor(wday(date)-1,levels=rev(1:7),
                          labels=rev(c("L","M","X","J","V","S","D"))),
                    semanames=ceiling(day(date) / 7))

Ahora sólo queda representar el gráfico mediante ggplot2 donde los paneles de facet_grid serán los años en eje X y los meses en eje Y:

# Realizamos el calendario
calendario1<- ggplot(df, aes(semanames, dia, fill = IBEX.Adjusted)) + 
  geom_tile(colour = "white") + facet_grid(año~mes) + 
  scale_fill_gradient(low = "red", high = "darkgreen", na.value = "black") +  
  labs(title="Cierre histórico del IBEX", x ="Semana del mes", y = "")
calendario1

Un gráfico que me gusta bastante y una original forma de representar series temporales muy largas, no he usado paletas de colores pero imagino que los resultados mejorarán, podéis aportar esas mejoras en los comentarios.

Calendario con openair y calendarPlot

Si deseamos representar un calendario de un año concreto tenemos la función calendarPlot de openair (que me ha costado instalar en Ubuntu) que no puede ser más sencilla:

library(openair)
calendarPlot(df, pollutant = "IBEX.Adjusted", year = 2019, cols = "Greens")

Este último calendario no lo he usado pero la sintaxis es muy sencilla y el resultado queda bastante bien. Ahora vosotros mismos podéis juzgar si hay o no hay rally de fin de año.

El análisis de supervivencia en R para segmentar el churn

El análisis de supervivencia es uno de los olvidados por el Machine Learning y la nueva forma de ver el oficio. A la regresión logística si la damos algo de recorrido porque aparece en scikit-learn (con sus cositas), sin embargo, el análisis de supervivencia no tiene ese cartel porque en el momento que trabajas con un gran número de variables estos modelos “empiezan a echar chispas”.  Sin embargo ofrecen una serie de gráficos y resultados que más allá de la estimación nos describen problemas y pueden servirnos para segmentar poblaciones en base a la duración hasta la ocurrencia de un evento.

El modelo de supervivencia tiene como variable fundamental el tiempo hasta que ocurre un evento y como este tiempo se modifica en base a unas variables explicativas, mas allá de una tasa nos puede permitir identificar segmentos y poblaciones con comportamientos distintos. El ejemplo que quiero mostraros es el paradigma de todo lo que estoy contando, identificar segmentos de clientes que abandonan mi compañía de telecomunicaciones, mas allá de priorizar clientes en base a su probabilidad de anulación tratamos de identificar características que hacen que mi cliente dure más o menos en la compañía.

El ejemplo que vamos a usar está sacado de este:

https://github.com/zangell44/survival-analysis-lifeline-basics/blob/master/customer_churn.ipynb

Tenéis la descripción de las variables, la más importante es tenure, tiempo en meses hasta que se produce el evento y churn que es el evento, la cancelación de la línea, el resto de variables son propias de la línea. En nuestro caso vamos a trabajar con R porque me parecen interesantes los objetos que generan algunas funciones. Leemos los datos y realizamos una pequeña transformación sobre la variable respuesta:

datos <- read.csv('https://raw.githubusercontent.com/treselle-systems/customer_churn_analysis/master/WA_Fn-UseC_-Telco-Customer-Churn.csv')

datos$Churn <- as.integer(ifelse(datos$Churn=="Yes",1,0))

Las librerías de R que vamos a usar son survival y survminer Seguir leyendo El análisis de supervivencia en R para segmentar el churn

Me rindo, es necesario trabajar en Agile

Imagen de previsualización de YouTube

“Agile sounds good” y representa todo eso que critico. Tenía compuesta y preparada una canción que versiona el “Me cago en el amor” de Tonino Carotone, “Me cago en el Agile” se llamaba. ¿Por qué este cambio de opinión tan radical?  Porque no se trabaja de forma horizontal, se trabaja de forma vertical y cada uno hace la guerra por su cuenta. Me voy a mi terreno Agile Analytics

Echamos y vendemos humo. Empecemos: arquitectos, ingenieros, científicos de datos,  analistas de negocio, diseñadores,…  y al final nos olvidamos que estamos ahí para ganar € o hacer ganar a nuestra organización €, €€€€€€ no estamos para conectar nodos edge, ingestar data lakes con millones de registros que nadie usa, diseñar algoritmos, crear contenedores, APIs, visualizaciones espectaculares, mapas interactivos, inteligencias artificiales, etecé, etecé. ¿Objetivo final del proyecto? ¿Cuántos € retorna? Bueno pues ha sido necesario de crear una parafernalia con pizarras y posit para que no nos desviemos de esos objetivos y que en último término sean capaces de medir cuantos € supone cada proyecto. Si todos los implicados en un proyecto trabajaran de forma conjunta, ¿serían necesarias estas figuras? No, pero como eso no pasa, no es que sea necesario, es que se torna imprescindible trabajar en Agile.

Me gustaría plantear una visión distinta de las personas y los roles dentro de un proyecto analítico:

  • Jefe de proyecto (project manager sounds better). Esto ni Agile, ni cascadas, hace falta alguien que se las lleve y que reparta, no queda más remedio. Es muy importante su rol en la documentación y entregables de resultados.
  • Científico, ingeniero o arquitecto de soluciones. Al final son los que trabajan tutelados por un jefe de proyecto.
  • Sponsor de negocio. Este es el que plantea el caso de negocio,  el que pone en marcha toda la maquinaria para plantear un proyecto.
  • Usuario de negocio. Persona que en último término va a usar las herramientas que estén desarrollando y el que tiene un problema que la analítica puede resolver. La línea entre sponsor y usuario es fina.
  • Product Owner (la prefiero en english). Esta figura es la clave porque es la verdadera figura horizontal a las anteriores, rol multidisciplinar tiene que entender el lenguaje de todas las personas implicadas y velar por la correcta administración del proyecto, el que se traga la correcta documentación e imputación de las tareas, que si el resto lo hiciera bien no sería necesario. Junto con el jefe de proyecto cuida del cumplimiento de los objetivos a corto plazo.
  • Scrum máster. Es la persona encargada de que todo lo anterior se lleve a cabo y para ello dispone de una serie de ceremonias y de ritos ridículos pero que sin ellos todas las figuras anteriormente citadas harían lo que les viene en gana. Tiene una tarea de interlocución a más alto nivel en la organización muy importante ya que en el caso de producirse retrasos, problemas o impedimentos en el desarrollo de los proyectos debe ser capaz de eliminar esos problemas. También mide junto con negocio y dirección cual es el impacto económico de los proyectos llevados a cabo.

Esta es mi visión de un proyecto en Agile Analytics y alguno llevo encima (con cierto éxito).  No entro en las ceremonias, que tienen su pena y su gloria también pero obligan a que todos los elementos participantes de un proyecto se reúnan, se escriban actas y se gestionen tareas. Si alguien quiere hablaré sobre ellas.

Ahora bien, hace 20 años yo trabajaba sentado con Ana (de Negocio), tenía 2 pcs porque con uno ejecutaba Business Object y si no me salía la cucaracha con el otro realizaba los análisis con Access/Excel. Vale que vendíamos politonos, paquetes de SMS y móviles de concha pero no era necesaria toda esta parafernalia y éramos 2. Podemos opinar sobre la complejidad de los problemas de negocio actuales, la información disponible o el entorno competitivo son argumentos para trabajar de este modo, pero en mi opinión el problema está en la lejanía y la especialización.  Al final no salían las cosas, así que algunos listos han vestido de metodología (que poco me gusta esta palabra) el sentido común y han dado una solución a este problema y con un halo marketiniano muy molón que llamamos Agile. A todo esto la mayor beneficiada ha sido 3M que en 2018 estaba en máximos de cotización, creo que ahora está cayendo un poco quizá haya vuelto el sentido común, no creo, hasta yo me he rendido.

Los parámetros del modelo GLM como relatividades, como recargos o descuentos

Los modelos GLM son muy empleados en el ámbito actuarial para la obtención de modelos de riesgo, estos modelos de riesgo son los elementos fundamentales en el cálculo de tarifas y qué es una tarifa, imaginad el precio del seguro de vuestra vivienda, bueno pues es un cálculo en el que partiendo de un precio base se van añadiendo recargos y descuentos en función del tipo de riesgo que se quiera asegurar (recargos y descuentos en función de los metros cuadrados, de la ubicación de la vivienda de las calidades de construcción….). Esta es una visión muy simplista porque al final se tienen múltiples garantías y es necesaria la combinación de garantías, pero se puede entender de ese modo, un precio base al que recargamos o descontamos precio. Estos recargos y descuentos se denominan frecuentemente relatividades y hoy quiero acercaros a la obtención de esas relatividades y como un modelo GLM se transforma en el precio de un seguro.

En la línea habitual del blog vamos a ilustrar con un ejemplo usando unos datos muy conocidos para el trabajo con GLM y modelos de cálculo de tarifas. El primer paso es cargar el conjunto de datos en nuestra sesión de R:

library(dplyr)

varib <- c(edad = 2L, sexo = 1L, zona = 1L, clase_moto = 1L, antveh = 2L,
           bonus = 1L, exposicion = 8L, nsin = 4L, impsin = 8L)

varib.classes <- c("integer", rep("factor", 3), "integer",
                   "factor", "numeric", rep("integer", 2))

con <- url("https://staff.math.su.se/esbj/GLMbook/mccase.txt")
moto <- read.fwf(con, widths = varib, header = FALSE,
                 col.names = names(varib),
                 colClasses = varib.classes,
                 na.strings = NULL, comment.char = "")

Los datos empleados pertenecen a una cartera de motocicletas, disponemos del número de siniestros (variable nsin), el importe de los siniestros (impsin), la exposición al riesgo de ese registro y una serie de factores que creemos pueden influir en la estimación del número de siniestros o del importe de los siniestros como son la edad, la zona, el nivel de bonificación,… Vamos a partir del modelo más sencillo, un modelo de frecuencia siniestral en base a un factor edad. Si realizamos con R un GLM clásico haríamos:

moto$edad_factor <- case_when(
  as.numeric(moto$edad) <=18 ~ 18, as.numeric(moto$edad) >=60 ~ 60,
  TRUE ~ as.numeric(moto$edad))

moto$edad_factor <- as.factor(moto$edad_factor)

glm.1 <- glm(nsin ~ edad_factor+offset(log(exposicion)), data=filter(moto,exposicion>0),
             family=poisson())
summary(glm.1)

Hemos creado un factor edad que va desde los 18 años hasta los 60, realizamos una regresión de poisson para estimar el número de siniestros, como al final lo que deseamos es crear una proporción de siniestros de la forma nsin/exposición (frecuencia siniestral) lo que hacemos es poner el nsin como variable dependiente y la exposición como variable offset, la única variable regresora es la edad en formato factor, con este modelo obtendremos un estimador para cada nivel del factor. Es un modelo aditivo de la forma log(Y) = B0 + Edad18*B1 + Edad19*B2 + … + log(exp) + Error pero si realizamos el exponencial de los parámetros obtenidos con el modelo tendremos E[Y/exp] = B’0 * Edad18*B’1 * Edad19*B`2 * … Es decir, el valor esperado para la frecuencia siniestral es función de unos parámetros que recargan o descuentan esa frecuencia esperada. Esos B’ que son el resultado de exp(B) es lo que denominamos relatividades. Esto es muy utilizado para la realización de modelos de riesgo en el cálculo de tarifas.

Obtención de las relatividades

Reiterando, el exponencial del parámetro obtenido con la formulación del modelo es lo que denominamos relatividad y esa relatividad multiplicada por un término independiente nos daría como resultado la estimación de la proporción de siniestros, la estimación de la frecuencia siniestral para cada nivel del factor. También es relevante estudiar y comprender como R presenta esos parámetros, si hacemos el exponencial de los parámetros del modelo glm.1 que hemos hecho tenemos:

data.frame(exp(glm.1$coefficients))
              exp.glm.1.coefficients.
(Intercept)                0.02986346
edad_factor19              0.48892314
edad_factor20              0.95974062
edad_factor21              0.73651804
….

¿Qué está pasando con la edad 18? Del término independiente pasa directamente a la edad 19 y de ahí hasta la edad 60, una estimación para cada nivel del factor a excepción del nivel 18. Bien, R considera al primer nivel del factor el nivel base, si lo vemos en forma de estimador un factor toma valor 1 si la observación está en ese nivel del factor y toma 0 si no lo está, pues si todos los estimadores presentes en el modelo toman el valor 0 el modelo estima que la proporción de siniestros en la edad 18 es de 0.02986, R no muestra ese estimador porque directamente no es necesario calcularlo, la edad 18 tiene una frecuencia siniestral del 3% Seguir leyendo Los parámetros del modelo GLM como relatividades, como recargos o descuentos

Los principales problemas de los españoles. Animaciones con R y gganimate

La realización de gráficos animados con R, gganimate y ggplot2 es algo que quiero empezar a trabajar en mis visualizaciones de datos, una buena forma de llamar la atención sobre nuestros gráficos. Para ilustrar el ejemplo he recogido los datos que publica mensualmente el CIS con las 3 principales preocupaciones de los españoles que podéis encontrar en este enlace, por cierto, este enlace tiene toda la pinta de ser una salida en SAS, no me parece muy apropiado pero no diré nada porque imagino que serán lectores del blog (ya podíais hacer una salida más acorde con los tiempos). El caso es que la primera parte de nuestro trabajo será el “scrapeado” de la web. Scrapear verbo regular de la primera conjugación:

library(XML)
library(dplyr)
library(lubridate)

#Lectura de los datos del CIS
url < - "http://www.cis.es/cis/export/sites/default/-Archivos/Indicadores/documentos_html/TresProblemas.html"
doc = htmlParse(url,  encoding = "UTF-8")
tableNodes = getNodeSet(doc, "//table")

#Leemos la tabla que tiene un formato un tanto peculiar
problemas <- readHTMLTable(tableNodes[[2]], skip.rows=1)
problemas <- problemas %>% filter(!is.na(V1)) 

#Transformamos los puntos en 0, parece que estuviera hecho con SAS
haz.cero.na=function(x){ifelse(x==".",0,as.numeric(as.character(x)))}

problemas < - cbind.data.frame(as.character(problemas$V1),sapply(problemas,haz.cero.na),stringsAsFactors=FALSE)
problemas <- problemas %>% select(-V1)

#El primer elemento de la tabla contiene los nombres que vamos a emplear
nombres < - readHTMLTable(tableNodes[[2]])[1,]
nombres$V1="Problema" 
nombres <- as.vector(t(nombres))

names(problemas) <- nombres

#Hay un registro en la tabla que tiene el número de encuestas, no es necesario
problemas <- filter(problemas,Problema != "(N)")

Cosas interesantes en el código. Hacemos HTMLParse de la web y nos quedamos con las tablas, Seguir leyendo Los principales problemas de los españoles. Animaciones con R y gganimate

Crear archivo csv desde SAS con Python

Con la librería sas7bdat de Python podemos leer archivos SAS y crear directamente un data frame, es la mejor librería para hacerlo, si la tabla SAS que deseáis leer está comprimida (compress=yes) con pandas no podréis hacerlo. Pero tengo que agradecer a mi compañero Juan que me haya descubierto la función convert_file para pasar directamente el archivo SAS a csv, es más eficiente y parece que consume menos recursos del equipo. La sintaxis es muy sencilla:

import pandas as pd
from sas7bdat import SAS7BDAT

start_time = time.time()
path_file_sas = '/ubicacion/archivo/sas/tabla_SAS.sas7bdat'
path_file_csv = 'ubicacion/archivo/csv/archivo_CSV.csv'
f = SAS7BDAT(path_file_sas)

f.convert_file(path_file_csv, delimiter=',', step_size=10000)

end_time = time.time()
(end_time - start_time) / 60 

La función convert_file realiza el proceso paso a paso, trozo a trozo, chunk to chunk. Si la tarea la realizas con un equipo esto te permite poder seguir usándolo. Me ha parecido un truco útil para poder importar tablas SAS a Python creando primero un csv, podéis agradecer a Juan.

 

Diagramas de Voronoi con spatial de python

En breve “mis cachorros”, como llamo a un grupo de los mejores Data Scientist de Europa (de los que tengo que hablar algún día) se van a enfrentar a un problema que probablemente tengan que resolver con análisis geométricos muy complejos. Para despertarles la curiosidad (sé que me leen) hoy traigo al blog una entrada que nos aproxima al método de interpolación geométrica más sencillo, al diagrama de Voronoi. Con spatial de scipy podemos trabajar con estos diagramas:

seed(89)
df = pd.DataFrame(np.random.uniform(1,100,size=(20, 2)), columns=list('XY'))
plt.scatter(df.X, df.Y,marker=".")
show()

voronoi_python1

Estos puntos aleatorios en el espacio de 2 dimensiones pueden generar regiones por interpolación y representarlas con voronoi_2d_plot:

from scipy.spatial import Voronoi, voronoi_plot_2d
vor = Voronoi(df)
voronoi_plot_2d(vor)

voronoi_python2

Ahora si queremos determinar si un punto de espacio está dentro de una de las celdas que delimitan los diagramas de Voronoi que hemos creado podemos hacerlo por vecinos cercanos con la función cKDTree:

from scipy.spatial import cKDTree
vor_kdtree = cKDTree(df)
puntos = [[1,100],[100,1]]
test_point_dist, test_point_regions = vor_kdtree.query(puntos,k=1)
test_point_regions

Y ahora viene lo único interesante de esta entrada, ¿cómo identificamos las regiones? No empleéis .regions, emplead:

pd.concat([df,pd.DataFrame(vor.point_region)],axis=1)

Los puntos (1,100) y (100,1) aparecen en la región que nos identifica la posición 19 y 9… Me ha costado tiempo entenderlo, me hago viejo. Saludos.

¿Puede la información de Twitter servir para calcular el precio de tu seguro?

rvaquerizo

Debemos de ir introduciendo el concepto de Social Pricing en el sector asegurador, si recordamos el año pasado Admirall y Facebook tuvieron un tira y afloja por el uso de la información de Facebook para el ajuste de primas de riesgo. Facebook alegaba a la sección 3.15 de su privacidad para no permitir emplear esta información a Admirall. Probablemente es un tema más económico. El caso es que tanto Facebook, como Instagram, como Twitter, como LinkedIn, como xVideos,… tienen información muy interesante acerca de nosotros, información que se puede emplear para el cálculo de primas en el sector asegurador (por ejemplo). No voy a decir como hacer esto, este blog no es el lugar, el que quiera conocer mis ideas que se ponga en contacto conmigo. Yo soy alguien “público”, no tengo problema en dejar mis redes sociales abiertas y este caso me sirve de ejemplo para analizar que dice Twitter de mí y también sirve de ejemplo para refrescar el manejo de información con Twitter con #rstats. Esta entrada es una combinación de entradas anteriores de esta bitácora así que recordemos como empezábamos a hacer scrapping de Twitter:

[sourcecode lang=”R”]
library(twitteR)
library(base64enc)

consumer_key="XXXXXXXXXxxxxXXXXXXXxx"
consumer_secret="xxXXXXXXXXxxXXXXXXXXXxxXXxxxxx"
access_token="81414758-XXxXxxxx"
access_secret="XXXxXXxXXxxxxx"

setup_twitter_oauth(consumer_key, consumer_secret, access_token=access_token, access_secret=access_secret)
[/sourcecode]

Vía Oauth ya podemos trabajar con el paquete twitteR desde nuestra sesión de R y ahora lo que vamos a crear es un objeto R del tipo “user” con la información que tiene el usuario r_vaquerizo (yo mismo):

[sourcecode lang=”R”]
rvaquerizo <- getUser(‘r_vaquerizo’)
rvaquerizo_seguidos <- rvaquerizo$getFriends(retryOnRateLimit=120)
seguidos <- do.call("rbind", lapply(rvaquerizo_seguidos, as.data.frame))
[/sourcecode]

El objeto rvaquerizo tiene mucha información sobre mí Seguir leyendo ¿Puede la información de Twitter servir para calcular el precio de tu seguro?

Ejemplo de web scraping con R. La formación de los diputados del Congreso

No sabía si realizar esta entrada sobre web scraping con R o con python. He obtado por la primera opción porque en un principio era una entrada para ilustrar un ejemplo de web scraping y al final se me están ocurriendo muchas ideas sobre el análisis de la web de Congreso de los diputados y he preferido hacerla con R porque tengo una mayor soltura para hacer distintos análisis. Quería empezar por estudiar la formación que tienen nuestros 350 diputados, para ello se me ocurrió descargarme las líneas que tienen en su ficha de diputado y crear un data frame con los datos personales referentes a su formación. Si entráis en la ficha de cualquier diputado (http://www.congreso.es/portal/page/portal/Congreso/Congreso/Diputados/BusqForm?_piref73_1333155_73_1333154_1333154.next_page=/wc/fichaDiputado?idDiputado=171&idLegislatura=12) veréis que les han dejado un pequeño texto donde describen su hoja de vida. La verdad es que cada uno a escrito lo que le ha parecido pero algún patrón se puede encontrar. Para ilustrar el ejemplo he preferido usar la librería rvest porque me ha parecido una sintaxis más sencilla. Yo no soy un buen programador, incluso soy un poco desastre, hasta guarrete programando y con rvest creo que el código es bastante claro.

El procedimiento para el web scraping será el siguiente:

  1. Identificar en la web del Congreso como funciona el formulario para cambiar de diputado, es sencillo basta con ver el link y tenemos fichaDiputado?idDiputado=171&idLegislatura=12″ es evidente que vamos a crear un bucle con el idDiputado.
  2. Que parte corresponde con el curriculum de cada personaje, esta parte también es sencilla, véis el código fuente y hay un bloque de contenido identificado como
    div id=”curriculum” esta es la parte que nos interesa.
  3. Tenemos que limpiar con alguna función de R el HTML y el texto que estamos “escrapeando”.
  4. Lo ponemos todo en un data frame por si queremos analizarlo.

Esta es la idea y se traduce en R del siguiente modo:

library(rvest)

curriculos = ""
for (dip in seq(1,350,by=1)){
url = paste0("http://www.congreso.es/portal/page/portal/Congreso/Congreso/Diputados/BusqForm?_piref73_1333155_73_1333154_1333154.next_page=/wc/fichaDiputado?idDiputado=",dip,"&idLegislatura=12")

congreso <- read_html(url)
curric <- congreso %>%
html_node("#curriculum") %>%
html_text %>%
strsplit(split = "\n") %>%
unlist() %>%
.[. != ""]
#Pequeña limpieza de texto
curric <- trimws(curric)
#Elimina las líneas sin contenido
curric <- curric[which(curric!="")]
#Nos quedamos justo con la linea que hay debajo de la palabra legislaturas
linea <- curric[grep("legislatura", curric)+1]
curriculos <- rbind(curriculos,linea)}

curriculos <- data.frame(curriculos[-1])

Ya podéis ver que la elegancia programando brilla por su ausencia pero queda todo muy claro. Particularidades, para identificar la formación dentro del texto libre he seleccionado aquellas líneas que están debajo de la palabra legislaturas, no he encontrado mejor forma y soy consciente de que falla, es suceptible de mejora. La función read_html de rvest es la que lee la web, el contenido que nos interesa lo seleccionamos con html_node pero es necesario que sea un texto y por eso aparece html_text  y por último particionamos el texto en función de los /n. Con el texto más o menos formateado pasamos la función TRIMWS que se cepilla los  espacios en blanco, tabuladores y saltos de línea. Tenía que meter esta función con calzador porque me parece útil para limipar textos con R y este ejemplo ilustra el funcionamiento. Para finalizar eliminamos las líneas vacías del texto con Which. Acumulamos las líneas con la formación de cada diputado y creamos el data frame curriculos que contiene lo que ellos han escrito como su formación.

No he trabajado mucho con ello, pero podemos buscar la palabra que más se repite replicando algún código ya conocido:

palabras = strsplit(curriculos, split=" ")
palabras = as.character(unlist(palabras))
palabras = data.frame(palabras)
names(palabras) = c("V1")
palabras$V1 = sub("([[:space:]])","",palabras$V1)
palabras$V1 = sub("([[:digit:]])","",palabras$V1)
palabras$V1 = sub("([[:punct:]])","",palabras$V1)
palabras$largo = nchar(palabras$V1)
palabras = subset(palabras, largo>4)

library(plyr)
conteo = data.frame(ddply(palabras, "V1",summarise, cuenta=length(V1) ))
conteo = conteo[order(-conteo$cuenta),]

Aproximadamente el 28% de los diputados son licenciados en derecho, no veo ingenierías por ningún sitio y muchos casados y ayuntamientos… No voy a valorar lo poco que he explorado pero es evidente que nos representan personas con una experiencia profesional muy acotada en las instituciones públicas (que forma más bonita de decir personas poco productivas). Seguiré escrapeando esta web os lo prometo.

Como obtener los centroides de municipios con SAS. Mapas con SGPLOT

mapa_municipios_sas2

Un amigo y lector del blog me ha pedido un mapa de códigos postales donde poder identificar los centroides para andar calculando distancias a otros puntos. Yo no tengo un mapa de España por códigos postales para poder usar con fines comerciales, pero si cuento en el blog como poder obtenerlo bajo ciertas condiciones. Lo que si puedo contar a Juan es como hacer un mapa por municipios con SAS, aunque ya he hablado de ello hay ciertos aspectos que pueden ser interesantes. y todo empieza donde siempre http://www.gadm.org/country la web donde tenemos los mapas “libres” por países, seleccionáis Spain y el formato shapefile una vez descargados los mapas en vuestros equipos empezamos con el trabajo en SAS:

[source languaje=”SAS”]
proc mapimport datafile="\directorio\mapa\ESP_adm_shp.shp"
out = work.espania;
run;
proc contents;quit;
[/source]

mapa_municipios_sas1

El procedimiento MAPIMPORT ha creado un conjunto de datos SAS donde tenemos caracterizados todos los polígonos que componen el shapefile. Entonces si tenemos que calcular el centroide de un municipio con SAS sugiero realizar un PROC SQL de la siguiente forma Seguir leyendo Como obtener los centroides de municipios con SAS. Mapas con SGPLOT