<jupyter_start><jupyter_text>Comenzamos importando las librerías. Es importante observar que se están utilizando alias en los paquetes para referenciar y desambiguar los nombres de las funciones que deriven de ellos.<jupyter_code>from pyspark.sql import SparkSession
from pyspark.sql import functions as F
from pyspark.sql import types as T<jupyter_output><empty_output><jupyter_text>Creamos la SparkSession con el master en el sistema local.<jupyter_code>spark = (SparkSession \
         .builder \
         .master("local") \
         .enableHiveSupport() \
         .appName("Padron_Python") \
         .getOrCreate())<jupyter_output><empty_output><jupyter_text>Importamos el set de datos desde una ruta local, declarando las comillas que envuelven los campos, que nos sustituya los campos vacíos por 0, que infiera el esquema y que considere la primera línea como header.<jupyter_code>padronDF = spark.read.format("csv") \
                     .option("inferSchema", True) \
					 .option("header", True) \
					 .option("emptyValue", "0") \
					 .option("quote", "\"") \
					 .option("escape", "\"") \
					 .option("sep", ";") \
					 .option("encoding", "ISO-8859-1") \
					 .load("C:/Users/luismiguel.dominguez/Escritorio/TFM/Dataset/padron1.txt")<jupyter_output><empty_output><jupyter_text>Mostramos los tipos para ver que todo se ha importado correctamente.<jupyter_code>padronDF.dtypes<jupyter_output><empty_output><jupyter_text>Comprobamos el número de barrios y de distritos diferentes que hay en nuestro dataset.<jupyter_code>padronDF.select(F.col("DESC_BARRIO")).distinct().show(40)
padronDF.select(F.col("DESC_BARRIO")).distinct().count()
padronDF.select(F.col("DESC_DISTRITO")).distinct().show(40)
padronDF.select(F.col("DESC_DISTRITO")).distinct().count()<jupyter_output>+--------------------+
|       DESC_DISTRITO|
+--------------------+
|<NAME>   |
|SALAMANCA           |
|CHAMBERI            |
|CHAMARTIN           |
|TETUAN              |
|VILLAVERDE          |
|MORATALAZ           |
|CENTRO              |
|USERA               |
|VICALVARO           |
|HORTALEZA           |
|CIUDAD LINEAL       |
|FUENCARRAL-<NAME> |
|MONCLOA-ARAVACA     |
|SAN BLAS-CANILLEJAS |
|RETIRO              |
|LATINA              |
|BARAJAS             |
|ARGANZUELA          |
|CARABANCHEL         |
|PUENTE DE VALLECAS  |
+--------------------+<jupyter_text>Como podemos ver, aún sobran espacios en blanco tras los campos tipo string.<jupyter_code>padronDF.select(F.col("DESC_DISTRITO"), F.length("DESC_DISTRITO")).distinct().show()<jupyter_output>+--------------------+---------------------+
|       DESC_DISTRITO|length(DESC_DISTRITO)|
+--------------------+---------------------+
|MONCLOA-ARAVACA     |                   20|
|CARABANCHEL         |                   20|
|ARGANZUELA          |                   20|
|CHAMARTIN           |                   20|
|BARAJAS             |                   20|
|TETUAN              |                   20|
|VILLAVERDE          |                   20|
|CHAMBERI            |                   20|
|LATINA              |                   20|
|USERA               |                   20|
|CENTRO              |                   20|
|HORTALEZA           |                   20|
|VICALVARO           |                   20|
|MORATALAZ           |                   20|
|CIUDAD LINEAL       |                   20|
|SALAMANCA           |                   20|
|<NAME> |                   20|
|<NAME>   |                   20|
|RETIRO              |                   20|
|PUENTE DE[...]<jupyter_text>Los quitamos con la función TRIM y mostramos que el resultado es el adecuado.<jupyter_code>padronDF_bueno = padronDF.withColumn("DESC_DISTRITO", F.rtrim("DESC_DISTRITO")) \
                         .withColumn("DESC_BARRIO", F.rtrim("DESC_BARRIO"))

padronDF_bueno.select(F.col("DESC_DISTRITO"), F.length("DESC_DISTRITO")).distinct().show()<jupyter_output>+-------------------+---------------------+
|      DESC_DISTRITO|length(DESC_DISTRITO)|
+-------------------+---------------------+
|         ARGANZUELA|                   10|
|<NAME>|                   19|
|              USERA|                    5|
|          SALAMANCA|                    9|
| <NAME>|                   18|
|  <NAME>|                   17|
|           CHAMBERI|                    8|
|          VICALVARO|                    9|
|             RETIRO|                    6|
|             CENTRO|                    6|
|SAN BLAS-CANILLEJAS|                   19|
|          CHAMARTIN|                    9|
|             LATINA|                    6|
|          MORATALAZ|                    9|
|            BARAJAS|                    7|
|             TETUAN|                    6|
|      <NAME>|                   13|
|          HORTALEZA|                    9|
|         VILLAVERDE|                   10|
|        CARABANCHEL|           [...]<jupyter_text>Lanzamos una query compleja similar a la que lanzamos en la shell para comprobar que podemos usar gran variedad de funciones sin problema. Guardamos este DataFrame en caché para que la siguiente consulta que lo utilice sea más rápida.<jupyter_code>cont = padronDF_bueno.select(F.col("COD_EDAD_INT"), F.col("DESC_DISTRITO"),F.col("espanolesmujeres")) \
                     .where(F.col("DESC_DISTRITO").isin("CENTRO", "BARAJAS", "RETIRO")) \
                     .groupBy(F.col("COD_EDAD_INT"))\ 
                     .pivot("DESC_DISTRITO").sum("espanolesmujeres") \
                     .orderBy("COD_EDAD_INT")

cont.cache().show()<jupyter_output>+------------+-------+------+------+
|COD_EDAD_INT|BARAJAS|CENTRO|RETIRO|
+------------+-------+------+------+
|           0|    170|   259|   318|
|           1|    179|   260|   370|
|           2|    209|   255|   396|
|           3|    235|   244|   426|
|           4|    250|   244|   436|
|           5|    255|   250|   431|
|           6|    243|   251|   448|
|           7|    270|   232|   431|
|           8|    252|   263|   438|
|           9|    266|   265|   422|
|          10|    264|   260|   416|
|          11|    263|   260|   437|
|          12|    285|   259|   427|
|          13|    252|   250|   398|
|          14|    282|   269|   431|
|          15|    263|   247|   423|
|          16|    244|   258|   412|
|          17|    257|   279|   443|
|          18|    213|   256|   413|
|          19|    207|   265|   430|
+------------+-------+------+------+
only showing top 20 rows<jupyter_text>Calculamos los porcentajes.<jupyter_code>cont.select("*").withColumn("Suma", (F.col("BARAJAS") + F.col("CENTRO")+F.col("RETIRO"))) \
                .withColumn("BARAJAS %", F.round(F.col("BARAJAS")/F.col("Suma")*100,2)) \
                .withColumn("CENTRO %", F.round(F.col("centro")/F.col("Suma")*100,2)) \
                .withColumn("RETIRO %", F.round(F.col("retiro")/F.col("Suma")*100,2)).show()<jupyter_output>+------------+-------+------+------+----+---------+--------+--------+
|COD_EDAD_INT|BARAJAS|CENTRO|RETIRO|Suma|BARAJAS %|CENTRO %|RETIRO %|
+------------+-------+------+------+----+---------+--------+--------+
|           0|    170|   259|   318| 747|    22.76|   34.67|   42.57|
|           1|    179|   260|   370| 809|    22.13|   32.14|   45.74|
|           2|    209|   255|   396| 860|     24.3|   29.65|   46.05|
|           3|    235|   244|   426| 905|    25.97|   26.96|   47.07|
|           4|    250|   244|   436| 930|    26.88|   26.24|   46.88|
|           5|    255|   250|   431| 936|    27.24|   26.71|   46.05|
|           6|    243|   251|   448| 942|     25.8|   26.65|   47.56|
|           7|    270|   232|   431| 933|    28.94|   24.87|    46.2|
|           8|    252|   263|   438| 953|    26.44|    27.6|   45.96|
|           9|    266|   265|   422| 953|    27.91|   27.81|   44.28|
|          10|    264|   260|   416| 940|    28.09|   27.66|   44.26|
|          11|    26[...]<jupyter_text>Guardamos el resultado de la query en una variable y la escribimos en formato parquet en nuestro sistema de ficheros local.<jupyter_code>escritura_DF = cont.select("*").withColumn("Suma", (F.col("BARAJAS") + F.col("CENTRO")+F.col("RETIRO"))) \
                .withColumn("BARAJAS %", F.round(F.col("BARAJAS")/F.col("Suma")*100,2)) \
                .withColumn("CENTRO %", F.round(F.col("centro")/F.col("Suma")*100,2)) \
                .withColumn("RETIRO %", F.round(F.col("retiro")/F.col("Suma")*100,2)).show()


escritura_DF.write.parquet("C:/Users/luismiguel.dominguez/Escritorio/TFM/Dataset/output/padron_output.txt")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.18369971936389148, 'fraction_numerical': 0.06875584658559401, 'mean_word_length': 1.4528247777459133, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 44, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '479503', 'license': 'Apache-2.0', 'n_tokens_mistral': 3433, 'n_tokens_neox': 2954, 'n_words': 541, 'path': 'Notebook/Padron_Python.ipynb', 'repo_name': 'Lism2992/TFM', 'size': '8632'}