Soluciones a los ejercicios propuestos

Nivel básico

1.

Haz un pequeño programa que le pida al usuario introducir dos números ($x_1$ y $x_2$), calcule la siguiente operación y muestre el resultado de la misma ($x$):

$$ x = \frac{20 * x_1 - x_2}{x_2 + 3} $$

Si intentas operar con el resultado de la función input obtendrás un error que te informa que no se pueden restar dos datos de tipo str. Usa la función int para convertir los datos introducidos por teclado a datos numéricos.


In [1]:
x1 = int(input("Introduce un número: "))
x2 = int(input("Y ahora otro: "))
x = (20 * x1 - x2)/(x2 + 3)

print("x =",x)


Introduce un número: 5
Y ahora otro: 5
x = 11.875

2.

Haz un programa que le pida al usuario un número (de ninjas). Si dicho número es menor que 50 y es par, el programa imprimirá "puedo con ellos!", en caso contrario imprimirá "no me vendría mal una ayudita..."

Nota: para saber si un número es par o no debes usar el operador $\%$ y para saber si dos condiciones se cuplen a la vez, el operador lógico and


In [2]:
num = int(input("Introduce número de ninjas: "))
if num < 50 and num%2==0:
    print("Puedo con ellos!")
else:
    print("No me vendría mal una ayudita...")


Introduce número de ninjas: 5
No me vendría mal una ayudita...

3.

Haz un bucle while que imprima todos los números desde el 0 hasta un número que introduzca el usuario. Si el número que introduce es negativo puedes tomar dos decisiones: pedirle que introduzca un número positivo o contar hacia atrás, tú eliges!


In [3]:
num = int(input("Intoduce un número: "))

# Opción 1: si el usuario introduce un número negativo pedir otro número
while num < 0:
    num = int(input("Introduce un número: "))

i = 0
while i <= num:
    print(i)
    i += 1


Intoduce un número: -1
Introduce un número: 5
0
1
2
3
4
5

In [4]:
num = int(input("Intoduce un número: "))

# Opción 2: si el usuario introduce un número negativo, contar hacia atrás
sign = lambda x: (1, -1)[x < 0]

i = 0
s = sign(num)
while i*s <= num*s:
    print(i)
    i += s


Intoduce un número: 5
0
1
2
3
4
5

4.

Genera con range los números pares del 0 al 10, ambos inclusive. ¿Qué cambiarías para generar del 2 al 10?


In [5]:
# Para generar del 0 al 10 ambos inclusive:
for i in range(0,11):
    print(i)


0
1
2
3
4
5
6
7
8
9
10

In [6]:
# Para generar del 2 al 10 sólo con números pares
for i in range(2, 11, 2):
    print(i)


2
4
6
8
10

5.

¿Cuál es la diferencia entre la sentencia break y la sentencia continue?

Cuando en un bucle se lee una instrucción break o una instrucción continue, se interumpe la iteración actual. Ahora bien, en el caso de break, se abandona el bucle y en el caso de continue se pasa a la siguiente iteración. Por ejemplo, el siguiente bucle imprime si un número es par o impar:


In [7]:
for num in range(2,10):
    if num % 2 == 0:
        print(num, "es par!")
        continue
    print(num, "es impar!")


2 es par!
3 es impar!
4 es par!
5 es impar!
6 es par!
7 es impar!
8 es par!
9 es impar!

6.

Haz una lista de la compra e imprime los siguientes elementos:

  • Penúltimo elemento
  • Del segundo al cuarto elemento
  • Los tres últimos
  • Todos!

Por último, elimina el tercer elemento de la lista usando la sentencia del


In [8]:
lista_compra = ['Leche', 'Chocolate', 'Arroz', 'Macarrones']

print("Penúltimo elemento: ", lista_compra[-2])
print("Del segundo al cuarto elemento: ", lista_compra[1:5])
print("Los tres últimos elementos: ", lista_compra[-3:])
print("Todos: ", lista_compra)

del lista_compra[2]
print(lista_compra)


Penúltimo elemento:  Arroz
Del segundo al cuarto elemento:  ['Chocolate', 'Arroz', 'Macarrones']
Los tres últimos elementos:  ['Chocolate', 'Arroz', 'Macarrones']
Todos:  ['Leche', 'Chocolate', 'Arroz', 'Macarrones']
['Leche', 'Chocolate', 'Macarrones']

7.

Crea una lista con todos los números pares del 0 al 10 en una única línea.


In [9]:
# solución 1:
[x for x in range(10) if x%2==0]


Out[9]:
[0, 2, 4, 6, 8]

In [10]:
# solución 2:
list(range(0,10,2))


Out[10]:
[0, 2, 4, 6, 8]

8.

Crea la siguiente matriz en una línea:

$$ M_{2 \times 3} = \left( \begin{matrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{matrix} \right)$$

In [11]:
[[j for j in range(i*i, i*i+3)] for i in range(1,3)]


Out[11]:
[[1, 2, 3], [4, 5, 6]]

9.

Vuelve a hacer la lista de la compra que hiciste en el último ejercicio, pero esta vez guarda cada elemento de la lista de la compra junto con su precio. Después, imprime los siguientes elementos:

  • El precio del tercer elemento.
  • El nombre del último elemento.
  • Tanto el nombre como el precio del primer elemento.

In [12]:
tuplas_compra = [('Leche', 2), ('Chocolate', 1), ('Arroz', 1.5), 
                 ('Macarrones', 2.1)]
print("Precio del tercer elemento: ", tuplas_compra[2][1])
print("Nombre del último elemento: ", tuplas_compra[-1][0])
print("Nombre y precio del primer elemento", tuplas_compra[0])


Precio del tercer elemento:  1.5
Nombre del último elemento:  Macarrones
Nombre y precio del primer elemento ('Leche', 2)

10.

¿Es buena idea usar la función set para eliminar los elementos repetidos de una lista?

Al usar la función set para eliminar los elementos repetidos de una lista perdemos el orden original de nuestra lista. Además, no funcionará si nuestra lista es de diccionarios o de listas, debido a que no son objetos hashables.

11.

Usando la tupla que creaste en el ejercicio sobre tuplas, crea un diccionario de tu lista de la compra. Una vez tengas el diccionario creado:

  • Imprime todos los elementos que vayas a comprar creando la siguiente frase con la función format: "he comprado __ y me ha costado __".
  • Consulta si has añadido un determinado elemento (por ejemplo un cartón de leche) a la lista de la compra
  • Elimina un elemento usando la función del

In [13]:
dict_compra = dict(tuplas_compra)

for compra in dict_compra.items():
    print("he comprado {} y me ha costado {}".format(compra[0], compra[1]))

print('He comprado leche?', 'Leche' in dict_compra)

del dict_compra['Arroz']
print(dict_compra)


he comprado Leche y me ha costado 2
he comprado Chocolate y me ha costado 1
he comprado Arroz y me ha costado 1.5
he comprado Macarrones y me ha costado 2.1
He comprado leche? True
{'Leche': 2, 'Chocolate': 1, 'Macarrones': 2.1}

Nivel medio

1.

Ahora que hemos visto cómo crear arrays a partir de un objeto y otros para crear arrays con tipos prefijados, crea distintos arrays con las funciones anteriores para 1D, 2D y 3D e imprímelas por pantalla. Prueba a usar distintos tipos para ver cómo cambian los arrays. Si tienes dudas sobre cómo usarlos, puedes consultar la documentación oficial.


In [14]:
import numpy as np

print(np.ones(5, dtype=np.int8))

print(np.random.random(5))

print(np.full(shape=(3,3), fill_value=4, dtype=np.int8))

print(np.arange(6))

print(np.linspace(start=1, stop=6, num=10))

print(np.eye(N=2))

print(np.identity(n=3, dtype=np.int8))


[1 1 1 1 1]
[ 0.72350908  0.19701379  0.35142354  0.69975202  0.62963783]
[[4 4 4]
 [4 4 4]
 [4 4 4]]
[0 1 2 3 4 5]
[ 1.          1.55555556  2.11111111  2.66666667  3.22222222  3.77777778
  4.33333333  4.88888889  5.44444444  6.        ]
[[ 1.  0.]
 [ 0.  1.]]
[[1 0 0]
 [0 1 0]
 [0 0 1]]

2.

Gracias a las distintas formas de indexar un array que nos permite NumPy, podemos hacer operaciones de forma vectorizada, evitando los bucles. Esto supone un incremento en la eficiencia del código y tener un código más corto y legible. Para ello, vamos a realizar el siguiente ejercicio.

Genera una matriz aleatoria cuadrada de tamaño 1000. Una vez creada, genera una nueva matriz donde las filas y columnas 0 y $n-1$ estén repetidas 500 veces y el centro de la matriz quede exactamente igual a la original. Un ejemplo de esto lo podemos ver a continuación:

$$ \left( \begin{matrix} 1 & 2 & 3 \\ 2 & 3 & 4 \\ 3 & 4 & 5 \end{matrix} \right) \Longrightarrow \left( \begin{matrix} 1 & 1 & 1 & 2 & 3 & 3 & 3 \\ 1 & 1 & 1 & 2 & 3 & 3 & 3 \\ 1 & 1 & 1 & 2 & 3 & 3 & 3 \\ 2 & 2 & 2 & 3 & 4 & 4 & 4 \\ 3 & 3 & 3 & 4 & 5 & 5 & 5 \\ 3 & 3 & 3 & 4 & 5 & 5 & 5 \\ 3 & 3 & 3 & 4 & 5 & 5 & 5 \end{matrix} \right) $$

Impleméntalo usando un bucle for y vectorizando el cálculo usando lo anteriormente visto para ver la diferencias de tiempos usando ambas variantes. Para medir el tiempo, puedes usar el módulo time.


In [15]:
from time import time

def clona_cols_rows(size=1000, clone=500, print_matrix=False,
                   create_random=True):
    if create_random:
        m = np.random.random((size,size))
    else:
        m = np.arange(size*size).reshape(size,size)
    
    n = np.zeros((size+clone*2, size+clone*2))
    
    antes = time()
    # en primer lugar, copiamos m en el centro de n
    for i in range(size):
        for j in range(size):
            n[i+clone, j+clone] = m[i,j]
    # después, copiamos la primera fila/columna en las 
    # primeras clone filas/columnas
    for i in range(clone):
        n[i,clone:clone+size] = m[0]
        n[clone:clone+size, i] = m[:,0]
    # una vez copiada la primera fila/columna, pasamos a 
    # copiar la última/columna
    for i in range(clone+size, size+clone*2):
        n[i, clone:clone+size] = m[-1]
        n[clone:clone+size, i] = m[:,-1]
    # por último, copiamos los valores de los extremos en las esquinas
    for i in range(clone):
        n[i, :clone] = np.full(clone, m[0,0])
        n[i, size+clone:] = np.full(clone, m[0,-1])
        n[i+size+clone, :clone] = np.full(clone, m[-1,0])
        n[i+size+clone, size+clone:] = np.full(clone, m[-1,-1])
    despues = time()
    
    if print_matrix:
        print(m)
        print(n)
    return despues-antes

clona_cols_rows(size=3, clone=2, print_matrix=True, create_random=False)

print("Tiempo con bucle for: ", clona_cols_rows(), " s")


[[0 1 2]
 [3 4 5]
 [6 7 8]]
[[ 0.  0.  0.  1.  2.  2.  2.]
 [ 0.  0.  0.  1.  2.  2.  2.]
 [ 0.  0.  0.  1.  2.  2.  2.]
 [ 3.  3.  3.  4.  5.  5.  5.]
 [ 6.  6.  6.  7.  8.  8.  8.]
 [ 6.  6.  6.  7.  8.  8.  8.]
 [ 6.  6.  6.  7.  8.  8.  8.]]
Tiempo con bucle for:  0.4089171886444092  s

In [16]:
def clona_vec_cols_rows(size=1000, clone=500, print_matrix=False,
                       create_random=True):
    if create_random:
        m = np.random.random((size,size))
    else:
        m = np.arange(size*size).reshape(size,size)
        
    n = np.zeros((size+clone*2, size+clone*2))
    
    antes=time()
    # en primer lugar, insertamos m en el centro de n
    n[clone:clone+size, clone:clone+size] = m
    # Copiamos la primera fila de m, en las primeras filas
    # de n, y la última fila de m en las últimas filas de n
    n[:clone, clone:clone+size] = m[0]
    n[size+clone:, clone:size+clone] = m[-1]
    # Lo mismo para las columnas
    n[:, :clone] = np.repeat(n[:,clone],clone).reshape(2*clone+size, clone)
    n[:, size+clone:] = np.repeat(n[:,-(clone+1)],clone).reshape(2*clone+size, clone)

    despues=time()
    
    if print_matrix:
        print(m)
        print(n)
    return despues-antes

clona_vec_cols_rows(size=3, clone=2, print_matrix=True, create_random=False)

print("Tiempo vectorizando: ", clona_vec_cols_rows(), " s")


[[0 1 2]
 [3 4 5]
 [6 7 8]]
[[ 0.  0.  0.  1.  2.  2.  2.]
 [ 0.  0.  0.  1.  2.  2.  2.]
 [ 0.  0.  0.  1.  2.  2.  2.]
 [ 3.  3.  3.  4.  5.  5.  5.]
 [ 6.  6.  6.  7.  8.  8.  8.]
 [ 6.  6.  6.  7.  8.  8.  8.]
 [ 6.  6.  6.  7.  8.  8.  8.]]
Tiempo vectorizando:  0.019988536834716797  s

3.

Una matriz de rotación $R$ es una matriz que representa una rotación en el espacio euclídeo. Esta matriz $R$ se representa como

$$ R = \left( \begin{matrix} \cos\theta & -\sin\theta \\ \sin\theta & -\cos\theta \end{matrix} \right) $$

donde $\theta$ es el número de ángulos rotados en sentido antihorario.

Estas matrices son muy usadas en geometría, informática o física. Un ejemplo de uso de estas matrices puede ser el cálculo de una rotación de un objeto en un sistema gráfico, la rotación de una cámara respecto a un punto en el espacio, etc.

Estas matrices tienen como propiedades que son matrices ortogonales (su inversa y su traspuesta son iguales) y su determinante es igual a 1. Por tanto, genera un array y muestra si ese array es una matriz de rotación.


In [17]:
R = np.random.random((2,2))

if (R.T == np.linalg.inv(R)).all() and np.linalg.det(R) == 1:
    print("Matriz de rotación!")
else:
    print("No es matriz de rotación u_u")


No es matriz de rotación u_u

4.

Dados el array que se ve a continuación, realiza los siguientes apartados:


In [18]:
array1 = np.array([ -1., 4., -9.])
  • Multiplica array1 por $\frac{\pi}{4}$ y calcula el seno del array resultante.

  • Genera un nuevo array cuyo valor sea el doble del resultado anterior mas el vector array1.

  • Calcula la norma del vector resultante. Para ello, consulta la documentación para ver qué función realiza esta tarea, y ten en cuenta los parámetros que recibe.


In [19]:
array2 = np.sin(array1 * np.pi/4)
array2


Out[19]:
array([ -7.07106781e-01,   1.22464680e-16,  -7.07106781e-01])

In [20]:
array3 = array2 * 2 + array1
array3


Out[20]:
array([ -2.41421356,   4.        , -10.41421356])

In [21]:
np.linalg.norm(array3)


Out[21]:
11.414213562373094

5.

Dada la siguiente matriz, realiza los siguientes apartados:


In [22]:
n_array1 =  np.array([[ 1., 3., 5.], [7., -9., 2.], [4., 6., 8.]])
  • Calcula la media y la desviación típica de la matriz.
  • Obtén el elemento mínimo y máximo de la matriz.
  • Calcula el determinante, la traza y la traspuesta de la matriz.
  • Calcula la descomposición en valores singulares de la matriz.
  • Calcula el valor de la suma de los elementos de la diagonal principal de la matriz.

In [23]:
media = np.mean(n_array1)
desv_tipica = np.std(n_array1)

print("Media =", media, " y desv típica =", desv_tipica)


Media = 3.0  y desv típica = 4.7609522857

In [24]:
maximo = np.max(n_array1)
minimo = np.min(n_array1)

print("Máximo =", maximo, " y minimo =", minimo)


Máximo = 8.0  y minimo = -9.0

In [25]:
det = np.linalg.det(n_array1)
traza = np.trace(n_array1)
traspuesta = n_array1.T

In [27]:
U, S, V = np.linalg.svd(n_array1)
print(U)
print(S)
print(V)


[[ 0.42294221  0.21462031 -0.88037379]
 [-0.50235772  0.86411535 -0.03068195]
 [ 0.75415953  0.45523926  0.47328703]]
[ 12.54717278  11.23601489   1.14909737]
[[-0.00613076  0.82209782  0.56931326]
 [ 0.71950642 -0.39175292  0.57344587]
 [ 0.69445873  0.41314021 -0.58910291]]

In [30]:
result = np.diag(array1).sum()
print("Resultado: ", result)


Resultado:  -6.0

6.

A veces, es necesario en nuestro problema, tener que eliminar los elementos repetidos de una lista, dejando aquellos que solo aparezcan una sola vez. Es muy común, que muchos usuarios llamen a la función set para esta tarea, haciendo de la lista un conjunto sin elementos repetidos, ordenándolos y luego, el resultado de esto, volverlo a convertir en una lista. Esto, puede no estar mal del todo, pero puede ser que en el caso peor, puede que estemos haciendo un gasto inútil de memoria, tiempo y cálculos, para que, en el caso de que no haya elementos repetidos, sólo obtengamos una lista ordenada.

Es por ello, por lo que existe otra forma de hacerlo. Utilizando lo ya visto, obtén una lista sin elementos repetidos que mantengan el orden de la lista original. Para hacerlo aún más divertido, no uses más de 4 líneas.


In [35]:
a = [1,1,1,2,5,3,4,8,5,8]
b = []
list(filter(lambda x: b.append(x) if not x in b else False, a))
print("Lista original:\t\t", a)
print("Lista sin repetidos:\t", b)


Lista original:		 [1, 1, 1, 2, 5, 3, 4, 8, 5, 8]
Lista sin repetidos:	 [1, 2, 5, 3, 4, 8]