<jupyter_start><jupyter_text>Actualización anaconda 0. Abrir terminalAbrir una nueva terminal ya sea usando `anaconda prompt` o cualquier otra terminal. Verificar versión de python ejecutando el comando ```conda info```Si la versión de python que te arroja el comando anterior es `3.7.x` entonces vamos a proceder a desinstalar la versión de anaconda que tenemos instalada. De lo contrario ir al paso **2**. 1. Desinstalar anaconda - Usuarios mac o linux1. Eliminar todo el directorio de instalación de anaconda tipicamente está ubicado en la siguiente dirección:```rm -rf ~/anaconda3```2. Elimine los siguientes archivos y directorios ocultos, que pueden haber sido creados en el directorio de inicio. Para ello use el siguiente comando:```rm -rf ~/.condarc ~/.conda ~/.continuum``` - Usuarios windowsEn la carpeta donde instaló Anaconda (Ejemplo: `C:\Users\username\Anaconda3`) debe haber un ejecutable llamado Uninstall-Anaconda.exe. Haga doble clic en este archivo para comenzar a desinstalar Anaconda. 2. Descargar última versión de Anaconda desde su página- Ir a el siguiente enlace y en la parte final de dicha página encontrar los archivos a descargar https://www.anaconda.com/products/individual.![image.png](attachment:image.png)- Luego de descargado el archivo de instalación, ejecutarlo para instalar la última versión de anaconda.- Finalmente actualice anaconda a la última versión disponible. Para ello ejecute el siguiente comando```conda update -n base -c defaults conda```  Optimización de código<jupyter_code># Librerías a usar en todo el programa
import numpy as np
import time,math 
import matplotlib.pyplot as plt<jupyter_output><empty_output><jupyter_text>Formas de optimizar el código en las `funciones` y los ciclos `for` Para ilustrar el método usemos el siguiente ejemplo: Muestre en una lista cada una de las letras de la siguiente variable `oldlist = 'Este es el texto de ejemplo'` en letra mayúscula.<jupyter_code>words = """
 In 1973, the Chicago Board of Options Exchange begun trading options in exchanges, although previously options 
 had been regularly traded by financial institutions in over the counter markets. In the same year, Black and 
 Scholes (1973), and Merton (1973), published their seminal papers on the theory of option pricing. Since then 
 the growth of the field of derivative securities has been phenomenal. In recognition of their pioneering and 
 fundamental contribution to option valuation, Scholes and Merton received in 1997 the Award of the Nobel Prize 
 in Economics. Unfortunately, Black was unable to receive the award since he had already passed away.

In essence, the Black-Scholes model states that by continuously adjusting the proportions of stocks and options 
in a portfolio, the investor can create a riskless hedge portfolio, where all market risks are eliminated. The 
ability to construct such a portfolio relies on the assumptions of continuous trading and continuous sample paths
of the asset price. In an efficient market with no riskless arbitrage opportunities, any portfolio with a zero 
market risk must have an expected rate of return equal to the risk-free interest rate. This approach led to the 
differential equation, known in physics as the "heat equation". Its solution is the Black-Scholes formula for 
pricing European options on non-dividend paying stocks 
"""
# Solucionarlo acá
oldlist = 'Este es el texto de ejemplo'
speed = []
t1 = time.time()
new_list = []
for letter in words:
    new_list.append(letter.upper())
t2 = time.time()
speed.append(t2 - t1)
print(t2 - t1)<jupyter_output>0.0006804466247558594<jupyter_text>- **Evitando puntos ...** Suponemos que no puedes usar la función `map` o una compresión de listas. Puede estar atascado con el bucle for. El ejemplo de bucle for tiene otra ineficiencia. Tanto `newlist.append ` como `word.upper` son referencias de funciones que se reevalúan cada vez a través del ciclo. El bucle original puede ser reemplazado por:<jupyter_code># Almacenando funciones en variables (eliminar "." en las iteraciones de los for)
t1 = time.time()

new_list = []
append_new = new_list.append
upper_new = str.upper
for letter in words:
    append_new(upper_new(letter))

t2 = time.time()

print(t2 - t1)<jupyter_output>0.0005972385406494141<jupyter_text>- **Variables locales.**La aceleración final disponible para nosotros para la versión que no es un `map` del bucle for, es usar variables locales siempre que sea posible. Si el ciclo anterior se convierte como una función, las variables append y upper se convierten en locales. Python accede a las variables locales de forma mucho más eficiente que las variables globales.<jupyter_code># Generación de función para utilizar variables locales
def upper_v_locales(words):
    new_list2 = []
    append_new2 = new_list2.append
    upper_new2 = str.upper
    for letter in words:
        append_new2(upper_new2(letter))
    return new_list2

t1 = time.time()
upper_v_locales(words)
t2 = time.time()

speed.append(t2 - t1)
print(t2 - t1)<jupyter_output>0.0005576610565185547<jupyter_text>Funciones lambdaLas funciones `lambda` o funciones anónimas, son un tipo de función que introduce python en su estructura, en donde se usa frecuentemente en dos situaciones principales: (a) si la función es bastante simple, y (b) si solo se usará una vez. Las funciones de Lambda se pueden usar donde sea que se requieran objetos de funciónPython utiliza dos formas distintas de crear funciones: usando la sintáxis `def` y `lambda`. A continuación se muestran dos ejemplos de los usos de estas dos sintaxis: Ejemplo raiz cuadrada<jupyter_code>###### Usando la sintáxis def
def sqrt1(x):
    return np.sqrt(x)

###### Usando la sintaxis lambda
sqrt_lambda = lambda x: np.sqrt(x)

print('Usando la sintáxis def obtenemos:',sqrt1(4))
print('Usando la sintáxis lambda obtenemos:',sqrt_lambda(4))<jupyter_output>Usando la sintáxis def obtenemos: None
Usando la sintáxis lambda obtenemos: 2.0<jupyter_text>Normalmente, las funciones se crean para uno de dos propósitos: **(a) reducir la duplicación de código, o (b) modularizar el código.**Si tienes una función que es usada una única vez, no necesitas darle un nombre a la función. Puede ser 'anónima' y además puede definirla justo en el lugar donde desea usarlo. Ahí es donde `lambda` es útil.  ¿Porqué el uso de la función lambda es en ocasiones confuso?**Primero:** Lambda es confuso porque: el requisito de que una lambda **pueda tomar solo una expresión** plantea la pregunta: ¿Qué es una expresión?. En Python, ¿cuál es la diferencia entre una expresión y una declaración (statement)?. Una buena respuesta es que una  expresión devuelve (o evalúa) un valor, mientras que una declaración no.Una pregunta que resulta entonces, es **¿qué tipo de cosas puedo, y no puedo, poner en una función lambda?** Y la respuesta a esa pregunta es básicamente   - Si no devuelve un valor, no es una expresión y no se puede poner en una lambda.   - Si puede imaginarlo en una declaración de asignación, en el lado derecho del signo igual, es una expresión y puede colocarse en una lambda.Usando estas reglas podríamos entonces llegar a las siguientes conclusiones:*1*. Los enunciados de asignación no se pueden usar en lambda. En Python, las declaraciones de asignación no devuelven nada, ni siquiera Ninguno (nulo).     **Ejemplo**<jupyter_code># Asignaciones en una función lambda
asignacion = lambda x,y: x == y
asignacion(6,7)<jupyter_output><empty_output><jupyter_text>*2*. Cosas simples como operaciones matemáticas, operaciones de cadenas, comprensión de listas, etc. están bien en una lambda.<jupyter_code># Ejemplo
########## Sumar elemento a elemento de una lista
suma = lambda a,b: a + b
l1 = [1 ,2, 3]
l2 = [4, 5, 6]
# 1. Usando for
sum1 = []
for i in range(len(l1)):
    sum1.append(suma(l1[i], l2[i]))

# 2. Usando compresión de listas
sum2 = [suma(l1[i], l2[i]) for i in range(len(l1))]
sum2

########## Obtener el mismo resultado usando vectores
sum3 = np.array(l1) + np.array(l2)
sum3
a = print(3)
b = lambda x: print(x)
b(4)<jupyter_output>3
4<jupyter_text>*3*. Las llamadas a funciones son expresiones. Está bien colocar una llamada de función en un lambda y pasar argumentos a esa función. Al hacerlo, envuelve la llamada a la función (argumentos y todo) dentro de una nueva función anónima. Incluso la función `print` puede ser usada dentro de una función lambda.- **Ejemplo** (compresión de listas)<jupyter_code>palabra = 'hola grupo es la prueba'

# Poner print dentro de una lambda, que regrese la letra mayúscula del argumento
funUpper = lambda word: print(word.upper())

# Poner dentro de una lambda una función que regrese la letra mayúscula
funUpper2 = lambda word: word.upper()

a = funUpper2(palabra)
print(a)<jupyter_output>HOLA GRUPO ES LA PRUEBA<jupyter_text>- **Ejemplo** (funciones anidadas)<jupyter_code>def suma(a,b):
    return a+b

# función anónima
suma_potencia = lambda n,a,b: \
                print('la suma de %d y %d a la potencia %d es: %.1f' % (a,b,n, suma(a,b)**n))
suma_potencia(10,30,4.2)<jupyter_output>la suma de 30 y 4 a la potencia 10 es: 2189077113773874.0<jupyter_text>*4*. Las expresiones condicionales, son expresiones (y no simplemente una sintaxis diferente para una instrucción if / else). Devuelven un valor y se pueden usar en una lambda   **Ejemplo**<jupyter_code># Probar estas dos funciones

# Escribir función anónima que regrese True si x>y de lo contrario False
some_condition = lambda x, y: True if x > y else False

# Utilizar la función anterior como condición en una lambda
f1 = lambda x, y: 100 if some_condition(x,y) else 0

# Crear una función que regrese 'big' si x>100 de lo contrario 'small'
f2 = lambda x: 'big' if x > 100 else 'small'

# Verificar f1 y f2 en la siguiente lista
l1 = [100,25,200,5]

# 1. Usando for
r_f2 = []
for num in l1:
    r_f2.append(f2(num))
# print(r_f2)

r_f1 = []
for i in range(len(l1) - 1):
    r_f1.append(f1(l1[i], l1[i + 1]))
print(r_f1)

# 2. Usando compresión de listas
compresion2 = [f2(num) for num in l1]
compresion1 = [f1(l1[i], l1[i + 1]) for  i in range(len(l1) - 1)]

print(compresion1)<jupyter_output>[100, 0, 100]
[100, 0, 100]<jupyter_text>**Segundo:** Lambda es confuso porque: lambda generalmente se describe como una herramienta para crear funciones, pero una especificación lambda no contiene una declaración de **return**.La declaración de *return* está, en cierto sentido, implícita en una lambda. Como una especificación lambda debe contener solo una expresión, y esa expresión debe devolver un valor, una función anónima creada por lambda devuelve implícitamente el valor devuelto por la expresión. Esto tiene perfecto sentido. Aún así, la falta de una declaración de *return* explícita es, creo, parte de lo que hace que sea difícil asimilar lambda, o al menos, difícil asimilarlo rápidamente.**Ejemplo de combinación de los dos tipos de funciones**<jupyter_code># Crear una función que regrese una función anónima que sea un incremento de cierto valor n (entrada)
def make_incrementor(n):
    return lambda x: x + n

f = make_incrementor(22)
i1 = 0; i2 = 5

print('Incrementar en %d unidades'% i1, f(i1),'\nIncrementar en %d unidades' %i2, f(i2))
# # f(100)
# f(1)<jupyter_output>Incrementar en 0 unidades 22 
Incrementar en 5 unidades 27<jupyter_text>- Función map()Puedes pensar en la función `map()` como un `for` movido al código C. La única restricción es que el 'cuerpo de bucle' de la función `map` debe ser una llamada a función. Además del beneficio sintáctico de la compresión de listas, a menudo son tan rápidas o más rápidas que el uso equivalente del `map`. La sintaxis de la función es:> `r = map(función, secuencia)`Con Python 3, map () devuelve un iterador, si queremos obtener los valores numéricos debemos usar compresión de listas o el comando `list`.**Ejemplos**<jupyter_code>Celsius = [39.2, 36.5, 37.3, 37.8]

# Convierta las temperaturas en °C a frados fahrenheit --> eq = float(9)/5)*i + 32

# 1. Usando llenado de listas
f1 = []
for temp in Celsius:
    f1.append((float(9)/5)*temp + 32)
print(f1)

# 2. Usando funciones y compresión de listas
f_conversion = lambda t: (float(9)/5)*t + 32
f2 = [f_conversion(temp) for temp in Celsius]
print(f2)

# 3. Usando funciones y funciones map
f3 = list(map(f_conversion, Celsius))
print(f3)

# 4. Usando vectores
f4 = f_conversion(np.array(Celsius))
print(f4)

# Comparar

# Ahora realizar el proceso inverso de fahrenheit a °C --> eq=float(5)/9)*(x-32)
Celsius = [39.2, 36.5, 37.3, 37.8]


# Tres métodos diferentes para aplicar una función a datos de una lista
oldlist = 'Este es el texto de ejemplo'

tiempo = []
############ Agregando letras mayúsculas a una lista
l1 = []
for word in oldlist:
    l1.append(word.upper())
print(l1)

############ Usando la función map
l2 = list(map(str.upper, oldlist))
print(l2)

############ Usando compresión de listas
l3 = [word.upper() for word in oldlist]
print(l3)
# print('Con el método de agregar datos a la lista:\n',newlist1)
# print('Usando la funcion map:\n',newlist2)
# print('Usando compresión de listas:\n', newlist3)<jupyter_output>['E', 'S', 'T', 'E', ' ', 'E', 'S', ' ', 'E', 'L', ' ', 'T', 'E', 'X', 'T', 'O', ' ', 'D', 'E', ' ', 'E', 'J', 'E', 'M', 'P', 'L', 'O']
['E', 'S', 'T', 'E', ' ', 'E', 'S', ' ', 'E', 'L', ' ', 'T', 'E', 'X', 'T', 'O', ' ', 'D', 'E', ' ', 'E', 'J', 'E', 'M', 'P', 'L', 'O']
['E', 'S', 'T', 'E', ' ', 'E', 'S', ' ', 'E', 'L', ' ', 'T', 'E', 'X', 'T', 'O', ' ', 'D', 'E', ' ', 'E', 'J', 'E', 'M', 'P', 'L', 'O']<jupyter_text>- Mientras todavía utilizamos `lamda` como una función, podemos tener una lista de funciones como una secuencia:**Ejemplo a)**: Construyamos un programa usando `map`, compresión de listas y estructura `for` típica para evaluar un vector de tamaño `N` para una lista de funciones<jupyter_code># Escribir el programa acá 
import math

N = 3
fns_np = [np.arctan, np.cos, np.sin]
fns_math = [math.atan, math.cos, math.sin]

xs = np.arange(N)

# 1.1 For típico (fns_math)
l1 = []
for fi in fns_math:
    aux = []
    for num in xs:
        aux.append(fi(num))
    l1.append(aux)
print(l1)

# 1.2 For típico (fns_np)
l2 = []
for fi in fns_np:
    aux = []
    l2.append(fi(xs))
# print(l2)

# 2. Compresión de listas
l3 = [[fi(num) for num in xs] for fi in fns_math]
print(l3)

# # 3. Funciones map
l4 = list(map(lambda fi: list(map(lambda num: fi(num), xs)), fns_np))

print(l4)
# print('f1 = ',call)
# print('f2 = ',call2)
# print('f3 = ',call3)<jupyter_output>[[0.0, 0.7853981633974483, 1.1071487177940904], [1.0, 0.5403023058681398, -0.4161468365471424], [0.0, 0.8414709848078965, 0.9092974268256817]]
[[0.0, 0.7853981633974483, 1.1071487177940904], [1.0, 0.5403023058681398, -0.4161468365471424], [0.0, 0.8414709848078965, 0.9092974268256817]]
[[0.0, 0.7853981633974483, 1.1071487177940904], [1.0, 0.5403023058681398, -0.4161468365471424], [0.0, 0.8414709848078965, 0.9092974268256817]]<jupyter_text>**Ejemplo b)**<jupyter_code>def square(x):
        return (x**2)
def cube(x):
        return (x**3)

funcs = [square, cube]

# Combinar map y compresión de listas para evaluar números 0-5 de cada función en cada iteración 
N = 6

# 1. For clásico (método a olvidar)

print(value1)

# 2. Función map anidada
value2 = 
print(value2)

# 3. Compresión de listas anidadas
values3 = 
print(values3)<jupyter_output>[[0, 0], [1, 1], [4, 8], [9, 27], [16, 64], [25, 125]]
[[0, 0], [1, 1], [4, 8], [9, 27], [16, 64], [25, 125]]
[[0, 0], [1, 1], [4, 8], [9, 27], [16, 64], [25, 125]]<jupyter_text>-  Además de eso, la función `map` se puede usar de manera más avanzada. Por ejemplo, dados múltiples argumentos de secuencia, envía elementos tomados de secuencias en paralelo como argumentos distintos a la función:**Ejemplo**<jupyter_code>p1 = pow(2,10)
p2 = pow(3,5)
p3 = pow(3,11)
p4 = pow(4,12)
print('Estos son los resultados de las potencias:',p1,p2,p3,p4)

# 1. Replicar lo anterior usando funciones map

numero = [2, 3, 3, 4]
potencias = [10, 5, 11, 12]

pot_map = 

print('Estos son los resultados usando map:',pot_map)

# 2. Ahora utilizar la función map para elever cada número a todas las potencias (2**10, 2**5,...,4**12)
# Mostrar todo en un DataFrame<jupyter_output>Estos son los resultados de las potencias: 1024 243 177147 16777216
Estos son los resultados usando map: [1024, 243, 177147, 16777216]<jupyter_text>Como programaría usando compresión de listas y funciones map, el caso cuando quiero evaluar de una lista de números dada, elevar cada número de dicha lista, a una lista de potencias dadas.  - Función filter()La función > `filter(función, secuencia)` ofrece una forma elegante de filtrar todos los elementos de una lista, para lo cual la función de `función` devuelve `True`. La función `filter(f, l)` necesita una función f como primer argumento. `f` devuelve un valor booleano, es decir, verdadero o falso. Esta función se aplicará a cada elemento de la lista `l`. Solo si `f` devuelve True, el elemento de la lista se incluirá en la lista de resultados.**Ejemplo**<jupyter_code># Explorar el funcionamiento del método módulo (%)
5%2
fib = [0,1,1,2,3,5,8,13,21,34,55]

# Selecciona los números impares de la lista
result = 
print('Numeros impares de la lista:',result)

# Selecciona los números pares de la lista
result = 
print('Numeros pares de la lista:',result)

# Replicar los mismo usando vectores<jupyter_output><empty_output><jupyter_text>- Función reduce()La función> `reduce(func, secuencia)`continuamente aplica la función `func()` a la `secuencia`. Devuelve un solo valor.Si `secuencia = [s1, s2, s3, ..., sn]`, la llamada de la función `reduce(func, secuencia)` funciona así:     - Al principio, los primeros dos elementos de secuencia se aplicarán a `func`, es decir, `func(s1, s2)`. La lista en la que se trabaja con reduce() se ve así: `[func (s1, s2), s3, ..., sn ] `   - En el siguiente paso, se aplicará func sobre el resultado anterior y el tercer elemento de la lista, es decir, `func (func (s1, s2), s3) `   - La lista se ve así ahora: `[func(func (s1, s2), s3), ..., sn] `   - Continuar así hasta que quede un solo elemento y devolver este elemento como resultado de reduce()![imagen.png](attachment:imagen.png)**Ejemplos**<jupyter_code>from functools import reduce
lista = [47,11,42,13]

# Realiza la suma de los elementos de una lista

# Determinar el máximo de una lista de valores numéricos 
f = 
print('El máximo valor de la lista es:',  )

# Calcular el producto de una lista 
print('El producto de la lista es:', )<jupyter_output>La suma de la lista es: 113
El máximo valor de la lista es: 102
El producto de la lista es: 12413915592536072670862289047373375038521486354677760000000000<jupyter_text>> Página donde pueden profundizar un poco más acerca de las funciones `map, filter, and reduce` [Enlace](http://www.bogotobogo.com/python/python_fncs_map_filter_reduce.php)  Colecciones de variables con alto rendimiento computacionalhttps://docs.python.org/3/library/collections.html  - Función `Counter()`Se proporciona una herramienta de contador para respaldar recuentos rápidos y convenientes. Por ejemplo:<jupyter_code>from collections import Counter

cnt = Counter()
colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']

Counter(colors)
# Find the ten most common words 
words = """
 In 1973, the Chicago Board of Options Exchange begun trading options in exchanges, although previously options 
 had been regularly traded by financial institutions in over the counter markets. In the same year, Black and 
 Scholes (1973), and Merton (1973), published their seminal papers on the theory of option pricing. Since then 
 the growth of the field of derivative securities has been phenomenal. In recognition of their pioneering and 
 fundamental contribution to option valuation, Scholes and Merton received in 1997 the Award of the Nobel Prize 
 in Economics. Unfortunately, Black was unable to receive the award since he had already passed away.

In essence, the Black-Scholes model states that by continuously adjusting the proportions of stocks and options 
in a portfolio, the investor can create a riskless hedge portfolio, where all market risks are eliminated. The 
ability to construct such a portfolio relies on the assumptions of continuous trading and continuous sample paths
of the asset price. In an efficient market with no riskless arbitrage opportunities, any portfolio with a zero 
market risk must have an expected rate of return equal to the risk-free interest rate. This approach led to the 
differential equation, known in physics as the "heat equation". Its solution is the Black-Scholes formula for 
pricing European options on non-dividend paying stocks 
"""
# método .most_common(10)
Counter(words.split()).most_common(10)
# words.split()<jupyter_output><empty_output><jupyter_text>- Función `deque()`Devuelve un nuevo objeto deque inicializado de izquierda a derecha (usando `append()`) con datos de iterable. Si no se especifica iterable, la nueva deque es vacía.Los deques son una generalización de pilas y colas (el nombre se pronuncia 'deck' y es la abreviatura de 'cola de dos extremos' ('double-ended queue')). Los Deques admiten 'memory efficient appends' , salto de elementos desde cualquier lado del deque con aproximadamente el mismo rendimiento $O(1)$ en cualquier dirección.Aunque los objetos de lista admiten operaciones similares, están optimizados para operaciones rápidas de longitud fija e incurren en costos de movimiento de memoria $O(n)$ para operaciones de inserción `pop(0)` e inserción `insert(0, v)` que cambian tanto el tamaño como la posición de la representación de datos subyacentes .Si no se especifica maxlen o es `None`, los deques pueden crecer hasta una longitud arbitraria. De lo contrario, la deque está limitada a la longitud máxima especificada. Una vez que se llena una etiqueta de longitud limitada, cuando se agregan nuevos elementos, se descarta el número correspondiente de elementos del extremo opuesto. Los deques de longitud limitada proporcionan una funcionalidad similar al filtro de cola en Unix. También son útiles para rastrear transacciones y otros grupos de datos donde solo la actividad más reciente es de interés.<jupyter_code>from collections import deque
d = deque('ghi')                 # make a new deque with three items
for elem in d:                   # iterate over the deque's elements
    print(elem.upper())
d.append('j')                    # add a new entry to the right side
d.appendleft('f')                # add a new entry to the left side
d     
# d.pop()                          # return and remove the rightmost item
d.popleft()                      # return and remove the leftmost item
list(d)  
list(reversed(d))                # list the contents of a deque in reverse
'h' in d                         # search the deque
d.extend('jkl')                  # add multiple elements at once
d
d.rotate(1)                      # right rotation
d
d.rotate(-1)                     # left rotation
d
deque(reversed(d))               # make a new deque in reverse order
d.clear()                        # empty the deque

d.extendleft('abc')              # extendleft() reverses the input order
d<jupyter_output><empty_output><jupyter_text>Comparación tiempo de simulación para grandes cantidades de datos Lo que se pretende en este apartado es mostrar la forma mas eficiente de realizar cálculos cuando se tiene gran cantidad de datos. Se comparán las técnicas tales como: ciclos for, paquete numpy, compresión de listas y la función map. Para efectos de simulación se desea comparar los tiempos necesarios para calular el valor del $log_{10}$ para un vector de tamaño $1\times 10^7$, que contiene valores aleatorios flotantes obtenidos mediante un distribución normal, para las cuatro técnicas mencionadas anteriormente.<jupyter_code># Número de muestras
import time
import math
N = 10**7
# Lista con valores aleatorios
l1 = np.random.normal(50,5,N)
speed = []

############ Usando ciclo for
t1 = time.time()
l2 = []
for item in l1:
    l2.append(math.log10(item))
t2 = time.time()
print("Con ciclos for y agregando los resutados toma {} segundos".format(t2-t1))
speed.append(t2-t1)
########### Usando numpy
t1 = time.time()
a2 = np.log10(l1)
t2 = time.time()
print("Usando la librería Numpy y el método log10 toma {} segundos".format(t2-t1))
speed.append(t2-t1)
########### Usando comprensión de listas
t1 = time.time()
cl = [math.log10(i) for i in l1]
t2 = time.time()
print("Usando compresión de listas toma {} segundos".format(t2-t1))
speed.append(t2-t1)
########### Usando map function 
t1 = time.time()
m1 = list(map(lambda x:math.log10(x),l1))
t2 = time.time()
print("Usando la función map para el método log10 toma {} segundos".format(t2-t1))
speed.append(t2-t1)
########### Usando deque function
t1 = time.time()
deq = deque(maxlen=N)
for item in l1:
    deq.append(math.log10(item))
t2 = time.time()

print("Usando deque function toma {} segundos".format(t2-t1))
speed.append(t2-t1)
########### Usando pandas
import pandas as pd
pandas = pd.Series(l1)

t1 = time.time()
pandas = pandas.apply(math.log10)
t2 = time.time()

print("Usando pandas toma {} segundos".format(t2-t1))
speed.append(t2-t1)
# pandas
ind = np.arange(1, 7)
plt.figure(figsize=[9,5])
plt.bar(ind,speed)
plt.xticks(ind,['Ciclo for', 'Numpy', 'Compresión de\n listas','Función map', 'Función deque', 'Pandas'])
plt.ylabel('Tiempo gastado ')
plt.show()<jupyter_output><empty_output><jupyter_text>Compresión de tuplas y Compresión de diccionarios<jupyter_code>diccionarios = {name:i for i, name in enumerate(['Carlos', 'Adriana', 'Pepito'])}
diccionarios

tuplas = (i for i in range(10))
print(*tuplas)

conjunto = {i for i in range(10)}
conjunto

set([1,1,2,3,5,4,4,8,5,6,7,5,44,5])<jupyter_output>0 1 2 3 4 5 6 7 8 9<jupyter_text>Tarea 2:1. Imagine una rutina contable utilizada en una librería. Funciona en una lista con sublistas, que se ven así:![imagen.png](attachment:imagen.png)Escriba un programa en Python, que devuelve una lista con tuplas de tamaño 2. Cada tupla consiste en el número de pedido y el costo total del pedido. El producto debe aumentarse en 10€ si el valor de la orden es inferior a 100,00 €. Escribe un programa Python usando unicamente las funciones **lambda y map**.`orders = [ ["34587", "Learning Python, <NAME>", 4, 40.95],            ["98762", "Programming Python, <NAME>", 5, 56.80],            ["77226", "Head First Python, <NAME>", 3,32.95],           ["88112", "Einführung in Python3, <NAME>", 3, 24.99]]`           2. La misma librería, pero esta vez trabajamos en una lista diferente. Las sublistas de nuestras listas se ven así: [número de orden, (número de artículo, cantidad, precio por unidad), ... (número de artículo, cantidad, precio por unidad)] `orders = [[1, ("5464", 4, 9.99), ("8274",18,12.99), ("9744", 9, 44.95)], 	       [2, ("5464", 9, 9.99), ("9744", 9, 44.95)],	       [3, ("5464", 9, 9.99), ("88112", 11, 24.99)],           [4, ("8732", 7, 11.99), ("7733",11,18.99), ("88112", 5, 39.95)] ]`Escriba un programa que devuelva una lista de dos tuplas que tengan la información de (número de pedido, cantidad total de pedido). Utilice la función `Reduce`. Recuerde el precio del pedido del producto debe aumentarse en 10€ si el valor de la orden es inferior a 100,00 €.3. Resolver los anteriores ejercicios usando pandas (DataFrame)<jupyter_code>########### Solución 1
orders = [ ["34587", "Learning Python, <NAME>", 4, 40.95], 
           ["98762", "Programming Python, <NAME>", 5, 56.80], 
           ["77226", "Head First Python, <NAME>", 3,32.95],
           ["88112", "Einführung in Python3, <NAME>", 3, 24.99]]

# El resultado debe ser como muestro en el resultado de esta celda
########### Solución 2
orders = [[1, ("5464", 4, 9.99), ("8274",18,12.99), ("9744", 9, 44.95)], 
          [2, ("5464", 9, 9.99), ("9744", 9, 44.95)],
          [3, ("5464", 9, 9.99), ("88112", 11, 24.99)],
          [4, ("8732", 7, 11.99), ("7733",11,18.99), ("88112", 5, 39.95)] ]


# Esta debe de ser su solución<jupyter_output><empty_output><jupyter_text>4. Use filter to eliminate all words that are shorter than 4 letters from a list of words`list='the notion of a lambda function goes all the way back to the origin of computer science'`<jupyter_code># Respuesta<jupyter_output><empty_output><jupyter_text>5. Use filter to determine the percentage of Fahrenheit temperatures in a list are within the range 32 to 80<jupyter_code>",########### Solución 4
import numpy as np
np.random.seed(55555)
temperatures = np.random.uniform(25,110,30)
print(temperatures)
# Respuesta<jupyter_output><empty_output><jupyter_text>6. Use reduce to find the lower left corner (minimum x and minimum y value) for a list of point locations> **Hint**: Explore the command `np.minimum.reduce` [link](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.reduce.html)<jupyter_code>########### Solución 5
np.random.seed(55555)
point_xy = np.random.randint(0,100,[30,2])
print(point_xy)
# Respuesta<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10970056575134539, 'fraction_numerical': 0.04808886435766524, 'mean_word_length': 4.524871355060034, 'pattern_counts': {'":': 0, '<': 94, '<?xml version=': 0, '>': 105, 'https://': 3, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '25', 'dir': 'jupyter-structured-clean-dedup', 'id': '108777', 'license': 'MIT', 'n_tokens_mistral': 10870, 'n_tokens_neox': 10047, 'n_words': 3781, 'path': 'TEMA-1/Clase4_OptmizacionProgramacion.ipynb', 'repo_name': 'Rub27182n/SPF-2021-I', 'size': '29018'}