Lectura de ficheros

Ficheros CSV

Carga de un fichero que CSV, separados por “;” y con separador decimal de “,” podemos usar varias funciones:

auto <- read.csv("../DataSets/auto-mpg.csv", 
                 header = TRUE, sep = ",",
                 stringsAsFactors = FALSE)
# o
#read.csv2 == read.csv("filename", sep = ";", dec = ",")
# sep = "\t" (¡¡¡En el vídeo me olvidé la barra!!!)

Cargando archivos directamente de una URL:

who_from_internet <- read.csv("https://frogames.es/course-contents/r/intro/tema1/WHO.csv") # do not work

Ficheros de un XML

Extrayendo información dentro de una página web. Normalmente está en dos formatos:

  1. XML

  2. Json

Cargaamos el fichero de XML que usaremos:

library(XML)
url <- "../DataSets/cd_catalog.xml"

El fichero que se ha creado es distinto a la formato de data frame. Vamos a usar las siguientes funciones para leerlo correctamente:

xmldoc <- xmlParse(url) #XMLInternalDocument es una posición de memória para localizar el documento, una estrucutra a nivel interno  programada en C
rootnode <- xmlRoot(xmldoc) # recuperamos el nodo raíz del XML, para trabajar con un archivo en C
rootnode[2] # accedemos al elemento que  queramos del nodo raíz
## $CD
## <CD>
##   <TITLE>Hide your heart</TITLE>
##   <ARTIST>Bonnie Tyler</ARTIST>
##   <COUNTRY>UK</COUNTRY>
##   <COMPANY>CBS Records</COMPANY>
##   <PRICE>9.90</PRICE>
##   <YEAR>1988</YEAR>
## </CD> 
## 
## attr(,"class")
## [1] "XMLInternalNodeList" "XMLNodeList"

Debemos leer y extraer dentro del XML. Vámos a extraer esos datos, para eso debemos hacer la siguiente función:

cds_data <- xmlSApply(rootnode, function(x) xmlSApply(x, xmlValue)) # x simboliza cada uno de los valores del XML, y aplicamos xmlValue para extraer los valores del XML
cds.catalog <- data.frame(t(cds_data), row.names = NULL) # pmodificamos el formato para darle una forma tratable, por eso vamos a hacer una transposición con la función t(),  avisando que las filas no tienen nombre.
cds.catalog[1:5,]

Dos buenas funciones para trabajar con lectura de XML y webs:

  • xpathSApply()
  • getNodeSet()

Leyendo tablas incrustadas en un HTML

Vamos a trabajar con un caso real para ver como extraer información de un página web.

population_url <- "../DataSets/WorldPopulation-wiki.htm"
tables <- readHTMLTable(population_url) # le pasams la url préviamente creada

most_populated <- tables[[6]] # indicamos a que tabla queremos acceder
head(most_populated, 3) 
custom_table <- readHTMLTable(population_url, which = 6) # indicamos la tabla específicaa que queremos extraer, evitando que extraigamos toda la información de la página web.

Leyendo datos desde un JSON

JSON (Java script) usaremos el paquete jsonlite:

library(jsonlite)

Cargamos los ficheros json:

dat.1 <- fromJSON("../DataSets/students.json")
dat.2 <- fromJSON("../DataSets/student-courses.json")

Cargando ficheros JSON a través de una API

Pdemos cargar ficheros json a través de apis, por ejemplo la de yahoo. Para hacer esto haremos uso del paquete “curl”:

library(curl)
url <- "http://www.floatrates.com/daily/usd.json"
currencies <- fromJSON(url) # avisamos que cargamos directamente desde un fitxero JSON
head(currencies, 1)
## $eur
## $eur$code
## [1] "EUR"
## 
## $eur$alphaCode
## [1] "EUR"
## 
## $eur$numericCode
## [1] "978"
## 
## $eur$name
## [1] "Euro"
## 
## $eur$rate
## [1] 0.8765859
## 
## $eur$date
## [1] "Wed, 21 Nov 2018 00:00:01 GMT"
## 
## $eur$inverseRate
## [1] 1.14079
# Seleccionando los datos para crear un dataframe
# currency.data <- currencies$list$resources$resource$fields

Sigamos trabajando con el fichero json que hemos cargado previamente. Podemos ver que tiene el mismo formato que un dataframe cargado a partir de un csv:

Los ficheros de ancho fijo

Archivos con un ancho fijado. Ejemplos de carga:

students_data <- read.fwf("../DataSets/student-fwf.txt",
                         widths=c(4, 15, 20, 15, 4), # añadimos los espacios que ocupan cada columna
                         col.names = c("id", "nombre", "email", 
                                       "carrera", "año") # añadimos las cabezeras
                         )
head(students_data)

En el caso anterior hemos dicho de forma implicita que hay 5 columnas (hemos especificado 5 espacios).

Pero también podemos especificar los parámetros cuando no las cabeceras no siguen los mismos parámetros que los valores de las columnas

students_data_header <- read.fwf("../DataSets/student-fwf-header.txt",
                                 widths = c(4,15,20,15,4),
                                 header = TRUE, sep = "\t", # especificamo que los headers son distintos, usamos "\t" para especificar que la separación es un tabulador
                                 skip = 2) # saltamos 2 lineas para no introducir los datos

Podemos también excluir algunas columnas, poniendo su valor en negativo:

students_data_no_email <- read.fwf("../DataSets/student-fwf.txt",
                          widths=c(4, 15, -20, 15, 4), # introducimos el valor negativo
                          col.names = c("id", "nombre", 
                                        "carrera", "año") # quitamos el nombre que no se incluye
)

Creando y cargando ficheros de Rdata y rds

Ideal para enviar ficheros en R. Creamos el dataset, unos pedidos donde introduciré el cliente, la fecha de pedido y el pago.

clientes <- c("Juan Gabriel", "Ricardo", "Pedro")
fechas <- as.Date(c("2017-12-27", "2017-11-1", "2018-1-1")) # formato fecha
pago <- c(315, 192.55, 40.15)
pedidos <- data.frame(clientes, fechas, pago) # añadimos los nombres de los vectores que hemos creado

Guardamos el fichero que hemos creado:

save(pedidos, file = "../DataSets/pedidos.Rdata")
saveRDS(pedidos, file="../DataSets/pedidos.rds") # se puede guardar en formato en RDS, otro formato para guardar los ficheros

# remove(pedidos) # eliminar un objeto creado

Podemos guardar también varios objetos dentro de este fichero, po ejemplo se creamos una lista de clientes VIP:

clientes_vip <- c("Juan Gabriel", "Ricardo")
save(pedidos, clientes_vip, file = "../DataSets/pedidos.Rdata") # guardamos los dos objetos dentro de este fichero.

Carga del archivo Rdata directamente con la función load():

load("../DataSets/pedidos.Rdata")

Para cargar ficheros RDS usamos la función RDS. A diferencia de un Rdata se debe especificar el objeto donde se va a guardar:

orders <- readRDS("../DataSets/pedidos.rds")

Podemos guardar todos los objetos de una sesión podemos usar todos los objetos de una sesión, muy útil para trabajos colavorativos:

save.image(file = "../DataSets/alldata.Rdata")
primes <- c(2,3,5,7,11,13)
pow2 <- c(2,4,8,16,32,64,128)
save(list = c("primes", "pow2"), file = "../DataSets/primes_and_pow2.Rdata") # podemos usar la función list para agrupar la función- 

attach("../DataSets/primes_and_pow2.Rdata") # avisarme cuand los objetos ya existen y queremos ser notificados, usamos la sentencia attach(), en este caso nos avisa.
## The following objects are masked _by_ .GlobalEnv:
## 
##     pow2, primes

Trato de los valores de NA

Como tratar los #NA (Not available):

data <- read.csv("../DataSets/missing-data.csv", na.strings = "")

Tratamos los datos:

data.cleaned <- na.omit(data) # usamos la fucnión que eliminara las filas donde hayan NAs

# Internamente na.omit() usa la función is.na() donde nos comprueva si un vector contiene los valores NA. 
is.na(data[4,2])
## [1] TRUE
is.na(data[4,1])
## [1] FALSE
is.na(data$Income)
##  [1] FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE FALSE
## [12] FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [23] FALSE FALSE FALSE FALSE FALSE

Limpieza selectiva de NA

Podemos crear un data frame donde se hayan extraido solamente los NA de una columna

#Limpiar NA de solamente la variable Income
data.income.cleaned <- data[!is.na(data$Income),]
#Filas completas para un data frame
complete.cases(data)
##  [1]  TRUE  TRUE  TRUE FALSE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE
## [12]  TRUE FALSE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE
## [23]  TRUE  TRUE  TRUE  TRUE  TRUE
data.cleaned.2 <- data[complete.cases(data), ] # coomplete cases nos dice si las filas estan completas de datos o no, en el caso que hayan NAs nos dará FALSE
#Convertir los ceros de ingresos en NA
data$Income[data$Income == 0] <- NA

En el caso que quisieramos calcular los valores como media o desviación típica de un data frame que contiene NA, debemos avisarle que los contiene para conseguir los valores buscados. Lo haremos con la orden “na.rm = TRUE” donde pediremos que quite los valores Not avaiable:

#Medidas de centralización y dispersión
mean(data$Income)
## [1] NA
mean(data$Income, na.rm = TRUE) 
## [1] 65763.64
sd(data$Income)
## [1] NA
sd(data$Income, na.rm = TRUE)
## [1] 26715.87

Rellenar NA con la media o con valores aleatorios

Si queremos rellenar NA con la media, podemos usar la funci?n ifelse () para que vaya hiendo por toda la columna y solo sustituyendo los valores NA por la media. Creeamos una nueva columna para hacer la operación:

data <- read.csv("../DataSets/missing-data.csv", na.strings = "")
data$Income.mean <- ifelse(is.na(data$Income), 
                           mean(data$Income, na.rm = TRUE), # reemplaca NA por la media
                           data$Income #Si no tiene NA, mantenme el valor de la columna
                           )

En big data usar la media como valor sustitutivo puede ser err?neo, es por eso que se hacen uso a veces de valores aleatorios generados a través de una muestra aleatoria del propio data frame de los datos que no faltan. Este concepto vale tanto en variables categoricas o num?ricas. Vamos a usar dos funciones para este caso:

rand.impute <- function(x){ #x viene a ser la columna del data frame con la que trabajaremos
  missing <- is.na(x) #missing va a ser un vector del mismo tama?o que x pero que contiene TRUE or false dependiendo si es x es igual NA o no
  n.missing <- sum(missing)# esta variable indica cuantos valores son NA dentro de x
  x.obs <- x[!missing] # x.obs son los valores x que NO tienen un valor NA dentro de x
  imputed <- x #imputed es el valor que vamos a devolver, le damos el valor x por  defecto
  imputed[missing] <- sample(x.obs, n.missing, replace = TRUE) # imputed en la posici?n que falten los missing values, va a ser un muestreo aleatorio de las observaviones de x que no esten missing, de tama?o n.missing, para que sea representativa respecto los missing values, y con la possibilidad de remplazo para que cambie los NA por valores aleatorios 
  return(imputed) # devuelveme el valor imputed 
}

En caso que queramos aplicar la misma técnica para variables categóricas, y teniendo en consideración la función anterior.

rand.impute.data.frame <- function(df,cols){
  names <- names(df) #  damos al vector name, los nombres de las columnas
  for (col in cols) {
    name <- paste(names[col], ".imputed", sep = "") #A?adir? el nombre imputed despues del column name para identificar las nuevas columnas
    df[name] = rand.impute(df[,col])#llamaremos la funci?n de sustituci?n de valores con valores aeatorios 
  }
  df #recordar devolver el data frame con el que estamos trabajando
}

Una vez a ya has creado las funciones, aplicas los resultados sobre el data frame, creando un nuevo daata freme para almacenarlos:

data <- rand.impute.data.frame(data, c(1,2)) 
#con estas variables puedo modificar los NA  de las columnas 1 y 2 del df

Evitar duplicaciones de datos

Usando la función “unique()” podemos seleccionar solo la svariables que son únicas. También podemos usar la función “duplicated()” para que nos indique con TRUE o FALSE si el valor es duplicado o no. Por ejemplo, si quisiera que solo me mostrase los duplicados en un data frame, podría ser:

family.salary = c(40000, 60000, 50000, 80000, 60000, 70000, 60000)
family.size = c(4, 3, 2, 2, 3, 4, 3)
family.car = c("Lujo", "Compacto", "Utilitario", "Lujo", 
               "Compacto", "Compacto", "Compacto")

family <- data.frame(family.salary, family.size, family.car)

family.unique <- unique(family)

duplicated(family)
## [1] FALSE FALSE FALSE FALSE  TRUE FALSE  TRUE
family[duplicated(family),]

Reescalando lineas de datos

Esta técnica nos permite reescalar los datos en base a unos máximo y unos mínimos, ya sean impuestos a través del propio data set o en la función que hemos llamado. Para trabajar con técnicas de reescalado usaremos la librería (scales), veamos el código:

library(scales)
students <- read.csv("../DataSets/data-conversion.csv")

students$Income.rescaled <- rescale(students$Income) # reescalando los datos

# El reescalado hace la siguiente operación para todos los datos
(students$Income - min(students$Income))/
  (max(students$Income) - min(students$Income))
##  [1] 0.07407407 0.00000000 0.03703704 0.05555556 0.53703704 0.16666667
##  [7] 0.90740741 1.00000000 0.01851852 0.35185185
rescale(students$Income, to = c(0, 100)) # Específicamos cual es el valor mínimo y el valor máximo
##  [1]   7.407407   0.000000   3.703704   5.555556  53.703704  16.666667
##  [7]  90.740741 100.000000   1.851852  35.185185
# Creamos una función para reescalar sus datos
rescale.many <- function(dataframe, cols){
  names <- names(dataframe) #add to the vector the data frame df columnn  names
  for(col in cols){
    name <- paste(names[col], "rescaled", sep = ".") # add a label with .rescaled to the new column
    dataframe[name] <- rescale(dataframe[,col]) 
  }
  cat(paste("Hemos reescalado ", length(cols), " variable(s)")) # nos imprime en la consola el n?mero de variables que ha impreso
  dataframe # a?ade la informaci?n al dataframe
}

# aplicamos la función 
students <- rescale.many(students, c(1,4))
## Hemos reescalado  2  variable(s)

Normalizando y estandarizand nuestro data frame

La función scale() nos ayudara a normalizar los datos (https://es.wikipedia.org/wiki/Distribuci%C3%B3n_normal) para poder ver su distribución de los datos. La función en R sería:

housing <- read.csv("../DataSets/BostonHousing.csv")

housing.z <- scale(housing, center = TRUE, scale = TRUE)
housing.mean <- scale(housing, center = TRUE, scale = FALSE)
housing.sd <- scale(housing, center = FALSE, scale = TRUE)
housing.none <- scale(housing, center = FALSE, scale = FALSE)

#sd = sqrt(sum(x^2)/(n-1)) # formula de la desviación standar

# Creamos una función para reescalar todo el dataset
scale.many = function(dataframe, cols){
  names <- names(dataframe)
  for(col in cols){
    name <- paste(names[col], "z", sep = ".")
    dataframe[name] <- scale(dataframe[,col])
  }
  cat(paste("Hemos normalizado ", length(cols), " variable(s)"))
  dataframe
}

housing <- scale.many(housing, c(1, 3, 5:8))
## Hemos normalizado  6  variable(s)

Categorizando información numérica:

Vamos a ver como podemos hacer “bins”, cajas a partir de una información:

students <- read.csv("../DataSets/data-conversion.csv")

bp <- c(-Inf, 10000, 31000, Inf) # Este es el vector que determinará los cortes
names <- c("Low", "Average", "High") # Creamos el vector que va a dar a los cortes 3 valores categóricos

students$Income.cat <- cut(students$Income, breaks = bp, labels = names) 
students$Income.cat2 <- cut(students$Income, breaks = bp) # se pondría un nombre por defecto, que define los rangos de cada "bin"
students$Income.cat3 <- cut(students$Income, 
                            breaks = 4, 
                            labels = c("Level 1", "Level 2", 
                                       "Level 3", "Level 4")
                            ) # se puede hacer de forma manual

Variables ficiticas para categorizaciones o “dummy” variables

Usaremos la libreria “dummies”- Útil para algoritmos como los KNN.

#dummy variables
students <- read.csv("../DataSets/data-conversion.csv")
library(dummies)
## dummies-1.5.6 provided by Decision Patterns
students.dummy <- dummy.data.frame(students, sep = ".")
names(students.dummy)
## [1] "Age"      "State.NJ" "State.NY" "State.TX" "State.VA" "Gender.F"
## [7] "Gender.M" "Height"   "Income"
dummy(students$State, sep=".")
##       C:/Users/romcl/OneDrive/Documents/Formacio/Ubiqum/Entrenament/Apuntes/ApuntesRMachineLearning/Apuntes/PreparacionDeDatos.Rmd.NJ
##  [1,]                                                                                                                               1
##  [2,]                                                                                                                               0
##  [3,]                                                                                                                               1
##  [4,]                                                                                                                               0
##  [5,]                                                                                                                               0
##  [6,]                                                                                                                               0
##  [7,]                                                                                                                               1
##  [8,]                                                                                                                               0
##  [9,]                                                                                                                               0
## [10,]                                                                                                                               0
##       C:/Users/romcl/OneDrive/Documents/Formacio/Ubiqum/Entrenament/Apuntes/ApuntesRMachineLearning/Apuntes/PreparacionDeDatos.Rmd.NY
##  [1,]                                                                                                                               0
##  [2,]                                                                                                                               1
##  [3,]                                                                                                                               0
##  [4,]                                                                                                                               0
##  [5,]                                                                                                                               1
##  [6,]                                                                                                                               0
##  [7,]                                                                                                                               0
##  [8,]                                                                                                                               0
##  [9,]                                                                                                                               0
## [10,]                                                                                                                               0
##       C:/Users/romcl/OneDrive/Documents/Formacio/Ubiqum/Entrenament/Apuntes/ApuntesRMachineLearning/Apuntes/PreparacionDeDatos.Rmd.TX
##  [1,]                                                                                                                               0
##  [2,]                                                                                                                               0
##  [3,]                                                                                                                               0
##  [4,]                                                                                                                               0
##  [5,]                                                                                                                               0
##  [6,]                                                                                                                               1
##  [7,]                                                                                                                               0
##  [8,]                                                                                                                               0
##  [9,]                                                                                                                               1
## [10,]                                                                                                                               0
##       C:/Users/romcl/OneDrive/Documents/Formacio/Ubiqum/Entrenament/Apuntes/ApuntesRMachineLearning/Apuntes/PreparacionDeDatos.Rmd.VA
##  [1,]                                                                                                                               0
##  [2,]                                                                                                                               0
##  [3,]                                                                                                                               0
##  [4,]                                                                                                                               1
##  [5,]                                                                                                                               0
##  [6,]                                                                                                                               0
##  [7,]                                                                                                                               0
##  [8,]                                                                                                                               1
##  [9,]                                                                                                                               0
## [10,]                                                                                                                               1
dummy.data.frame(students, names = c("State", "Gender"), sep = ".")

Formas de eliminar información que falta

Cargando los datos y entendindolos

housing.data <- read.csv("../DataSets/housing-with-missing-value.csv",
                         header = TRUE, stringsAsFactors = FALSE)


summary(housing.data) # Podemos ver que aparecen missing values
##        X              crim                zn             indus      
##  Min.   :  1.0   Min.   : 0.00632   Min.   :  0.00   Min.   : 0.46  
##  1st Qu.:127.2   1st Qu.: 0.08204   1st Qu.:  0.00   1st Qu.: 5.19  
##  Median :253.5   Median : 0.25651   Median :  0.00   Median : 9.69  
##  Mean   :253.5   Mean   : 3.61352   Mean   : 11.36   Mean   :11.14  
##  3rd Qu.:379.8   3rd Qu.: 3.67708   3rd Qu.: 12.50   3rd Qu.:18.10  
##  Max.   :506.0   Max.   :88.97620   Max.   :100.00   Max.   :27.74  
##                                                                     
##       chas              nox               rm             age        
##  Min.   :0.00000   Min.   :0.3850   Min.   :3.561   Min.   :  2.90  
##  1st Qu.:0.00000   1st Qu.:0.4490   1st Qu.:5.886   1st Qu.: 45.02  
##  Median :0.00000   Median :0.5380   Median :6.208   Median : 77.50  
##  Mean   :0.06917   Mean   :0.5547   Mean   :6.285   Mean   : 68.57  
##  3rd Qu.:0.00000   3rd Qu.:0.6240   3rd Qu.:6.623   3rd Qu.: 94.08  
##  Max.   :1.00000   Max.   :0.8710   Max.   :8.780   Max.   :100.00  
##                                                                     
##       dis              rad              tax           ptratio     
##  Min.   : 1.130   Min.   : 1.000   Min.   :187.0   Min.   :12.60  
##  1st Qu.: 2.100   1st Qu.: 4.000   1st Qu.:279.0   1st Qu.:17.40  
##  Median : 3.207   Median : 5.000   Median :330.0   Median :19.10  
##  Mean   : 3.795   Mean   : 9.515   Mean   :408.2   Mean   :18.47  
##  3rd Qu.: 5.188   3rd Qu.:24.000   3rd Qu.:666.0   3rd Qu.:20.20  
##  Max.   :12.127   Max.   :24.000   Max.   :711.0   Max.   :22.00  
##                   NA's   :40                       NA's   :40     
##        b              lstat            medv      
##  Min.   :  0.32   Min.   : 1.73   Min.   : 5.00  
##  1st Qu.:375.38   1st Qu.: 6.95   1st Qu.:17.02  
##  Median :391.44   Median :11.36   Median :21.20  
##  Mean   :356.67   Mean   :12.65   Mean   :22.53  
##  3rd Qu.:396.23   3rd Qu.:16.95   3rd Qu.:25.00  
##  Max.   :396.90   Max.   :37.97   Max.   :50.00  
## 
##Eliminar todas las observaciones que contengan algún NA
housing.data.1 <- na.omit(housing.data)
summary(housing.data.1)
##        X              crim                zn             indus      
##  Min.   :  1.0   Min.   : 0.00632   Min.   :  0.00   Min.   : 0.46  
##  1st Qu.:120.5   1st Qu.: 0.07373   1st Qu.:  0.00   1st Qu.: 5.13  
##  Median :252.0   Median : 0.25356   Median :  0.00   Median : 8.56  
##  Mean   :251.4   Mean   : 3.66428   Mean   : 11.79   Mean   :11.03  
##  3rd Qu.:381.5   3rd Qu.: 3.69503   3rd Qu.: 15.00   3rd Qu.:18.10  
##  Max.   :506.0   Max.   :88.97620   Max.   :100.00   Max.   :27.74  
##       chas              nox               rm             age        
##  Min.   :0.00000   Min.   :0.3850   Min.   :3.561   Min.   :  2.90  
##  1st Qu.:0.00000   1st Qu.:0.4480   1st Qu.:5.886   1st Qu.: 45.25  
##  Median :0.00000   Median :0.5380   Median :6.195   Median : 76.70  
##  Mean   :0.06729   Mean   :0.5529   Mean   :6.277   Mean   : 68.51  
##  3rd Qu.:0.00000   3rd Qu.:0.6240   3rd Qu.:6.630   3rd Qu.: 94.30  
##  Max.   :1.00000   Max.   :0.8710   Max.   :8.780   Max.   :100.00  
##       dis              rad              tax           ptratio     
##  Min.   : 1.130   Min.   : 1.000   Min.   :187.0   Min.   :12.60  
##  1st Qu.: 2.083   1st Qu.: 4.000   1st Qu.:278.0   1st Qu.:17.40  
##  Median : 3.360   Median : 5.000   Median :330.0   Median :19.10  
##  Mean   : 3.861   Mean   : 9.599   Mean   :407.8   Mean   :18.47  
##  3rd Qu.: 5.287   3rd Qu.:24.000   3rd Qu.:666.0   3rd Qu.:20.20  
##  Max.   :12.127   Max.   :24.000   Max.   :711.0   Max.   :22.00  
##        b              lstat            medv      
##  Min.   :  0.32   Min.   : 1.73   Min.   : 5.00  
##  1st Qu.:374.96   1st Qu.: 6.91   1st Qu.:16.60  
##  Median :391.45   Median :11.41   Median :21.10  
##  Mean   :357.24   Mean   :12.76   Mean   :22.38  
##  3rd Qu.:396.25   3rd Qu.:17.14   3rd Qu.:25.00  
##  Max.   :396.90   Max.   :37.97   Max.   :50.00

¿Cómo podemos eliminar NAs de solo algunas columnas? Por ejemplo, solo los de la variable “rad” del dataset:

##Eliminar las NAs de ciertas columnas
drop_na <- c("rad") # elegimos la variable de la que queremos conservar todos los NAs
housing.data.2 <- housing.data[ 
  complete.cases(housing.data[,!(names(housing.data))%in% drop_na]),] # hacemos desaparecer los NAs de todas las columnas excepto las de "rad"

summary(housing.data.2)
##        X              crim                zn             indus      
##  Min.   :  1.0   Min.   : 0.00632   Min.   :  0.00   Min.   : 0.46  
##  1st Qu.:126.2   1st Qu.: 0.07880   1st Qu.:  0.00   1st Qu.: 5.13  
##  Median :254.5   Median : 0.25651   Median :  0.00   Median : 8.56  
##  Mean   :253.5   Mean   : 3.73046   Mean   : 11.53   Mean   :11.06  
##  3rd Qu.:380.8   3rd Qu.: 3.68939   3rd Qu.: 12.50   3rd Qu.:18.10  
##  Max.   :506.0   Max.   :88.97620   Max.   :100.00   Max.   :27.74  
##                                                                     
##       chas              nox               rm             age        
##  Min.   :0.00000   Min.   :0.3850   Min.   :3.561   Min.   :  2.90  
##  1st Qu.:0.00000   1st Qu.:0.4490   1st Qu.:5.886   1st Qu.: 45.62  
##  Median :0.00000   Median :0.5380   Median :6.211   Median : 76.80  
##  Mean   :0.06438   Mean   :0.5536   Mean   :6.284   Mean   : 68.72  
##  3rd Qu.:0.00000   3rd Qu.:0.6240   3rd Qu.:6.630   3rd Qu.: 94.38  
##  Max.   :1.00000   Max.   :0.8710   Max.   :8.780   Max.   :100.00  
##                                                                     
##       dis              rad              tax           ptratio     
##  Min.   : 1.130   Min.   : 1.000   Min.   :187.0   Min.   :12.60  
##  1st Qu.: 2.091   1st Qu.: 4.000   1st Qu.:279.0   1st Qu.:17.40  
##  Median : 3.299   Median : 5.000   Median :330.0   Median :19.10  
##  Mean   : 3.824   Mean   : 9.599   Mean   :408.7   Mean   :18.47  
##  3rd Qu.: 5.215   3rd Qu.:24.000   3rd Qu.:666.0   3rd Qu.:20.20  
##  Max.   :12.127   Max.   :24.000   Max.   :711.0   Max.   :22.00  
##                   NA's   :35                                      
##        b              lstat             medv      
##  Min.   :  0.32   Min.   : 1.730   Min.   : 5.00  
##  1st Qu.:375.24   1st Qu.: 6.923   1st Qu.:16.73  
##  Median :391.38   Median :11.235   Median :21.20  
##  Mean   :358.05   Mean   :12.662   Mean   :22.53  
##  3rd Qu.:396.23   3rd Qu.:17.043   3rd Qu.:25.00  
##  Max.   :396.90   Max.   :37.970   Max.   :50.00  
## 
##Eliminar toda una columna
housing.data$rad <- NULL
summary(housing.data)
##        X              crim                zn             indus      
##  Min.   :  1.0   Min.   : 0.00632   Min.   :  0.00   Min.   : 0.46  
##  1st Qu.:127.2   1st Qu.: 0.08204   1st Qu.:  0.00   1st Qu.: 5.19  
##  Median :253.5   Median : 0.25651   Median :  0.00   Median : 9.69  
##  Mean   :253.5   Mean   : 3.61352   Mean   : 11.36   Mean   :11.14  
##  3rd Qu.:379.8   3rd Qu.: 3.67708   3rd Qu.: 12.50   3rd Qu.:18.10  
##  Max.   :506.0   Max.   :88.97620   Max.   :100.00   Max.   :27.74  
##                                                                     
##       chas              nox               rm             age        
##  Min.   :0.00000   Min.   :0.3850   Min.   :3.561   Min.   :  2.90  
##  1st Qu.:0.00000   1st Qu.:0.4490   1st Qu.:5.886   1st Qu.: 45.02  
##  Median :0.00000   Median :0.5380   Median :6.208   Median : 77.50  
##  Mean   :0.06917   Mean   :0.5547   Mean   :6.285   Mean   : 68.57  
##  3rd Qu.:0.00000   3rd Qu.:0.6240   3rd Qu.:6.623   3rd Qu.: 94.08  
##  Max.   :1.00000   Max.   :0.8710   Max.   :8.780   Max.   :100.00  
##                                                                     
##       dis              tax           ptratio            b         
##  Min.   : 1.130   Min.   :187.0   Min.   :12.60   Min.   :  0.32  
##  1st Qu.: 2.100   1st Qu.:279.0   1st Qu.:17.40   1st Qu.:375.38  
##  Median : 3.207   Median :330.0   Median :19.10   Median :391.44  
##  Mean   : 3.795   Mean   :408.2   Mean   :18.47   Mean   :356.67  
##  3rd Qu.: 5.188   3rd Qu.:666.0   3rd Qu.:20.20   3rd Qu.:396.23  
##  Max.   :12.127   Max.   :711.0   Max.   :22.00   Max.   :396.90  
##                                   NA's   :40                      
##      lstat            medv      
##  Min.   : 1.73   Min.   : 5.00  
##  1st Qu.: 6.95   1st Qu.:17.02  
##  Median :11.36   Median :21.20  
##  Mean   :12.65   Mean   :22.53  
##  3rd Qu.:16.95   3rd Qu.:25.00  
##  Max.   :37.97   Max.   :50.00  
## 

Formas de completar la información que falta

Uaremos la libreria “Hmisc”, muy ´tiles paraa la representación de tablas y de datos. Imaginemos que queremos remplazar los valores de NAs por valores conocidos, podemos hacer uso de la función impute() de la libreria “Hmisc”:

library(Hmisc)
## Loading required package: lattice
## Loading required package: survival
## Loading required package: Formula
## Loading required package: ggplot2
## 
## Attaching package: 'Hmisc'
## The following objects are masked from 'package:base':
## 
##     format.pval, units
# Reemplazamos los valores NAS de la columna seleccionada por la "media"
housing.data.copy1 <- housing.data
housing.data.copy1$ptratio <- impute(housing.data.copy1$ptratio, mean) # NAs por la media
housing.data.copy1$rad <- impute(housing.data.copy1$rad, mean)
summary(housing.data.copy1)
## 
##  40 values imputed to 18.4676
##        X              crim                zn             indus      
##  Min.   :  1.0   Min.   : 0.00632   Min.   :  0.00   Min.   : 0.46  
##  1st Qu.:127.2   1st Qu.: 0.08204   1st Qu.:  0.00   1st Qu.: 5.19  
##  Median :253.5   Median : 0.25651   Median :  0.00   Median : 9.69  
##  Mean   :253.5   Mean   : 3.61352   Mean   : 11.36   Mean   :11.14  
##  3rd Qu.:379.8   3rd Qu.: 3.67708   3rd Qu.: 12.50   3rd Qu.:18.10  
##  Max.   :506.0   Max.   :88.97620   Max.   :100.00   Max.   :27.74  
##       chas              nox               rm             age        
##  Min.   :0.00000   Min.   :0.3850   Min.   :3.561   Min.   :  2.90  
##  1st Qu.:0.00000   1st Qu.:0.4490   1st Qu.:5.886   1st Qu.: 45.02  
##  Median :0.00000   Median :0.5380   Median :6.208   Median : 77.50  
##  Mean   :0.06917   Mean   :0.5547   Mean   :6.285   Mean   : 68.57  
##  3rd Qu.:0.00000   3rd Qu.:0.6240   3rd Qu.:6.623   3rd Qu.: 94.08  
##  Max.   :1.00000   Max.   :0.8710   Max.   :8.780   Max.   :100.00  
##       dis              tax           ptratio            b         
##  Min.   : 1.130   Min.   :187.0   Min.   :12.60   Min.   :  0.32  
##  1st Qu.: 2.100   1st Qu.:279.0   1st Qu.:17.40   1st Qu.:375.38  
##  Median : 3.207   Median :330.0   Median :18.60   Median :391.44  
##  Mean   : 3.795   Mean   :408.2   Mean   :18.47   Mean   :356.67  
##  3rd Qu.: 5.188   3rd Qu.:666.0   3rd Qu.:20.20   3rd Qu.:396.23  
##  Max.   :12.127   Max.   :711.0   Max.   :22.00   Max.   :396.90  
##      lstat            medv      
##  Min.   : 1.73   Min.   : 5.00  
##  1st Qu.: 6.95   1st Qu.:17.02  
##  Median :11.36   Median :21.20  
##  Mean   :12.65   Mean   :22.53  
##  3rd Qu.:16.95   3rd Qu.:25.00  
##  Max.   :37.97   Max.   :50.00
# Reemplazamos los valores NAS de la columna seleccionada por la "mediana"
housing.data.copy2 <- housing.data
housing.data.copy2$ptratio <- impute(housing.data.copy2$ptratio, median)
housing.data.copy2$rad <- impute(housing.data.copy2$rad, median)
summary(housing.data.copy2)
## 
##  40 values imputed to 19.1
##        X              crim                zn             indus      
##  Min.   :  1.0   Min.   : 0.00632   Min.   :  0.00   Min.   : 0.46  
##  1st Qu.:127.2   1st Qu.: 0.08204   1st Qu.:  0.00   1st Qu.: 5.19  
##  Median :253.5   Median : 0.25651   Median :  0.00   Median : 9.69  
##  Mean   :253.5   Mean   : 3.61352   Mean   : 11.36   Mean   :11.14  
##  3rd Qu.:379.8   3rd Qu.: 3.67708   3rd Qu.: 12.50   3rd Qu.:18.10  
##  Max.   :506.0   Max.   :88.97620   Max.   :100.00   Max.   :27.74  
##       chas              nox               rm             age        
##  Min.   :0.00000   Min.   :0.3850   Min.   :3.561   Min.   :  2.90  
##  1st Qu.:0.00000   1st Qu.:0.4490   1st Qu.:5.886   1st Qu.: 45.02  
##  Median :0.00000   Median :0.5380   Median :6.208   Median : 77.50  
##  Mean   :0.06917   Mean   :0.5547   Mean   :6.285   Mean   : 68.57  
##  3rd Qu.:0.00000   3rd Qu.:0.6240   3rd Qu.:6.623   3rd Qu.: 94.08  
##  Max.   :1.00000   Max.   :0.8710   Max.   :8.780   Max.   :100.00  
##       dis              tax           ptratio            b         
##  Min.   : 1.130   Min.   :187.0   Min.   :12.60   Min.   :  0.32  
##  1st Qu.: 2.100   1st Qu.:279.0   1st Qu.:17.40   1st Qu.:375.38  
##  Median : 3.207   Median :330.0   Median :19.10   Median :391.44  
##  Mean   : 3.795   Mean   :408.2   Mean   :18.52   Mean   :356.67  
##  3rd Qu.: 5.188   3rd Qu.:666.0   3rd Qu.:20.20   3rd Qu.:396.23  
##  Max.   :12.127   Max.   :711.0   Max.   :22.00   Max.   :396.90  
##      lstat            medv      
##  Min.   : 1.73   Min.   : 5.00  
##  1st Qu.: 6.95   1st Qu.:17.02  
##  Median :11.36   Median :21.20  
##  Mean   :12.65   Mean   :22.53  
##  3rd Qu.:16.95   3rd Qu.:25.00  
##  Max.   :37.97   Max.   :50.00
# Reemplazamos los valores NAS de la columna seleccionada por un valor fijo
housing.data.copy3 <- housing.data
housing.data.copy3$ptratio <- impute(housing.data.copy3$ptratio, 18)
housing.data.copy3$rad <- impute(housing.data.copy3$rad, 7)
summary(housing.data.copy3)
## 
##  40 values imputed to 18
##        X              crim                zn             indus      
##  Min.   :  1.0   Min.   : 0.00632   Min.   :  0.00   Min.   : 0.46  
##  1st Qu.:127.2   1st Qu.: 0.08204   1st Qu.:  0.00   1st Qu.: 5.19  
##  Median :253.5   Median : 0.25651   Median :  0.00   Median : 9.69  
##  Mean   :253.5   Mean   : 3.61352   Mean   : 11.36   Mean   :11.14  
##  3rd Qu.:379.8   3rd Qu.: 3.67708   3rd Qu.: 12.50   3rd Qu.:18.10  
##  Max.   :506.0   Max.   :88.97620   Max.   :100.00   Max.   :27.74  
##       chas              nox               rm             age        
##  Min.   :0.00000   Min.   :0.3850   Min.   :3.561   Min.   :  2.90  
##  1st Qu.:0.00000   1st Qu.:0.4490   1st Qu.:5.886   1st Qu.: 45.02  
##  Median :0.00000   Median :0.5380   Median :6.208   Median : 77.50  
##  Mean   :0.06917   Mean   :0.5547   Mean   :6.285   Mean   : 68.57  
##  3rd Qu.:0.00000   3rd Qu.:0.6240   3rd Qu.:6.623   3rd Qu.: 94.08  
##  Max.   :1.00000   Max.   :0.8710   Max.   :8.780   Max.   :100.00  
##       dis              tax           ptratio            b         
##  Min.   : 1.130   Min.   :187.0   Min.   :12.60   Min.   :  0.32  
##  1st Qu.: 2.100   1st Qu.:279.0   1st Qu.:17.40   1st Qu.:375.38  
##  Median : 3.207   Median :330.0   Median :18.60   Median :391.44  
##  Mean   : 3.795   Mean   :408.2   Mean   :18.43   Mean   :356.67  
##  3rd Qu.: 5.188   3rd Qu.:666.0   3rd Qu.:20.20   3rd Qu.:396.23  
##  Max.   :12.127   Max.   :711.0   Max.   :22.00   Max.   :396.90  
##      lstat            medv      
##  Min.   : 1.73   Min.   : 5.00  
##  1st Qu.: 6.95   1st Qu.:17.02  
##  Median :11.36   Median :21.20  
##  Mean   :12.65   Mean   :22.53  
##  3rd Qu.:16.95   3rd Qu.:25.00  
##  Max.   :37.97   Max.   :50.00

Pero puede que antes de remplazar los valores, se puede hacer uso de la función md.pattern(), de la libreria “mice”, que muestra los patrones de los NAs:

library(mice)
## 
## Attaching package: 'mice'
## The following objects are masked from 'package:base':
## 
##     cbind, rbind
md.pattern(housing.data)

##     X crim zn indus chas nox rm age dis tax b lstat medv ptratio   
## 466 1    1  1     1    1   1  1   1   1   1 1     1    1       1  0
## 40  1    1  1     1    1   1  1   1   1   1 1     1    1       0  1
##     0    0  0     0    0   0  0   0   0   0 0     0    0      40 40

En este caso se conocen todos los valores de 431 observaciones. 35 se conocen todos los valores excepto los de “rad”, y otros 35 también todos los valores excepto “ptratio.” Hay 5 valores donde no se conoce ni “rad” ni “ptratio”.

Podemos visualizar la información con un plot agregado:

library(VIM)
## Loading required package: colorspace
## Loading required package: grid
## Loading required package: data.table
## VIM is ready to use. 
##  Since version 4.0.0 the GUI is in its own package VIMGUI.
## 
##           Please use the package to use the new (and old) GUI.
## Suggestions and bug-reports can be submitted at: https://github.com/alexkowa/VIM/issues
## 
## Attaching package: 'VIM'
## The following object is masked from 'package:datasets':
## 
##     sleep
# Vamos a agregar nuestros datos
aggr(housing.data, 
     col= c('green', 'red'), # introducmos los valores conocidos y no conocidos
     numbers = TRUE, # introducción de porcentajes a la derecha 
     sortVars = TRUE, # ordenar las variables de mayor a menor
     labels = names(housing.data), # añadiendo etiquetas de las variables
     cex.axis = 0.75, # reducir el tamaño de la fuente en los ejes
     gap = 1, # juntar o separar más los dos gráficos
     ylab = c("Histograma de NAs", "Patrón") # añadir títulos al eje de las Y a cada uno de los gráficos
)     

## 
##  Variables sorted by number of missings: 
##  Variable      Count
##   ptratio 0.07905138
##         X 0.00000000
##      crim 0.00000000
##        zn 0.00000000
##     indus 0.00000000
##      chas 0.00000000
##       nox 0.00000000
##        rm 0.00000000
##       age 0.00000000
##       dis 0.00000000
##       tax 0.00000000
##         b 0.00000000
##     lstat 0.00000000
##      medv 0.00000000

Combinando y separando los datos. Corrección de datos

library(tidyr)
## 
## Attaching package: 'tidyr'
## The following object is masked from 'package:mice':
## 
##     complete
crime.data <- read.csv("../DataSets/USArrests.csv", 
                       stringsAsFactors = FALSE)

Para este caso empezaremos a usar el paquete library (tidyr), que servirá mucho para las series temporales. Para empezar crearemos una nueva columna con cbind():

# Añadimos una columna con el número de fila con el nombre de la columna llamada "state"
crime.data <- cbind(state = rownames(crime.data), crime.data)

Otroas funcioens de tidyr que se pueden consultar en el curso de tidyverse.

Uso de modelos predictivos para eliminar NAs

Este método nos permite evitar usar el borrado de NAs como el metodo más rápido de tratar NAs, así que usaremos métodos de imputación multivarintes para reemplazar valores desconocidos con valores predictivos.

Para eso usaremos el housing missing values, de la libreria mice, que permite elaborar un modelo de datos que predice los valores de las variablies a las que se quiere ajustar:

library(mice)

housing.data <- read.csv("../DataSets/housing-with-missing-value.csv",
                         header = TRUE,
                         stringsAsFactors = FALSE)

columns <- c("ptratio", "rad") #These are two columns we want to modify values

imputed_data <- mice(housing.data[,names(housing.data) %in% columns], 
                     m = 5,# obtener al máximo de imputaciones 5, contra más imputaciones mejor
                     maxit = 50,# número de iteraciones internas
                     method = "pmm",#predicitive mean matching, hay 4 methods
                     seed = "2018", #misma función que el set.seed
                     printFlag = FALSE # no muestres por consola
           )
#mothodos de prediccion de datos:
# - pmm: comparación predictiva de medias
# - logreg: regresión logística (solo puede ver dos niveles)
# - polyreg: regresión logística politómica (factor columna de dos o más niveles)
# - polr: probabilidades proporcionales

complete.data <- mice::complete(imputed_data)# completame el dfpredicted con el "complete" del paquete mice usando el modelo predictivo
housing.data$ptratio <- complete.data$ptratio# asigna valores a la columna del df original
housing.data$rad <- complete.data$rad

anyNA(housing.data) #?Hay algún NA? true o false, no debería haber ninguno. 
## [1] FALSE

También podemos usar el paquete hmisc para crear modelos predictivos, la función seria:

impute_arg <- aregImpute(~ptratio + rad, 
                         data = housing.data, 
                         n.impute = 5)# número de valores previstos que va a calcular
## Iteration 1 
Iteration 2 
Iteration 3 
Iteration 4 
Iteration 5 
impute_arg
## 
## Multiple Imputation using Bootstrap and PMM
## 
## aregImpute(formula = ~ptratio + rad, data = housing.data, n.impute = 5)
## 
## n: 506   p: 2    Imputations: 5      nk: 3 
## 
## Number of NAs:
## ptratio     rad 
##       0       0 
## 
##         type d.f.
## ptratio    s   NA
## rad        s   NA
## 
## Transformation of Target Variables Forced to be Linear
## 
## R-squares for Predicting Non-Missing Values for Each Variable
## Using Last Imputations of Predictors
## named numeric(0)

Detección de outliers a través de boxplots

Antes de empezar las visualizaciones como ínimos les deberíamos echar un vistazo para inter los datos. Primero vamos a detectar los outliers para variables univariantes y continuas. Procedamos a realizar la creación del boxplot:

ozone.data <- read.csv("../DataSets/ozone.csv", stringsAsFactors = F)

boxplot(ozone.data$pressure_height, 
        main = "Pressure Height",
        boxwex = 0.5)$out # con este $out podemos seleccionar los outliers dentro de el dataset, y boxwex nos permite gestionar la anchura de la caja

##  [1] 5480 5410 5350 5480 5490 5470 5320 5420 5440 5480 5450 5500
summary(ozone.data$pressure_height)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##    5320    5700    5770    5753    5830    5950      12

¿Cómo varía la presión a lo largo de los meses del año?

boxplot(pressure_height ~ Month, 
        data = ozone.data,
        main = "Presure Height per Month"
        )

¿Cómo se distribuye el ozono a lo largo del año?

boxplot(ozone_reading ~Month,
        data = ozone.data,
        main = "Ozone reading per Month")$out
## [1] 11.06  9.93 22.89 24.29 29.79
mtext("Hola") # Nos permite añadir texto dentro de un plot de R

Enmascarando los outliers con transformaciones y cappings

Podemos crear una función para detectar los outliers:

replace_outliers <- function(x, removeNA = TRUE){
  qrts <- quantile(x, probs = c(0.25, 0.75), na.rm = removeNA)# dame los quartiles 1 i 3
  caps <- quantile(x, probs = c(.05, .95), na.rm = removeNA)# los valores que vamos a quitar
  iqr <- qrts[2]-qrts[1]# c?lculo del rango interquart?lico
  h <- 1.5 * iqr # la ha es de hight averigual el rango interquartilico
  x[x<qrts[1]-h] <- caps[1]
  x[x>qrts[2]+h] <- caps[2]
  x
}

capped_pressure_height <- replace_outliers(ozone.data$pressure_height)

par(mfrow = c(1,2))
boxplot(ozone.data$pressure_height, main = "Presión con outliers")
boxplot(capped_pressure_height, main = "Presión sin outliers")