<jupyter_start><jupyter_text>Básico de PythonEsta sección, esta pensada para ser una breve introducción al lenguaje de programación *Python* con la intención de conocer los comandos básicos para hacer uso de sus estructuras de datos y las herramientas necesarias que se utilizaran durante el curso. No concideramos que sea un curso formal de programación, pues se pensó para que todos los comando de *Python* puedan ser ejecutados dentro de un notebook utilizando *Jupyter-lab* para tener una familiaridad con el lenguaje y así tener el conocimiento necesario para generar código que sea de utilidad en el análisis de datos. Para iniciar una sesión dentro de *jupyter-lab* es necesario tenerlo instalado (se describe en [Instalación](faltalink)) y ejecutar `jupyter-lab` dentro del ambiente donde se realizó la instalación.  Cadenas de símbolos (*String*)En todo curso que involucra algún lenguaje de programación empiezan con *Hello world*,  **este no es un curso de progeamación** pero vamos hacer muchas cosas similares por lo que vamos ha intentarlo. Es decir lo primero que deseamos es poder imprimir cosas, para tal proposito *Python* tiene la función `print()` esta función nos permite imprimir dentro de la terminal lo que deseamos.<jupyter_code>print('Hello world!!')<jupyter_output>Hello world!!<jupyter_text>Hemos impreso nuestra primera línea usando *Python*, se puede ver que la función print no imprime las comillas, ¿que pasa si las quitamos?<jupyter_code>print(! Hola mundo !)<jupyter_output><empty_output><jupyter_text>De aquí podemos hacer un par de observaciones, la función `print` acepta *strings* que son cadenas de símbolos. Para declarar que se empieza una cadena de símbolos, se hace utilizando `'` o bien `"`, para declarar que hemos terminado la cadena la próxima `'` o `"` (respectivamente) determina el fin.<jupyter_code>print('!Hola mundo !')<jupyter_output>!Hola mundo !<jupyter_text>Podemos hacer varias cosas con un *string* como es "multiplicarlo"<jupyter_code>print('Hola mundo '*2)
print('Hola mundo '*4)<jupyter_output>Hola mundo Hola mundo Hola mundo Hola mundo<jupyter_text>"sumarlo" (juntarlo )<jupyter_code>print('Hola mundo' + 'junto mal')
print('Hola mundo' + ' ' + 'junto mal')<jupyter_output>Hola mundo junto mal<jupyter_text>Y otras operaciones, durante el curso veremos más operaciones que se puden hacer con las cadenas de símbolos.    VariablesDentro de los lenguajes de programación es necesario dar nombres a las cosas, en *pyhton* esta asignación se hace usando el símbolo de =.<jupyter_code>a= 2
a<jupyter_output><empty_output><jupyter_text>La línea anterior asignó el valor 2 a la variable `a`. Como estamos dentro de un notebook dentro de *jupyter-lab* al llamar a la variable `a` imprime lo que se encuentra dentro de la variable.<jupyter_code>b= 5
a+b<jupyter_output><empty_output><jupyter_text>Se pueden realizar operaciones con las variables, si se tienen definidas estas operaciones entre tipos los tipos definidos. Como es el caso de las *strings* y los enteros.<jupyter_code>a = '<NAME>'
b = 'Jupiter'
a+b

a[0:5]+b<jupyter_output><empty_output><jupyter_text>A diferencia de otros lenguajes de programación como son *C++* o *Java*, en *Python* no es necesario declarar la variable ni determinar el tipo de variable. Usando la función `type` es posible ver que tipo de variable es.<jupyter_code>a= 5
b= 'Hola'
type(a)
type(b)<jupyter_output><empty_output><jupyter_text>Es importante observar que las operaciones son de tipo específico. Por ejemplo el operando `+` aplicado a las variables de tipo *int* o *float* se aplica la función la suma, mientras que el caso de variables *string* funciona como la unión de las cadenas.<jupyter_code>a+b<jupyter_output><empty_output><jupyter_text>Como  se observa, el operando `+` no esta definido para usarse con *int* y *str*(*string*).Existen distintos tipos de variables como son:| Tipo | Descripción ||:-------|:-----------:|| *int*| Para guardar enteros ($\mathbb{Z}$).|| *float*| Números de doble presición (ejemplo $2.34$).| |  *bool*| Valores verdadero(`True`) o falso (`False`). || *str* | Cadenas de símbolos con codificación (UTF-8).|| *bytes*| Código ASCII en bytes.|| *None* | Valor de *Python* para nulo.| Los elementos en *Python* se pueden comparar, para saber si un elemento es igual a otro o si cumple con alguna condición específica. Las comparaciones entre los elementos de *Python* tienen que ser del mismo tipo, en algunos casos se permite hacer comparaciones entre tipos como *float* e *int*, sin embargo, lo que sucede en el fondo *Pyhton* cambia el tipo y se hace la comparacion.Las comparaciones se hacen usando `==` (iguales), `>` (mayor que), `= ` (mayor o igual que), `<=` (menor o igual que). El resultado de las comparaciones es siempre un *booleano* (tipo `bool`).<jupyter_code>4==5
4>=5
'b' < 'b'
'acs'=='acs'
4.5>4
4 > 'a'<jupyter_output><empty_output><jupyter_text>Utilizando estas comparaciones es posible hacer algebra booleana utilizando los operadores lógicos implementados para ello, |Operador| Descripción |Ejemplo||---------|-----------|-------||`and`    | Si los dos operandos son `True` entonces la condición se vuelve `True`| `a and b`|| `or`    | Si alguno de los operandos es `True` entonces la condición se vuelve `True`| `a or b`|| `not`   | Se regresa el estado inverso del operando| `not a`|<jupyter_code>4== 4 and 5<4
4== 4 or 5<4
not 4==4<jupyter_output><empty_output><jupyter_text>ListasLas listas en python son especialmente útiles, pues nos permiten tener una estructura para el manejo de los datos y estructuras, para declarar una lista se utilizan `[ ]` y separando por `,` sus elementos.<jupyter_code>mi_lista= [1, 2, 3,4]
mi_lista<jupyter_output><empty_output><jupyter_text>Se le pueden añadir elementos a las listas utilizando el método `append` implementado detro de las lista, de la siguiente forma<jupyter_code>mi_lista.append(5)
mi_lista<jupyter_output><empty_output><jupyter_text>También se pueden remover elementos de la lista usando el método `pop`<jupyter_code>a = mi_lista.pop()
print(a)
mi_lista<jupyter_output>5<jupyter_text>Como se observa el método `pop` remueve el último elemento en la lista y lo asigna a la variable `a`, no es necesario asignar el valor a una variable para remover el último elemento.<jupyter_code>mi_lista.pop()
mi_lista<jupyter_output><empty_output><jupyter_text>Para acceder a los elementos de una lista en python se hace a través de `[]`, python enumera los elementos de las listas a partir de 0 para el primer elemento y de forma asendente, también es posible acceder a los elementos usando enteros negativos.<jupyter_code>mi_lista[0]
mi_lista[2]
mi_lista[-1]<jupyter_output><empty_output><jupyter_text>Es posible cambiar el valor de los elementos<jupyter_code>mi_lista[0]= 5
mi_lista<jupyter_output><empty_output><jupyter_text>Pero para aumentar el tamaño de las listas es necesario usar el método `append` u otro.<jupyter_code>mi_lista[3]= 5
mi_lista<jupyter_output><empty_output><jupyter_text>Para remover un elemento especifico utilizamos el método `remove`, el cual elimina la primera aparición de elemento que se desea remover.<jupyter_code>mi_lista = [1,2,3, 4,2]
mi_lista.remove(2)
mi_lista<jupyter_output><empty_output><jupyter_text>Es posible unir dos o más listas<jupyter_code>mi_lista = [1,2,3, 4]
mi_lista_2= [3,4,5,6]
mi_lista+mi_lista_2

mi_lista<jupyter_output><empty_output><jupyter_text>Los elementos de las listas pueden ser de distintos tipos<jupyter_code>mi_lista = [1,2,4,'Hola', 2.34, str(4.56)]
mi_lista<jupyter_output><empty_output><jupyter_text>En la lista generada en la linea anterior se hace notar la función *str()*, esta convierte lo que se encuentre dentro de los paréntesis a tipo  *string*, siempre y cuando la conversión sea posible. Como ejemplo se transforma el número flotante a un *string*. Este tipo de funciones también existen para *int* , *bool* o *float*.<jupyter_code>int(2.75)
float(3)
float('3')
bool(1)<jupyter_output><empty_output><jupyter_text>A partir de las listas podemos tomar "rebanadas" de estas. Para tal propósito, en las listas utilizamos `:` para indicar los rangos que se desean, como se ve en los ejemplos a continuaciónTomemos los elementos de la posición 2 a la posición 5<jupyter_code>mi_lista= [1,2,3,4,5,6]
mi_lista[2:5]<jupyter_output><empty_output><jupyter_text>De la posición 0 a la posición antes que 4<jupyter_code>mi_lista[:4]<jupyter_output><empty_output><jupyter_text>De la posición  3 hasta el último elemento<jupyter_code>mi_lista[3:]<jupyter_output><empty_output><jupyter_text>Diccionarios Los diccionarios en *Python* nos ofrecen la posibilidad de hacer funciones entre conjuntos de forma directa, para la construcción de los diccionarios usamos `{ }` y `:`para determinar la regla de la relación entre los conjuntos. Veamos el siguiente ejemplo.<jupyter_code>mi_dict= {'a': 'Hola', 'b': 'jupyter', 'c':'mundo'}
mi_dict['a']
mi_dict['b']
print(mi_dict['a'], mi_dict['c'])
mi_dict['d']<jupyter_output><empty_output><jupyter_text>La función de los diccionarios es regresar los valores que se le asignan a cada elemento, a los elementos antes de `:` se les denomina *keys* (llave) y a los que se encuentran después se les denomina *values* (valor)<jupyter_code>mi_dict.keys()
mi_dict.values()<jupyter_output><empty_output><jupyter_text>Si se desea añadir una pareja llave-valor al diccionario, se puede hacer directamente<jupyter_code>mi_dict[3]= 'luna'
mi_dict[3]
mi_dict<jupyter_output><empty_output><jupyter_text>Para eliminar una pareja llave-valor utilizamos el método `pop`<jupyter_code>mi_dict.pop('b')
mi_dict<jupyter_output><empty_output><jupyter_text>Si se desea añadir más de un elemento al diccionario o añadir todo un diccionario a uno ya exixtente esto se puede hacer usando el método `update` y otro diciionario.<jupyter_code>mi_dict.update({'e': 'marte', 3:'casa', 2:'Hola'})
mi_dict<jupyter_output><empty_output><jupyter_text>Es importante recalcar que en los diccionarios puede haber llaves que tengan el mismo valor pero no llaves iguales<jupyter_code>mi_dic_2= {'a': 'Hola', 'b': 'mundo', 'a': 'jupyter'}
mi_dic_2<jupyter_output><empty_output><jupyter_text>En este caso el diccionario asigna a la llave el último valor asignado.  Aunque Python nos permite tener como llaves (*keys*) cualquier tipo de objeto es preferible utilizar elementos que sean *hashables* como lo son *int*, *float* o *strings*, hay ciertas estructuras o valor en python que nos son de esta clase de elementos. La idea es que este tipos de estructuras se les puede dar un cierto "nombre" para identificar a los elementos, una explicación más detallada de lo que son los elemenntos *hashable* esta fuera del alcance de este curso. Tuplas Otra estructura importante en *Python* son las "tuplas", estos objetos nos permiten almacenar valores como *int*, *float*  o *strings* de forma similar a una notación vectorial (como coordenadas). Para declarar a una tupla se hace con `()` y se separa a los elementos usando `,`.<jupyter_code>tu= (1,2,3,'a') 
tu<jupyter_output><empty_output><jupyter_text>Una de las propiedades importante que distingue a las *tuplas* de las listas, es que las tuplas son objetos inmutables. Es decir, éstas no pueden ser modificadas una vez que fueron declaradas, manteniendo la integridad de los datos que contienen.<jupyter_code>tu[0]
tu[0]= 5<jupyter_output><empty_output><jupyter_text>Existen ciertas operaciones que se pueden realizar con las tuplas, si sumamos (`+`) tuplas el resultado es concatenar las tuplas, si multiplicamos por un entero $n$  el resultado es la tupla concatenada $n$.<jupyter_code>tu_2= (4,5,6,'b')
tu+tu_2
tu*2<jupyter_output><empty_output><jupyter_text>ConjuntosLos conjunto en *python* nos permiten almacenar conjuntos de distintos elementos, como su palabra lo dice, los conjuntos son conjunto en el sentido matemático, es decir, podemos hacer las operaciones usuales de conjuntos como son unión, intersección, diferencia (resta), diferencia simétrica, añadir elementos etc. Para declarar un conjunto se utiliza `{}` separando sus elementos por `,`<jupyter_code>conjunto_1= {1,2,3,4,5,6,7,8,7,6,5, '5', (2,4)}
conjunto_1<jupyter_output><empty_output><jupyter_text>Para añadir elementos al conjunto se puede hacer usando el método `add`<jupyter_code>conjunto_1.add('li')
conjunto_1<jupyter_output><empty_output><jupyter_text>Si deseamos obtener el conjunto de una estructura que contiene datos como pueden ser listas, tuplas o diccionarios se puede hacer a través de la función `set`<jupyter_code>con_lista= set(mi_lista)
con_lista<jupyter_output><empty_output><jupyter_text>Las operaciones entre conjuntos se hacen a través de los métodos implementados en el objeto, utilizando como argumento otro conjunto.<jupyter_code>conjunto_2= {'a', 'b', 'c', '2', 6,8, 15}
conjunto_1.union(conjunto_2)
conjunto_1.difference(conjunto_2)
conjunto_1.intersection( conjunto_2)<jupyter_output><empty_output><jupyter_text>Condicionales y ciclosYa hemos visto que se pueden comparar elementos en *Python*, esto nos permite diferenciar entre los distintos elementos, en cierta estructura como pueden ser diccionarios, listas o tuplas.Las estructuras de control son una de las principales herramientas en lenguajes de programación, estas nos permiten estableces condiciones para poder tomar desiciones. Las estructuras de control que usaremos  con mayor frecuencia son `if` `else`, `for` , `while`. Estas estructuras se declaran usando la palabra seguida de una condición logica que se debe de cumplir y `:`, en la siguiente linea se indenta (con un número fijo de espacios o con *tab* ) y se escribe la linea de código a ejecutar. `if x == 4:    print('Es cuatro')`     if La estructura más utilizada es la estructura `if else` en esta se da una condición lógica, si la condición se cumple entonces se ejecuta el código que se encuentra indentado, si no se cumple la condición puede continuar la ejecución del código donde no esta indentado. La estructura `if` permite dos condicionales más, `elif` y `else`. `elif` permite añadir un condicional más a la estructura y `else` se ejecuta si ninguna de las condiciones se cumple.<jupyter_code>x= 4
if x == 4:
    print('Es cuatro')
x= 5
if x == 4:
    print('Es cuatro')
print('Se termino la estructura')
if x == 4:
    print('Es cuatro')
else:
    print('No es cuatro')
print('Se termino la estructura de control')
x= 12
if x == 4:
    print('Es cuatro')
elif x>4 and x < 10:
    print('Es mayor que 4')
else:
    print('No es cuatro y es mayor que 10')
print('Se termino la estructura de control')<jupyter_output>No es cuatro y es mayor que 10
Se termino la estructura de control<jupyter_text>For La estructura de control `for` se utiliza para hacer cíclos sobre los elementos dentro de una estructura de datos. En el caso de python lo usual es aplicar cierto código a los elementos.Para declarar los ciclos `for ` se utiliza la la palabra `for` el nombre de una variable, que nos servirá para referirnos al elemento dentro del ciclo, seguido por la palabra `in` y la estructura sobre la cual deseamos que se haga el ciclo terminado la línea con `:`. Al igual que con `if`, el código que se desea ejecutar dentro del ciclo debe estar en una nueva línea indentada con un cierto número de espacios o bien con un número fijo de tabulados ("tabs"). El ciclo se termina cuando la línea del código a ejecutar esta en la misma línea que la palabra `for`.<jupyter_code>lista= [1,2,3,4,5]
for i in lista:
    print('Número ', i*2)
print('Se acabo el ciclo')<jupyter_output>Numero  2
Numero  4
Numero  6
Numero  8
Numero  10
Se acabo el ciclo<jupyter_text>Existen otro tipos de estructuras implementadas dentro de *python* que podemos utilizar para crear ciclos o para utilizarlas en otros casos como `range`, se puede utilizar esta función para generar los cíclos.<jupyter_code>for j in range(3, 15):
    print(j)<jupyter_output>3
4
5
6
7
8
9
10
11
12
13
14<jupyter_text>while La estructura  `while` es similar a la estructura de control `for`, esta nos permite ejecutar el código deseado dentro de un ciclo mientras se cumpla una condición determinada. Cuando dicha condición ya no se cumple entonces se sale del ciclo. Para declarar la estructura de control se hace a través de la palabra `while`, una condición que se debe de cumplir (True) para entrar en el ciclo y `:` al igual que en las estructuras de control anteriores, en una nueva línea indentada por un número fijo de espacios o tabulaciones se escribe el código a ejecutar. El ciclo termina en donde la nueva línea de código se encuentra indentada a la par de la palabra `while`. `while x <= 3:     print(x , 'es menor o igual que 3')    x += 1`<jupyter_code>x = 0
while x <= 3: 
    print(x , 'es menor o igual que 3')
    x += 1
print('termino el ciclo')<jupyter_output>0 es menor o igual que 3
1 es menor o igual que 3
2 es menor o igual que 3
3 es menor o igual que 3
termino el ciclo<jupyter_text>La diferencia entre el `for`y `while` radica en que en `for` se sabe que el número de veces que se ejecutara el ciclo, mientras que en `while` el ciclo se seguirá ejecutando mientras se cumpla la condición. Por esta razón no se recomienda usar esta estructura de control cuando se emnpieza a programar, debido a que se pueden cometer errores con facilidad y generar ciclos infinitos. Cuando se use esta estructura, se recomienda estar seguro de la condición del ciclo no sea infinita al menos que así se desee.    FuncionesLas funciones son bloques de código para reutilizar, adicionalmente esto nos ayuda a dividir el código en distintos bloques lo cual ayuda a la lectura, comprensión, y limpieza  del código. Para declarar una función se hace usando la palabra `def` seguida del nombre de la función con `()` encerrando los parámetros de la función terminando con `:`. En una nueva línea, y al igual que con las estructuras de control, para definir el código que se ejecuta dentro de la función este se encuentra indentado usando un número fijo de espacios o un número fijo de tabulares la función termina usando la palabra `return` o cuando el indentado se encuentra a la par de la palabra `def`.`def imprime_saludo():    print('Que bueno que estoy aprendiendo Python')    return `El código que contiene la función sólo se ejecuta cuando se hace un llamado a la funcíon, esto se hace simplemente escribiendo el nombre de la función y poniendo entre parentesis los párametros que se le pasan a ésta.<jupyter_code>def imprime_saludo():
    print('Que bueno que estoy aprendiendo Python')
    return 

imprime_saludo()<jupyter_output>Que bueno que estoy aprendiendo Python<jupyter_text>Para que la función utilice argumentos, estos se declaran entre los paréntesis cuando se define la función. Para hacer referencia en el código a ejecutar dentro de la función, se hace con el nombre declarado entre los paréntesis.<jupyter_code>def hola_tu( nombre):
    print('Hola ', nombre, ' que bueno  estas aprendiendo Python')
    return 

hola_tu( 'Miguel')<jupyter_output>Hola  Miguel  que bueno  estas aprendiendo Python<jupyter_text>Las funciones pueden (o no) regresar objetos, los cuales muchas veces son *strings*, números o cosas mucho más complejas. Para que la función regrese un objeto es necesario escribir la variable que contiene dicho objeto despues de la palabra `return`. El objeto que se regresa de la función tiene que ser asignado a una variable esta asignación se hace utilizando la asignación normal en ptython `=`.<jupyter_code>def hola_tu_2(nombre):
    print('Hola ', nombre, ' que bueno  estas aprendiendo Python')
    ret = 'Te va ayudar mucho'
    return ret
mi_nom= 'Miguel'
que= hola_tu_2(mi_nom) ### Se llama a la función 
print(que) ## Ver que hay en la variable<jupyter_output>Hola  Miguel  que bueno  estas aprendiendo Python
Te va ayudar mucho<jupyter_text>Es recomendable y una buena práctica escribir un pequeño texto que nos ayude a describir para que sirve la función, esto se hace usando `"""` o `'''` y se cierra el texto con `"""` o `'''` respectivamente. Lo que se escribe ayuda a la reutilización del código tanto para la persona que desarrollando la función y como documentación del código desarrollado.<jupyter_code>def hola_tu_2(nombre):
    """Imprime el nombre con una frase y regresa un agradecimiento  que es un string"""
    print('Hola ', nombre, ' que bueno  estas aprendiendo Python')
    ret = 'Te va ayudar mucho'
    return ret<jupyter_output><empty_output><jupyter_text>Funciones implementadas en PythonExisten muchas funciones implentadas en *Python* que nos ayudan a resolver tareas comunes necesarias a la hora de programar, el conocer estas funciones nos ayuda a que desarrollar de forma más rápida y que la ejecución sea más eficiente y veloz pues la funciones en la mayoria de los casos se encuentran optimizadas. El enlistar todas las funciones que se encuentran implementadas dentro de *pyhton* se encuentran fuera del alcance de este curso, pero se considera enlistar las que se consideraron de mayor útilidad para el curso, a continuacion se dan ejemplos de algunas de estas funciones.  RangeLa función  `range` nos permite definir un intervalo de números enteros con un mínimo, un máximo y el tamaño de incremento entre uno y otro. Se puede omitir el mínimo y el incremento, el comportamiento por defecto es tomar el mínimo como 0 y el incremento como 1<jupyter_code>for i in range(5, 15, 3):
    print(i)<jupyter_output>5
8
11
14<jupyter_text>enumerateLa función `enumerate` enumera sobre un objeto iterable y regresa una tupla, donde la primera entrada es el entero la posición en el objeto iterable y la segunda es el elemento iterable.<jupyter_code>lista_1= ['diez', 'nueve', 'ocho', 'siete', 'seis', 'cinco', 'cuatro', 'tres', 'dos', 'uno']
for i in enumerate(lista_1):
    print (i)<jupyter_output>(0, 'diez')
(1, 'nueve')
(2, 'ocho')
(3, 'siete')
(4, 'seis')
(5, 'cinco')
(6, 'cuatro')
(7, 'tres')
(8, 'dos')
(9, 'uno')<jupyter_text>ZipLa función `zip` nos permite fusionar dos objetos iterables en un conjunto de tuplas donde cada entrada de la tupla corresponde a un elemento de las listas<jupyter_code>lista_1= ['diez', 'nueve', 'ocho', 'siete', 'seis', 'cinco', 'cuatro', 'tres', 'dos']
lista_2 = list('abcdefghij')
res =zip(lista_2, lista_1)
for j in res:
    print(j)<jupyter_output>('a', 'diez')
('b', 'nueve')
('c', 'ocho')
('d', 'siete')
('e', 'seis')
('f', 'cinco')
('g', 'cuatro')
('h', 'tres')
('i', 'dos')<jupyter_text>list`list` nos permite crear listas sobre objetos iterables, si no se pasa ningún argumento entonces `list` regresa una lista vacía.<jupyter_code>list('1234567')<jupyter_output><empty_output><jupyter_text>list Regresa la lontgitud del objeto<jupyter_code>len(lista_1)
len(conjunto_1)<jupyter_output><empty_output><jupyter_text>Funciones castLas funciones `int` , `float`, `str` y `bool` convierten a lo que se pasa como argumento en un entero, punto flotante, cadena de símbolos o un boleano respectivamente.  max, minDe un objeto iterable regresa el máximo o el mínimo respectivamente.<jupyter_code>max([1,4,6,7,3])
min({1,3,4,3,5,6,5,7})
max(list('abcdefghijk'))<jupyter_output><empty_output><jupyter_text>setDe un objeto iterable regresa el conjunto, si no se pasa ningun argumento regresa un conjunto vacío.<jupyter_code>set(list('abcdesftredfredfre'))<jupyter_output><empty_output><jupyter_text>absRegresa el valor absoluto del argumento.<jupyter_code>abs(-5.8)<jupyter_output><empty_output><jupyter_text>any Regresa `True`de un objeto iterable si al aplicar `bool` alguno de elementos regresa `True`<jupyter_code>any([0, None, False ])

any([0, None, False, 'a' ])<jupyter_output><empty_output><jupyter_text>all Regresa `True` si todos los elementos de un objeto iterable regresan `True` al aplicar `bool`.<jupyter_code>all([0, None, False, 'a' ])
all([1,2,3,4,5,6])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08566389518770472, 'fraction_numerical': 0.011169900058788948, 'mean_word_length': 5.706561531962827, 'pattern_counts': {'":': 0, '<': 222, '<?xml version=': 0, '>': 220, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '57', 'dir': 'jupyter-structured-clean-dedup', 'id': '8702', 'license': 'Apache-2.0', 'n_tokens_mistral': 8378, 'n_tokens_neox': 8328, 'n_words': 3128, 'path': 'Basicos.ipynb', 'repo_name': 'msalazarcgeo/Curso_intro_Prog_Ana_Dat', 'size': '23818'}