<jupyter_start><jupyter_text>4. Data Frames y SQL.  Lección 13: Creación de DataFrames. Primero debemos importar las librerias necesarias para la creación de las estructuras (DataFrames)<jupyter_code>from pyspark import SparkContext
from pyspark.sql import SparkSession

from pyspark.sql.types import StructType, StructField
from pyspark.sql.types import IntegerType, StringType, FloatType
from pyspark.sql.types import Row
from pyspark.sql import SQLContext<jupyter_output><empty_output><jupyter_text>Iniciamos dos contextos de spark, SparkContex, que requiere dos parametros (master es la dirección ip de la máquina donde se ejecuta la aplicación, appName es el nobre de la aplicación)<jupyter_code>spark = SparkContext(master="local", appName="DataFrames")
sqlContext = SQLContext(spark)<jupyter_output><empty_output><jupyter_text>Podemos crear DataFrames de distintas maneras, a continuación crearemos un DF a partir de un archivo csv ya existente.**Nota:** Es altamente recomendable que en la medida de lo posible, **todos** los DF se creen directamente desde los datos y no desde RDDs. Las siguientes celdas son para deducir la ruta del archivo que se convertirá en un DataFrame<jupyter_code>!ls
!ls ./files/
!head -n 5 ./files/juegos.csv
!pwd
path = './files/'<jupyter_output><empty_output><jupyter_text>La siguiente celda muestra la definición del esquema del dataframe (juegoSchema), muy similar a la definición de una tabla de SQL<jupyter_code>juegoSchema = StructType([
    StructField("juego_id", IntegerType(),False),
    StructField("year", StringType(), False),
    StructField("temporada", StringType(), False),
    StructField("ciudad", StringType(), False)
])<jupyter_output><empty_output><jupyter_text>Cada campo requiere de tres parámetros; el nombre del campo, el tipo de dato en el campo y si es posible que sea nulo o no (True si puede ser nulo, False si no puede ser nulo) A continuación, se asigna a la variable juegoDF el contexto sql, que posee una definición llamada juegoSchema, con la opción de que la primera fila sea considerada como el encabezado de la tabla. Finalmente, toda esa estructura funciona como contenedor del contenido del archivo tipo csv que habita en una ruta predeterminada y un nombre definido.<jupyter_code>juegoDF = sqlContext.read.schema(juegoSchema)\
    .option("header","true").csv(path + "juegos.csv")<jupyter_output><empty_output><jupyter_text>El metodo ```show(4)``` muestra las primeras 4 filas de la estructura.<jupyter_code>#juegoDF.show(4)
spark<jupyter_output><empty_output><jupyter_text>Nota: la dirección de la Interfaz del usuario de la aplicación, para este caso, es la siguiente: http://192.168.1.69:4040/jobs/job/?id=0, donde la ip del master es la local (192.168.1.69). La aplicación de Spark siempre se abre en el puerto 4040, si y solo si las sesiones previas de Spark ya fueron cerradas previamente, de lo contrario se utilizara otro puerto.  Fin de la lección 13  Lección 14: Inferencia de tipos de datos. En esta lección vamos a crear un Dataframe a partir de un RDD existente, para esto vamos a recrear un RDD (ver la lección 9)**Nota** : Es recomendable que el origen de los DF sean los archivos y no RDDs.<jupyter_code>deportistaOlimpicoRDD = spark.textFile(path + "deportista.csv")\
    .map(lambda l : l.split(","))
deportistaOlimpicoRDD2 = spark.textFile(path + "deportista2.csv")\
    .map(lambda l : l.split(","))
DF_From_RDD = deportistaOlimpicoRDD.union(deportistaOlimpicoRDD2)
DF_From_RDD.count()<jupyter_output><empty_output><jupyter_text>Primero vamos a eliminar el encabezado del RDD con una función especializada:<jupyter_code>def eliminaEncabezado(indice, interador):
    return iter(list(interador)[1:])
DF_From_RDD = DF_From_RDD.mapPartitionsWithIndex(eliminaEncabezado)
DF_From_RDD.take(5)<jupyter_output><empty_output><jupyter_text>Procederemos a convertir los tipos de cada campo del RDD<jupyter_code>DF_From_RDD = DF_From_RDD.map(lambda l :(
    int(l[0]),
    l[1],
    int(l[2]),
    int(l[3]),
    int(l[4]),
    float(l[5]),
    int(l[6])
))<jupyter_output><empty_output><jupyter_text>Luego crearemos el esquema, que es la definición del DataFrame<jupyter_code>schemaDeportistaOlimpico = StructType([
    StructField("deportista_id", IntegerType(),False),
    StructField("nombre", StringType(), False),
    StructField("genero", IntegerType(), False),
    StructField("edad", IntegerType(), False),
    StructField("altura", IntegerType(), False),
    StructField("peso", FloatType(), False),
    StructField("equipo_id", IntegerType(), False),
])<jupyter_output><empty_output><jupyter_text>Por último, pasaremos los argumentos necesarios para crear el DF a partir del RDD<jupyter_code>deportistaOlimpicoDF_demo = sqlContext\
                        .createDataFrame(DF_From_RDD, schemaDeportistaOlimpico)
deportistaOlimpicoDF_demo.count()<jupyter_output><empty_output><jupyter_text>Recuerda guardar las estructuras omitiendo los metodos de visualización, como ```show``` y ```take``` Ahora debemos transformar los RDDs pasados en DF (incluyendo Deportistas olimpicos desde archivo)<jupyter_code>deportistaOlimpicoDF_pt1 = sqlContext.read.schema(schemaDeportistaOlimpico)\
    .option("header","true").csv(path + "deportista.csv")
deportistaOlimpicoDF_pt2 = sqlContext.read.schema(schemaDeportistaOlimpico)\
    .option("header","true").csv(path + "deportista2.csv")
deportistaOlimpicoDF=deportistaOlimpicoDF_pt1.union(deportistaOlimpicoDF_pt2)
deportistaOlimpicoDF.count()
schemaequiposOlimpicos = StructType([
    StructField("equipo_id", IntegerType(),False),
    StructField("nombre_equipo", StringType(), False),
    StructField("pais", StringType(), False)
])
paisesDF = sqlContext.read.schema(schemaequiposOlimpicos)\
    .option("header","true").csv(path + "paises.csv")
schemaResultado = StructType([
    StructField("resultado_id", IntegerType(),False),
    StructField("medalla", StringType(), False),
    StructField("deportista_id", IntegerType(), False),
    StructField("juego_id", IntegerType(), False),
    StructField("evento_id", IntegerType(), False)
])
resultadoDF = sqlContext.read.schema(schemaResultado)\
    .option("header","true").csv(path + "resultados.csv")<jupyter_output><empty_output><jupyter_text>Fin de la lección 14  Lección 15: Operaciones sobre DF. Faltaron cargar algunos DF, cargaremos estas estructuras desde los archivos.<jupyter_code>#!ls ./files/
!head -n 5 ./files/deporte.csv
deporteSchema = StructType([
    StructField("deporte_id", IntegerType(),False),
    StructField("deporte", StringType(), False)
])
deportesDF = sqlContext.read.schema(deporteSchema)\
    .option("header","true").csv(path + "deporte.csv")
deportesDF.show(4)
#!ls ./files/
!head -n 5 ./files/evento.csv
eventoSchema = StructType([
    StructField("evento_id", IntegerType(),False),
    StructField("evento", StringType(), False),
    StructField("deporte_id", IntegerType(), False)
])
deportesOlimpicosDF = sqlContext.read.schema(eventoSchema)\
    .option("header","true").csv(path + "evento.csv")
deportesOlimpicosDF.show(4)<jupyter_output>+---------+--------------------+----------+
|evento_id|              evento|deporte_id|
+---------+--------------------+----------+
|        1|Basketball Men's ...|         1|
|        2|Judo Men's Extra-...|         2|
|        3|Football Men's Fo...|         3|
|        4|Tug-Of-War Men's ...|         4|
+---------+--------------------+----------+
only showing top 4 rows<jupyter_text>Para mostrar el esquema de un DF, necesitamos hacer uso del método ```printSchema```<jupyter_code>deportesDF.printSchema()
deportistaOlimpicoDF.printSchema()<jupyter_output>root
 |-- deportista_id: integer (nullable = true)
 |-- nombre: string (nullable = true)
 |-- genero: integer (nullable = true)
 |-- edad: integer (nullable = true)
 |-- altura: integer (nullable = true)
 |-- peso: float (nullable = true)
 |-- equipo_id: integer (nullable = true)<jupyter_text>Para renmbrar columnas, necesitamos seguir los siguientes pasos<jupyter_code>deportistaOlimpicoDF = deportistaOlimpicoDF.withColumnRenamed("genero","sexo").drop("altura")<jupyter_output><empty_output><jupyter_text>Con el método ```drop``` eliminas un campo, y cone método ```withColumnRenamed``` cambias el encabezado de alguna de las columnas.  Recuerda:Todos los elementos de la estructura (DF) son inmutables, por lo que estas acciones deben guardarse en otra variable, o en la misma variable si se desean efectuar los cambios.<jupyter_code>deportistaOlimpicoDF.printSchema()<jupyter_output>root
 |-- deportista_id: integer (nullable = true)
 |-- nombre: string (nullable = true)
 |-- sexo: integer (nullable = true)
 |-- edad: integer (nullable = true)
 |-- peso: float (nullable = true)
 |-- equipo_id: integer (nullable = true)<jupyter_text>Ahora vamos a importar un método desde pyspark.sql llamado col, que nos permitirá, entre otras cosas, renombrar  una columna (Como en el ejemplo anterior)<jupyter_code>from pyspark.sql.functions import *
deportistaOlimpicoDF=deportistaOlimpicoDF.select("deportista_id","nombre",
                            col("edad").alias("edad_al_jugar"),"equipo_id")
deportistaOlimpicoDF.show(5)
deportistaOlimpicoDF.sort("edad_al_jugar").show()<jupyter_output>+-------------+--------------------+-------------+---------+
|deportista_id|              nombre|edad_al_jugar|equipo_id|
+-------------+--------------------+-------------+---------+
|          224|     <NAME>|            0|      308|
|          487|      <NAME>|            0|      721|
|          226|<NAME>bd...|            0|     1003|
|           58|    <NAME>|            0|      154|
|          230|    <NAME>|            0|      308|
|          102|   <NAME>|            0|      308|
|          260|  <NAME>|            0|     1003|
|          139|<NAME>|            0|     1043|
|          281|      <NAME>|            0|      487|
|          163|     <NAME>|            0|     1095|
|          285|<NAME>bd...|            0|      497|
|          173| <NAME>|            0|     1003|
|          179|Ibrah<NAME>...|            0|     1003|
|          378|     Ange[...]<jupyter_text>En la tabla anterior podemos observar que hay jugadores con edad 0. Esto es absurdo, ya que la edad 0 es un método para llenar valores no disponibles. A continuación vamos a limpiar nuesto DF con un filtro.<jupyter_code>deportistaOlimpicoDF= deportistaOlimpicoDF.filter((deportistaOlimpicoDF.edad_al_jugar != 0))
deportistaOlimpicoDF.sort("edad_al_jugar").show()<jupyter_output>+-------------+--------------------+-------------+---------+
|deportista_id|              nombre|edad_al_jugar|equipo_id|
+-------------+--------------------+-------------+---------+
|        71691|  <NAME>|           10|      333|
|        70616|          <NAME>|           11|      199|
|       118925|<NAME>...|           11|      413|
|        52070|        <NAME>|           11|      514|
|        22411|<NAME>...|           11|      413|
|        40129|    <NAME>|           11|      507|
|        47618|<NAME>...|           11|      742|
|        76675|   <NAME>|           11|      967|
|        37333|<NAME>...|           11|      982|
|        51268|      <NAME>|           11|      861|
|       126307|        <NAME>|           11|      825|
|        48939|             <NAME>|           12|      738|
|        49142|        <NAME>|           12|      302|
|        42835|   Werner[...]<jupyter_text>Fin de la lección 15  Lección 16: Agrupaciones y operaciones join sobre DF Ahora estamos validando las definiciones de algunos DF<jupyter_code>deportistaOlimpicoDF.printSchema()
resultadoDF.printSchema()
juegoDF.printSchema()
#juegoDF=juegoDF.select("juego_id",
#                            col("year").alias("anio"),"temporada","ciudad")
#juegoDF.printSchema()
deportesOlimpicosDF=deportesOlimpicosDF.select("evento_id",
                            col("evento").alias("Nombre_de_disciplina"),"deporte_id")
deportesOlimpicosDF.printSchema()
deportistaOlimpicoDF.printSchema()<jupyter_output>root
 |-- deportista_id: integer (nullable = true)
 |-- nombre: string (nullable = true)
 |-- edad_al_jugar: integer (nullable = true)
 |-- equipo_id: integer (nullable = true)<jupyter_text>Una vez que expusimos los esquemas, ahora procederemos a hacer un join entre dos DF<jupyter_code>demoDF = deportistaOlimpicoDF.\
            join(resultadoDF,\
                 deportistaOlimpicoDF.deportista_id == resultadoDF.deportista_id,"left").\
            join(juegoDF,juegoDF.juego_id == resultadoDF.juego_id,"left").\
            join(deportesOlimpicosDF,\
            deportesOlimpicosDF.evento_id == resultadoDF.evento_id,"left").\
            select(deportistaOlimpicoDF.nombre,deportistaOlimpicoDF.edad_al_jugar,\
                   resultadoDF.medalla,juegoDF.year,deportesOlimpicosDF.Nombre_de_disciplina)
demoDF.show()<jupyter_output>+--------------------+-------------+-------+-------------+--------------------+
|              nombre|edad_al_jugar|medalla|         year|Nombre_de_disciplina|
+--------------------+-------------+-------+-------------+--------------------+
|           <NAME>|           24|     NA|  1992 Verano|Basketball Men's ...|
|            A Lamusi|           23|     NA|  2012 Verano|Judo Men's Extra-...|
| <NAME>|           24|     NA|  1920 Verano|Football Men's Fo...|
|<NAME>|           34|   Gold|  1900 Verano|Tug-Of-War Men's ...|
|<NAME> ...|           21|     NA|1994 Invierno|Speed Skating Wom...|
|<NAME> ...|           21|     NA|1994 Invierno|Speed Skating Wom...|
|<NAME> ...|           21|     NA|1992 Invierno|Speed Skating Wom...|
|<NAME> ...|           21|     NA|1992 Invierno|Speed Skating Wom...|
|<NAME> ...|           21|     NA|1988 Invierno|Speed Skating Wom...|
|<NAME> ...|           21|    [...]<jupyter_text>**Nota:** Hay un error cuando los origenes de los DF no son los archivos. El error ocurre cuando el origen de los DF no es el mismo, la solución es crear todos los DF desde una misma fuente (archivos CSV).  Fin la lección 16  Lección 17: Solución al reto de joins.<jupyter_code>resultadoDF.filter(resultadoDF.medalla != "NA")\
    .join(deportistaOlimpicoDF,deportistaOlimpicoDF.deportista_id == resultadoDF.deportista_id,"left")\
    .join(paisesDF,paisesDF.equipo_id == deportistaOlimpicoDF.equipo_id,"left")\
    .select("medalla","nombre_equipo","pais").sort(col("pais").desc()).show()<jupyter_output>+-------+-------------+----+
|medalla|nombre_equipo|pais|
+-------+-------------+----+
|   Gold|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
| Silver|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
| Bronze|     Zimbabwe| ZIM|
| Silver|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
| Silver|     Zimbabwe| ZIM|
| Silver|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
|   Gold|     Zimbabwe| ZIM|
+-------+-------------+----+
only showing top 20 rows<jupyter_text>Fin de la lección 17.  Lección 18: Funciones de Agrupación.<jupyter_code>medallistaXAnio = deportistaOlimpicoDF \
    .join(
        resultadoDF, 
        deportistaOlimpicoDF.deportista_id == resultadoDF.deportista_id, 
        "left"
    ) \
    .join(
        juegoDF, 
        juegoDF.juego_id == resultadoDF.juego_id, 
        "left"
    ) \
    .join(
        paisesDF, 
        deportistaOlimpicoDF.equipo_id == paisesDF.equipo_id, 
        "left"
    ) \
    .join(
        deportesOlimpicosDF, 
        deportesOlimpicosDF.evento_id == resultadoDF.evento_id, 
        "left"
    ) \
    .join(
        deportesDF, 
        deportesOlimpicosDF.deporte_id == deportesDF.deporte_id, 
        "left"
    ) \
    .select(
        "pais",
        "year",
        "medalla",
        deportesOlimpicosDF.Nombre_de_disciplina.alias("Nombre_Subdisciplina"),
        deportesDF.deporte.alias("Nombre disciplina"),
        deportistaOlimpicoDF.nombre    
    )
medallistaXAnio.show()
medallistaXAnio2 = medallistaXAnio.filter(medallistaXAnio.medalla != "NA")\
    .sort("year")\
    .groupby("pais", "year", "Nombre_Subdisciplina")\
    .count()
medallistaXAnio2.printSchema()<jupyter_output>root
 |-- pais: string (nullable = true)
 |-- year: string (nullable = true)
 |-- Nombre_Subdisciplina: string (nullable = true)
 |-- count: long (nullable = false)<jupyter_text>Esta manera de agrupar no es muy recomendadad, debido a que Python asigna un tipo "long" al resultado de conteo. A continuación se muestra la manera màs recomendadaa de hacer una agrupación.<jupyter_code>medallistaXAnio2.groupBy("pais", "year")\
    .agg(sum("count").alias("Total de medallas"),\
        avg("count").alias("Medallas promedio")).show()<jupyter_output>+----+-----------+-----------------+------------------+
|pais|       year|Total de medallas| Medallas promedio|
+----+-----------+-----------------+------------------+
| USA|1896 Verano|               20|1.6666666666666667|
| GER|1896 Verano|               30|               2.5|
| GBR|1896 Verano|                8|1.1428571428571428|
| FRA|1896 Verano|               11|             1.375|
| GRE|1896 Verano|                9|1.2857142857142858|
| HUN|1896 Verano|                6|               1.0|
| AUS|1896 Verano|                3|               1.0|
| AUT|1896 Verano|                5|               1.0|
| DEN|1896 Verano|                6|               1.0|
| SUI|1896 Verano|                3|               1.0|
| SWE|1900 Verano|                6|               3.0|
| USA|1900 Verano|               65|2.4074074074074074|
| FRA|1900 Verano|              179| 3.314814814814815|
| GER|1900 Verano|               27|               4.5|
| NOR|1900 Verano|                9|            [...]<jupyter_text>Fin de la lección 18.  Lección 19: SQL. En esta lección vamos a registar algunos DFs como si fueran tablas tradicionales de SQL.<jupyter_code>resultadoDF.registerTempTable("resultado")
deportistaOlimpicoDF.registerTempTable("deportista")
paisesDF.registerTempTable("paises")
sqlContext.sql("SELECT * FROM resultado").show(5)
paisesDF.printSchema()
resultadoDF.printSchema()
deportistaOlimpicoDF.printSchema()
sqlContext.sql("""
                SELECT medalla, nombre_equipo, pais FROM resultado AS r
                JOIN deportista AS d
                ON r.deportista_id = d.deportista_id
                JOIN paises AS p
                ON p.equipo_id = d.equipo_id
                WHERE medalla <> "NA"
                ORDER BY pais DESC
                """).show(5)
spark<jupyter_output><empty_output><jupyter_text>Recomendación: Cuando estes cargando archivos o conexiones con bases de datos y vayas a darle vida a un DF, no hay problema en utilizar el sqlContext (Es lo más normal). Sin embargo, cuando empiezas a hacer cruces y demás operaciones join y de acrupación, opera con los DF directamente.El verdadero poder de Spark está en sus funcions nattivas.  Fin de la lección 19.  Lección 20: ¿Qué es un UDF?. Las funciones definidas por el usuario o UDF, por sus siglas en inglés, son una funcionalidad agregada en Spark para definir funciones basadas en columnas las cuales permiten extender las capacidades de Spark al momento de transformar el set de datos.Este tipo de implementaciones son convenientes cuando tenemos un desarrollo extenso donde hemos identificado la periodicidad de tareas repetitivas como suele ser en pasos de limpieza de datos, transformación o renombrado dinámico de columnas.Por lo anterior es común encontrar en un proyecto de Spark una librería independiente donde existen todas estas funciones agregadas para que los desarrolladores involucrados en el proyecto puedan usarlas a conveniencia.El uso de UDF no implica que las funciones que podemos crear nativamente con Python, Scala, R o Java no sean útiles. Una UDF tiene el objetivo de ofrecer un estándar interno en el proyecto que nos encontremos realizando. Además, en caso de ser necesario, una UDF puede ser modificada con ayuda de decoradores para que sea más extensible en diversos escenarios a los cuales nos podemos enfrentar.Otro motivo para usar UDF es que en el módulo de Spark MLlib, la librería nativa de Spark para operaciones de Machine Learning, las UDF juegan un papel vital al momento de hacer transformaciones. Por lo cual tener un uso familiar de estas ampliará considerablemente la curva de aprendizaje de Spark MLlib.  Fin de la lección 20.  Lección 21: UDF<jupyter_code>!head -n 5 ./files/deportistaError.csv
deportistaOlimpicoRDD =  spark.textFile(path+"deportistaError.csv").map(lambda line : line.split(","))
deportistaOlimpicoRDD=deportistaOlimpicoRDD.mapPartitionsWithIndex(eliminaEncabezado)

deportistaOlimpicoRDD = deportistaOlimpicoRDD.map(lambda l : (
l[0],
l[1],
l[2],
l[3],
l[4],
l[5],
l[6]
))

schema = StructType([
StructField("deportista_id",StringType(),False)     ,
StructField("nombre",StringType(),False)        ,
StructField("genero",StringType(),False)        ,
StructField("edad",StringType(),True)      ,
StructField("altura",StringType(),True)        ,
StructField("peso",StringType(),True)      ,
StructField("equipo_id",StringType(),True)     
])

deportistaErrorDF = sqlContext.createDataFrame(deportistaOlimpicoRDD,schema)
deportistaErrorDF.show()<jupyter_output>+-------------+--------------------+------+----+------+----+---------+
|deportista_id|              nombre|genero|edad|altura|peso|equipo_id|
+-------------+--------------------+------+----+------+----+---------+
|            1|           <NAME>|     1|  24|   180|  80|      199|
|            2|            <NAME>|     1|  23|   170|  60|      199|
|            3| <NAME>|     1|  24|      |    |      273|
|            4|<NAME>|     1|  34|      |    |      278|
|            5|<NAME> ...|     2|  21|   185|  82|      705|
|            6|     <NAME>|     1|  31|   188|  75|     1096|
|            7|        <NAME>|     1|  31|   183|  72|     1096|
|            8|"Cornelia ""Cor""...|     2|  18|   168|    |      705|
|            9|    <NAME>|     1|  26|   186|  96|      350|
|           10|"<NAME> ...|     1|  26|      |    |      350|
|           11|  <NAME>|     1|  22|   182|76.5|      350|
|     [...]<jupyter_text>En la celda anterior podemos ver que carga el DF, pero en la ausencia de datos no hay una palabra NULL. Esto lo resolveremos con la siguiente UDF. Los pasos para crear la udf son:    1. Crear la función base    2. Registrarla como udf    3. Indicar al sqlContext que la usaremos como función nativa en sqlContext (opcional)<jupyter_code>from pyspark.sql.functions import udf

def conversionEnteros(valor):
    return int(valor) if len(valor) > 0 else None

conversionEnteros_udf = udf(lambda z: conversionEnteros(z), IntegerType())
sqlContext.udf.register("conversionEnteros_udf", conversionEnteros_udf)
deportistaErrorDF.select(conversionEnteros_udf("altura")).show()<jupyter_output>+----------------+
|<lambda>(altura)|
+----------------+
|             180|
|             170|
|            null|
|            null|
|             185|
|             188|
|             183|
|             168|
|             186|
|            null|
|             182|
|             172|
|             159|
|             171|
|            null|
|             184|
|             175|
|             189|
|            null|
|             176|
+----------------+
only showing top 20 rows
{'fraction_non_alphanumeric': 0.14690831556503198, 'fraction_numerical': 0.032622601279317695, 'mean_word_length': 2.689584644430459, 'pattern_counts': {'":': 0, '<': 140, '<?xml version=': 0, '>': 141, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '26', 'dir': 'jupyter-structured-clean-dedup', 'id': '212521', 'license': 'MIT', 'n_tokens_mistral': 8338, 'n_tokens_neox': 7817, 'n_words': 1919, 'path': 'Notebooks/Seccion_4_Data_Frames_y_SQL.ipynb', 'repo_name': 'Meluiscruz/Intro_a_Spark', 'size': '23864'}