Manipulación y limpieza de datos. Data OPEC
Beatriz Valdez
Introducción
El análisis de datos se ha convertido en una herramienta fundamental para la toma de decisiones informadas en diversos sectores. La limpieza y el procesamiento de datos representan un desafío significativo en el análisis de datos.Se estima que esta actividad puede consumir hasta el 75% del tiempo total del análisis.
No es fácil automatizar completamente la limpieza de datos. Cada base de datos, cada marco de datos, presenta características únicas y desafíos específicos. Esta diversidad dificulta la creación de procedimientos generales y automatizados para la limpieza. No obstante,la identificación de patrones comunes en datos provenientes de la misma fuente puede contribuir a optimizar las estrategias de limpieza y procesamiento.
En este post comparto los procedimientos que he seguido para limpiar datos obtenidos desde la página web de la OPEP. La aproximación que he tomado para limpiar la data no es necesariamente la mejor, ni la más elegante, para cada caso, pero me han sido útiles para obtener la data en la forma en que la necesito para el análisis.
Preprocesamientos
Funciones útiles
Cuando en nuestro marco de datos hay caracteres extraños, R transforma automáticamente toda la variable en tipo caracter o en factor. Por ejemplo:
head(opecOilPro[,1:2],12)
## pais X1960
## 1 Algeria 181.1
## 2 Angola 1.1
## 3 Ecuador 7.5
## 4 IR.Iran 1,067.7
## 5 Iraq 972.2
## 6 Kuwait1 1,691.8
## 7 Libya â<U+0080><U+0093>
## 8 Nigeria 17.4
## 9 Qatar 174.6
## 10 Saudi.Arabia1 1,313.5
## 11 UAE â<U+0080><U+0093>
## 12 Venezuela 2,846.1
#verifico la clase de las variables
apply(opecOilPro, 2, class)
## pais X1960 X1970 X1980 X1990 X2000
## "character" "character" "character" "character" "character" "character"
## X2010
## "character"
También se observa que se mezclan regiones y países. Genero entonces una función que me permita solucionar tanto el tipo de variables como la separación de los países de las regiones
# para eliminar caracteres en general
sacaExtranio <-function(x, patron) as.numeric(gsub(",", "", x))
# eliminar solo comas
saca<-function(x) as.numeric(gsub(",", "", x))
Aquí se observa con mayor claridad que las regiones están mezcladas con los países:
head(worldConsuPPet)
## pais.region X2006 X2007 X2008 X2009 X2010 X.change10.09
## 1 North.America 22,613.4 22,642.1 21,377.6 20,586.8 21,114.9 2.6
## 2 Canada 2,208.7 2,261.6 2,197.9 2,108.7 2,188.1 3.8
## 3 United.States 20,402.1 20,377.8 19,177.1 18,475.5 18,924.2 2.4
## 4 Othersna 2.7 2.7 2.6 2.6 2.6 2.3
## 5 Latin.America 7,014.4 7,355.8 7,548.8 7,583.1 7,836.3 3.3
## 6 Argentina 501.3 550.1 562.9 565.9 589.7 4.2
Adicionalmente, hay una columna que posiblemente no me sea de utilidad. Creo una función para solucionar esto. Puedo unir la solución de este problema con el del anterior
arregla<-function(x, eliminar, numericas){
# elimino columna
x <-x[,-eliminar]
#transformo en numerico
x[, numericas] <- sapply(x[, numericas], saca)
return(x)
}
extraer <-function(x, accion, valor){
switch(accion,
pais = x[- valor,],
region= x[valor,],
otros = x[- valor]
)
}
En algunos análisis necesitaré apilar la data y luego sacar algunos países o regiones específicas
apilar <-function(x){
#cambio el nombre
names(x)[2:6]<-c(2006:2010)
pRegiones<-stack(x[2:6])
names(pRegiones)<-c(rep(x[,1],
nrow(pRegiones)/nrow(x)))
return(pRegiones)
}
listadoRegiones<-function(apilado){
a<-pRegiones[which(pRegiones$pais=="North.America"),]
b<-pRegiones[which(pRegiones$pais=="Latin.America"),]
c<-pRegiones[which(pRegiones$pais=="Eastern.Europe"),]
d<-pRegiones[which(pRegiones$pais=="Western.Europe"),]
e<-pRegiones[which(pRegiones$pais=="Middle.East"),]
f<-pRegiones[which(pRegiones$pais=="Asia.and.Pacific"),]
return(list(a=a,b=b,c=c,d=d,e=e,f=f))
}
Puedo unir algunos de los procedimientos anteriores para extraer en bloque información o para analizar en bloque:
dos <- function(...){
data <- list(...)
n<- length(data)
d1 <- list()
for (i in 1:n) {
d1[[i]]<-arregla(data[[i]], 7, c(2:6))
}
return(d1)
invisible(NULL)
}
Para extraer las regiones y los países:
reg <-c("North.America","Latin.America",
"Netherland.Antilles", "Eastern.Europe",
"Western.Europe", "Middle.East", "AsiaandPacific")
l<-function(df) df[df$pais.region %in% reg,]
tres <-function(lista){
n<- length(lista)
d1 <- list()
for(i in 1:n){
d1[[i]]<-l(lista[[i]])
}
return(d1)
invisible(NULL)
}
l2<-function(df) df[!df$pais.region %in% reg,]
cuatro <-function(lista){
n<- length(lista)
d1 <- list()
for(i in 1:n){
d1[[i]]<-l2(lista[[i]])
}
return(d1)
invisible(NULL)
}
Aplicación al Pre-procesamiento
Con la funcion dos que he creado transformo rápidamente los ocho marcos de datos, eliminando caracteres extraños y transformando la data en numérica
limpios1 <-dos(reservas, OilWorldPrd, opecRigs,
worldRefineryCap, worldOoutpuPet,
worldConsuPPet, worldOilExport,
worldExportPP, worldImportP, worldImportPP)
titulos <-list("reservas.prob","produccion.petroleo",
"balancines", "capacidad.refin",
"derivados.pet", "consumo.deriv",
"export.crudo", "export.der",
"export.crudo", "importaciones.crud"
)
names(limpios1)<-titulos
verifico:
# primeras seis observaciones del primer marco de datos
head(limpios1[[1]])
## region.pais X2006 X2007 X2008 X2009 X2010
## 1 North.America 26699 25872 26217 24021 24021
## 2 Canada 4942 4900 4900 4900 4900
## 3 United.States 21757 20972 21317 19121 19121
## 4 Latin.America 124256 137421 210210 248820 334881
## 5 Argentina 2468 2587 2616 2520 2505
## 6 Brazil 12182 12624 12624 12802 12857
# cuantos marcos de datos he pre-procesado
length(limpios1)
## [1] 10
Extraigo ahora las regiones e inspecciono el segundo marco de datos creado
regiones1 <- tres(limpios1)
head(regiones1[[2]])
## pais.region X2006 X2007 X2008 X2009 X2010
## 1 North.America 6447.8 6452.6 6299.2 6577.5 6718.3
## 4 Latin.America 10077.8 9835.9 9635.2 9506.8 9664.4
## 15 Eastern.Europe 11532.4 12003.7 12039.5 12386.6 12644.2
## 23 Western.Europe 4501.5 4319.9 4046.5 3817.5 3522.1
## 33 Middle.East 22900.8 22361.6 23141.6 20868.5 21026.4
Extraigo los paises e inspecciono el cuarto marco de datos creado
regiones2 <-cuatro(limpios1)
head(regiones2[[4]])
## pais.region X2006 X2007 X2008 X2009 X2010
## 2 Canada 2041.2 1969.5 2029.5 2039.3 1902.0
## 3 United.States 17272.6 17447.2 17379.7 17763.5 17869.2
## 5 Argentina 624.6 626.1 626.1 627.1 627.1
## 6 Brazil 1908.3 1908.3 1908.3 1908.3 1908.3
## 7 Colombia 285.9 285.9 285.9 285.9 290.9
## 8 Ecuador 176.0 188.4 188.4 188.4 188.4
tail(regiones2[[4]])
## pais.region X2006 X2007 X2008 X2009 X2010
## 47 Australia 704.7 701.1 707.1 724.7 757.2
## 48 Total.world 86653.1 87362.4 87476.1 88272.9 88677.3
## 49 OPEC 8261.3 8286.8 8352.5 8575.2 8819.2
## 50 OPEC.percentage 9.5 9.5 9.5 9.7 9.9
## 51 OECD 45023.2 45053.2 45138.9 45592.9 46053.6
## 52 FSU 8261.0 8311.0 8015.0 8015.0 8196.0
Todavia debo eliminar algunos casos: OPEC, OPEC.percentage, OCDE y FSU:
reg<- c("Total.world","OPEC", "OPEC.percentage",
"OECD", "FSU")
reg2Limpia <-cuatro(regiones2)
tail(reg2Limpia[[3]])
## [1] pais X2006 X2007 X2008 X2009 X2010
## <0 rows> (or 0-length row.names)
En los productos derivados del petróleo generados por los países OPEP tenemos también mezclados las variables que nos dan cuenta de los productos, con aquellas que nos dan cuenta del país.
head(opecProd, 12)
## region.pais X2006 X2007 X2008 X2009 X2010 X.change10.09
## 1 Algeria 451.2 501.8 516.5 411.6 631.5 53.4
## 2 Gasoline 49.4 44.8 60.9 60.9 69.5 14.1
## 3 Kerosene 20.9 22.6 21.6 57.2 34.1 â<U+0080><U+0093>40.3
## 4 Distillates 138.2 141.4 178.0 166.5 180.7 8.5
## 5 Residuals 100.9 104.3 121.6 92.6 118.7 28.2
## 6 Others 141.7 188.7 134.5 34.3 228.5 565.5
## 7 Angola 49.8 60.6 47.8 46.2 47.0 1.7
## 8 Gasoline 1.5 1.4 1.8 0.9 1.3 52.6
## 9 Kerosene 6.3 7.6 7.0 10.0 8.5 â<U+0080><U+0093>15.0
## 10 Distillates 9.3 10.5 10.8 10.4 10.6 1.6
## 11 Residuals 10.5 11.3 11.0 13.7 12.4 â<U+0080><U+0093>9.9
## 12 Others 22.3 29.8 17.2 11.2 14.2 27.0
En este caso, aplicar cualquiera de las funciones anteriores no nos daría resultado porque los nombres de las variables no son únicos. Así, por ejemplo, “Gasolina” se repite 12 veces, por tanto, la variable es, digamos, ambigua. Es necesario, por consiguiente particularizar los nombres, de forma tal que, además, nos permita conservar los valores de la producción para cada país
# elimino la columna 7
opecProd <-opecProd[, -7]
#agrego una nueva variable
pais<-rep(c("Algeria", "Angola","Ecuador","Iran",
"Iraq", "Kuwait", "Libya",
"Nigeria", "Qatar", "Saudi.Arabia",
"Arab.Emirates","Venezuela"), each=6)
# creo un data frame para manipularlo
opepProd <-data.frame(pais, opecProd)
# extraigo la produccion agregada
produccionTotal <-opepProd[
which(opepProd$region.pais == pais),]
head(produccionTotal)
## pais region.pais X2006 X2007 X2008 X2009 X2010
## 1 Algeria Algeria 451.2 501.8 516.5 411.6 631.5
## 7 Angola Angola 49.8 60.6 47.8 46.2 47.0
## 13 Ecuador Ecuador 133.0 170.2 194.3 189.3 185.1
## 19 Iran Iran 1447.9 1498.0 1587.0 1726.1 1743.3
## 25 Iraq Iraq 484.2 480.8 453.2 456.6 513.2
## 31 Kuwait Kuwait 886.7 877.4 1003.2 892.7 979.4
#Elimino la primera fila
produccionTotal<-produccionTotal[,-1]
# extraigo los productos
productosOpec <-opepProd[
which(opepProd$region.pais != pais),]
head(productosOpec)
## pais region.pais X2006 X2007 X2008 X2009 X2010
## 2 Algeria Gasoline 49.4 44.8 60.9 60.9 69.5
## 3 Algeria Kerosene 20.9 22.6 21.6 57.2 34.1
## 4 Algeria Distillates 138.2 141.4 178.0 166.5 180.7
## 5 Algeria Residuals 100.9 104.3 121.6 92.6 118.7
## 6 Algeria Others 141.7 188.7 134.5 34.3 228.5
## 8 Angola Gasoline 1.5 1.4 1.8 0.9 1.3
# creo una nueva variable uniendo pais y producto
productos<-paste0(substring(productosOpec$pais, 1, 4),".",
productosOpec$region.pais)
productosOpep <-data.frame(productos, productosOpec[,3:7])
head(productosOpep)
## productos X2006 X2007 X2008 X2009 X2010
## 2 Alge.Gasoline 49.4 44.8 60.9 60.9 69.5
## 3 Alge.Kerosene 20.9 22.6 21.6 57.2 34.1
## 4 Alge.Distillates 138.2 141.4 178.0 166.5 180.7
## 5 Alge.Residuals 100.9 104.3 121.6 92.6 118.7
## 6 Alge.Others 141.7 188.7 134.5 34.3 228.5
## 8 Ango.Gasoline 1.5 1.4 1.8 0.9 1.3
Con respecto a los pozos y los pozos productivos:
head(opecWells,2)
## pais X2006 X2007 X2008 X2009 X2010 change10.09
## 1 Algeria 302 260 249 265 258 â<U+0080><U+0093>7
## 2 Angola 57 75 99 60 118 58
head(opecPWells, 2)
## pais X2006 X2007 X2008 X2009 X2010 change10.09
## 1 Algeria 1.580 1.79 2.028 2.028 2.014 â<U+0080><U+0093>14
## 2 Angola 1.183 1.25 1.321 1.321 1.325 4
# elimino la columna 7
opecWells <-opecWells[,-7]
opecPWells <-opecPWells[,-7]
Finalmente, tengo el marco de datos con los balancines disponibles en el mundo:
head(opecRigs)
## pais X2006 X2007 X2008 X2009 X2010 change10.09
## 1 North.America 2,174 2,171 2,143 1,485 2,109 624
## 2 Canada 456 360 361 313 398 85
## 3 United.States 1,718 1,811 1,782 1,172 1,711 539
## 4 Latin.America 328 389 424 426 424 â<U+0080><U+0093>2
## 5 Argentina 81 87 70 55 61 6
## 6 Bolivia 3 2 3 4 5 1
# elimino columna 7 y transformo en numérica variables 2 al 6
balancines<-arregla(opecRigs, 7, c(2:6))
head(balancines)
## pais X2006 X2007 X2008 X2009 X2010
## 1 North.America 2174 2171 2143 1485 2109
## 2 Canada 456 360 361 313 398
## 3 United.States 1718 1811 1782 1172 1711
## 4 Latin.America 328 389 424 426 424
## 5 Argentina 81 87 70 55 61
## 6 Bolivia 3 2 3 4 5
# extraigo los balancines según región y paises
reg <-c("North.America","Latin.America",
"Netherland.Antilles", "Eastern.Europe",
"Western.Europe", "Middle.East", "AsiaandPacific")
balancines.reg<-balancines[balancines$pais %in% reg,]
head(balancines.reg,3)
## pais X2006 X2007 X2008 X2009 X2010
## 1 North.America 2174 2171 2143 1485 2109
## 4 Latin.America 328 389 424 426 424
## 14 Eastern.Europe 297 409 509 473 400
# balancines por países
balancines.pais<-balancines[!balancines$pais %in% reg,]
head(balancines.pais)
## pais X2006 X2007 X2008 X2009 X2010
## 2 Canada 456 360 361 313 398
## 3 United.States 1718 1811 1782 1172 1711
## 5 Argentina 81 87 70 55 61
## 6 Bolivia 3 2 3 4 5
## 7 Brazil 33 46 59 66 75
## 8 Chile 1 2 1 4 3
En el caso particular de esta data, ya he hecho las principales limpiezas. Haría falta eliminar la X
de los años. R suele agregar esa letra al inicio de los encabezados de las variables que se inician con números. Completada la limpieza, la data está lista para explorarla, efectuar limpiezas adicionales,las transformaciones necesarias y analizarla. El corolario obligado es que vale la pena planificar también el pre-procesamiento, creado funciones que faciliten la limpieza de la data, cuando tal cosa sea posible y, de serlo, entonces, aplicar pre-procesamientos en bloque.
No hay comentarios.:
Publicar un comentario