# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: initPython383
#     language: python
#     name: initpython383
# ---

# <img align="left" style="padding-right:10px;" width="150" src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Star_Wars_Logo.svg/320px-Star_Wars_Logo.svg.png" />
#
# *elaborado por <NAME>.*

# < [Colecciones de objetos: pandas](modulo1_tema4_Py_32_pandas.ipynb) | [Índice](modulo1_tema4_Py_00_indice.ipynb) | [Gestión de datos](modulo1_tema4_Py_50_gest_dat.ipynb) >
#
# __[Abre en Colab](https://colab.research.google.com/github/griu/init_python_b1/blob/master/modulo1_tema4_Py_40_contr_flujo.ipynb)__   *: <span style="color:rgba(255, 99, 71, 0.8)">Padawan! Cuando inicies sesión en Colab, prepara el entorno ejecutando el siguiente código.</span>*

# + [markdown] id="KOoKpFvlxaQK"
# # Preparación del entorno
#
# ¡Padawan! cuando inicies sesión en Colab, prepara el entorno ejecutando el siguiente código:

# + colab={"base_uri": "https://localhost:8080/"} executionInfo={"elapsed": 25678, "status": "ok", "timestamp": 1604317087349, "user": {"displayName": "alumnos bigdata", "photoUrl": "", "userId": "10710302360204190833"}, "user_tz": -60} id="2SBF5dlSTi-h" outputId="b85ff6ea-725c-464c-abf4-fc481a6882de"
if 'google.colab' in str(get_ipython()):
    # !git clone https://github.com/griu/init_python_b1.git /content/init_python_b1
    # !git -C /content/init_python_b1 pull
    # %cd /content/init_python_b1

# + [markdown] id="oy-iI-ICxHRs"
# # 7 - Control de Flujo
#
# Las herramientas de control de flujo permiten automatizar tareas. En este capítulo, trabajaremos las funciones condicionales y los bucles.

# + [markdown] id="OQ4nIubYxHR1"
# ##### 7.1. Datos de ejemplo
#
# Este capítulo, utilizará ejemplos de vehículos de Star Wars:

# + colab={"base_uri": "https://localhost:8080/", "height": 645} executionInfo={"elapsed": 615, "status": "ok", "timestamp": 1604334675390, "user": {"displayName": "alumnos bigdata", "photoUrl": "", "userId": "10710302360204190833"}, "user_tz": -60} id="hEe4mx7GxHR7" outputId="3496b893-1834-43f1-8344-ab8426b08425"
# %matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()  # para el estilo de graficos

entidades = ['planets','starships','vehicles','people','species']
entidades_df = {x: pd.read_pickle('www/' + x + '_df.pkl') for x in entidades}
vehicles_df = entidades_df['vehicles'][["cost_in_credits","length","max_atmosphering_speed"
                                        ,"crew","cargo_capacity","pilots","films"]].dropna()

vehicles_df

# + [markdown] id="ieAB6NihxHSf"
# ### 7.2. Funciones
#
# Hagamos un breve repaso sobre lo que hemos tratado hasta el momento respecto a las funciones en Python. 
#
# Hemos introducido el concepto de función en Python en el capítulo de [Elementos básicos de Python](modulo1_tema4_Py_10_elem_bas.ipynb). 
#
# A continuación, en el capítulo de [Listas, tuplas y diccionarios](modulo1_tema4_Py_30_colec_obj.ipynb), hemos explicado la posibilidad de devolver varios elementos, a la vez, en forma de tuplas.
#
# En [numpy](modulo1_tema4_Py_31_numpy.ipynb), se han explicado las funciones universales (ufunc) como un grupo de funciones que vectorizan al aplicarse sobre los elementos de los array numpy. 
#
# Finalmente, en [pandas](modulo1_tema4_Py_32_pandas.ipynb), se ha comentado la posibilidad de aplicar las funciones universales de numpy a objetos pandas (Series y DataFrame) y cómo estas funciones respetan los índices fila y columna. También, hemos comentado el alineamiento de los índices cuando  realizamos operaciones aritméticas entre dos objetos pandas.
#
# En el capítulo de gestión de datos, trataremos 2 conceptos adicionales sobre las funciones.
#
# Por un lado, veremos cómo vectorizar cualquier tipo de función, sobre los elementos de los objetos pandas, a través de la función apply.
#
# > **Recuerda**: en el tema de R, las funciones apply ya las definimos con la misma finalidad.
#
# El segundo concepto que veremos, van a ser las funciones de agregación (suma, media, cuantiles...). Las definiremos, primero, sobre objetos numpy y, posteriormente, sobre pandas.
#
# La combinación de ambos conceptos, funciones vectorizadas y funciones de agregación sobre objetos pandas, van a terminar de rellenar tu caja de herramientas para poder iniciarte en data science.

# + [markdown] id="w4Mj0KCGxHSl"
# ### 7.3. Condicionales
#
# Hagamos, también, aquí un breve repaso de los aspectos que ya hemos comentado respecto a estructuras condicionales.
#
# En el capítulo de los [Elementos básicos de Python](modulo1_tema4_Py_10_elem_bas.ipynb), introducimos la estructura básica *if-else*. 
#
# En el capítulo [Listas, tuplas y diccionarios](modulo1_tema4_Py_30_colec_obj.ipynb), utilizamos la escritura if-else en las *list comprehension*.

# + colab={"base_uri": "https://localhost:8080/"} executionInfo={"elapsed": 805, "status": "ok", "timestamp": 1604334680895, "user": {"displayName": "alumnos bigdata", "photoUrl": "", "userId": "10710302360204190833"}, "user_tz": -60} id="U37h-MkCxHSr" outputId="318572e7-54f1-461f-dbf0-15df38b0c1ed"
[x for x in range(5) if x%2==0]  # lista de pares menores a 5

# + [markdown] id="7D1lNGyoxHTG"
# Los capítulos de [Numpy](modulo1_tema4_Py_31_numpy.ipynb) y [Pandas](modulo1_tema4_Py_32_pandas.ipynb), también, han servido para tratar los filtros, como un forma de operaciones condicionales sobre vectores y data frames.
#
# Una nueva forma de realizar transformaciones condicionales con arrays numpy y series pandas es `np.where()`.
#
# Por ejemplo, veamos la siguiente variable *crew* que nos informa del número de tripulantes que puede llevar, como máximo, un vehículo:

# + colab={"base_uri": "https://localhost:8080/", "height": 238} executionInfo={"elapsed": 584, "status": "ok", "timestamp": 1604334683476, "user": {"displayName": "<NAME>", "photoUrl": "", "userId": "10710302360204190833"}, "user_tz": -60} id="1lrpxmxCxHTK" outputId="b619f2ff-4d1e-4aa5-f1b1-1a721c53ed0b"
vehicles_df[['crew']].head()

# + [markdown] id="3VgZZLh2xHTl"
# Para transformar esta variable en una nueva que indique si un vehículo puede llevar 1, 2 o 3 o más tripulantes:

# + id="8q1e0vBoxHTq" outputId="f45f0ed9-1256-41a4-d074-cee154fbb68e"
vehicles_df['crew_r'] = np.where(vehicles_df.crew<3, vehicles_df.crew, 3)
vehicles_df[['crew','crew_r']].head()

# + [markdown] id="AQkfJ3NhxHUG"
# > **Observa**: esta función de numpy aplica elemento a elemento. Observa, también, que se ha aplicado a una serie de un DataFrame, obteniendo una nueva serie.

# + [markdown] id="5TYmfjSFxHUL"
# ### 7.4. Bucles
#
# Hemos tratado Los bucles for, de forma básica, en las *list comprehension* del capítulo de [Listas, tuplas y diccionarios](modulo1_tema4_Py_30_colec_obj.ipynb).
#
# Una forma de definir bucles con for es a través de listas y diccionarios:

# + id="t6_TYmh5xHUO" outputId="34972ea2-e9aa-4acf-c0b5-77203f7d6aea"
crew_list = [1,2,3]
for n_crew in crew_list:
    
    n_vehi = vehicles_df[vehicles_df.crew_r == n_crew].shape[0]
    
    if n_vehi == 1:
        txt_vehicles = 'vehículo'
    else:
        txt_vehicles = 'vehiculos'
    
    txt_crew = 'tripulante'
    if n_crew != 1:
        txt_crew = txt_crew + 's'
    
    txt_n_crew = str(n_crew)
    if n_crew==3:
        txt_n_crew = txt_n_crew + ' o más'
    
    print("Hay {} {} con {} {}".format(n_vehi, txt_vehicles, txt_n_crew, txt_crew))

# + [markdown] id="QIZPmrr-xHUj"
# Este bucle recorre la lista `n_crew` y nos indica el número de vehículos con esa cantidad de tripulantes.
#
# Cuando recorremos un diccionario con un `for`, por defecto, éste lo hace por sus claves:

# + id="ZHAx-3BjxHUo" outputId="7ec6e5e6-252d-427a-878d-0fc3d8a7444f"
vehiculos_tripulantes = {'un': 8, 'dos': 3, '3 o más': 6}

for x in vehiculos_tripulantes:
    print(x)

# + [markdown] id="DFCZzr_CxHVA"
# Podemos iterar sobre la tupla `(clave,valor)` con `.items()`:

# + id="mkfnPPTyxHVF" outputId="6241afc1-f689-4633-e6bb-d96fff7bb895"
for txt_n_crew, n_vehi in vehiculos_tripulantes.items():
    print("Hay",n_vehi,"vehículo/s con",txt_n_crew, "tripulante/s")

# + [markdown] id="CFkpi16ZxHVb"
# Los bucles con numpy, tienen una lógica simétrica a las listas. 
#
# Para poder recorrer 2 colecciones de objetos (listas, diccionarios, numpy, series...) con el mismo número de elementos de forma correlativa, utilizamos la función `zip()`:

# + id="y7rrja5IxHVf" outputId="e17d08cf-704d-482f-8875-265280b739c2"
a = [1,2,3]
b = [8,3,6]

for x,y in zip(a,b):
    print("Hay",y,"vehículo/s con",[x if x<3 else '3 o más'][0], "tripulante/s")

# + [markdown] id="JBsJHb8ZxHV1"
# Para iterar **por columnas** de un DataFrame, utilizamos `.iteritems()`. En cada iteración obtenemos la tupla`(nombre columna, valor serie)`:

# + id="4q3OSBTgxHV3" outputId="5b103309-1149-4cba-dde0-411760eb923d"
for nombreCol,variable in vehicles_df.iteritems():
    print(nombreCol,", tiene tipo:",variable.dtype)

# + [markdown] id="t29XrHuaxHWT"
# De la misma forma, pero ahora iterando un DataFrame **por filas** con `.iterrows()`:

# + id="-F2dtHCHxHWX" outputId="ac4c864d-c5e7-4b49-93b6-444a0817a997"
for nombre,fila in vehicles_df.iloc[0:2,0:2].iterrows():
    print(nombre,", cuesta:",fila.cost_in_credits," y mide:",fila.length , "metros")

# -

# < [Colecciones de objetos: pandas](modulo1_tema4_Py_32_pandas.ipynb) | [Índice](modulo1_tema4_Py_00_indice.ipynb) | [Gestión de datos](modulo1_tema4_Py_50_gest_dat.ipynb) >
#
# __[Abre en Colab](https://colab.research.google.com/github/griu/init_python_b1/blob/master/modulo1_tema4_Py_40_contr_flujo.ipynb)__

StarcoderdataJupyterScriptsDedupFiltered