-
Notifications
You must be signed in to change notification settings - Fork 0
EDA Parte 2
¿ Qué son outliers?
Los valores atípicos (outilers en inglés) son aquellos puntos que están mas allá del límite inferior o superior.
Definiciones Previas
"Primer cuartil: el 25% de los valores son menores o igual a este valor (punto 2 en el gráfico anterior). Mediana o Segundo Cuartil: Divide en dos partes iguales la distribución. De forma que el 50% de los valores son menores o igual a este valor (punto 3 en el gráfico siguiente). Tercer cuartil: el 75% de los valores son menores o igual a este valor (punto 4 en el gráfico siguiente). Rango Intercuartílico (RIC): Diferencia entre el valor del tercer cuartil y el primer cuartil."(Montes, 2020)
Proceso
- Para no abrazar errores, lo primero que debemos hacer y filtrar los datos nulos
- Calcular los cuartiles con
stat.approxQuantile
- Calcular la desviación estándar y el promedio con:
stddev
ymean
- Calcular limite superior e inferior
- Calculo de IQR; es decir el rango intercuartil
- Presentar los datos considerados como valores admisibles
val data2= df.drop("id_persona").select($"ingreso_laboral").filter("ingreso_laboral is NOT NULL")
data2.summary().show
val inilimit =0
val finlimit = 146030
val outliers = data2.stat.approxQuantile("ingreso_laboral",Array(0.25,0.75),0.00)
val dest= data2.select(stddev("ingreso_laboral")).first()(0).asInstanceOf[Double]
val avg= data2.select(mean("ingreso_laboral")).first()(0).asInstanceOf[Double]
val li = dest - 3 * avg
val ls = dest + 3 * avg
Podemos apreciar summary
(resumen en español),nos brinda datos númericos significativos como los cuartiles, minimo, máximo, total de filas, promedio y desviación estándar del dataframe
summary | ingreso_laboral |
---|---|
count | 504742 |
mean | 487.10984027483346 |
stddev | 767.7250086176327 |
min | 0 |
25% | 170 |
50% | 370 |
75% | 588 |
max | 146030 |
Luego filtramos en base al limite superior ls e invocamos summary
val newslimits = data2.filter(expr("ingreso_laboral") <= ls)
newslimits.toDF.summary().show
summary | ingreso_laboral |
---|---|
count | 497044 |
mean | 435.3529385728426 |
stddev | 378.2715590246983 |
min | 0 |
25% | 165 |
50% | 360 |
75% | 564 |
max | 2229 |
De la misma manera calculamos los valores átipicos de la variable factor_expansión, y lo podemos encontrar en el notebook Outliers Fato de Expansión
Lo denominamos multivariado por trabajamos con variabas columnas como género, ingreso_laboral, nivel de instrucción ,entre otras.
Con el fin de poder tener datos especificos sin reescribir código creamos algunas funciones, como por ejemplo nivelInstruccion2
, la que recibe dos parametros el nivel de instrucción y el año.
def nivelInstruccion2(nInstrc:String, anio:Int)={
val aux = pro.select("nivel_de_instruccion","ingreso_laboral","anio","genero").filter($"nivel_de_instruccion" === nInstrc && $"anio" ===anio).groupBy("nivel_de_instruccion","genero")
.agg(count('nivel_de_instruccion).as("count"), avg('ingreso_laboral), max('ingreso_laboral))
val total = pro.filter($"nivel_de_instruccion" === nInstrc && $"anio" ===anio).count()
val hom = aux.filter('genero === "1 - Hombre").drop('genero).select($"nivel_de_instruccion",$"avg(ingreso_laboral)",$"max(ingreso_laboral)",$"count".cast("Double")/total *100)
val hom2 = hom.withColumnRenamed(hom.schema.last.name,"Hombres").withColumn("Hombres", format_number('Hombres, 2) ).withColumnRenamed("avg(ingreso_laboral)","SueldoPromedioHombres")
.withColumn("SueldoPromedioHombres", format_number('SueldoPromedioHombres, 2) )
.withColumnRenamed("max(ingreso_laboral)","SueldoMaxHombres")
val muj = aux.filter('genero =!= "1 - Hombre").drop('genero).select($"nivel_de_instruccion",$"avg(ingreso_laboral)",$"max(ingreso_laboral)",$"count".cast("Double")/total *100)
val muj2 = muj.withColumnRenamed(muj.schema.last.name,"Mujeres").withColumn("Mujeres", format_number('Mujeres, 2) ).withColumnRenamed("avg(ingreso_laboral)","SueldoPromedioMujeres")
.withColumn("SueldoPromedioMujeres", format_number('SueldoPromedioMujeres, 2) )
.withColumnRenamed("max(ingreso_laboral)","SueldoMaxMujeres")
hom2.join( muj2 , "nivel_de_instruccion").select($"nivel_de_instruccion",$"Hombres" ,$"Mujeres" ,$"SueldoPromedioHombres" ,$"SueldoPromedioMujeres" ,$"SueldoMaxHombres" ,$"SueldoMaxMujeres").show
}
Resultado:
nivelInstruccion2("10 - Post-grado",2019)
nivel_de_instruccion | Hombres | Mujeres | SueldoPromedioHombres | SueldoPromedioMujeres | SueldoMaxHombres | SueldoMaxMujeres |
---|---|---|---|---|---|---|
10 - Post-grado | 48.82 | 51.18 | 1,805.20 | 1,485.12 | 20000 | 25300 |
De manera similar realizamos nivelInstruccion3
y nivelInstruccion4
, que se encuentran en el notebook Avances3Variable.zpln
nivelInstruccion3(2019)
nivel_de_instruccion | Hombres | Mujeres | SueldoPromedioHombres | SueldoPromedioMujeres | SueldoMaxHombres | SueldoMaxMujeres |
---|---|---|---|---|---|---|
09 - Superior Universitario | 8.73 | 9.20 | 896.76 | 743.78 | 999 | 999 |
08 - Superior no universitario | 1.23 | 0.99 | 794.83 | 580.16 | 998 | 990 |
05 - Educación Básica | 2.79 | 1.47 | 278.24 | 217.42 | 97 | 990 |
10 - Post-grado | 0.93 | 0.98 | 1,805.20 | 1,485.12 | 999 | 997 |
02 - Centro de alfabetización | 0.18 | 0.28 | 193.78 | 146.69 | 91 | 97 |
01 - Ninguno | 1.69 | 2.01 | 210.38 | 132.46 | 992 | 990 |
04 - Primaria | 18.09 | 13.06 | 358.28 | 232.91 | 998 | 990 |
07 - Educación Media | 7.35 | 4.34 | 353.64 | 287.94 | 995 | 988 |
06 - Secundaria | 15.64 | 11.04 | 534.70 | 371.82 | 998 | 999 |
nivelInstruccion4("Loja","10 - Post-grado",2019)
provincia | nivel_de_instruccion | Hombres | Mujeres | SueldoPromedioHombres | SueldoPromedioMujeres | SueldoMaxHombres | SueldoMaxMujeres |
---|---|---|---|---|---|---|---|
Loja | 10 - Post-grado | 46.34 | 53.66 | 1,645.11 | 1,190.36 | 800 | 996 |
Ya que estamos tratando con mas de dos variables, y resulta un poco extensas las funciones, tenemos estas dos funciones .stat.crosstab
y pivot
, que nos permiten simplificar o disminuir la cantidad de código para responder una pregunta por ejemplo:
Nos permite trabajar con los datos únicos tanto de provincia y sectorizacion y presentar la frecuencia respecto de los mismos
z.show(data3.stat.crosstab("provincia", "sectorizacion").orderBy("provincia_sectorizacion"))
De la anterior consulta notamos el uso del .stat.crosstab
, y además .show
que nos permite hacer visualizaciones del dataframe que le pasemos como parametro.
En la siguiente porción de código vemos el uso del pivot
, y es muy diferente del crosstab
ya que solo admite un argumento y funciona con los tipos de datos RelationalGroupedDataset, y pivot
los genera por esto nos servimos de agg
para agreagar las columnas que nesecitemos en nuestro caso el promedio del ingreso laboral y otras columnas mas, y al realizar esto creamos un dataframe
val avgSalGenero =data3.groupBy("rama_actividad").pivot("genero").agg(mean("ingreso_laboral"),max("ingreso_laboral"))
.orderBy($"rama_actividad")
val resultado = avgSalGenero.withColumnRenamed("1 - Hombre_avg(CAST(ingreso_laboral AS DOUBLE))","Hombres").withColumn("Hombres", format_number('Hombres,2))
.withColumnRenamed("2 - Mujer_avg(CAST(ingreso_laboral AS DOUBLE))","Mujeres").withColumn("Mujeres", format_number('Mujeres,2))
.withColumnRenamed("1 - Hombre_max(ingreso_laboral)","SueldoMaxHombre")
.withColumnRenamed("2 - Mujer_max(ingreso_laboral)","SueldoMaxMujer")
z.show(resultado)
Notebook CorssTabPivot
rama_actividad | Hombres | SueldoMaxHombre | Mujeres | SueldoMaxMujer |
---|---|---|---|---|
null | 63.88 | 970 | 31.26 | 954 |
Agricultura, ganadería caza y silvicultura y pesca | 301.46 | 999 | 177.15 | 998 |
Explotación de minas y canteras | 924.98 | 998 | 801.59 | 997 |
Industrias manufactureras | 544.63 | 999 | 361.10 | 999 |
Suministros de electricidad, gas, aire acondicionado | 1,145.91 | 998 | 746.80 | 990 |
Distribución de agua, alcantarillado | 699.80 | 998 | 727.03 | 995 |
Construcción | 449.02 | 999 | 865.75 | 999 |
Comercio, reparación vehículos | 584.75 | 999 | 366.05 | 999 |
Transporte y almacenamiento | 502.47 | 998 | 543.60 | 997 |
Actividades de alojamiento y servicios de comida | 539.17 | 999 | 354.65 | 998 |
Información y comunicación | 805.92 | 998 | 500.95 | 996 |
Actividades financieras y de seguros | 1,054.58 | 999 | 879.84 | 997 |
Actividades inmobiliarias | 808.38 | 992 | 657.58 | 990 |
Actividades profesionales, científicas y técnicas | 786.40 | 995 | 605.10 | 995 |
Actividades y servicios administrativos y de apoyo | 561.86 | 998 | 353.06 | 995 |
Administración pública, defensa y seguridad social | 1,092.45 | 999 | 1,011.21 | 999 |
Enseñanza | 943.01 | 999 | 841.54 | 999 |
Actividades, servicios sociales y de salud | 1,130.80 | 999 | 804.25 | 999 |
Artes, entretenimiento y recreación | 540.08 | 998 | 511.05 | 990 |
Otras actividades de servicios | 404.96 | 998 | 235.26 | 998 |