Hola:
Hace como un mes pregunte si se podÃa desarrollar una barra de progreso
que informara del progreso de una subida de datos a SQL Server desde R.
Miguel Ãngel me dio una orientacion de como enfocar el problema y al final
lo he conseguido hacer usando el paquete snowfall.
Ahora bien hay una parte del código que, aunque funciona no entiendo muy
bien como, porque "adapte" un código que encontré por internet.
El proceso consiste básicamente en crear dos funciones:
-La primera es una barra de progreso que va obteniendo, a intervalos
regulares, el numero de registros que hay en la tabla donde se realiza la
inserción de datos.
-La segunda es una que establece la conexión al SQL Server e inserta los
datos en el.
La idea es que mientras un cluster se encarga de gestionar la barra de
progreso, el otro realiza la inserción de los datos.
La cuestión es que esta instrucción (que funciona bien) no entiendo como
funciona:
sfClusterApply( tarea , function(f) f())
En concreto function(f) f() es lo que aplica las funciones de la lista
tareas (t1 y t2) a cada cluster por separado y en paralelo, pero no
entiendo que es lo que realiza esa sintaxis.
¿Alguien me podrÃa explicar porque se puede definir asà y no como yo
hubiera pensado que era:?;
sfClusterApply( tarea, pb(tab,asubir,entabla,frec),subida(datos,tab))
El código de todo el proceso es el siguiente:
#Cargamos los paquetes necesarios
library(snowfall)
library(RODBC)
#Cargamos el df (datos) que vamos a subir al SQL Server
load("C:\\Documents and Settings\\My Documents\\datos.Rdata")
###########################################
# Iniciamos los 2 clusters #################
###########################################
#Iniciamos dos cluster para trabajar en paralelo y el log lo guardamos en
esclavos txt
sfInit( parallel=TRUE, cpus=2, slaveOutfile="esclavos.txt" )
#Cargamos paquete RODBC en los dos cluster
sfLibrary( RODBC )
############################################
# Definimos variables del proceso ############
############################################
tab <- as.character("Pruebas_R") #Nombre de la tabla donde se realizara
la inserción de los datos
asubir <- as.numeric(nrow(datos)) #Numero de registros (filas) de nuestro
df datos que se van a subir al #SQL Server
canal <- odbcDriverConnect( "case=nochange; Driver=SQL Server; Server=X;
Database=X; uid=X; pwd=X; wsid=X;") #Abrimos conexion RODBC
entabla <- as.numeric(sqlQuery(canal,paste("SELECT Count(*) ", " FROM
",tab, sep=""))) #Nº de registro
que hay actualmente en tabla en la que vamos a insertar #los datos
close(canal) #Cerramos conexión RODBC
rm(canal) #Eliminamos conexión RODBC
frec <- 0.1 #Establecemos frecuencia
de actualización de la barra de progreso
###########################################
# FUNCIONES ############################
###########################################
#Función que genera una barra de progreso que se actualiza según la
variable frec e informa del numero de registros
#insertados hasta ese momento y de los registros que quedan por insertar
pb <-function( tab,asubir,entabla ,frec ){
canal1 <- odbcDriverConnect( "case=nochange;
Driver=SQL Server; Server=X; Database=X; uid=X; pwd=X; wsid=X;") #Conexión
RODBC
barra <- winProgressBar(title="SUBIENDO DATOS A
SQL ", label = "Subido el: ", min= 0, max= 1,initial= 0, width = 800)
#Definimos barra de progreso
total <- as.numeric(0) #Vble total acumulara el
nº registros que
#hay en la
tabla
while ( entabla + asubir > total ) #El bucle se
realizara hasta que todos los datos estén subidos
{
canal1 <- odbcReConnect(canal1)
#Conexión RODBC
total <-
as.numeric(sqlQuery(canal1,paste("SELECT Count(*) FROM ",tab, sep="")))
#Obtenemos el nº de registros que hay en la tabla en ese
#momento
porcen <- as.numeric((total -
entabla) / asubir) #Calculamos porcentaje de registros subidos del total a
subir
setWinProgressBar(barra,
porcen,title="SUBIENDO DATOS A SQL", #Actualizamos la
barra de progreso con la
label
=paste("Subido el: ", round(porcen *100,0), "% de los datos. #la
información obtenida y calculada
Se han subido
",total - entabla, " registros de ", asubir, "." , sep=""))
flush.console() #Refrescamos la
consola
Sys.sleep(frec) #Hacemos una
pausa de 0.1 segundos
}
close(barra, canal1) #Cerramos los objetos usados
rm(barra,canal1,total) #Eliminamos los objetos
usados
}
#Funcion que realiza la insercion de los registros del df (datos) en la
tabla de SQL Server (tabla)
subida <- function( datos, tab)
{
canal2 <- odbcDriverConnect( "case=nochange;
Driver=SQL Server; Server=X; Database=X; uid=X; pwd=X; wsid=X;") #Conexión
RODBC
sqlSave(canal2,datos,tablename= tab, rownames =
FALSE, append=TRUE, fast=TRUE ) #Realizamos la inserción del df (datos)
#en tabla
(tabla)
close(canal2) #Cerramos conexión RODBC
rm(canal2) #Eliminamos conexión RODBC
}
##############################
# Preparación de los cluster #####
##############################
sfRemoveAll() #Eliminamos los objetos que pudieran contener los cluster
sfExport("tab","asubir","entabla","frec","datos", "pb","subida")
#Exportamos a los 2 cluster los objetos que necesitamos
tarea <- list( t1 = function() pb(tab,asubir,entabla,frec),t2 = function()
subida(datos,tab)) #Creamos lista con las dos funciones definidas
previamente
############################
# Inserción de datos #######
############################
hora.ini <- Sys.time() #Establecemos
tiempo de inicio del proceso
sfClusterApply( tarea , function(f) f()) #Lanzamos
en el primer cluster la t1 de la lista tarea, en el segundo cluster se
lanzara t2 de la lista tarea de forma paralela
print(paste("Tiempo
transcurrido",round(difftime(Sys.time(),hora.ini,units="hours" ),digits =
2) , "horas")) #Una vez finalizada la inserción informamos del
tiempo que hemos tardado
sfStop() #Detenemos los dos cluster
Un saludo
José Luis Gilsanz Gómez
EstadÃstica
Tasaciones Hipotecarias
MarÃa de Molina, 54 - 28006 - Madrid
Tel. : 34-914549694
Fax : 34-917822164
Email : jluis.gilsanz en tasacionesh.com
Site web: www.tasacionesh.es
-- AVISO LEGAL --
Los datos personales que en esta comunicación aparecen, asà como los que
nuestra empresa mantiene de Vd. y de su empresa, son tratados con la
finalidad de mantener el contacto asà como realizar las gestiones que en
esta aparecen (Ley Orgánica 15/1999, de 13 de diciembre, de Protección de
Datos de Carácter Personal).
Puede ejercer sus derechos de acceso, rectificación, cancelación y
oposición dirigiéndose a atencion.clientesth en tasacionesh.com.
La utilización de su dirección de correo electrónico por parte de nuestra
empresa queda sujeta a las disposiciones de la Ley 34/2002, de Servicios
de la Sociedad de la Información y el Comercio Electrónico. Si Vd. recibe
comunicación comercial por nuestra parte y desea dejar de recibirla,
rogamos nos lo comunique por vÃa electrónica a través de la dirección
atencion.clientesth en tasacionesh.com .
{In Archive} Resumen de R-help-es, Vol 50, EnvÃo 14
(Internet)
r-help-es-request
To:
r-help-es
05/04/2013 13:07
Sent by : r-help-es-bounces en r-project.org
Please respond to r-help-es
Archive:
This message is being viewed in an archive.
EnvÃe los mensajes para la lista R-help-es a
r-help-es en r-project.org
Para subscribirse o anular su subscripción a través de la WEB
https://stat.ethz.ch/mailman/listinfo/r-help-es
O por correo electrónico, enviando un mensaje con el texto "help" en
el asunto (subject) o en el cuerpo a:
r-help-es-request en r-project.org
Puede contactar con el responsable de la lista escribiendo a:
r-help-es-owner en r-project.org
Si responde a algún contenido de este mensaje, por favor, edite la
linea del asunto (subject) para que el texto sea mas especifico que:
"Re: Contents of R-help-es digest...". Además, por favor, incluya en
la respuesta sólo aquellas partes del mensaje a las que está
respondiendo.
Asuntos del dÃa:
1. Re: Barra de progreso en RODBC (jluis.gilsanz en tasacionesh.com)
----------------------------------------------------------------------
Message: 1
Date: Fri, 5 Apr 2013 13:05:51 +0200
From: jluis.gilsanz en tasacionesh.com
To: miguel.angel.rodriguez.muinos en sergas.es
Cc: r-help-es en r-project.org
Subject: Re: [R-es] Barra de progreso en RODBC
Message-ID:
<OF5A83E487.D4B34CDF-ONC1257B44.003C120B-C1257B44.003CF664 en bnpparibas.com>
Content-Type: text/plain; charset="iso-8859-1"
Hola Miguel Ãngel.
Pues me acabas de dar una idea estupenda¡¡¡
Haré unas pruebas de la velocidad media de subida de registros desde R a
MSSQL.
Obtendré un valor de x registros por segundo.
Creare esa ventana (me pondré a bucear en la ayuda para ver como hacerlo)
y como se cuantos registros voy a insertar podré mostrar un progreso
aproximado.
Suponiendo que consiga 1100 registros subidos por segundo y que tenga
1.658.900 registros a subir, tendrÃa unos 1508 segundos de proceso (unos
25 minutos).
Seria cuestión de tomar la hora de inicio del proceso, añadir 26 o 27
(papochiacaso) minutos y hacer correr una barra o similar durante esos 26
minutos en pequeños intervalos.
Me gusta la idea Miguel Ãngel, muchas gracias.¡¡¡
Voy a investigar el tema de las ventanas que comentas¡¡¡
GRACIAS
José Luis Gilsanz Gómez
EstadÃstica
Tasaciones Hipotecarias
MarÃa de Molina, 54 - 28006 - Madrid
Tel. : 34-914549694
Fax : 34-917822164
Email : jluis.gilsanz en tasacionesh.com
Site web: www.tasacionesh.es
-- AVISO LEGAL --
Los datos personales que en esta comunicación aparecen, asà como los que
nuestra empresa mantiene de Vd. y de su empresa, son tratados con la
finalidad de mantener el contacto asà como realizar las gestiones que en
esta aparecen (Ley Orgánica 15/1999, de 13 de diciembre, de Protección de
Datos de Carácter Personal).
Puede ejercer sus derechos de acceso, rectificación, cancelación y
oposición dirigiéndose a atencion.clientesth en tasacionesh.com.
La utilización de su dirección de correo electrónico por parte de nuestra
empresa queda sujeta a las disposiciones de la Ley 34/2002, de Servicios
de la Sociedad de la Información y el Comercio Electrónico. Si Vd. recibe
comunicación comercial por nuestra parte y desea dejar de recibirla,
rogamos nos lo comunique por vÃa electrónica a través de la dirección
atencion.clientesth en tasacionesh.com .
RE: [R-es] Barra de progreso en RODBC
(Internet)
miguel.angel.rodriguez.muinos
To:
Jluis GILSANZ
Cc:
r-help-es
05/04/2013 11:33
Hola José Luis.
Se me ocurre una cosa que puede valerte (aunque no es demasiado ?fino?)?.
Puedes crear una ventana en la que pintes una barra animada (e, incluso un
contador y/o cronómetro)? la activas justo antes de lanzar la petición y
la desactivas cuando se devuelva el control a R.
Asà el usuario verá algo en pantalla mientras espera y no tendrá esa
sensación de que el proceso ?se colgó?.
Eso te valdrÃa?
NOTA: En tu proceso de una hora, podrÃas ponerles mejor unos videos
musicales!
J
Un saludo,
Miguel.
De: r-help-es-bounces en r-project.org [
mailto:r-help-es-bounces en r-project.org] En nombre de
jluis.gilsanz en tasacionesh.com
Enviado el: viernes, 05 de abril de 2013 11:16
Para: cgb en datanalytics.com
CC: r-help-es en r-project.org; gilbellosta en gmail.com
Asunto: Re: [R-es] Barra de progreso en RODBC
Importancia: Alta
Hola de nuevo:
Ahora creo que he conseguido explicarme bien, esos callbacks de RODBC a R
era justo lo que necesitaba para mostrar el progreso.
Pero como RODBC no los tiene, mi gozo en un pozo :-(
La opción de partir los datos en varios lotes ya la habÃa sopesado pero
teniendo en cuenta que esto era una especie de refinamiento del código no
me merece la pena.
Seguiré ejecutando la query directamente en el MSSQL para saber cuantos
registros han subido como hacia hasta ahora.
Muchas gracias por vuestra ayuda.
Un saludete
Re: [R-es] Barra de progreso en RODBC
(Internet)
cgb
To:
Jluis GILSANZ
Cc:
r-help-es
04/04/2013 16:14
Sent by : gilbellosta en gmail.com
Hola, ¿qué tal?
La única manera en que podrÃas conseguir lo que quieres es que el
_driver_ de ODBC proporcionara _callbacks_ a R (para indicarle, por
ejemplo, por dónde va en la tarea encomendada). Pero no es el caso.
Una vez que llamas a sqlFetch o sqlSave, R pierde el control de lo que
pasa hasta que el _driver_ decide que ha terminado de hacer lo que se
le ha encomendado.
La única manera de disponer de barras de progreso serÃa partiendo la
captura e inserción de datos en bloques para actualizarla tú a mano.
Un saludo,
Carlos J. Gil Bellosta
http://www.datanalytics.com
El dÃa 4 de abril de 2013 10:34, <jluis.gilsanz en tasacionesh.com>
escribió:
▾ Quoted text (6 lines)
Hola de nuevo a todos:
Soy José Luis, Miguel Ãngel ;-)
En las tres opciones que me habéis proporcionado tanto tu mismo como
Carlos,
▾ Quoted text (1 line)
las barras de progreso se aplican a procesos iterativos bien sean bucles
o
▾ Quoted text (4 lines)
bien funciones tipo apply.
En mi caso tanto la importación de la Excel como la exportación al MSSQL
se
▾ Quoted text (6 lines)
hacen en una sola instrucción sin utilizar ni bucles ni funciones tipo
apply.Aunque supongo que internamente RODBC leerá/escribirá los datos de
forma iterativa en ambas instrucciones la subida/bajada de datos en R se
hace "del tirón".
Es decir la primera barra de progreso deberÃa mostrar el progreso del
numero
▾ Quoted text (1 line)
de registros leÃdos hasta ese momento vs el numero total de registros en
la
▾ Quoted text (5 lines)
instruccion:
XLS2010 <- sqlFetch(xls, "2010")
La segunda barra de progreso deberÃa mostrar el progreso del numero de
registros insertados en la tabla SQL hasta ese momento vs el numero
total
▾ Quoted text (2 lines)
de registros del df datos en la instrucción:
sqlSave(channel,datos,tablename ="Poblacion", rownames = FALSE,
append=TRUE,
▾ Quoted text (24 lines)
fast=TRUE )
No sé si consigo explicarme con propiedad.
Muchas gracias por los aportes
Un saludo
Re: [R-es] Barra de progreso en RODBC
(Internet)
cof
To: miguel.angel.rodriguez.muinos
Cc: Jluis GILSANZ, r-help-es
03/04/2013 17:02
▾ Mailing list footer
________________________________
Hola,
Hay alguna más...:
http://cran.r-project.org/web/packages/pbapply/pbapply.pdf
Y otra en el paquete plyr:
http://cran.r-project.org/web/packages/plyr/plyr.pdf
Saludos,
Carlos Ortega
www.qualityexcellence.es
El 3 de abril de 2013 14:33, <miguel.angel.rodriguez.muinos en sergas.es>
escribió:
Hola jluis (probablemente, José o Juan Luis).
A ver si esto te sirve...
http://ryouready.wordpress.com/2009/03/16/r-monitor-function-progress-with-a-progress-bar/
▾ Mailing list footer
_____________________________
Miguel Ãngel RodrÃguez MuÃños
Dirección Xeral de Innovación e Xestión da Saúde Pública
ConsellerÃa de Sanidade
Xunta de Galicia
http://dxsp.sergas.es
De: r-help-es-bounces en r-project.org [
mailto:r-help-es-bounces en r-project.org]
▾ Quoted text (13 lines)
En nombre de jluis.gilsanz en tasacionesh.com
Enviado el: miércoles, 03 de abril de 2013 13:40
Para: r-help-es en r-project.org
Asunto: [R-es] Barra de progreso en RODBC
Hola:
Me encuentro en la tesitura de hacer el siguiente proceso:
1-.Leer una excel e importar los datos a R
2-.Transformar esos datos mediante R
3.-Subir esos datos transformados a MS SQL server.
El proceso en si lo tengo completado sin problemas, pero me gustaria
afinar
▾ Quoted text (8 lines)
un poco mas el codigo y poner una barra de progreso en los pasos 1 y 3.
En ambos pasos utilizo RODBC para hacer la conexion:
En 1- el codigo seria
xls <- odbcConnectExcel("Poblacion.xls")
XLS2010 <- sqlFetch(xls, "2010")
Pues bien la instruccion sqlFetch tarda unos 3 o 4 minutos en leer la
excel
▾ Quoted text (1 line)
y me gustaria mostrar una barra de progreso o similar mientras se
ejecuta.
▾ Quoted text (7 lines)
Tras importar la excel, y luego de varias transformaciones subo el df
resultante (llamado datos) mediante
channel <- odbcDriverConnect( "case=nochange; Driver=SQL Server;
Server=XXXXXXXX; Database=XXXXXXX; uid=XXXXt; pwd=XXXXt; wsid=XXXXXX;")
sqlSave(channel,datos,tablename ="Poblacion", rownames = FALSE,
append=TRUE,
▾ Quoted text (6 lines)
fast=TRUE )
En este caso tarda aproximadamente una hora en la que R parece "muerto".
Haciendo una consulta contra la tabla Poblacion (en el analizador de
consultas de MSSQL) puedo ver en cada momento cuantos registros se han
insertado hasta ese momento pero me gustaria que R mostrara una
indicacion
▾ Quoted text (4 lines)
del estado de la insercion de datos en el Servidor.
Muchas gracias
▾ Mailing list footer
________________________________
Nota: A información contida nesta mensaxe e os seus posibles documentos
adxuntos é privada e confidencial e está dirixida únicamente ó seu
destinatario/a. Se vostede non é o/a destinatario/a orixinal desta
mensaxe,
▾ Quoted text (14 lines)
por favor elimÃnea. A distribución ou copia desta mensaxe non está
autorizada.
Nota: La información contenida en este mensaje y sus posibles documentos
adjuntos es privada y confidencial y está dirigida únicamente a su
destinatario/a. Si usted no es el/la destinatario/a original de este
mensaje, por favor elimÃnelo. La distribución o copia de este mensaje no
está autorizada.
See more languages: http://www.sergas.es/aviso_confidencialidad.htm
[[alternative HTML version deleted]]
▾ Mailing list footer
_______________________________________________
R-help-es mailing list
R-help-es en r-project.org
https://stat.ethz.ch/mailman/listinfo/r-help-es
--
Saludos,
Carlos Ortega
www.qualityexcellence.es
-- AVISO LEGAL --
Los datos personales que en esta comunicación aparecen, asà como los que
nuestra
empresa mantiene de Vd. y de su empresa, son tratados con la finalidad
de
▾ Quoted text (4 lines)
mantener
el contacto asà como realizar las gestiones que en esta aparecen (Ley
Orgánica
15/1999, de 13 de diciembre, de Protección de Datos de Carácter
Personal).
▾ Quoted text (1 line)
Puede ejercer sus derechos de acceso, rectificación, cancelación y
oposición
▾ Quoted text (2 lines)
dirigiéndose a atencion.clientes en tasacionesh.com
La utilización de su dirección de correo electrónico por parte de
nuestra
▾ Quoted text (6 lines)
empresa
queda sujeta a las disposiciones de la Ley 34/2002, de Servicios de la
Sociedad de
la Información y el Comercio Electrónico. Si Vd. recibe comunicación
comercial por
nuestra parte y desea dejar de recibirla, rogamos nos lo comunique por
vÃa
▾ Quoted text (4 lines)
electrónica
a través de la dirección atencion.clientes en tasacionesh.com
▾ Mailing list footer
_______________________________________________
R-help-es mailing list
R-help-es en r-project.org
https://stat.ethz.ch/mailman/listinfo/r-help-es
-- AVISO LEGAL --
Los datos personales que en esta comunicación aparecen, asà como los que
nuestra
empresa mantiene de Vd. y de su empresa, son tratados con la finalidad de
mantener
el contacto asà como realizar las gestiones que en esta aparecen (Ley
Orgánica
15/1999, de 13 de diciembre, de Protección de Datos de Carácter Personal).
Puede ejercer sus derechos de acceso, rectificación, cancelación y
oposición
dirigiéndose a atencion.clientes en tasacionesh.com
La utilización de su dirección de correo electrónico por parte de nuestra
empresa
queda sujeta a las disposiciones de la Ley 34/2002, de Servicios de la
Sociedad de
la Información y el Comercio Electrónico. Si Vd. recibe comunicación
comercial por
nuestra parte y desea dejar de recibirla, rogamos nos lo comunique por vÃa
electrónica
a través de la dirección atencion.clientes en tasacionesh.com
Nota: A información contida nesta mensaxe e os seus posibles documentos
adxuntos é privada e confidencial e está dirixida únicamente ó seu
destinatario/a. Se vostede non é o/a destinatario/a orixinal desta
mensaxe, por favor elimÃnea. A distribución ou copia desta mensaxe non
está autorizada.
Nota: La información contenida en este mensaje y sus posibles documentos
adjuntos es privada y confidencial y está dirigida únicamente a su
destinatario/a. Si usted no es el/la destinatario/a original de este
mensaje, por favor elimÃnelo. La distribución o copia de este mensaje no
está autorizada.
See more languages: http://www.sergas.es/aviso_confidencialidad.htm
-- AVISO LEGAL --
Los datos personales que en esta comunicación aparecen, asà como los que
nuestra
empresa mantiene de Vd. y de su empresa, son tratados con la finalidad de
mantener
el contacto asà como realizar las gestiones que en esta aparecen (Ley
Orgánica
15/1999, de 13 de diciembre, de Protección de Datos de Carácter Personal).
Puede ejercer sus derechos de acceso, rectificación, cancelación y
oposición
dirigiéndose a atencion.clientes en tasacionesh.com
La utilización de su dirección de correo electrónico por parte de nuestra
empresa
queda sujeta a las disposiciones de la Ley 34/2002, de Servicios de la
Sociedad de
la Información y el Comercio Electrónico. Si Vd. recibe comunicación
comercial por
nuestra parte y desea dejar de recibirla, rogamos nos lo comunique por vÃa
electrónica
a través de la dirección atencion.clientes en tasacionesh.com
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <
https://stat.ethz.ch/pipermail/r-help-es/attachments/20130405/6f13d444/attachment.html
------------ próxima parte ------------
A non-text attachment was scrubbed...
Name: no disponible
Type: image/jpeg
Size: 24195 bytes
Desc: no disponible
URL: <
https://stat.ethz.ch/pipermail/r-help-es/attachments/20130405/6f13d444/attachment.jpe
------------------------------
_______________________________________________
R-help-es mailing list
R-help-es en r-project.org
https://stat.ethz.ch/mailman/listinfo/r-help-es
Fin de Resumen de R-help-es, Vol 50, EnvÃo 14
*********************************************
-- AVISO LEGAL --
Los datos personales que en esta comunicación aparecen, asà como los que nuestra
empresa mantiene de Vd. y de su empresa, son tratados con la finalidad de mantener
el contacto asà como realizar las gestiones que en esta aparecen (Ley Orgánica
15/1999, de 13 de diciembre, de Protección de Datos de Carácter Personal).
Puede ejercer sus derechos de acceso, rectificación, cancelación y oposición
dirigiéndose a atencion.clientes en tasacionesh.com
La utilización de su dirección de correo electrónico por parte de nuestra empresa
queda sujeta a las disposiciones de la Ley 34/2002, de Servicios de la Sociedad de
la Información y el Comercio Electrónico. Si Vd. recibe comunicación comercial por
nuestra parte y desea dejar de recibirla, rogamos nos lo comunique por vÃa electrónica
a través de la dirección atencion.clientes en tasacionesh.com
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <https://stat.ethz.ch/pipermail/r-help-es/attachments/20130509/b6cf23b4/attachment-0001.html >
------------ próxima parte ------------
A non-text attachment was scrubbed...
Name: no disponible
Type: image/jpeg
Size: 24195 bytes
Desc: no disponible
URL: <https://stat.ethz.ch/pipermail/r-help-es/attachments/20130509/b6cf23b4/attachment-0001.jpe >