Clase 18: Introducción al uso de clases¶
En esta sesión veremos el uso de clases
y programación orientada a objetos
.
Repaso
Introducción a las clases
Definir una clase
Llamar funciones dentro de una clase
Actualizar parámetros
Ejercicio
1. Repaso¶
Revisamos qué es
Python
, por qué es tan popular y cómo instalamosAnaconda
yJupyter
.Aprendimos qué es una
librería
, cómo se instala y cómo utilizar diferentes módulos.Revisamos como crear
variables
y los diferentestypes
(tipos) que podemos usar.Vimos la diferentecia entre
arrays
ylistas
.Creamos
loops
para obtener iteraciones, cómo acceder a los elementos de una lista/array utilizando loops.Aprendimos el uso de condicionales:
if/else
.Creamos
funciones
(def), la flexibilidad de éstas y vimos qué es el input y output.Aprendimos qué es un
diccionario
, qué es una llave (key) y valor (value). Cómo nos sirve para ordenar nuestra información y cómo podemos vincularlo con loops y condicionales.Revisamos librerías de gŕaficos:
Matplotlib
yPlotly
.Trabajamos con datos estructurados mediante la librería
Pandas
:Importar datos
Limpiar información
Datos de texto, numéricos y fechas
Crear un DataFrame
Manipular el DataFrame
Usando pandas aprendimos a manejar bases de
datos relacionales
: tipo SQL.Nos introdujimos al mundo del
análisis de texto
(text mining).
Librerías que hemos ocupados:
Numpy
Pandas
Matplotlib
Plotly
nltk
re
2. Introducción¶
La programación orientada a objectos
es un enfoque de desarrollo de sistemas centrado en objetos
y como interactúan. Por ejemplo, pensemos en los elementos de alrededor, un computador, celular, escritorio, cama, etc. ¿Cómo interactúan? Me conecto al computador, utilizo el celular, subo una foto a instagram, etc.
En la programación vamos a tener objetos y vamos a establecer mecanismos para que estos interactúen. Los códigos se van a enfocar en establecer objetos
y clases
.
En este contexto, un objeto
va a ser una forma específica de organizar un código y que va a estar definida, de tal forma, que va a englobar los datos y el comportamiento. Esto significa que los datos y los procesos (funciones) van a pertenecer a uno o más objetos.
Otra forma de ver los procedemientos es el paradigma procedural (procedural paradigm), que en simple es dividir el problema en en pequeñas partes (funciones) y vamos combinando los procedimientos, donde se comparte data entre procesos o mediante variables globales. Por otro lado, la programación orientada a objetos divide el problema en pequeñas partes (objetos) y el código está construido alrededor de los objetos. “Los objetos buscan representar cosas que existen en el mundo real en un sistema de cómputo”. Los objetos no comparten datos.
Las clases
(class) nos permiten ordenar datos y funciones. De forma incompleta e introductoria, podemos pensar las clases como una gran función de funciones, que nos va a permitir ordenar códigos que pueden ser grandes y con gran cantidad de sub-funciones.
Cuando creamos una nueva clase
(class) vamos a crear un nuevo tipo
(type) de objeto
. Cada clase
va a tener atributos particulares a ésta y métodos para modificarla.
Existen lenguajes que funcionan exclusivamente orientados a objetos, como Java, y otros como Python que son lenguajes multipropósito que permiten trabajar con mecanismos del tipo procedural
u objetos
.
Veamos un ejemplo
from IPython.display import Image
import numpy as np
import scipy.io as sio
Image("Clases.png")

Image("Clases2.png")

3. Definir una clase¶
class Empresa:
#Dos cosas fundamentales: __init__() y "self"
#init(): cada clase tiene la función __init__(). Se ejecuta cada vez se llama la clase.
# su función es asignar valores a los objetos.
#self: el parámetro self permite hacer referencia dentro de una instancia de la clase,
#sean parámetros o métodos. No necesariamente se tiene que llamar self.
def __init__(self, ingresos, costos, salarios, personas):
self.ingresos = ingresos #variable única a cada instancia
self.costos = costos
self.salarios = salarios
self.personas = personas
emp1 = Empresa("100", "50", "20", "10") #Probar quitando un argumento
print("Empresa 1:", "Ingresos, costos", (emp1.ingresos, emp1.costos))
emp2 = Empresa("1000", "200", "500", "30") #Probar quitando un argumento
print("Empresa 2:", "Ingresos, costos", (emp2.ingresos, emp2.costos))
Empresa 1: Ingresos, costos ('100', '50')
Empresa 2: Ingresos, costos ('1000', '200')
4. Llamar funciones dentro de una clase¶
# llamar funciones dentro de la clase
class Empresa:
def __init__(self, ingresos, costos, salarios, personas):
self.ingresos = float(ingresos)
self.costos = float(costos)
self.salarios = float(salarios)
self.personas = float(personas)
def myfunc(self):
ingresos = str(self.ingresos)
costos = str(self.costos)
print("La Empresa tiene ingresos y costos por " + ingresos + " y " + costos + " respectivamente.")
def utilidades(self):
ingresos = self.ingresos
costos = self.costos
return ingresos-costos
def salario_pp(self):
salarios = self.salarios
personas = self.personas
return salarios/personas
def utilidades_pp(self):
utilidades = self.utilidades()
personas = self.personas
return utilidades/personas
ingresos = input('¿Cuál es el ingreso de la empresa?')
costos = input('¿Cuáles son los costos de la empresa?')
salarios = input('¿Cuál es el total de salarios?')
personas = input('¿Cuántas personas trabajan en la empresa?')
emp1 = Empresa(ingresos, costos, salarios, personas) #Probar quitando un argumento
---------------------------------------------------------------------------
StdinNotImplementedError Traceback (most recent call last)
<ipython-input-5-52e05aea364c> in <module>
29
30
---> 31 ingresos = input('¿Cuál es el ingreso de la empresa?')
32 costos = input('¿Cuáles son los costos de la empresa?')
33 salarios = input('¿Cuál es el total de salarios?')
~/miniconda3/lib/python3.9/site-packages/ipykernel/kernelbase.py in raw_input(self, prompt)
843 """
844 if not self._allow_stdin:
--> 845 raise StdinNotImplementedError(
846 "raw_input was called, but this frontend does not support input requests."
847 )
StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
emp1.myfunc()
emp1.utilidades()
emp1.salario_pp()
emp1.utilidades_pp()
La Empresa tiene ingresos y costos por 100.0 y 10.0 respectivamente.
45.0
5. Actualizar parámetros¶
class Ej_param1:
def __init__(self, α, β):
self.α = α
self.β = β
self.γ = self.α / self.β
def myfunc(self):
α, β, γ = self.α, self.β, self.γ
return α * β**γ
α = 0.3
β = 0.7
par = Ej_param1(α, β)
resultado = par.myfunc()
print(resultado)
0.2574747827902883
class Ej_param2:
def __init__(self, α=0.5, β=0.7):
self.α = α
self.β = β
self.γ = self.α / self.β
def myfunc(self):
α, β, γ = self.α, self.β, self.γ
return α * β**γ
par = Ej_param2(α = 0.3) #probar sin actualizar valores o actualizando valores
resultado = par.myfunc()
print(resultado)
0.2574747827902883
class Ej_param3:
def __init__(self, **kwargs):
#unspecified number of arguments to a function
#kwargs allows you to pass keyworded variable length of arguments to a function
self.parameters()
self.update_parameters(kwargs)
self.parameters2()
def parameters(self):
#Parámetros básicos
self.α = 0.5
self.β = 0.7
def parameters2(self):
#Parámetros compuestos
self.γ = self.α / self.β
def update_parameters(self, kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
#syntax: setattr(object, name, value)
def myfunc(self):
α, β, γ = self.α, self.β, self.γ
return α * β**γ
par = Ej_param3(α = 0.3) #probar sin actualizar valores o actualizando valores
resultado = par.myfunc()
print(resultado)
0.2574747827902883
6. Ejercicio 1¶
Supongamos que modelo de oferta y demanda:
Definir una función para la oferta y otra para la de demanda.
Graficar las curvas \(S(q)\) y \(D(q)\) para un set de \(q\in (0,16)\).
Obtener el precio y cantidad de equilibrio.
Graficar el equilibrio.
Agregar todo lo anterior en una clase.
Definir una función para la oferta y otra para la de demanda.
#1. Definir una función para la oferta y otra para la de demanda.
#Oferta
def S(q):
return (q**2)
#Demanda
def D(q):
return (q - 20)**2
Graficar las curvas \(S(q)\) y \(D(q)\) para un set de \(q\in (0,16)\).
#2. Graficar las curvas $S(q)$ y $D(q)$ para un set de $q\in (0,16)$.
#Librerías
%matplotlib inline
#Magic function: muestra los gráficos directo después de crearlos
import numpy as np
import matplotlib.pyplot as plt
#Crear vector de cantidad
q = np.linspace(0, 16, 1000)
#Graficar
plt.plot(q, S(q), label = "Oferta") #Gŕafico oferta
plt.plot(q, D(q), label = "Demanda") #Gráfico demanda
plt.title("Oferta y demanda") #Título
plt.legend() #Leyenda
plt.xlabel("Cantidad $q$") #Label eje x
plt.ylabel("Precio") #Label eje y
Text(0, 0.5, 'Precio')

Obtener el precio y cantidad de equilibrio.
El equilibrio se encuentra donde la función de oferta y demanda se intersectan: $\(S(q) = D(q)\)$
#3. Obtener el precio y cantidad de equilibrio.
#Librería: Symbolic Computation -> trabajar con problemas matemáticos simbólicamente
import sympy as sy
q = sy.Symbol('q')
print("q:", q)
eq = sy.Eq(S(q), D(q))
eq
q: q
q_sol = sy.solve(eq)
print("q_sol:", q_sol)
q_sol: [10]
p_sol = S(q_sol[0])
print("Equilibrio (q,p):", (q_sol, p_sol))
Equilibrio (q,p): ([10], 100)
Graficar el equilibrio.
#4. Graficar el equilibrio.
plt.figure(figsize= (10, 8))#create figure and reset q to be numbers
q = np.linspace(0, 16, 1000)
plt.plot(q, S(q), label = "Oferta")#plot supply, demand, and equilibrium points
plt.plot(q, D(q), label = "Demanda")
plt.plot(q_sol[0], p_sol, 'o', markersize = 14)
plt.title("Oferta y demanda")#add titles and legend
plt.legend()
plt.xlabel("Cantidad $q$")
plt.ylabel("Precio")
ax = plt.axes()#add arrow with annotation
ax.annotate('Equilibrio (10, 100)', xy=(10,100), xytext=(10, 250), arrowprops=dict(facecolor='black'))
<ipython-input-15-06f2ed6b7c24>:14: MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance. In a future version, a new instance will always be created and returned. Meanwhile, this warning can be suppressed, and the future behavior ensured, by passing a unique label to each axes instance.
ax = plt.axes()#add arrow with annotation
Text(10, 250, 'Equilibrio (10, 100)')

Agregar todo lo anterior en una clase.
class S_D:
def __init__(self, q, β=1):
self.q = q
self.β = β
#Oferta
def S(self):
q = self.q
β = self.β
return (q**2)
#Demanda
def D(self):
q = self.q
return (q - 20)**2
def sol(self):
β = self.β
#Cantidad
q = sy.Symbol('q')
S = self.S()
D = self.D()
#Equilibrio : oferta=demanda
eq = sy.Eq(S, D)
#Solución
q_sol = sy.solve(eq)
p_sol = β*q_sol[0]**2
return q_sol[0], p_sol
def plot(self, Q):
#Llamar del self
# q=self.q
q_sol, p_sol = self.sol()
self.q = Q
plt.figure(figsize= (10, 8))
plt.plot(Q, self.S(), label = "Oferta")#plot supply, demand, and equilibrium points
plt.plot(Q, self.D(), label = "Demanda")
plt.plot(q_sol, p_sol, 'o', markersize = 14)
plt.title("Oferta y demanda")#add titles and legend
plt.legend()
plt.xlabel("Cantidad $q$")
plt.ylabel("Precio")
ax = plt.axes()#add arrow with annotation
ax.annotate('Equilibrio' + str((q_sol, p_sol)), xy=(q_sol, p_sol), xytext=(q_sol, 250), arrowprops=dict(facecolor='black'))
plt.show()
Q = np.linspace(0.1, 16, 1000)
q = sy.Symbol('q')
sd = S_D(q, β=1)
sd.sol()
sd.plot(Q)
<ipython-input-31-2225e630ba8b>:48: MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance. In a future version, a new instance will always be created and returned. Meanwhile, this warning can be suppressed, and the future behavior ensured, by passing a unique label to each axes instance.
ax = plt.axes()#add arrow with annotation

7. Ejercicio 2¶
Usando el ejemplo de bases relacionales que vimos en clases, crear una clase
que tenga como características las bases de nombre, edad y almuerzo.
Crear una función que según un nombre muestre la hora promedio de almuerzo.
Función que grafique el promedio de la hora de almuerzo por día.
Crear función que devuelva el data frame con las variables id, nombre, edad, día, hora y almuerzo.
Función que devuelva el DataFrame corregido, excluyendo los NaN.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
nombre = pd.read_excel("ejemplo_sql.xlsx", sheet_name='nombre', thousands=",")
edad = pd.read_excel("ejemplo_sql.xlsx", sheet_name='edad', thousands=",")
almuerzo = pd.read_excel("ejemplo_sql.xlsx", sheet_name='Almuerzo', thousands=",")