Documentación Técnica - Shomira/Proyecto-PAvanzada GitHub Wiki
A continuación se explicará a detalle cada uno de los bloques de código utilizados para realiza el Análisis Exploratorio de Datos realizado en "DataBriks", y como pre-requisito se necesita haber subido los archivos CSV con los datos (Serán presentados en el mismo orden que en el código)
Respecto a los archivos CSV, el general fue provisto por el docente, extraído de INEC; el de provincias fue extraído de Provincias; y el de cantones de Cantones
Esquema de definición de datos
Para la construcción de nuestro DataFrame del CSV general, es necesario crear su estructura, para asegurar la consistencia de los datos que cargaremos con el tipo de dato que esperamos para trabajar, y de esta forma detectar inconsistencias desde el inicio.
Para esto definiremos un valor llamado myDataSchem
, en el cual almacenaremos nuestro esquema; a este lo definiremos mediante una clase llamada StructType
, que nos permite construir una estructura deseada; a esta le asignaremos como parámetro un objeto de tipo Array
que contendrá campos StructField()
con el nombre que le asignaremos a cada columna de nuestros dataset (permitiéndonos luego acceder a este dato mediante su nombre) y el tipo de dato que éste deberá contener. Para una mejor comprensión, se lo puede comparar con el objeto Case Class
de Scala
val myDataSchem = StructType(
Array(
StructField("id", DecimalType(26, 0), true),
StructField("anio", IntegerType, true),
StructField("mes", IntegerType, true),
StructField("provincia", IntegerType, true),
StructField("canton", IntegerType, true),
StructField("area", StringType, true),
StructField("genero", StringType, true),
StructField("edad", IntegerType, true),
StructField("estado_civil", StringType, true),
StructField("nivel_de_instruccion", StringType, true),
StructField("etnia", StringType, true),
StructField("ingreso_laboral", IntegerType, true),
StructField("condicion_actividad", StringType, true),
StructField("sectorizacion", StringType, true),
StructField("grupo_ocupacion", StringType, true),
StructField("rama_actividad", StringType, true),
StructField("factor_expansion", DoubleType, true)
)
);
Carga de datos (Data General)
Empezaremos definiendo un valor ("data") en el que se almacenara el DataFrame con todos los datos generales. Para esto haremos uso de algunos métodos propios de Spark.
Primero usamos el comando spark.read
que nos permitirá leer el archivo que deseamos cargar; luego estableceremos las configuraciones de lectura mediante el método option()
, en el cual pondremos como parámetro dichas configuraciones, como el delimitador que posee nuestro archivo y la restricción de que posee encabezado (esto para que no cargue la primera fila como elemento de nuestro DataFrame); por ultimo, usamos el método csv()
, pues es el tipo de archivo que utilizamos, y le mandamos como parámetro la dirección en DataBriks en la que se encuentra.
val data = spark
.read
.schema(myDataSchem)
.option("delimiter", "\t")
.option("header","true")
.csv("/FileStore/tables/Datos_ENEMDU_PEA_v2.csv")
Carga de datos (Provincias)
Se realiza el mismo proceso que en el apartado anterior, pero con unas ligeras diferencias. Al ser distintos CSV, el que contiene las provincias posee otro delimitador, que es el ";"; y además, al ser pocos nuestros datos, no nos daremos el trabajo de crear un esquema para ellos, en su lugar simplemente usaremos un option()
y le pasaremos como parámetro "inferSchema" y "true", lo que hará al gestor inferir los tipos de datos según crea conveniente (este proceso solo es recomendable cuando se confía en que los datos no tendrán ningún error o que haya la necesidad de definir un tipo de dato especial). A estos datos se los almacena en un diferente valor.
val dataProv = spark
.read
.option("delimiter", ";")
.option("header","true")
.option("inferSchema", "true")
.csv("/FileStore/tables/TABLAPROVINCIAS.csv")
Carga de Datos(Cantones)
Se realiza un proceso igual que en el apartado anterior, con la unica diferencia que el delimitador del CSV a cargar es ",", en todo lo demás se realizan las mismas sentencias y se lo almacena en un valor diferente.
val dataCant = spark
.read
.option("delimiter", ",")
.option("header","true")
.option("inferSchema", "true")
.csv("/FileStore/tables/Cantones.csv")
Construcción de nuestro DataFrame Final
Para este proceso haremos uso de una función muy útil que es join()
. Esta función nos permite unir columnas de 2 DataFrames mientras tengan una columna en común, claramente estos se unirán en un nuevo DataFrame que debemos definir.
Nosotros ahora contamos con 3 DataFrames, por lo cual primero pasaremos a unir, el general y el de provincias. Aquí tenemos un caso especial y muy conveniente, la columna por la que queremos unirlos tiene el mismo nombre. Esto nos ahorra las cosas, pues nuestro método simplemente deberá aplicarle a un DataFrame, le mandaremos como parámetro el DataFrame a unir y la columna por la cual queremos unirlos; al aplicarlos de esta manera la columna a unir será un vinculo, para que todos los datos del segundo DataFrame se ubiquen en el primero.
val innerProvince = data.join(dataProv, "provincia")
Ahora realizamos el mismo procedimiento con el otro DataFrame que falta, pero aquí tenemos una diferencia, las columnas a unir no tienen el mismo nombre. Para esto simplemente debemos enviarle una condición como segundo parámetro, de que se una cuando el valor de la columna del primer DataFrame y el del segundo sean iguales.
val dataProvCantones = innerProvince.join(dataCant, innerProvince("canton") === dataCant("codigoCanton"))
Finalmente, procedemos a eliminar columnas que ya no son de nuestro interés, es decir, aquellas que nos sirvieron para unir nuestros datos. Esta sentencia la hacemos mediante la función drop()
, a la cual simplemente le enviamos como parámetros las columnas que se desean eliminar, y el DataFrame resultante lo almacenamos en un valor
val dataProvCant = dataProvCantones.drop("provincia", "canton", "codigoCanton")
Frecuencia de los datos según la Etnia
Ahora que tenemos nuestro DataFrame con todos los datos, empezamos a realizar un análisis respecto a nuestra columna de interés, las etnias, calculando cuantas etnias existen en nuestros datos, y cual es la frecuencia con la que se presentan.
Para esto nosotros haremos uso de métodos como el groupBy()
y el sort()
El primero de estos nos sirve, como su nombre lo indica, para agrupar filas según cada valor diferente de una columna que se le asignará como parámetro. Tener esta nueva estructura nos permite realizar algunas acciones un poco más interesantes como son las funciones de agregación. En nuestro caso, para obtener el análisis deseado haremos uso de la función count
, la cual nos permitirá contar cuantas filas se agruparon en cada etnia.
Ahora, la estructura que nos generan estas sentencias son un nuevo DataFrame que tendrá 2 columnas: la columna por la que agrupamos y una generada a través de la función de agregación, que tendrá el mismo nombre de la función.
El segundo método, nos ordena las filas de un DataFrame según la columna que le demos como parámetro de manera ascendente. Ademas se puede usar dentro del método, otro llamado desc()
que nos permitirá ordenar los datos de manera descendente.
Para realizar nuestro análisis deseado usaremos el método groupBy()
enviándole como parámetro la columna etnia, usaremos la función count
para contabilizar las agrupaciones, y ordenaremos nuestro resultado de manera descendente usando sort(desc())
según nuestra columna count
Ahora que tenemos nuestros datos ordenados según las frecuencias de las etnias de manera descendente procedemos a realizar una visualización.Para esto haremos uso de la función display()
, que permite visualizar un DataFrame tanto en formato de tablas como mediante gráficas estadísticas. Aquí enviaremos como parámetro el código descrito anteriormente dado que nos lanza un DataFrame.
display(dataProvCant.groupBy("etnia").count.sort(desc("count")))
Definición de DataFrames de interés
Al tener una cantidad de datos considerablemente grande, procederemos a extraer varios DataFrame que contengan solo porciones de los datos que son de interés para este análisis, con el fin de optimizar los procesos al trabajar con una menor densidad de datos.
Para extraerlos haremos uso del método where()
, que sirve para filtrar aquellos datos de una columna determinada que cumplan una condición establecida.
En este análisis crearemos 5 DataFrames, que corresponderán a datos específicos de las etnias Mestizo, Indígena, Montubio, Blanco y una que contendrá los datos de las 4 etnias juntas. Utilizaremos el método where()
en nuestro dataProvCant, y filtraremos según la condición de que la fila tenga como "etnia" a la Mestiza; en este filtro de debe anteponer $
a la columna que se desea comparar, el cual convierte a nuestro dato de etnia en un objeto, permitiendo que sea comparado mediante operadores lógicos (el operador lógico de igualdad en Spark es un triple igual ===
; y el o lógico es ||
).
Crearemos un valor para cada DataFrame que deseamos crear, con los datos de las etnias de interés, que para el ultimo serán las 4 etnias juntas, concatenando las condiciones del where()
de las anteriores sentencias mediante un "o".
val dataInd = dataProvCant.where($"etnia" === "1 - Indígena")
val dataMon = dataProvCant.where($"etnia" === "5 - Montubio")
val dataMes = dataProvCant.where($"etnia" === "6 - Mestizo")
val dataBla = dataProvCant.where($"etnia" === "7 - Blanco")
val data4Etnias = dataProvCant.where($"etnia" === "1 - Indígena" || $"etnia" === "5 - Montubio" || $"etnia" === "6 - Mestizo" || $"etnia" === "7 - Blanco")
Salarios máximos de cada etnia (Global)
Para esta consulta y aprovechando los DataFrame creados anteriormente, haremos uso de data4Etnias y aplicaremos un groupBy()
según la columna etnia como lo hicimos en una consulta anterior. A continuación aplicaremos otra función de agregación, max()
que sirve para sacar el dato máximo de un conjunto de filas y le mandaremos como parámetro el ingreso_laboral. Esta función la aplicaremos dentro de un método llamado agg()
, el cual nos permite añadir una columna según las sentencias ubicadas como parámetros; usamos este método para definir un alias, es decir un nuevo titulo para la columna agregada, esto se lo hace por medio de un "as" seguido del nombre que le queremos poner a nuestra columna entre comillas.
Por ultimo usamos un sort()
para ordenar los resultados de manera ascendente según la etnia
Todo éste código lo ubicamos dentro de un display()
para obtener una mejor visualización
display(data4Etnias.groupBy("etnia").agg(max("ingreso_laboral")as "Ingreso Laboral Maximo").sort("etnia"))
Salarios mínimos de cada etnia (Global)
Se procede de la misma forma que en la consulta anterior, con la diferencia que la función de agregación usada será min()
y el nuevo alias a la columna agregada será diferente
display(data4Etnias.groupBy("etnia").agg(min("ingreso_laboral")as "Ingreso Laboral Minimo").orderBy("etnia"))
Salarios máximos de cada etnia (Por año)
Para realizar esta consulta necesitaremos un nuevo concepto que es pivote, esto es una agregación donde una o más columnas de agrupación tienen sus valores distintos transpuestos en columnas individuales.
Este concepto se lo puede aplicar por medio de la función pivot()
, y en nuestro caso le enviaremos como parámetros la columna etnia. Esto nos resultará en nuevas columnas con cada uno de los valores distintos de las etnias que existen en nuestro DataFrame, y su respectiva agrupación según esas nuevas columnas.
Ahora, nuestra consulta empezará agrupando cada uno de los años mediante un groupBy()
a nuestro DataFrame data3Etnias, y luego aplicaremos la función pivote según cada etnia; ahora, como ya no necesitamos agregar una nueva columna para obtener el valor máximo del salario (lo calcularemos en cada una de las columnas pivote) lo que haremos será simplemente aplicar la función de agregación max()
sin la función agg()
, y enviándole como parámetro el ingreso_laboral; por ultimo aplicaremos un sort()
según los años y todo esto lo visualizaremos en un display()
.
display(data4Etnias.groupBy("anio").pivot("etnia").max("ingreso_laboral").orderBy("anio"))
Salarios mínimos de cada etnia (Por años)
Realizaremos las mismas sentencias que en la consulta anterior, con la única diferencia de que la función de agregación a usar será min()
display(data4Etnias.groupBy("anio").pivot("etnia").min("ingreso_laboral").orderBy("anio"))
Salario promedio de cada etnia (Global)
De igual forma que en las consultas anteriores, usaremos data4Etnias para realizar esta consulta. Empezaremos aplicándole un groupBy()
según las etnias. Seguido aplicaremos un agg()
para agregar una columna adicional; dentro de este le aplicaremos una nueva función llamada round()
, que nos servirá para redondear un decimal a su entero mas próximo, y dentro de esta usaremos la función de agregación avg()
, enviándole como parámetro el ingreso_laboral, lo que nos devolverá el promedio del ingreso_laboral de cada fila en los grupos generados; finalmente dentro de nuestro agg()
le aplicaremos un as y le pondremos un titulo mas descriptivo a la columna generada.
Luego aplicaremos un sort()
según las etnias para ordenar nuestros resultados
Todas estas sentencias se las colocará dentro de un display()
como función de visualización.
display(data4Etnias.groupBy("etnia").agg(round(avg("ingreso_laboral"))as "Ingreso Laboral Promedio").orderBy("etnia"))
Salario promedio de cada etnia (Por año)
Usando *data4Etnias le aplicaremos un groupBy()
según los años, y le aplicaremos la función pivot()
según la columna etnia, luego usaremos la función agg()
de la misma forma que el la consulta anterior (sacando el promedio y redondeando), pero sin darle un alias, pues cada promedio se agregará a las columnas pivote generadas. A continuación aplicamos un sort()
y como parámetro los años.
Todas estas sentencias se las colocará dentro de un display()
como función de visualización.
display(data4Etnias.groupBy("anio").pivot("etnia").agg(round(avg("ingreso_laboral"))).sort("anio"))
Porcentaje donde Ingreso Laboral sea menor al salario básico, de acuerdo a cada Etnia
Usando *data4Etnias le aplicaremos un groupBy()
pero esta vez le enviaremos una expresión lógica, para lo cual usaremos un $
adelante del nombre de la columna ingreso_laboral para poder operar y compararemos aquellos que son mayores a 400, la cual nos lanzará 3 resultados posibles: true, false y null; seguido le aplicaremos un as
para darle un título a esta nueva columna. Luego usaremos un pivot()
por etnia y le aplicaremos un count
.
Todas estas sentencias se las colocará dentro de un display()
como función de visualización.
display(data4Etnias.groupBy("etnia").pivot($"ingreso_laboral" < 400).count.sort("etnia"))
Porcentaje donde el campo Ingreso Laboral es Nulo, de acuerdo a cada Etnia
De la misma manera que en la sentencia anterior, usamos *data4Etnias y le aplicaremos un groupBy()
pero esta vez le enviaremos la expresión lógica, evaluando aquellos valores del campo ingreso_laboral que sean nulos y le pondremos igualmente un alias. Luego usaremos un pivot()
por etnia y le aplicaremos un count
.
Todas estas sentencias se las colocará dentro de un display()
como función de visualización.
display(data4Etnias.groupBy($"ingreso_laboral".isNull as "Ingreso Laboral nulo").pivot("etnia").count)
Distribución de los Grupos de Ocupación según cada Etnia
Para realizar la distribución empezaremos realizando a *data4Etnias un groupBy()
según los grupos de ocupación, y luego haciéndole un pivot()
por etnia. Entonces procedemos a aplicarle un count
, y para una mejor visualización, aplicamos un sort()
según los grupos de ocupación.
Todas estas sentencias se las colocará dentro de un display()
como función de visualización.
display(data4Etnias.groupBy($"grupo_ocupacion").pivot("etnia").count.sort("grupo_ocupacion"))
Distribución de la Sectorización según cada Etnia
Procedemos de la misma forma que en la sentencia anterior, pero realizando a *data4Etnias el groupBy()
y el sort()
según la sectorización.
display(data4Etnias.groupBy("sectorizacion").pivot("etnia").count.orderBy("sectorizacion"))
¿Que porcentaje de personas que tienen un nivel de instrucción "Superior Universitario" ganan menos que el salario básico?
Para esta consulta, a *data4Etnias le realizaremos un filter()
, que, como su nombre lo indica sirve para filtrar filas según una condición y funciona de manera parecida al where()
; a éste le enviaremos la condición de que el nivel de instrucción sea igual al nivel superior universitario.
Luego, como en una consulta anterior, aplicaremos un groupBy()
para la condición de que su salario sea menor al básico y le asignamos un alias. Luego aplicamos un pivot()
según las etnias y la función de agregación count
.
Finalmente toda esta sentencia la ubicamos dentro de un display()
para su visualización.
display(data4Etnias.filter($"nivel_de_instruccion" === "09 - Superior Universitario" ).groupBy($"ingreso_laboral" < 400 as "Ingreso Laboral Menor que el Básico").pivot("etnia").count)
Distribución de las Ramas de Actividad según cada Etnia
Aplicaremos aquí el mismo proceso que en las distribuciones anteriores, pero realizando a *data4Etnias el groupBy()
y el sort()
según la rama actividad.
display(data4Etnias.groupBy($"rama_actividad").pivot($"etnia").count.sort("rama_actividad"))
Distribución de personas en cada rama de actividad de aquellos ubicados en el SECTOR INFORMAL según cada etnia
Procedemos igual que en la consulta anterior, con la diferencia de que en esta consulta aplicaremos en un inicio a *data4Etnias un filter()
, con la condición de que la sectorización de cada fila sea el sector informal.
display(data4Etnias.filter($"sectorizacion" === "2 - Sector Informal").groupBy($"rama_actividad").pivot($"etnia").count.sort("rama_actividad"))
Distribución de personas en cada rama de actividad que tengan un nivel de instrucción primaria según cada etnia
Procedemos igual que en la consulta anterior, con la diferencia en el filter()
se aplicará la condición de que el nivel de instrucción de cada fila sea primaria.
display(data4Etnias.filter($"nivel_de_instruccion" === "04 - Primaria").groupBy($"rama_actividad").pivot($"etnia").count.orderBy("rama_actividad"))
Distribución de personas en cada rama de actividad que tengan un nivel de instrucción secundaria según cada etnia
Procedemos igual que en la consulta anterior, con la diferencia en el filter()
se aplicará la condición de que el nivel de instrucción de cada fila sea secundaria.
display(data4Etnias.filter($"nivel_de_instruccion" === "06 - Secundaria").groupBy($"rama_actividad").pivot($"etnia").count.orderBy("rama_actividad"))
Numero de mujeres por cada año y por etnia que pertenecieron a la rama_actividad Agricultura, ganadería caza y silvicultura y pesca
Para esta consulta le aplicamos a nuestro data4Etnias un filter()
con las condiciones que sea igual a la rama actividad deseada y que el género sea igual a 2 - Mujer; ambas condiciones concatenadas por un "y" lógico &&
.
Luego procedemos a agrupar mediante un groupBy()
según el año, y aplicamos un pivot()
por etnia. Finalmente ordenamos por medio de un sort()
según el año; y todo esto lo ubicamos dentro de un display()
para su visualización.
display(data4Etnias.filter($"rama_actividad" === "01 - A. Agricultura, ganadería caza y silvicultura y pesca" && $"genero" === "2 - Mujer").groupBy($"anio").pivot($"etnia").count.sort("anio"))
OUTLIERS INGRESO LABORAL
Para este apartado, realizaremos el mismo proceso por separado para cada etnia de interés utilizando los DataFrames independientes definidos en el tercer bloque de código, por lo que solamente se explicará los procesos para la etnia indígena y para los demás simplemente se deberá replicar con los datos respectivos.
Aquí lo que buscamos es extraer un DataFrame con todos los outliers de la columna ingreso_laboral según cada etnia independiente.
Primero crearemos un nuevo DataFrame (dfEdadInd) mediante el método select()
, que como su nombre lo indica, nos permite seleccionar columnas especificas de nuestro DataFrame, descartando así las demás; a ésta le enviaremos solamente la columna ingreso_laboral y filtraremos aquellos en los no sea su valor nulo mediante un where()
.
val dfEdadInd = dataInd.select("edad").where($"edad".isNotNull)
De aquí en adelante haremos uso solamente de este DateFrame. Pues el anterior no provocaría errores en los cálculos debido a los valores nulos.
Ahora sacaremos en un valor la media de nuestro nuevo DataFrame. Para esto aplicaremos un select()
y dentro de éste aplicaremos la función de agregación mean()
enviándole como parámetro la única columna: ingreso_laboral. Esto nos resultará en un DataFrame con una sola columna que guardará el valor de la media. Luego aplicaremos la función first()(0)
para extraer únicamente el primer valor (que en nuestro caso es el único). Finalmente aplicamos la función asInstanceOf[]
enviándole como parámetro "Double", lo cual nos transformará el valor resultante en un tipo de dato double.
val avgS = dfSueldoInd.select(mean("ingreso_laboral")).first()(0).asInstanceOf[Double]
Ahora, de la misma forma que antes, sacaremos la desviación estándar del DataFrame y la almacenaremos en un valor. Para esto realizamos el mismo proceso que antes, pero con la función de agregación stddev()
val stdDesvS = dfSueldoInd.select(stddev("ingreso_laboral")).first()(0).asInstanceOf[Double]
A continuación sacaremos los limites que determinarán los outliers en nuestros datos. Lo haremos sirviéndonos de los valores calculados anteriormente. Para esto haremos uso de criterios estadísticos, siendo los limites superior e inferior igual la media más y menos, respectivamente, a 3 veces la desviación estándar.
val inferiorS = avgS - 3 * stdDesvS
val superiorS = avgS + 3 * stdDesvS
Estas sentencias descritas de realizan para cada DataFrame de etnia.
Finalmente pasamos a crear nuestro DataFrame solamente con los outliers detectados, cabe recalcar que solo consideraremos los superiores, pues según los datos generados hasta aquí, el limite inferior es negativo, y ningún salario laboral se encuentra en ese rango. Para esto definimos un nuevo valor el cual será el resultado de, a nuestro DataFrame data4Etnias, aplicarle un where()
con las condiciones de que para cada etnia, se filtren solo los valores de ingreso laboral que son mayores a su limite superior.
Este proceso lo hacemos mediante la concatenación de varias condiciones mediante el operador lógico "o"; estas condiciones serán que la etnia sea igual a la deseada, unidad con un "y" lógico a la condición de que el ingreso laboral sea mayor a su limite superior.
val dataOutliersIngreso = data4Etnias.where(($"etnia" === "1 - Indígena" && $"ingreso_laboral" > superiorS) || ($"etnia" === "5 - Montubio" && $"ingreso_laboral" > superiorSMon) || ($"etnia" === "6 - Mestizo" && $"ingreso_laboral" > superiorSMes) || ($"etnia" === "7 - Blanco" && $"ingreso_laboral" > superiorSBla))
Ingresos Laborales mínimos de los Outliers de ingreso laboral de cada etnia
Para esta sentencia usamos el mismo código de la consulta Salarios mínimos de cada etnia (Global), pero ahora usando el DataFrame dataOutliersIngreso
display(dataOutliersIngreso.groupBy("etnia").agg(min("ingreso_laboral")as "Ingreso Laboral Minimo").sort("etnia"))
Distribución según el grupo ocupación de cada etnia (Outliers Ingreso laboral)
Para esta consulta usamos el mismo código de la consulta Distribución de los Grupos de Ocupación según cada Etnia, pero ahora usando el DataFrame dataOutliersIngreso
display(dataOutliersIngreso.groupBy($"grupo_ocupacion").pivot("etnia").count.sort("grupo_ocupacion"))
Distribución según el nivel de instrucción de cada etnia (Outliers Ingreso laboral)
Para esta consulta usamos el mismo código de la consulta Distribución de los Niveles de Instrucción según cada Etnia, pero ahora usando el DataFrame dataOutliersIngreso
display(dataOutliersIngreso.groupBy($"nivel_de_instruccion").pivot("etnia").count.sort("nivel_de_instruccion"))
Distribución según la provincia de cada etnia (Outliers Ingreso laboral)
Para esta consulta usaremos las mismas sentencias que las anteriores, pero le enviaremos a los métodos groupBy()
y sort()
el parámetro "nomProvincia" para obtener los resultados deseados.
display(dataOutliersIngreso.groupBy($"nomProvincia").pivot("etnia").count.sort("nomProvincia"))
OUTLIERS EDAD
Realizaremos aquí el mismo proceso que para los Outliers de la columna ingreso laboral, únicamente cambiaremos los nombres de los valores.Quedandonos en el caso de provincia de la siguiente manera
val dfEdadInd = dataInd.select("edad").where($"edad".isNotNull)
val avgE = dfEdadInd.select(mean("edad")).first()(0).asInstanceOf[Double]
val stdDesvE = dfEdadInd.select(stddev("edad")).first()(0).asInstanceOf[Double]
val inferiorE = avgE - 3 * stdDesvE
val superiorE = avgE + 3 * stdDesvE
Este proceso se lo realiza para cada etnia independiente.
Luego, de forma similar se realiza la creación de nuestro DataFrame con únicamente los Outliers Superiores, pues los limites inferiores siguen siendo negativos.
val dataOutliersEdad = data4Etnias.where(($"etnia" === "1 - Indígena" && $"edad" > superiorE) || ($"etnia" === "5 - Montubio" && $"edad" > superiorEMon) || ($"etnia" === "6 - Mestizo" && $"edad" > superiorEMes) || ($"etnia" === "7 - Blanco" && $"edad" > superiorEBla))
Edad mínima de los outliers de cada etnia
Para esta sentencia usamos el mismo código de la consulta Salarios mínimos de cada etnia (Global), pero ahora usando el DataFrame dataOutliersEdad
display(dataOutliersEdad.groupBy("etnia").agg(min("ingreso_laboral")as "Ingreso Laboral Minimo").sort("etnia"))
Ingresos Laborales promedio de los Outliers de edad de cada etnia
Para esta sentencia usamos el mismo código de la consulta Ingreso Laboral promedio de cada etnia (Global), pero ahora usando el DataFrame dataOutliersEdad
display(dataOutliersEdad.groupBy("etnia").agg(avg("ingreso_laboral")as "Ingreso Laboral Promedio").sort("etnia"))
Distribución según el nivel de instrucción de cada etnia (Outliers Edad)
Para esta consulta usamos el mismo código de la consulta Distribución de los Niveles de Instrucción según cada Etnia, pero ahora usando el DataFrame dataOutliersEdad
display(dataOutliersEdad.groupBy($"nivel_de_instruccion").pivot("etnia").count.sort("nivel_de_instruccion"))
SQL
Trabajando en DataBricks tenemos unas opciones sencillas para realizar consultas SQL.
Para esto el primer paso es crear una tabla dinámica con nuestros datos y le asignamos un nombre que irá como parámetro
dataProvCant.createOrReplaceTempView("EDU_TABLE")
Ahora, creada nuestra tabla es muy sencillo crear consultas SQL, solamente necesitamos escribir %sql
sobre cada consulta y la tendremos
Nombres de cada provincias junto a: el número de etnias que están presentes en esa provincia, el promedio del ingreso laboral anual de todos los registrados en dicha provincia y el número de registros que existen en ésta
%sql
Select nomProvincia, count(DISTINCT etnia) , avg(ingreso_laboral * 12) , count(*)
From EDU_TABLE
GROUP BY nomProvincia
ORDER BY 4;
Nombre y cantidad de registros de cada provincia que tengan un ingreso laboral mayor a 20000 y se encuentren en el grupo de Profesionales científicos e intelectuales
%sql
Select nomProvincia, count(*)
From EDU_TABLE
WHERE ingreso_laboral > 20000 AND grupo_ocupacion == "02 - Profesionales científicos e intelectuales"
GROUP BY nomProvincia
ORDER BY count(*);
Grupo de ocupación y cantidad de registros de aquellos que se encuentran en las provincias de Pichincha o Guayas, con un nivel de instrucción de Post-grado y con un ingreso laboral mayor a 10000
%sql
Select grupo_ocupacion, count(*)
From EDU_TABLE
WHERE (nomProvincia == "PICHINCHA" OR nomProvincia == "GUAYAS") AND nivel_de_instruccion == "10 - Post-grado" AND ingreso_laboral > 10000
GROUP BY grupo_ocupacion
ORDER BY count(*);
Trabajando con Zeppelin
Para este análisis exploratorio de datos, cabe destacar que se puede realizar en otra herramienta como Zeppelin, que se la puede recomendar para usuarios Linux ya que su instalación es facil y nada compleja con respecto al SO Windows.
El análisis que se ha hecho, todas las consultas también son ejecutables en la herramienta zeppelin. Únicamente cambia la función de visualización, a cada consulta de la herramienta Databricks; pues se reemplaza la función display()
por la función z.show()