El siguiente informe nace como parte de las actividades de la asignatura Estadistica Avanzada del Master en Data Science en la Universitat Oberta de Catalunya, con esto busco ofrecer un blog personal de informes que permitan evidenciar el crecimiento académico que se puede ir adquiriendo con el paso del Master y como R Studio es una herramienta de gran uso.
Es de resaltar que mi primer contacto con el Software R se da en este trabajo, por lo que soy consciente de que existen mejores ténicas para el uso de este, las cuales iran reflejandose con el paso de los informes.
Los datos a tratar corresponden a una investigación médica orientada a estudiar la capacidad pulmonar de las personas en función de si eran fumadoras o no. A cada persona, se le preguntó, a través de un cuestionario, su género, edad, hábitos de deporte, la ciudad de residencia, si era fumadora, y en caso de que lo fuera, cuántos cigarrillos al día de promedio fumaba y los años que hacía que fumaba. Además, se midió el peso, la altura y la capacidad pulmonar a partir de un test de aire expulsado, desde donde se tomó como capacidad pulmonar la medida FEF (forced expiratory flow), que es la velocidad del aire saliendo del pulmón durante la porción central de una espiración forzada. Se mide en litros / segundo.
El archivo se denomina Fumadores_raw.csv, contiene 300 registros y 9 variables. Estas variables son: Sex, Sport, Years, Cig, PC, City, Weight, Age, Height.
El objetivo concreto es preparar el archivo para su posterior análisis. A continuación se realizará un paso a paso de de la fuente de datos.
Recuerda inspeccionar previamente el archivo con un editor de texto para identificar el tipo de separador.
Carga del Archivo
archivo<- read.csv("Fumadores_raw.csv", sep=",",na.strings = "NA")
archivo<-as.data.frame(archivo) #
El archivo cuenta con 300 observaciones y 9 variables (Sex, Sport, Years, Cig, PC, City, Weight, Age, Height).
Para escribir código r en línea, debes escribir entre ``: r y la función que quieras invocar. Por ejemplo, para saber cuantos registros existen se escribe: r nrow(archivo), cantidad de variables: r length(archivo) y nombres de las variables: r names(archivo)
A continuación se presenta una impresión de los 6 primeros registros del archivo
Datos
head(archivo)
En este apartado se indica el tipo de variables estadística, es decir la clase a la que pertenece cada variable.
Tipos de Variables
| Variable | Tipo de Dato | Tipo Estadistico |
|---|---|---|
| Sex | factor | Cualitativa |
| Sport | integer | Cuantitativa |
| Years | integer | Cuantitativa |
| Cig | integer | Cuantitativa |
| PC | factor | Cualitativa |
| City | factor | Cualitativa |
| Weight | integer | CUantitativa |
| Age | integer | Cuantitativa |
| Height | integer | Cuantitativa |
Como se puede observar en el tipo de dato, R no ha asignado el tipo de dato apropiado, por lo que a continuación procedemos a asignarlo:
pc_column<- archivo$PC #carga de columna especifica
pc_column<- sub(',', '\\.', pc_column) #sustitucion de comas por puntos
pc_column<- as.numeric(pc_column) # Cambio de Formato a numerico
pc_column<- format(round(pc_column, 3), nsmall = 3) #Redondeo a 3 decimales
pc_column<- as.numeric(pc_column) # Reformateo a numerico
archivo$PC<-pc_column # actualizacion de datos del dataframe original
class(archivo$PC) # Clase
## [1] "numeric"
summary(pc_column) #Resumen estadistico de la variable
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 1.557 2.913 3.554 3.331 3.794 4.466 2
archivo$City<-as.character(archivo$City) # Transformando el tipo a character
class(archivo$City) #verificando la clase
## [1] "character"
archivo$Sport<- factor(archivo$Sport) # Transformando el tipo a factor
class(archivo$Sport) #verificando la clase
## [1] "factor"
Es habitual que en el tratamiento de datos algunas de las variables presentan ciertas inconsistencias, como por ejemplo un ingreso ecónomico en dolares y pesos; el peso de un grupo de personas con valores en libras y kilos; la altura de un grupo de personas en metros y centimetros. Por lo general, los sistemas transaccionales buscan disminuir este tipo de errores, sin embargo, en nuestro caso encontramos la variable Weight con una variación bastante extrema, permitiendo identificar que algunos valores estan en unidades diferentes. A continuación, procedemos a normalizar estos a través de una función denominada gram2kilogram(peso), la cual recibe una variable peso y valida si es kilo o gramo a través de una condicional, una vez validado procede a operar aritmeticamente el valor si este esta en gramos, retornando el valor en kilo.
#Funcion para limpiar variable con valores en miles
#Para esta funcipon, partimos de la premisa que ningún ser humano puede pesar 1000 kilogramos.
gram2Kilogram<- function(peso){
if(peso > 1000){ #comprueba si el valor es mayor a mil, de serlo, estará en gramos.
peso = peso/1000 # transforma a kilos
return(peso) #retorna el peso en kilos
} else{
return(peso) # si no es mayor a 1000 es porque este se encuentra en kilos.
}
}
weight_column<- archivo$Weight #carga de columna especifica
boxplot(weight_column, main="Box Plot Weight Error Values", col="green") # Grafico para conocer la representacion de los datos con outliers
summary(weight_column) #resumen de la variable
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 57 65 68 4673 71 74000
Procedemos a normalizar la variable weight y obtenemos:
for (i in 1:length(weight_column)) { # bucle para recorrer cada uno de los valores de Weight
weight_column[i]<- gram2Kilogram(weight_column[i])
}
boxplot(weight_column, main="Box Plot Weight Fixed", col="blue") # Grafico para verificar la distribucion de los datos corregidos
archivo$Weight<- weight_column # actualizacion de datos del dataframe original
Como se puede observar en el grafico anterior, se han normalizado los valores de la variable weight a tarvés de una división sobre valores mayores a 1000.
Normalizar / Estandarizar variables cualitativas.
library(lettercase)
library(stringi)
city_column<-archivo$City
head(city_column) # Verificando Inconsistencias
## [1] "Barcelona" " Terrassa" " La Bisbal"
## [4] "Blanes " "Sant Boi de Llobregat" " Barcelona"
city_column<- str_ucfirst(city_column) # Colocar en mayuscula la primer letra
city_column<-trimws(city_column) # eliminacion de espacios en blanco
city_column<-iconv(city_column, to="ASCII//TRANSLIT") # Eliminar acentos
archivo$City<-city_column # actualizacion de datos del dataframe original
head(city_column) # Previsualizacion de datos corregidos
## [1] "Barcelona" "Terrassa" "La Bisbal"
## [4] "Blanes" "Sant Boi De Llobregat" "Barcelona"
library(stringr)
sex_column<- archivo$Sex # Verificando Inconsistencias
levels(sex_column) # Categorias erroneas
## [1] " f" " F" " f " " F " " m" " M" " m "
## [8] " M " "f" "F" "f " "F " "m" "M"
## [15] "m " "M "
sex_column<-as.character(sex_column) # casteo de la variable a caracter
sex_column<-str_delete_whitespace(sex_column) # eliminacion de espacios en blanco
archivo$Sex<-as.factor(str_all_caps(sex_column)) # actualizacion de datos del dataframe original con funcion de mayusculas
levels(archivo$Sex) # Previsualizacion de datos corregidos
## [1] "F" "M"
sport_column<- archivo$Sport
head(sport_column) # impresion de registros de la variable sport
## [1] 1 1 4 2 1 4
## Levels: 1 2 3 4
#Asignando nombres a cada uno de los niveles
sport_column<- factor(archivo$Sport, levels=c(1,2,3,4),labels=c("None","Sometimes","Regularly","Every Day"))
head(sport_column)
## [1] None None Every Day Sometimes None Every Day
## Levels: None Sometimes Regularly Every Day
archivo$Sport<- sport_column # asignando la variable trasnformada de nuevo al set de datos
Como es mencionado en la descripcion de la fuente de datos, years indica cuanto tiempo en años lleva fumando uno de los entrevistados, por lo que si Cig (cigarrillos al día) es igual a cero, years debería ser 0. La anterior situación queda expuesta en el siguiente grafico, donde se puede observar que para valores de CIG en 0, existen valores mayores a 0 en YEAR.
plot(archivo$Cig,archivo$Years, main= "Years vs Cig", xlab="CIG", ylab="PC", pch=19, col="blue") #mostrando el error
for (i in 1:length(archivo$Cig)) { # Normalizando years en cero y cig en cero
if(archivo$Cig[i]==0)
{
archivo$Years[i]<-0
}else if(archivo$Years[i]==0){
archivo$Cig[i]<-0
}
}
plot(archivo$Cig,archivo$Years, main= "Years vs Cig Fixed", xlab="CIG", ylab="PC", pch=19, col="green") #mostrando el error
#
Procedemos a corregir dicha anomalía:
plot(archivo$Cig,archivo$Years, main= "Years vs Cig Fixed", xlab="CIG", ylab="PC", pch=19, col="green") #mostrando el error
La mejor forma de identificar los valores atípicos (outlier) en variables cuantitativas es a través de un boxplot, ya que en este podemos identificar como estan representados los datos con respecto a sus métricas descriptivas (media, mediana, cuartiles):
boxplot(archivo$Years, main="Box Plot Years", col="gray")
boxplot(archivo$Cig, main="Box Plot Cig", col="purple")
boxplot(archivo$PC, main="Box Plot PC", col="pink")
boxplot(archivo$Weight, main="Box Plot Weight", col="yellow")
boxplot(archivo$Age, main="Box Plot Age", col="red")
boxplot(archivo$Height, main="Box Plot Height", col="blue")
Ahora, procedemos a realizar las estimaciones robustas y no robustas de tendencia central y dispersión para cada variable cuantitativa.
library(psych)
| Variable | Media Aritmetica | Mediana | Media Recortada | Media Winsorizada | Desviacion Estandar |
|---|---|---|---|---|---|
| Years | 8.4633333 | 0 | 7.0148148 | 8.1133333 | 12.5416492 |
| Cig | 7.2733333 | 0 | 6.1111111 | 7.05 | 10.4134571 |
| PC | 3.3314664 | 3.554 | 3.3571926 | 3.3342634 | 0.6283275 |
| Weight | 67.7166667 | 68 | 67.7333333 | 67.71 | 3.828653 |
| Age | 45.5866667 | 46 | 45.4925926 | 45.5433333 | 10.6269593 |
| Height | 171.4366667 | 172 | 171.4740741 | 171.4266667 | 5.7436301 |
| Variable | RIC | DAM |
|---|---|---|
| Years | 15.25 | 0 |
| Cig | 13 | 0 |
| PC | 0.88075 | 0.541149 |
| Weight | 6 | 4.4478 |
| Age | 14 | 10.3782 |
| Height | 10 | 7.413 |
colSums(is.na(archivo))
## Sex Sport Years Cig PC City Weight Age Height
## 0 0 0 0 2 0 0 0 0
Como se puede evidenciar, PC presenta un total de 2 observaciones con valores perdidos.
En este apartado se ha usado KNN como algoritmo para imputar los valores perdidos a través de la medición de distancias Gower entre cada valor de la variable
#Missing Value
library(VIM)
archivo<- kNN(archivo)
archivo<-subset(archivo, select = Sex:Height)
archivo$PC<-as.numeric(archivo$PC)
colSums(is.na(archivo))
## Sex Sport Years Cig PC City Weight Age Height
## 0 0 0 0 0 0 0 0 0
Como se puede obervar en el conteno de valores NA en la variable PC, esta ha sido imputada a partir de KNN con un k por defecto.
Se realiza un resumen estadistico - descriptivo de cada una de las columnas depuradas, entre las métricas estan: MINIMOS, MAXIMOS , Rango Intercuartilico (RIC) y Media
#library(pastecs)
#stat.desc(archivo$Years)
| Variable | Minimos | Maximos | RIC | Media |
|---|---|---|---|---|
| Years | 0 | 51 | 15.25 | 8.4633333 |
| Cig | 0 | 47 | 13 | 7.2733333 |
| PC | 1.557 | 4.466 | 0.88475 | 3.33099 |
| Weight | 57 | 79 | 6 | 67.7166667 |
| Age | 19 | 77 | 14 | 45.5866667 |
| Height | 158 | 186 | 10 | 171.4366667 |
table(archivo$Sex)
##
## F M
## 137 163
table(archivo$Sport)
##
## None Sometimes Regularly Every Day
## 127 83 48 42
table(archivo$City)
##
## Alcanar Barcelona Blanes
## 12 102 11
## Cadaques Cardedeu Cardona
## 2 3 6
## Girona La Bisbal Lleida
## 10 7 13
## Montgat Pineda De Mar Puigcerda
## 6 11 3
## Ripoll Sant Boi De Llobregat Sitges
## 6 12 13
## Solsona Tarragona Terrassa
## 5 14 42
## Tossa Valls
## 7 15
Una vez se han depurado todas las variables, se genera el archivo con los datos:
# Write CSV
write.table(archivo, file = "fichero_clean.csv",row.names=FALSE, na="",col.names=TRUE, sep=",")
# row.names indica el nombre de cada fila, no es nuestro caso, pero podríamos asignarles ids
# na indica al archivo que si existen valores nulos los deje en vacio
# col.names indica el nombre de las columnas como cabecera en el archivo
# sep indica el tipo de separador con que registraran los datos en el archivo csv
Tipos de Variables
| Variable | Tipo de Dato | Tipo Estadistico |
|---|---|---|
| Sex | factor | Cualitativa |
| Sport | factor | Cualitativa |
| Years | numeric | Cuantitativa |
| Cig | numeric | Cuantitativa |
| PC | numeric | Cuantitativa |
| City | character | Cualitativa |
| Weight | numeric | CUantitativa |
| Age | integer | Cuantitativa |
| Height | integer | Cuantitativa |
barplot(prop.table(table(archivo$Sex)), main="Distribucion Sex", xlab="Personas", col=c("red","blue"),legend.text=c("Femeninno","Masculino"), ylim=c(0,0.8), ylab ="Frecuencias Relativas",las=1)
barplot(prop.table(table(archivo$Sport)), main="Distribucion Sport", xlab="Personas", col=c("green","blue", "red", "yellow"),legend.text=c("None","Sometimes","Regularly","Every Day"), ylim=c(0,0.8), ylab ="Frecuencias Relativas",las=1, legend = rownames(archivo$Sport))
barplot(prop.table(table(archivo$City)), main="Distribucion City", xlab="Ciudades",legend.text=levels(archivo$City),ylim=c(0,0.8), ylab ="Frecuencias Relativas",las=1, , legend = rownames(archivo$Sport))