diff --git a/.gitignore b/.gitignore index 594c573..4ce4b8c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ venv **.DS_Store **.ipynb build +clases/**/*.csv diff --git a/clases/01_introduccion/numpy_intro.py b/clases/01_introduccion/numpy_intro.py index 59bb55a..89ff162 100644 --- a/clases/01_introduccion/numpy_intro.py +++ b/clases/01_introduccion/numpy_intro.py @@ -7,9 +7,9 @@ # extension: .py # format_name: light # format_version: '1.5' -# jupytext_version: 1.6.0 +# jupytext_version: 1.5.1 # kernelspec: -# display_name: Python 3 +# display_name: Python 3 (venv) # language: python # name: python3 # --- @@ -211,11 +211,13 @@ print(f"b: {b.shape}") a + b +# + tags=["raises-exception"] # Armamos un array que tenga distinta cantidad de filas y columnas que a b = np.array([5, 1, 8]) print(f"a: {a.shape}") print(f"b: {b.shape}") a + b +# - # Armamos un array que tenga la misma cantidad de filas que a b = np.array([[2], [1]]) diff --git a/clases/01_introduccion/pandas_intro.py b/clases/01_introduccion/pandas_intro.py index 37c604d..c236859 100644 --- a/clases/01_introduccion/pandas_intro.py +++ b/clases/01_introduccion/pandas_intro.py @@ -7,9 +7,9 @@ # extension: .py # format_name: light # format_version: '1.5' -# jupytext_version: 1.6.0 +# jupytext_version: 1.5.1 # kernelspec: -# display_name: Python 3 +# display_name: Python 3 (venv) # language: python # name: python3 # --- @@ -30,11 +30,20 @@ # Para comenzar, vamos a crear nuestro primer DataFrame a partir de un archivo CSV que contiene un [dataset sobre superhéroes](https://www.kaggle.com/claudiodavi/superhero-set/home). from collections import Counter +import requests + +# Empezamos por descargarlo del drive de la materia. + +with requests.get( + "https://docs.google.com/spreadsheets/d/1nuJAaaH_IP8Q80CsyS940EVaePkbmqhN3vlorDxYMnA/export?format=csv" +) as r, open("superheroes.csv", "wb") as f: + for chunk in r.iter_content(): + f.write(chunk) # + import pandas as pd -df = pd.read_csv('../../datasets/superheroes.csv') +df = pd.read_csv("superheroes.csv") # - # También podemos crear dataframes desde listas, diccionarios y otras estructuras. @@ -156,6 +165,8 @@ def rate_height(height): # ## Eliminar filas con nulos +df + df = df.dropna(subset=['Skin color']) df @@ -167,9 +178,7 @@ def rate_height(height): # Tenemos duplicados! -df.merge(df, left_on='Skin color', right_on='Skin color')[ - ['Race_x', 'Race_y'] -].drop_duplicates() +df.merge(df, left_on='Skin color', right_on='Skin color')[['Race_x', 'Race_y']] # Tenemos que sacar los que son iguales en ambas columnas! @@ -178,6 +187,32 @@ def rate_height(height): ].drop_duplicates() same_skin_color[same_skin_color.Race_x != same_skin_color.Race_y] +# + +# pd.merge? +# - + +df1 = pd.DataFrame({'col': [1, 2, 3], 'val': [10, 11, 12]}) +df2 = pd.DataFrame({'col': [2, 3, 4], 'val': [13, 14, 15]}) + +df1 + +df2 + +pd.merge(df1, df2, how='left', left_on='col', right_on='col') + +pd.merge(df1, df2, how='inner', left_on='col', right_on='col') + +pd.merge(df1, df2, how='right', left_on='col', right_on='col') + +pd.merge(df1, df2, how='outer', left_on='col', right_on='col') + +# + +# df1.merge? + +# + +# df1.join? +# - + # Por último, para ver los pares únicos same_skin_color = df.merge(df, left_on='Skin color', right_on='Skin color')[ @@ -213,9 +248,17 @@ def rate_height(height): # queremos ver los nombres df = df.reset_index() +df + df.groupby("Race") -df.columns +df.groupby("Race").agg(list) + +(df['Alignment'] == 'good').mean() * 100 + +(df['Alignment'] == 'good').sum() / (df['Alignment'] == 'good').size + +df.groupby("Race")['Alignment'].apply(len) # + @@ -238,6 +281,25 @@ def perc_good(grouping): df.Race.value_counts() +# Y si lo queremos como porcentajes? + +df.Race.value_counts() / df.Race.value_counts().sum() * 100 + +df.Race.value_counts(normalize=True) + +# Veamos como podemos obtener las filas del dataframe original donde la columna `Race` este entre aquellos valores con mas del 5% de repeticiones. + +over5 = df.Race.value_counts(normalize=True) > 0.05 +mutants_over5 = df.Race.value_counts()[over5] + +# Teniendo la indexacion, veamos como resolverlo con `isin` + +df[df.Race.isin(mutants_over5.index)].head(5) + +# Alternativamente, con `merge` + +df.merge(mutants_over5, left_on='Race', right_index=True, how='inner') + # ## Pivoting @@ -278,13 +340,13 @@ def alignment_to_numeric(alignment): # # Ordenando -df.sort_index() +df.set_index('name').sort_index() df.sort_values(by=['Height', 'Weight'], ascending=False) # # Operaciones de strings -df.name.str.lower() +df.name.apply(lambda x: x.lower()) # Entre [otras](https://pandas.pydata.org/pandas-docs/stable/user_guide/text.html) @@ -302,6 +364,7 @@ def alignment_to_numeric(alignment): descripciones = ['cuarentena', 'cumpleañito', 'hoy'] desc_serie = pd.Series(data=descripciones, index=indice_fechas) +desc_serie # ### to_datetime @@ -326,16 +389,29 @@ def alignment_to_numeric(alignment): # ### Filtro por fecha # -# Usamos un dataset que registra el clima y demás datos para distintas fechas de [alquiler de bicicletas](https://www.kaggle.com/c/bike-sharing-demand/data?select=train.csv) +# Usamos un dataset que registra el clima y demás datos para distintas fechas de [alquiler de bicicletas](https://www.kaggle.com/c/bike-sharing-demand/data?select=train.csv). +# +# `pd.read_csv` nos deja leer archivos csv desde una URL. Este dataset esta tambien disponible en el drive de la materia. Leemos el dataset sin bajarlo a un archivo intermedio. -bicis_df = pd.read_csv('../datasets/bicis.csv').set_index('datetime') +# + +GSPREADHSEET_DOWNLOAD_URL = ( + "https://docs.google.com/spreadsheets/d/{gid}/export?format=csv&id={gid}".format +) + +bicis_df = pd.read_csv( + GSPREADHSEET_DOWNLOAD_URL(gid="1YocUXbrd6uYpOLpU53uMS-AD9To8y_r30KbZdsSSiVQ") +).set_index('datetime') bicis_df +# - bicis_df.loc['2012-12-19 20:00:00'] +# Para poder quedarnos con un rango de fechas, debemos tener el índice ordenado +bicis_df = bicis_df.sort_index() bicis_df.loc['2012-11-19 20:00:00':'2012-12-30 20:00:00'] bicis_df.truncate(before='2012-11-19 22:00:00', after='2012-12-01 00:00:00') +# - # ### `dt` accessor diff --git a/clases/01_introduccion/python_intro.py b/clases/01_introduccion/python_intro.py index 5a68082..85563fe 100644 --- a/clases/01_introduccion/python_intro.py +++ b/clases/01_introduccion/python_intro.py @@ -63,6 +63,9 @@ # Los strings en python puden escribirse tanto con comillas simples (`'`) como comillas dobles (`"`). Normalmente vemos texto entre comillas triples para escribir _docstrings_, segun la guia de estilo de Python, el PEP8. +"""Esto es un docstring. +""" + # ### Declaracion de variables string = 'Hola' @@ -97,7 +100,6 @@ # Ojo que las variables pueden cambiar de tipo! -# + elemento = 1 print(elemento) print(type(elemento)) @@ -107,7 +109,7 @@ print(type(elemento)) # + -elemento = ['dos'] +elemento = [2] print(elemento) print(type(elemento)) @@ -134,21 +136,30 @@ lista.append(1) # Inserto un 1 al final lista.append("dos") # Inserto un "dos" al final lista.append(3.0) # Inserto un 3.0 al final +lista +# - + lista.insert(2, 10) # Inserto en posicion 2 un 10 print(lista) -# - len(lista) lista.pop() +lista + lista.index(10) lista.remove(10) lista +# + tags=["raises-exception"] for elemento in lista: print(elemento) + print(elemento + 1) +# - + +lista for i, elemento in enumerate(lista): print(f"{i}-ésimo elemento: {elemento}") @@ -177,6 +188,13 @@ print(tupla[1]) tupla[1] = 3 # Falla. No se puede mutar +# - + +l = [1, 2] +l + +l[1] = 3 +l # + [markdown] slideshow={"slide_type": "slide"} # #### Diferencia entre lista y tupla @@ -193,9 +211,15 @@ print(numeros[2]) # Imprimo elemento en la posición 2 +numeros[len(numeros) - 1] + print(numeros[-1]) # # Imprimo elemento en la última posición -print(numeros[0:2]) # Imprimo de la pos 0 a la pos 2 + +numeros[-2] + + +print(numeros[0:3]) # Imprimo de la pos 0 a la pos 2 print(numeros[-4:-2]) @@ -205,7 +229,16 @@ print(numeros[3:]) -print(numeros[::2]) +print(numeros[0:10:2]) + +# ```python +# lista[::] +# ``` + +l1 = [1, 2] +l2 = [3, 4] +l1 + l2 + numeros[7] = 'siete' # Las listas se pueden mutar print(numeros) @@ -224,11 +257,11 @@ print(palabra[3:]) # + -tupla = (0, 1) +tupla = (0, 1, 2, 3, 4) print(tupla) -print(tupla[0]) -print(tupla[1]) +print(tupla[:2]) +print(tupla[2:]) # + [markdown] slideshow={"slide_type": "slide"} # #### Diccionarios de Python @@ -281,12 +314,25 @@ # + # diccionario.get? +# - + +help(diccionario.get) # + slideshow={"slide_type": "slide"} -diccionario.get('clave1000', 2) +print(diccionario.get('clave1000')) # + slideshow={"slide_type": "slide"} print('clave1' in diccionario) # Verifico si la clave está en el diccionario +# - + +l = [1, 2, 3, 4] +2 in l + +for clave, valor in diccionario.items(): + print("la clave es %s y el valor es %s" % (clave, valor)) + +for clave, valor in diccionario.items(): + print("la clave es {} y el valor es {}".format(clave, valor)) # + slideshow={"slide_type": "slide"} # Cómo iterar un diccionario elemento por elemento @@ -297,7 +343,7 @@ diccionario.items() ): # diccionario.items() va devolviendo tuplas con el formato (clave,valor) print( - f"{clave}: {valor}" + f"la clave es {clave} y el valor es {valor}" ) # con esta sintaxis se desempaquetan en clave y valor (similar a enumerate) # + slideshow={"slide_type": "slide"} @@ -340,6 +386,15 @@ # # Algo importante para notar es que los bloques se definen por **niveles de identacion**. +v = 1 +if v == 1: + print("uno") +elif v == 2: + print("dos") +else: + print("ni idea") + print(v) + # ## Iteraciones # # ```python @@ -354,14 +409,21 @@ # # Para iterar sobre un rango de valores, usamos `range` -for i in range(1, 11, 2): +for i in range(1, 11, 3): print(i) - # ## Operadores logicos # # `not`, `or`, `and` +if True or False: + print("yay") + +1 == 2 + +1 != 2 + + # + [markdown] slideshow={"slide_type": "slide"} # ## Funciones en Python @@ -384,6 +446,16 @@ def busqueda_binaria(lista, elemento): print(busqueda_binaria([1, 4, 6, 7, 9, 10], 2)) +# + +def a(b): + if a == 1: + print(a) + return (b, b, b) + + +print(a(3)) + + # + slideshow={"slide_type": "slide"} tags=["raises-exception"] def suma(a, b): return a + b @@ -401,13 +473,18 @@ def suma(a, b): # El valor por default de divisor es 1 -def division(dividendo, divisor=1): +def division(dividendo, divisor=2): return dividendo / divisor print(division(4)) # Usa el valor por default + +# + tags=["raises-exception"] print(division(1, 2)) # Parámetros por orden print(division(dividendo=1, divisor=2)) # Parámetros por nombre +print(division(divisor=2)) +# - + print(division(divisor=2, dividendo=1)) # + @@ -422,7 +499,7 @@ def division(dividendo, divisor=1): separadas = "hola, don, pepito".split(",") print(separadas) -unidas = "".join(separadas) +unidas = " - ".join(separadas) print(unidas) # - @@ -435,11 +512,14 @@ def division(dividendo, divisor=1): print(math.pi) -from math import pi +# + +from math import pi, e -print(pi) +print(pi, e) # - +math.gcd(56, 78) + # ## Manejo de excepciones # # Se pueden encapsular errores esperados en un bloque 'try/except' para evitar cortar el flujo del programa @@ -450,8 +530,10 @@ def division(dividendo, divisor=1): try: division(1, 0) -except ZeroDivisionError: - print('No se puede dividir por cero, ojo!') +except (ZeroDivisionError, TypeError) as e: + print('No se puede dividir por cero, ojo!', e) +finally: + print(1) # + [markdown] slideshow={"slide_type": "slide"} # ## Lectura y escritura de archivos @@ -481,6 +563,10 @@ def division(dividendo, divisor=1): with open('archivo.csv', 'r') as f: print(f.read()) +f = open('archivo.csv', 'w') +f.write("algo, algo") +f.close() + # + [markdown] slideshow={"slide_type": "slide"} # ## Objetos diff --git a/requirements.txt b/requirements.txt index e7c3450..c53711f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,6 +14,7 @@ pandas pandas-profiling plotly pre-commit +requests scikit-learn seaborn sklearn