jueves, 30 de julio de 2015

La latosa coma decimal europea

[Lenguajes: R]

Problema

La información real proviene de fuentes heterogéneas y como tal, puede contener errores debidos a la mala definición de requerimientos a los responsables de las funtes de información, o a errores conceptuales o de configuración del software empleado en la recabación de información.

Por ejemplo, inexplicablemente, algunas versiones de Microsoft Excel traen como formatos de entrada de números, en el continente americano, la europea coma decimal, en lugar del usual y legal punto decimal. Lo peor del caso, es que, en algún levantamiento de información, sin atender a este aspecto, se conjunta toda la información levantada con diferentes formatos en una sola columna de un archivo, dando lugar a una expresión heterogénea de los números; lo cual puede producir verdaderos dolores de cabeza, sobre todo si el volumen de información es inmenso. ¿Cómo se puede manejar este tipo de errores en R?

Para analizar este problema más de cerca, propongo el siguiente ejemplito de juguete:

Se hizo un censo, y la información se conjuntó en una tabla de Excel con dos columnas, que se leyó en R de la manera siguiente:

tt <- read.csv2("heterogeneo.csv", stringsAsFactors=F)
tt
##   uno    dos
## 1   a    1.2
## 2   b    3.5
## 3   c    6.4
## 4   d   -7.2
## 5   e    5,3
## 6   f    6.8
## 7   g  0,001

Detección del problema

Se nota primeramente que hemos leído la infomación bloqueando la interpretación de los strings de caracteres como factores; esto es, precisamente para tratar los strings de caracteres justamente como strings de caracteres en todo el desarrollo del problema.

Se espera que la columna “dos” de la tabla leída sea de tipo numeric; veamos, sin embargo, qué es lo que resulta al consultar su clase:

## La clase de la columna dos:
class(tt$dos)
## [1] "character"

Esto indica que la lectura no se ha hecho adecuadamente. Al revisar con detalle, se observa que en los renglones 5 y 7 se han puesto comas decimales en lugar de puntos decimales. Esto pudiera no ser evidente en una tabla con un elevado número de renglones. En seguida muestro cómo detectar los lugares exactos del problema:

# Se forza una conversión a "numeric"
nn <- as.numeric(tt$dos)
## Warning: NAs introducidos por coerción
# La operación anterior arroja un **Warning**, pero no interrumpe los
# cálculos.
# En un gran número de renglones la siguiente impresión, posiblemente
# no mostraría los sitios del problema:
nn
## [1]  1.2  3.5  6.4 -7.2   NA  6.8   NA
# Para saber los índices (renglones) exactos de los elementos que han
# causado el problema, se hace así:
is.na(nn) # Vector de lógicos
## [1] FALSE FALSE FALSE FALSE  TRUE FALSE  TRUE
which( is.na(nn) ) # Así se convierte el vector de lógicos a índices
## [1] 5 7

NOTA: El uso de la función which() aplicable a los vectores booleanos se ha ilustrado en un post previo: Transformación de selecciones booleanas en selecciones indexadas.

Solución

La solución del problema es sencilla. Se parte del hecho de que la columna se ha leído como un string de caracteres. La clave es simplemente convertir los caracteres “,” a “.”, en los strings que conforman el vector, de la siguiente manera:

# Guardamos el resultado en la misma columna:
tt$dos <- sub(",", ".", tt$dos, fixed = TRUE)
tt$dos
## [1] " 1.2"   " 3.5"   " 6.4"   " -7.2"  " 5.3"   " 6.8"   " 0.001"

En seguida se ejecuta la conversión de toda la columna a numeric:

# Nuevamente guardamos el resultado en la misma columna:
tt$dos <- as.numeric(tt$dos)
tt
##   uno    dos
## 1   a  1.200
## 2   b  3.500
## 3   c  6.400
## 4   d -7.200
## 5   e  5.300
## 6   f  6.800
## 7   g  0.001
# Y la clase de la columna es:
class(tt$dos)
## [1] "numeric"

Con esto se concluye el ejemplo.


Si quieres ver este mismo post en mis publicaciones de Rpubs:


No hay comentarios.:

Publicar un comentario