tag recommendation moz metadescription length descriptions description r

recommendation - Lidiar con fechas desordenadas



tag meta description (5)

El wolfram alpha http://www.wolframalpha.com/ es definitivamente una gran herramienta para hacer ese trabajo.

Al menos, interpreta con éxito alguna entrada desordenada en sus datos. Valdría la pena intentarlo.

No estoy seguro si el sitio es adecuado para un conjunto de datos extremadamente grande, pero si los datos no son tan grandes, será útil.

No es difícil escribir un script automatizado que envíe consultas, obtenga datos y lo analice, aunque no estoy seguro si el sitio permite dicho uso.

Espero que no pensaras que estaba pidiendo consejo de relación.

Con poca frecuencia, tengo que ofrecer a los encuestados la capacidad de especificar cuándo ocurrió un evento. Lo que resulta es una cadena horriblemente desordenada que honestamente simplemente no sé qué hacer. Más allá de la recodificación a mano.

Aquí hay una muestra corta, de miles:

c("May2/ 12 noon", "9:45 am", "11:00 AM AST", "April 27 / 12:00 AST", "11:40 AM AST", "April 25 2011", "April 12th 2011 / 8:44", "April 12 2011 / 8:36am", "April 12 2011 / 8:30am", "April 12th 2011 / 8:18", "April 12 2011 / 8:12am", "April 11th 2011 / 5:57pm", "April 11th 2011 / 5:49pm", "April 11th 2011 / 5:42pm", "April 11th 2011 / 5:36pm", "April 11th 2011 / 5:27", "April 5 @ 11:26am", "8:50", "April 4th 12:45pm", "April 4th around 10am", "April 4th around 10am", "Mar 18, 2011 9:33am", "Mar 18, 2011 9:27am", "df", "fg", "12:16", "9:50", "Feb 8, 2011 / 12:20pm", "8:34 am 2/4/11", "Jan 31, 2011 2:50pm", "Jan 31, 2011 2:45pm", "Jan 31, 2011 2:38pm", "Jan 31, 2011 2:26pm", "11h09", "11:00 am", "1h02 pm", "10h03", "2h10", "Jan 13, 2011 9:50am Van", "Jan 12, 2011", "Jan 12, 2011 3:59pm", "Jan 12 14:19PM", "Jan 12, 2011 1:35pm", "Jan 12,2011 1:28pm", "1h36", "9h15", "9h09", "8h51", "8h45", "8h35", "1h12 pm", "12h59", "11h52 am", "10h45", "15h55", "Dec 31, 10 11:11am", "Dec 31,10 10:15am", "Dec 30, 2010 12:32pm", "Dec 30, 2010 12:18pm", "9:16 am", "11h16 am", "11h12", "9h29 am", "11h38", "Dec 16, 2010", "December 16, 2010", "December 16, 2010", "Dec 15,2010", "DEC 14 2010", "Dec 14 11:38", "Dec 14 11:35", "Dec 14 11:25", "December 13, 2010", "Dec 10, 1:38 pm", "Dec 10, 1:26 pm", "Dec 10, 1:20 pm", "Dec 10, 1:12 pm", "December 9 2010", "11h10 am", "10h59 am", "10:50 am", "Tues Dec 7th, 9:45 Van time", "Dec 3, 2010 12:30pm", "Dec 3, 2010 12:20pm", "Dec 3, 2010 12:10 pm", "November 30, 2010 4.02pm", "November 30, 2010", "november 29 120pm", "November 29 2010 11:27", "10:12am November 29, 2010", "Nov 26/10 1:18pm", "10:56 am", "Nov 24", "nov 24/ 4:20 PM AST", "Nov 24/4:00 PM AST", "NOVEMBER 24/10 2:10 pm", "November 24/10 11:00 a.m.", "12:05 MST", "3.55PM", "Nov. 17/10 12:45 pm", "Nov. 16/10 12:00 noon", "Nov. 16/10 11;50 a.m.", "nov 16/10 11:30 a.m.", "November 12, 2010 @ 12:23pm", "november 11 2010 2:20pm", "November 11 2010 2:15pm", "November 11 2:00pm", "Nov. 10/10:22am", "nov. 8/10...3:19 pm", "Nov 8/10 1;50 p.m.", "November 8/10...12 noon", "November 8/10..10: am", "Nov 5, 2010 1:10 pm", "11:32 am CST", "Nov 4 11:10", "nov 3 10am", "9:30 am", "11/02/2010 1:50PM", "Oct 29/10 2:50PM", "Oct 28 @ 11:20am", "27Oct10 10:40am", "10/26/2010 11:18", "Oct 26/10 11am", "Oct 26/10 10:30 am", "Oct 26 10:50", "10/25/2010 13:50", "10/22/2010 10:15", "Oct 22/10 10AM", "Oct 21, 2010 3:00 pm", "Oct 21, 2010 2:59", "10/21/2010 11:50", "10/21/2010 11:45", "10/21/2010 11:40", "10/21/2010 11:30", "11:30", "Oct 20 approx 1pm", "Oct 20/10 4:50PM", "13:48", "13:45", "Oct 20, 2010 11:45 am", "October 19th 3:05pm", "Oct 18,2010 2:15pm", "Oct 18/10 3:10PM", "10:30 am", "Oct 15/10 11:50am", "oct 14 @ 11:05am", "Oct 14/ 11:06", "4:40 oct 13 atlantic", "oct 13 4:05 pm atlantic", "oct 13 1:45 atlantic time", "Oct 13 / 10:37", "OCT 12 3:33", "Oct 12,2010 1:10pm", "Oct 12 / 11:45", "Oct 12 / 9:45", "Oct 8. 2010/ 2:00", "Oct 8/10- 1145am", "2 Sept 2010 3.52pm", "2 Sept 2010 10.21am", "1 Sept 2010 2.05pm", "1 Sept 2010", "31 Aug 2010 - 11.52am", "31 aug 10:40am", "31 aug 2010 - 10am")

En general, estos eventos ocurren cerca de la fecha en que el encuestado llena la encuesta, pero no siempre. La fecha de la encuesta se registra automáticamente y en un formato uniforme y se puede traducir fácilmente a POSIX usando el as.Date lo tanto, los elementos que solo contienen el tiempo pueden ignorarse y fusionarse con la fecha en que completaron la encuesta.

Tus pensamientos son muy apreciados.

Nota 1: Algunos de ustedes pueden decir que deberían haber hecho X, Y o Z en términos de validar las respuestas. Para ti, digo - demonios sí - la próxima vez. ¡No lo diseñé! Solo tengo que lidiar con eso.

Algunos hechos que pueden ayudar en una solución alternativa:

  • Los horarios siempre serán de día hábil, de 9 a.m. a 6 p.m. (por lo tanto, am / pm no importa)
  • Los años no importan, ya que puedo sacarlos de otro campo (siempre será 2011/2010, que afortunadamente está fuera del posible cronograma en cualquier anotación)
  • No me importan los husos horarios, ya que tengo su ubicación geográfica

Lo que he hecho hasta ahora

mos <- strsplit('' jan feb mar apr may jun jul aug sep oct nov dec january february march april may june july august september october november december '', ''/n'')[[1]][-1] days <- strsplit('' mon tue wed thu fri sat sun monday tuesday wednesday thursday friday saturday sunday '', ''/n'')[[1]][-1] ## Messy Date Wrangling x <- ## that hot ghetto mess above # minimize x <- tolower(x) # remove unnecessary crap x <- sub("2011"," ",x) x <- sub("2010"," ",x) x <- sub("am"," ",x) x <- sub("pm"," ",x) x <- sub("[p][.][m]"," ",x) x <- sub("[a][.][m]"," ",x) x <- sub("[.]{3}"," ",x) x <- str_trim(x, side="both") # divide x <- strsplit(x,c(" ")) # conquer? lapply(x, function(x) pmatch(x,mos)) lapply(x, function(x) pmatch(x,days))


Este puede ser uno de los pocos casos en que otra herramienta distinta de R es la mejor para usar. Sé que hay algunos módulos para Perl que ya se han desarrollado para analizar fechas de aspecto desordenadas, en el módulo DateTime :: Format :: Natural :: Lang :: EN se pueden analizar cadenas como: "1st martes pasado noviembre". Me parece recordar otro módulo que podría entender cosas como "el segundo martes después del primer lunes de febrero".

También hay una herramienta en http://www.datasciencetoolkit.org/ que capta lo que parecen fechas en el texto y los convierte a un formato estándar.


Expreso mi simpatía por que su cita no haya resultado tan bonita como se esperaba. ;-)

He construido una solución (aún parcial) siguiendo las líneas sugeridas por @Rguy.

(Tenga en cuenta que este código todavía tiene un error: no siempre devuelve la hora correcta. Por alguna razón, no siempre hace una coincidencia codiciosa en los dígitos antes del colon, por lo tanto, a veces regresa a la 1:00 cuando el tiempo son las 11:00)

Primero, construye una función auxiliar que envuelve gsub y grep . Esta función toma un vector de caracteres como uno de sus argumentos y lo colapsa en una sola cadena separada por |. El efecto de esto es permitirle pasar fácilmente varios patrones para que coincida con una expresión regular:

find.pattern <- function(x, pattern_list){ pattern <- paste(pattern_list, collapse="|") ret <- gsub(paste("^.*(", pattern, ").*", sep=""), "//1", x, ignore.case=TRUE) ret[ret==x] <- NA ret2 <- grepl(paste("^(", pattern, ")$", sep=""), x, ignore.case=TRUE) ret[ret2] <- x[ret2] ret }

A continuación, use algunos nombres de variables incorporados para construir un vector de meses y abreviaturas:

all.month <- c(month.name, month.abb)

Finalmente, construya un marco de datos con diferentes extractos:

ret <- data.frame( data = dat, date1 = find.pattern(dat, "//d+///d+///d+"), date2 = find.pattern(dat, paste(all.month, "//s*//d+[(th)|,]*//s{0,3}[(2010)|(2011)]*", collapse="|", sep="")), year = find.pattern(dat, c(2010, 2011)), month = find.pattern(dat, month.abb), #Use base R variable called month.abb for month names hour = find.pattern(dat, c("//d+[//.:h]//d+", "12 noon")), ampm = find.pattern(dat, c("am", "pm")) )

Los resultados:

head(ret, 50) data date1 date2 year month hour ampm 20 April 4th around 10am <NA> April 4th <NA> Apr <NA> am 21 April 4th around 10am <NA> April 4th <NA> Apr <NA> am 22 Mar 18, 2011 9:33am <NA> Mar 18, 2011 2011 Mar 9:33 am 23 Mar 18, 2011 9:27am <NA> Mar 18, 2011 2011 Mar 9:27 am 24 df <NA> <NA> <NA> <NA> <NA> <NA> 25 fg <NA> <NA> <NA> <NA> <NA> <NA> 26 12:16 <NA> <NA> <NA> <NA> 12:16 <NA> 27 9:50 <NA> <NA> <NA> <NA> 9:50 <NA> 28 Feb 8, 2011 / 12:20pm <NA> Feb 8, 2011 2011 Feb 2:20 pm 29 8:34 am 2/4/11 2/4/11 <NA> <NA> <NA> 8:34 am 30 Jan 31, 2011 2:50pm <NA> Jan 31, 2011 2011 Jan 2:50 pm 31 Jan 31, 2011 2:45pm <NA> Jan 31, 2011 2011 Jan 2:45 pm 32 Jan 31, 2011 2:38pm <NA> Jan 31, 2011 2011 Jan 2:38 pm 33 Jan 31, 2011 2:26pm <NA> Jan 31, 2011 2011 Jan 2:26 pm 34 11h09 <NA> <NA> <NA> <NA> 11h09 <NA> 35 11:00 am <NA> <NA> <NA> <NA> 1:00 am 36 1h02 pm <NA> <NA> <NA> <NA> 1h02 pm 37 10h03 <NA> <NA> <NA> <NA> 10h03 <NA> 38 2h10 <NA> <NA> <NA> <NA> 2h10 <NA> 39 Jan 13, 2011 9:50am Van <NA> Jan 13, 2011 2011 Jan 9:50 am 40 Jan 12, 2011 <NA> Jan 12, 2011 2011 Jan <NA> <NA>


No voy a intentar escribir la función en este momento, pero tengo una idea que podría funcionar.

Busque en cada cadena un número de 4 dígitos para llamar al año.

Use grep para buscar en cada cadena las primeras 3 letras de la abreviatura de los meses. Parece que casi todos sus datos (al menos arriba) tienen un identificador como ese. Almacenaba el valor que se encuentra en un vector de "meses" y ponía espacios en blanco donde no se encuentra ningún valor. Aquí hay una versión realmente fea del código (haré esto más eficiente más tarde, ¡y agregaré el caso cuando el mes no esté en mayúscula!)

mos <- c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec") blah <- lapply(1:12, function(i) grepl(mos[i], test)) lapply(blah, function(i) which(i)) months <- 0*(1:length(test)) for (i in 1:12) { months[blah[[i]]] <- i } months [1] 5 0 0 4 0 4 4 4 4 4 4 4 4 4 4 4 4 0 4 4 4 3 3 0 0 0 0 2 0 1 [31] 1 1 1 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 12 12 12 12 0 [61] 0 0 0 0 12 12 12 12 0 12 12 12 12 12 12 12 12 12 0 0 0 12 12 12 12 11 11 0 11 11 [91] 11 0 11 0 11 0 11 0 0 11 11 11 0 11 0 11 11 11 0 11 11 11 11 0 11 0 0 0 10 10 [121] 10 0 10 10 10 0 0 10 10 10 0 0 0 0 0 10 10 0 0 10 10 10 10 0 10 0 10 0 0 0 [151] 10 0 10 10 10 10 10 9 9 9 9 8 0 0

El "día" más comúnmente sigue la palabra usada para el mes inmediatamente. Entonces, si hay un número de uno o dos dígitos después del mes (que es el carácter), extraiga ese número y llámelo el día.

Los tiempos suelen tener el ":" o "." símbolo en ellos, y así buscar cada cadena para ese personaje. Si se encuentra en una cadena, crea un vector "Tiempo" con todos los dígitos inmediatamente antes y después de ese carácter (en teoría, incluyendo 2 antes y 2 después no deberían causar un problema). Coloque espacios en blanco siempre que el símbolo no esté presente. Sería bueno si todos los datos estuvieran confinados definitivamente a un período <12 horas, porque entonces no tendrás que preocuparte por AM y PM. Si no, tal vez busque también "AM" y "PM" en la cadena.

Luego, intente convertir las cadenas que tienen las cuatro de las anteriores a POSIXct. Los que no se convierten, tendrá que ingresar manualmente, por supuesto. Creo que me llevaría unas horas codificar la función descrita anteriormente y, dependiendo de la variabilidad y el tamaño de su conjunto de datos, puede o no valer la pena el esfuerzo. Además, existe cierto riesgo de resultados incorrectos, por lo que agregar un intervalo de tiempo aceptable ayudaría a evitar eso.

En resumen, parece que va a tener que codificar una función con muchas excepciones y luego terminar codificando manualmente una buena parte de las veces de todos modos. Aunque espero que alguien pueda ofrecerte una mejor solución.

¡Buena suerte!


Otros ya han abordado enfoques y paquetes estándar. Tomaré una perspectiva diferente. El uso de expresiones regulares y formatos fijos te permitirá obtener la mayor parte del camino. Por lo demás, me limitaría a abordarlo como lo haría con cualquier problema en "coincidencia de patrones": métodos estadísticos o aprendizaje automático. Ya ha especificado los intervalos de fecha y hora, y la marca de tiempo de los registros también es informativa. Al extraer una gran cantidad de funciones de texto (aquí es donde las expresiones regulares resultarían útiles), podría tratar de asignar a los tiempos de interés.

Solo hay tres cosas que hacer para que esto funcione:

  1. Extracción de características
  2. Generación de conjuntos de entrenamiento
  3. Construye y despliega modelos

Construye y despliega modelos? Permítanme presentarles a mi amigo R y la vista de la tarea de aprendizaje automático . :) Los modelos básicos para explorar incluyen modelos multinomiales (echa un vistazo a glmnet ), árboles de decisión y máquinas de vectores de soporte. Puede usar árboles de decisión y SVM como entradas para un modelo multinomial (y los SVM pueden no ser necesarios después de todo). Para ser honesto, esta parte es nebulosa: uno podría hacer este modelo como componentes de fecha desconectados o como un proceso de refinamiento, por ejemplo, obtener el año, si es posible, luego los minutos (porque el rango es mucho mayor que por horas, días, meses) ), luego día del mes y finalmente horas y meses. Básicamente, me gustaría tratar de identificar "partes del tiempo" (análogas a partes del discurso) para los componentes numéricos / de cuerda.

Extracción de características: probaría las divisiones con dos puntos, comas, barras, guiones, puntos, etc. Todo lo que no sea un valor numérico. Luego crearía conjuntos de datos basados ​​en las características en orden y en cualquier orden (es decir, un valor indicador de las características vistas, ignorando las posiciones).

Datos de entrenamiento: Mechanical Turk de Amazon.

O bien, ya sabes, ignora toda esa programación y palabrería estadística y envía todo a Mechanical Turk. :)