En la primera parte del proyecto hemos aprendido a graficar funciones utilizando el módulo matplotlib
. En esta parte aprenderemos a resolver límites utilizando el módulo sympy
, además de poder graficar la función en cuestión y ver cómo ésta se va aproximando al valor del límite que buscamos.
Sabemos que siempre podemos resolver un límite utilizando el método de aproximación, es decir, evaluando la función en valores muy muy cercanos al valor del límite. Por ejemplo, si deseamos calcular
$$ \lim\limits_{x\rightarrow 2}x^{2}= $$podemos hacerlo evaluando $f(x)=x^{2}$ en valores muy muy cercanos a 2. Recordemos que en estos casos es muy útil realizar una tabla para auxiliarnos en estas evaluaciones; Python nos brinda una herramienta muy poderosa para el análisis de datos mediante el módulo pandas
, el cual tendrá dedicado una gran parte del curso en próximas lecciones, sin embargo, para el fin de este proyecto sólo trabajaremos con las tablas o dataframes.
Para ello crearemos un diccionario donde colocaremos en listas de comprensión los valores que asignaremos a la variable independiente $x$ y los valores que toma $f(x)$, es importante mencionar que el número de elementos de ambas listas debe ser el mismo. Por ejemplo creamos un diccionario asignando los valores $-3,-2,\ldots,2,3$ a $x$ respecto a la función $f(x)=x^{2}$:
# importamos el módulo necesario
import pandas as pd
# creamos un diccionario
datos = {"x":[i for i in range(-3,4)], "f(x)":[i ** 2 for i in range(-3,4)]}
print(datos)
{'x': [-3, -2, -1, 0, 1, 2, 3], 'f(x)': [9, 4, 1, 0, 1, 4, 9]}
lo cual consigue hacer la asociación que queríamos, esto es $f(-3)=9, f(-2)=4, f(0)=0, f(2)=4$, etcétera. Finalmente, para poder visualizarlo primero crearemos un dataframe usando pd.Dataframe()
que recibe como parámetro el diccionario que creamos anteriormente
df = pd.DataFrame(datos)
print(df)
x f(x) 0 -3 9 1 -2 4 2 -1 1 3 0 0 4 1 1 5 2 4 6 3 9
donde la primer columna es creada en automático para indexar las filas. Podemos acceder a los elementos de un dataframe utilizando df.iloc()
que recibe como parámetros el índice correspondiente a la fila y/o el índice correspondiente a la columna. Por defecto nuestra primer columna tiene el índice cero. Por ejemplo, si deseamos obtener el valor correspondiente a la primer fila (índice 0) y a la segunda columna (índice 1) usamos
print(df.iloc[0,1])
9
De este modo puede pensarse las posiciones de los elementos de un dataframe como las entradas de una matriz (en términos matemáticos). Para ayudar a visualizar las posiciones crearemos el siguiente dataframe
posicion = {"x":[[i,0] for i in range(0,7)], "f(x)":[[i,1] for i in range(0,7)]}
df_posicion = pd.DataFrame(posicion)
print(df_posicion)
x f(x) 0 [0, 0] [0, 1] 1 [1, 0] [1, 1] 2 [2, 0] [2, 1] 3 [3, 0] [3, 1] 4 [4, 0] [4, 1] 5 [5, 0] [5, 1] 6 [6, 0] [6, 1]
de donde, la primer entrada de [ , ]
hace referencia al índice de la fila y la segunda entrada al índice de la columna. visualicemos ambos dataframes:
print(df_posicion)
print("_"*20)
print(df)
x f(x) 0 [0, 0] [0, 1] 1 [1, 0] [1, 1] 2 [2, 0] [2, 1] 3 [3, 0] [3, 1] 4 [4, 0] [4, 1] 5 [5, 0] [5, 1] 6 [6, 0] [6, 1] ____________________ x f(x) 0 -3 9 1 -2 4 2 -1 1 3 0 0 4 1 1 5 2 4 6 3 9
De tal manera podemos acceder, por ejemplo, a los siguientes valores
print(df.iloc[0,0])
print("-"*20)
print(df.iloc[2,1])
print("-"*20)
print(df.iloc[6,0])
-3 -------------------- 1 -------------------- 3
Finalmente, podemos acceder a los valores de más filas:
# acceder a los valores HASTA la fila 0
print(df.iloc[:1])
print("-"*20)
# acceder a los valores HASTA la fila 1
print(df.iloc[:2])
print("-"*20)
# acceder a los valores HASTA la fila 2
print(df.iloc[:3])
print("-"*20)
# acceder a los valores comenzando en la fila 1 y hasta la última fila
print(df.iloc[1:])
print("-"*20)
# acceder a los valores comenzando en la fila 2 y hasta la fila 5
print(df.iloc[2:6])
print("-"*20)
x f(x) 0 -3 9 -------------------- x f(x) 0 -3 9 1 -2 4 -------------------- x f(x) 0 -3 9 1 -2 4 2 -1 1 -------------------- x f(x) 1 -2 4 2 -1 1 3 0 0 4 1 1 5 2 4 6 3 9 -------------------- x f(x) 2 -1 1 3 0 0 4 1 1 5 2 4 --------------------
Ahora bien, realicemos las aproximaciones para hallar el límite mencionado líneas arriba. Lo que haremos será aproximarnos al valor de $x=2$ mediante los números de la forma $2 + \frac{1}{n}$, con $n=-4,-3,-2,-1,1,2,3,4$ (donde $n\neq0$); para que la función $f(x)=x^{2}$ tome dichos valores de aproximación crearemos una lista de comprensión dentro de otra lista de comprensión, esto es
valores = {"x": [2 + 1 / i for i in range(-4,5) if i != 0], "f(x)": [i ** 2 for i in
[2 + 1 / i for i in range(-4,5) if i != 0]]}
print(valores)
{'x': [1.75, 1.6666666666666667, 1.5, 1.0, 3.0, 2.5, 2.3333333333333335, 2.25], 'f(x)': [3.0625, 2.777777777777778, 2.25, 1.0, 9.0, 6.25, 5.4444444444444455, 5.0625]}
o visualicemos lo anterior mediante un dataframe:
df = pd.DataFrame(valores)
print(df)
x f(x) 0 1.750000 3.062500 1 1.666667 2.777778 2 1.500000 2.250000 3 1.000000 1.000000 4 3.000000 9.000000 5 2.500000 6.250000 6 2.333333 5.444444 7 2.250000 5.062500
Ahora graficaremos la función en cuestión y los puntos obtenidos en el dataframe anterior. Es importante mencionar que podemos iterar sobre los valores dentro de un dataframe, lo cual conseguiremos accediendo a dichos valores como lo hicimos líneas arriba accediendo a las posiciones del dataframe (es decir, usando df.iloc[]
.
import matplotlib.pyplot as mplot
# la pareja ordenada está conformado por los valores
print(f'Punto:({df.iloc[0,0]},{df.iloc[0,1]})')
# graficamos la pareja ordenada
mplot.plot(df.iloc[0,0], df.iloc[0,1], marker="o")
mplot.show()
Punto:(-0.1,0.9983341664682815)
Después graficamos todos los puntos del dataframe realizando una iteración:
# iteración
for i in range(0,8):
mplot.plot(df.iloc[i,0], df.iloc[i,1], marker = "o", color = "b")
mplot.show()
import numpy as np
# graficamos los puntos
for i in range(0,8):
mplot.plot(df.iloc[i,0], df.iloc[i,1], marker = "o", color = "b")
# definimos la función
x = np.arange(0,3, 0.01)
y = x ** 2
# graficamos la funcion
mplot.plot(x,y, color = "k")
# graficamos el punto de interés en el límite, en este caso es x=2, junto con las líneas auxiliares
mplot.plot(2,4, marker = "o", color = "r")
u = 0
while u <= 2 and u >= 0:
mplot.plot(u,4, marker=",", color="k")
u += 0.08
v = 0
while v <= 4 and v >= 0:
mplot.plot(2,v, marker=",", color="k")
v += 0.1
mplot.show()
lo cual muestra cómo nos vamos aproximando mediante la función al valor del límite, es decir, mientras más cercanos sean los valores de $x$ a $2$ podemos ver que la función se va acercando cada vez más a $f(x)=4$. Lo cual ya sabíamos pues podemos resolver el límite como
$$ \lim\limits_{x\rightarrow 2}x^{2}=\lim\limits_{x\rightarrow 2}2^{2}=4 $$Para ver mejor esto podemos afinar las aproximaciones que hicimos en nuestro dataframe, lo cual conseguiremos aumentando el rango de iteración en las listas de comprensión del diccionario valores
. Después, es de nuestro interés ver los datos ordenados en el dataframe de menor a mayor en la columna $x$, para ello utilizaremos df.sort_values(by="x")
. Veamos:
# afinamos los valores de aproximación
valores = {"x": [2 + 1 / i for i in range(-10,11) if i != 0], "f(x)": [i ** 2 for i in
[2 + 1 / i for i in range(-10,11) if i != 0]]}
# creamos el dataframe
df = pd.DataFrame(valores)
# ordenamos los valores de menor a mayor respecto a la columna x
df.sort_values(by="x")
x | f(x) | |
---|---|---|
9 | 1.000000 | 1.000000 |
8 | 1.500000 | 2.250000 |
7 | 1.666667 | 2.777778 |
6 | 1.750000 | 3.062500 |
5 | 1.800000 | 3.240000 |
4 | 1.833333 | 3.361111 |
3 | 1.857143 | 3.448980 |
2 | 1.875000 | 3.515625 |
1 | 1.888889 | 3.567901 |
0 | 1.900000 | 3.610000 |
19 | 2.100000 | 4.410000 |
18 | 2.111111 | 4.456790 |
17 | 2.125000 | 4.515625 |
16 | 2.142857 | 4.591837 |
15 | 2.166667 | 4.694444 |
14 | 2.200000 | 4.840000 |
13 | 2.250000 | 5.062500 |
12 | 2.333333 | 5.444444 |
11 | 2.500000 | 6.250000 |
10 | 3.000000 | 9.000000 |
Graficamos nuevamente la gráfica con los puntos anteriores
# graficamos los puntos, debemos ajustar el rango de iteración
for i in range(-10,11):
mplot.plot(df.iloc[i,0], df.iloc[i,1], marker = "o", color = "b")
# definimos la función
x = np.arange(0,3, 0.01)
y = x ** 2
# graficamos la funcion
mplot.plot(x,y, color = "k")
# graficamos el punto de interés en el límite, en este caso es x=2, junto con las líneas auxiliares
mplot.plot(2,4, marker = "o", color = "r")
u = 0
while u <= 2 and u >= 0:
mplot.plot(u,4, marker=",", color="k")
u += 0.08
v = 0
while v <= 4 and v >= 0:
mplot.plot(2,v, marker=",", color="k")
v += 0.1
mplot.show()
Para finalizar la parte de límites podemos utilizar el módulo sympy
para calcular de forma muy rápida y sencilla el límite de una función. Por ejemplo, si deseamos calcular
empleamos
from sympy import *
# creamos la función:
x = symbols("x")
y = (x ** 2 - 1) / (x - 1)
# usamos limit(y,x, n) para hallar el límite de la función cuando x tiende a n
limit(y,x,1)
Resolvamos manualmente el límite anterior:
\begin{align*} \lim\limits_{x\rightarrow 1}\frac{x^{2}-1}{x-1}=\lim\limits_{x\rightarrow 1}\frac{(x+1)(x-1)}{x-1}=\lim\limits_{x\rightarrow 1}(x+1)=1+1=2 \end{align*}Podemos también calcular límites infinitos. En este caso utilizaremos dos "o" seguidas para hacer alusión al símbolo de infinito $\infty$. Por ejmplo podemos calcular el límite $$ \lim\limits_{x\rightarrow\infty}\left(1+\frac{1}{x}\right)^{x} $$
# creamos la función
y = (1 + (1 / x)) ** x
# calculamos el límite infinito
limit(y,x,oo)
Calculemos algunos otros límites
import numpy as np
from IPython.display import display, Math
# límite trigonométrico
y1 = sin(x) / x
v1 = limit(y1,x,0)
print("El valor del límite: ")
display(Math(r' \lim\limits_{x\rightarrow 0}\frac{sin(x)}{x}'))
print("es ", v1)
print("_"*20)
# límite logarítmico por la derecha
y2 = log(x) / x
v2 = limit(y2,x,+0)
print("El valor del límite: ")
display(Math(r' \lim\limits_{x\rightarrow 0^{+}}\frac{ln(x)}{x}'))
print("es ", v2)
print("_"*20)
# límite al infinito negativo
y3 = 1 / x
v3 = limit(y3,x,-oo)
print("El valor del límite: ")
display(Math(r' \lim\limits_{x\rightarrow \infty^{-}}\frac{1}{x}'))
print("es ", v3)
print("_"*20)
El valor del límite:
es 1 ____________________ El valor del límite:
es -oo ____________________ El valor del límite:
es 0 ____________________
Para finalizar la parte II del proyecto grafiquemos la función $f(x)=\frac{sin(x)}{x}$ y veamos cómo nos aproximamos al valor de $x=0$:
# realizamos una aproximación a x=0
valores = {"x": [1 / i for i in range(-10,11) if i != 0], "f(x)": [np.sin(i) / i for i in
[1 / i for i in range(-10,11) if i != 0]]}
# creamos el dataframe
df = pd.DataFrame(valores)
# graficamos los puntos
for i in range(-10,11):
mplot.plot(df.iloc[i,0], df.iloc[i,1], marker = "o", color = "b")
# definimos la función
x = np.arange(-np.pi,np.pi, 0.01)
y = np.sin(x) / x
# graficamos la funcion
mplot.plot(x,y, color = "k", label="$f(x)=\frac{sin(x)}{x}$")
# graficamos el punto de interés en el límite, en este caso es x=0, junto con las líneas auxiliares
mplot.plot(0,1, marker = "o", color = "r")
u = -np.pi
while u <= 0 and u >= -np.pi:
mplot.plot(u,1, marker=",", color="k")
u += 0.05
v = 0
while v <= 1 and v >= 0:
mplot.plot(0,v, marker=",", color="k")
v += 0.01
mplot.legend()
mplot.show()