Herramientas Computacionales

para la Investigación Interdisciplinaria Reproducible



  • Profesor: Dr. José Manuel Magallanes, PhD (jmagallanes@pucp.edu.pe)
    Profesor del Departamento de Ciencias Sociales, Pontificia Universidad Católica del Peru.
    Senior Data Scientist del eScience Institute and Visiting Professor at Evans School of Public Policy and Governance, University of Washington.
    Fellow Catalyst, Berkeley Initiative for Transparency in Social Sciences, UC Berkeley.

Sesión 2: Introducción al Python

Parte B: Control de Ejecución en Python

En esta parte veremos 3 esquemas:

  1. Ejecución Condicional.
  2. Loops.
  3. Manejo de Errores.

También presentaré el concepto de comprehensions que ofrece Python (pero no R).


Ejecución Condicional.

Es la situación donde el programa ejecuta alguna sección del código, dependiendo si alguna condición se cumple o no:

In [1]:
from math import sqrt

value=-100

#condición
if value >= 0: 
    # si es Verdadero
    rootValue=sqrt(value)
    print (rootValue)
else:
    # si es Falso
    print('Lo lamento, no calculo raíces cuadradas de números negativos')
Lo lamento, no calculo raíces cuadradas de números negativos

Nótese que sólo se usa indentación para identificar secciones de comandos. Sin la sección del else el programa funciona, pero no habrá mensaje de por qué no hay resultado mostrado.

Loops

Aquí le dices a la computadora cómo hacer algo muchas veces; así como indicarle cuándo dejarade hacerlo:

In [5]:
from math import sqrt  # esta función tiene que llamarse

values=[9,25,100]

for value in values:  # mientras hayan valores en 'values'...
    print(sqrt(value)) 
3.0
5.0
10.0

Arriba, el código muestra el resultado, pero si deseas sólo guardalo:

In [6]:
values=[9,25,100]
rootValues=[] # creando lista vacía

for value in values:
    rootValues.append(sqrt(value))  # actualizando lista

# si quieres verlos:
rootValues
Out[6]:
[3.0, 5.0, 10.0]

Es evidente que si combinamos for e if-else tendremos mejores programas:

Above, you saw that Python gives an error ('ValueError'), it is because sqrt is not defined for negative values; then the process ended abruptly. The code below controls the execution better:

In [11]:
values=[9,25,-100]
rootValues=[]

for value in values:
    if value >=0:
        rootValues.append(sqrt(value))
    else:
        print('Puse un None, lo verás luego...')
        rootValues.append(None)
        
# check:
rootValues
Puse un None, lo verás luego...
Out[11]:
[3.0, 5.0, None]

Si deseas detener la ejecución, usa break:

In [12]:
values=[9,25,-100,144,-72]
rootValues=[]

for value in values:
    if value <0:
        print('Mejor me detengo, se ha ingresado un valor inválido')
        break
    rootValues.append(sqrt(value))
        

# check:
rootValues
Mejor me detengo, se ha ingresado un valor inválido
Out[12]:
[3.0, 5.0]

El comando continue puede ser útil para usar toda la data aun cuando hay errores:

In [18]:
import numpy as np

values=[9,None,np.nan,np.inf, '1000',-100, 144,-72]
for value in values: # notice the order of 'IFs'
    if value in [None,np.nan,np.inf]: # condition1
        print ('NA, nan o inf ha sido ingresado')
        continue
    if isinstance(value, str): #condition2
        print ('Encontré un texto...no haré nada')
        continue
    if value < 0: # condition3
        print ('Encontré un negativo...no haré nada')
        continue
    print (sqrt(value), 'es la raíz de ',value)            
3.0 es la raíz de  9
NA, nan o inf ha sido ingresado
NA, nan o inf ha sido ingresado
NA, nan o inf ha sido ingresado
Encontré un texto...no haré nada
Encontré un negativo...no haré nada
12.0 es la raíz de  144
Encontré un negativo...no haré nada

Vea que None y NaN tienen diferente naturaleza:

In [24]:
type(None),type(np.nan)
Out[24]:
(NoneType, float)

NaN es común en operaciones numéricas:

In [25]:
10 + np.nan
Out[25]:
nan

Pero hay error si usas None:

In [26]:
10 + None
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-26-fc4662b20529> in <module>()
----> 1 10 + None

TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
In [21]:
10 + np.nan
Out[21]:
nan

A veces, quieres contar un valor particular:

In [27]:
values=[9,25,-100,144,-72]

counterOfInvalids=0 # el contador se inicializa

for value in values:
    if value <0:
        counterOfInvalids +=1 #incrementando contador

# ver
counterOfInvalids
Out[27]:
2

Este código te enseña a guardar posiciones:

In [28]:
values=[9,25,-100,144,-72]
positionInvalids=[]
currentPosition=0 # posición inicial (de arranque)

for value in values:
    if value <0:
        positionInvalids.append(currentPosition)
    currentPosition+=1 # atención dónde pones esto!

# to see the results:
positionInvalids 
Out[28]:
[2, 4]
In [29]:
# testing:
for pos in positionInvalids:
    print (values[pos])
    
-100
-72

Manejo de errores

Hemos controlado errores antes con if-else; veamos unas situaciones alternativas.

In [30]:
# what kind of error you get:
print (sqrt(-10))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-30-bf05804398cd> in <module>()
      1 # what kind of error you get:
----> 2 print (sqrt(-10))

ValueError: math domain error
In [31]:
# what kind of error you get:
print (sqrt('10'))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-31-388a664baf86> in <module>()
      1 # what kind of error you get:
----> 2 print (sqrt('10'))

TypeError: must be real number, not str

Python is giving different types of errors (Type and Value), let's use that:

In [32]:
values=[10,-10,'10']
In [34]:
for value in values:
    try:
        print (sqrt(value))
    except ValueError:
        print (value,'valor equivocado!')
    except TypeError:
        print (value,'se recibió texto!!')
        
3.1622776601683795
-10 valor equivocado!
10 se recibió texto!!

Comprehensions

Python crea estructuras 'al paso' usando esta capacidad.

Por ejemplo, si quieres una lista de las raices de otra:

In [36]:
#esto da error:

values=[9,25,49,121]
sqrt(values)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-36-4cf025132815> in <module>()
      2 
      3 values=[9,25,49,121]
----> 4 sqrt(values)

TypeError: must be real number, not list
In [37]:
#esto no:

from math import sqrt

values=[9,25,49,121]
[sqrt(value) for value in values]  
Out[37]:
[3.0, 5.0, 7.0, 11.0]

Los Dicts también pueden usar comprehensions:

In [41]:
values=[9,25,49,-121]
{value:(sqrt(value) if value > 0 else None) for value in values}  
Out[41]:
{9: 3.0, 25: 5.0, 49: 7.0, -121: None}

La función zip crea tuplas:

In [56]:
letters=['a','b','c','a']
numbers=[10,20,30,100]
list(zip(letters,numbers))
Out[56]:
[('a', 10), ('b', 20), ('c', 30), ('a', 100)]

Las listas Zippeadas son útiles en las comprehensions:

In [58]:
[n for n,l in zip(numbers,letters) if l=='a']
Out[58]:
[10, 100]

AUSPICIO:

El desarrollo de estos contenidos ha sido posible gracias al grant del Berkeley Initiative for Transparency in the Social Sciences (BITSS) at the Center for Effective Global Action (CEGA) at the University of California, Berkeley

RECONOCIMIENTO

El autor reconoce el apoyo que el eScience Institute de la Universidad de Washington le ha brindado desde el 2015 para desarrollar su investigación en Ciencia de Datos.