16 votos

¿Cómo puedo limpiar los datos de formato incoherente en R?

A menudo me lidiar con desordenado datos de la encuesta que requiere una gran cantidad de limpieza antes de cualquier estadística que se puede hacer. Yo solía hacerlo "manualmente" en Excel, en ocasiones, el uso de fórmulas de Excel y, a veces, la comprobación de las entradas de uno-por-uno. Empecé a hacer más y más de estas tareas, la escritura de scripts para hacer en R, la cual ha sido muy beneficioso (beneficios incluyen tener un registro de lo que se hace, menos posibilidad de errores, y ser capaz de re-utilización de código si el conjunto de datos se actualiza).

Pero todavía hay algunos tipos de datos que tengo problemas para manejar de manera eficiente. Por ejemplo:

> d <- data.frame(subject = c(1,2,3,4,5,6,7,8,9,10,11),
+   hours.per.day = c("1", "2 hours", "2 hr", "2hr", "3 hrs", "1-2", "15 min", "30 mins", "a few hours", "1 hr 30 min", "1 hr/week"))
> d
   subject hours.per.day
1        1             1
2        2       2 hours
3        3          2 hr
4        4           2hr
5        5         3 hrs
6        6           1-2
7        7        15 min
8        8       30 mins
9        9   a few hours
10      10   1 hr 30 min
11      11     1 hr/week

hours.per.day está destinado a ser el número promedio de horas por día en una determinada actividad, pero lo que tenemos es exactamente lo que el sujeto escribió. Supongamos que tomar algunas decisiones sobre qué hacer con respuestas ambiguas, y quiero que la ordenada de la variable hours.per.day2 como sigue.

   subject hours.per.day hours.per.day2
1        1             1      1.0000000
2        2       2 hours      2.0000000
3        3          2 hr      2.0000000
4        4           2hr      2.0000000
5        5         3 hrs      3.0000000
6        6           1-2      1.5000000
7        7        15 min      0.2500000
8        8       30 mins      0.5000000
9        9   a few hours      3.0000000
10      10   1 hr 30 min      1.5000000
11      11     1 hr/week      0.1428571

Suponiendo que el número de casos es bastante grande (digamos 1000) y sabiendo que los sujetos eran libres para escribir cualquier cosa que le gustaba, ¿cuál es la mejor manera de abordar esto?

13voto

Max Gordon Puntos 2361

Me gustaría utilizar gsub() para identificar las cadenas que sé, y quizás después de hacer el resto con la mano.

test <- c("15min", "15 min", "Maybe a few hours", 
          "4hr", "4hour", "3.5hr", "3-10", "3-10")
new_var <- rep(NA, length(test))

my_sub <- function(regex, new_var, test){
    t2 <- gsub(regex, "\\1", test)
    identified_vars <- which(test != t2)
    new_var[identified_vars] <- as.double(t2[identified_vars])
    return(new_var)    
}

new_var <- my_sub("([0-9]+)[ ]*min", new_var, test)
new_var <- my_sub("([0-9]+)[ ]*(hour|hr)[s]{0,1}", new_var, test)

Para conseguir un trabajo con el que usted necesita para cambiar a mano sugiero algo como esto:

# Which have we not found
by.hand <- which(is.na(new_var))

# View the unique ones not found
unique(test[by.hand])
# Create a list with the ones
my_interpretation <- list("3-10"= 5, "Maybe a few hours"=3)
for(key_string in names(my_interpretation)){
    new_var[test == key_string] <- unlist(my_interpretation[key_string])
}

Esto nos da:

> new_var
[1] 15.0 15.0  3.0  4.0  4.0  3.5  5.0  5.0

Regex puede ser un poco difícil, cada vez me estoy haciendo nada con regex puedo ejecutar algunas pruebas sencillas. Se ?regex para el manual. He aquí algunos conceptos básicos de comportamiento:

> # Test some regex
> grep("[0-9]", "12")
[1] 1
> grep("[0-9]", "12a")
[1] 1
> grep("[0-9]$", "12a")
integer(0)
> grep("^[0-9]$", "12a")
integer(0)
> grep("^[0-9][0-9]", "12a")
[1] 1
> grep("^[0-9]{1,2}", "12a")
[1] 1
> grep("^[0-9]*", "a")
[1] 1
> grep("^[0-9]+", "a")
integer(0)
> grep("^[0-9]+", "12222a")
[1] 1
> grep("^(yes|no)$", "yes")
[1] 1
> grep("^(yes|no)$", "no")
[1] 1
> grep("^(yes|no)$", "(yes|no)")
integer(0)
> # Test some gsub, the \\1 matches default or the found text within the ()
> gsub("^(yes|maybe) and no$", "\\1", "yes and no")
[1] "yes"

6voto

lmn Puntos 1

@Max sugerencia es buena. Parece que si usted escribe un algoritmo que reconoce los números así como de tiempo común asociadas a las palabras y abreviaturas, obtendrá la mayor parte del camino. Esto no va a ser hermoso código, pero funciona y se puede mejorar con el tiempo a medida que usted venir a través de un problema.

Pero para una más eficaz (y, en principio, un tiempo) enfoque, intente buscar en Google "análisis de un lenguaje natural, el tiempo de la cadena." Algunas de las conclusiones más interesantes son los de Este abierto de la API de tiempo, un buen módulo de Python, y uno de los muchos relacionados hilos como este en Stack Overflow.

Básicamente, el lenguaje natural de análisis es un problema común y que debe buscar soluciones en otros idiomas aparte del R. Usted puede construir herramientas en otro idioma que usted puede tener acceso mediante R, o, al menos, usted puede obtener buenas ideas para su propio algoritmo.

5voto

AusTravel Puntos 6

R contiene algunas estándar de funciones para la manipulación de datos, que puede ser utilizado para limpieza de los datos, en su base de paquete (gsub, transform, etc.), así como en los diversos paquetes de terceros, tales como stringr, remodelar, reshape2, y plyr. Ejemplos y mejores prácticas de uso de estos paquetes y sus funciones se describen en el siguiente artículo: http://vita.had.co.nz/papers/tidy-data.pdf.

Además, R ofrece algunos paquetes específicamente centrado en la limpieza de los datos y la transformación:

Un enfoque global y coherente para la limpieza de los datos en R, incluyendo ejemplos y el uso de editrules y deducorrect paquetes, así como una descripción de flujo de trabajo (framework) de limpieza de datos en R, se presenta en el siguiente artículo, que recomiendo encarecidamente: http://cran.r-project.org/doc/contrib/de_Jonge+van_der_Loo-Introduction_to_data_cleaning_with_r.pdf.

4voto

AdamSane Puntos 1825

Algo así como que, si era lo suficientemente largo, creo que me gustaría una lista de expresiones regulares y las reglas de transformación, y tomar los nuevos valores a otra columna (para que siempre tenga la oportunidad de ver el doble sin volver a cargar los datos en bruto); el RE, que se aplicarán en orden a la no-tan-lejos-datos transformados hasta que todos los datos fueron transformados o todas las reglas se habían agotado. Es probablemente la mejor manera de mantener una lista de valores lógicos que indican que las filas todavía no se han transformado.

Algunas de esas reglas son obvias, por supuesto, y probablemente va a manejar el 80-90% de los casos, pero el problema es que siempre habrá algunos de ustedes no saben que van a venir (la gente está muy inventiva).

Entonces usted necesita un guión que va a través y presenta los originales de los que aún no se ha transformado-por-la-lista-de-obvio-las reglas de los valores de a uno a la vez, dándole a usted la oportunidad de hacer una expresión regular (por ejemplo) para identificar estos casos y dar una nueva transformación para los casos que se ajusten a ella, que se añade a la lista original y se aplica a los que aún no se han transformado las filas del vector original, antes de comprobar si hay cualquier de los casos para presentar a usted.

También podría ser razonable tener la opción de saltar de un caso (de modo que usted puede ir a más fácil), así que usted puede pus muy duros de los casos hasta el final.

Peor de los casos, hacer un par de a mano.

Puede seguir la lista completa de las reglas de generar, aplicar de nuevo cuando los datos crece o una nueva, similar conjunto de datos que viene.

No sé si es de forma remota acercarse a las mejores prácticas (me gustaría pensar que algo mucho más formal sería necesario), sino en términos de procesamiento de grandes cantidades de datos rápidamente, podría tener algún valor.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X