<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Tarea 1
Step1:  Operaciones con arrays
$$
X + 2B = \begin{bmatrix} 3 & 6 & 9 \ 12 & 15 & 18 \end{bmatrix}
$$
Step2:  Multiplicación de matrices con numpy.matmul()
$$
X^t \times  X = \begin{bmatrix} 17 & 22 & 27 \ 22 & 29 & 36 \ 27 & 36 & 45 \end{bmatrix}
$$
Step3:  Obteniendo datos específicos
Step4:  Selección y multi selección de elementos...
$$
X = \begin{bmatrix} 1 & 2 & 3 \ 4 & 5 & 6  \end{bmatrix}
$$
Step5:  Vectores
Numpy es vector-ready
Step6:  Creando clases en Python
Creando clases en Python from scratch
Step7:  ... implementando métodos que faciliten la utilización de dicha clase para nuestros fines de Álgegra Lineal
Métodos especiales de clase
1. Método de Pretty Print
He aquí el método para imprimir bonito, primero mostramos como se imprime por default sin existir el método
Step8:  <span style="color
Step9:  Prueba de validador
Step10:  Prueba con vectores
Step11:  Index & Item Assignment
Step12:  <span style="color
Step13:  Inicialización de una matriz en ceros con numpy
Step14:  <span style="color
Step15:  Transposición
Step16:  <span style="color
Step17:  Suma
Step18:  <span style = "color
Step19:  <span style = "color
<ASSISTANT_TASK:>
Python Code:
import numpy as np
X = np.array([[1, 2, 3], [4, 5, 6]])
X
Explanation: Tarea 1: alumno Jorge III Altamirano Astorga
Introducción
Presento la siguiente tarea para la materia de Propedéutico de la Maestría en Ciencia de Datos del Instituto Tecnológico Autónomo de México. Le agradezco al Maestro Mauricio García Tec por su comprensión y por compartir conocimiento nuevo para mí.
Importación e inicialización de arrays
import numpy as np
x = [1, 2, 3]
y = [4, 5, 6]
x + y
Matrices como arrays
Presentación de matrices
Matríz con numpy:
[[1,2,3],[4,5,6]]
Corresponde a la matriz
$$
X = \begin{bmatrix} 1 & 2 & 3 \ 4 & 5 & 6  \end{bmatrix}
$$
End of explanation
X + 2*X
Explanation: Operaciones con arrays
$$
X + 2B = \begin{bmatrix} 3 & 6 & 9 \ 12 & 15 & 18 \end{bmatrix}
$$
End of explanation
np.matmul(X.transpose(), X) #X^t * X
Explanation: Multiplicación de matrices con numpy.matmul()
$$
X^t \times  X = \begin{bmatrix} 17 & 22 & 27 \ 22 & 29 & 36 \ 27 & 36 & 45 \end{bmatrix}
$$
End of explanation
X[1,1]
Explanation: Obteniendo datos específicos
End of explanation
X[1, :] #1. Fila entera
X[:, 1] #2. Columna entera
X[0:2, 0:2] #3. Slice de n:m, n,n+1,...,m-1
X.shape #Dimensión de arrays
Explanation: Selección y multi selección de elementos...
$$
X = \begin{bmatrix} 1 & 2 & 3 \ 4 & 5 & 6  \end{bmatrix}
$$
End of explanation
vec = np.array([1, 2, 3])
print(vec)
Explanation: Vectores
Numpy es vector-ready
End of explanation
class Array:
    "Clase mínima para Álgebra Lineal"
    def __init__(self, list_of_rows):
        "Constructor"
        self.data = list_of_rows
        self.shape = (len(list_of_rows), len(list_of_rows[0]))
A = Array([[1, 2, 3], [4, 5, 6]])
A.__dict__ # la propiedad oculta *dict* muestra las propiedades internas de la clase
A.data #accediendo a la propiedad *data* de la clase
A.shape #accediendo a la propiedad *shape* de la clase
Explanation: Creando clases en Python
Creando clases en Python from scratch
End of explanation
Array([[1,2,3], [4,5,6]])
print(Array([[1,2,3], [4,5,6]]))
# Prueba de clase
class JorgeClass:
    def __init__(self):
        pass # para no hacer nada
    def say_hi(self):
        print("¡Método de impresión simple!")
    def __repr__(self):
        return "Representación sin imprimir nada"
    def __str__(self):
        return "Método explícito para *print* como objeto"
x = JorgeClass()
x.say_hi()
x
print(x)
Explanation: ... implementando métodos que faciliten la utilización de dicha clase para nuestros fines de Álgegra Lineal
Métodos especiales de clase
1. Método de Pretty Print
He aquí el método para imprimir bonito, primero mostramos como se imprime por default sin existir el método
End of explanation
import re
class Array:
    "Clase mínima para Álgebra Lineal"
    data = list()
    def __init__(self, list_of_rows):
        "Constructor"
        self.data = list_of_rows
        nrow = len(list_of_rows)
        #  ___caso vector: redimensionar correctamente
        if not isinstance(list_of_rows[0], list):
            nrow = 1
            self.data = [[x] for x in list_of_rows]
        # ahora las columnas deben estar bien aunque sea un vector
        ncol = len(self.data[0])
        self.shape = (nrow, ncol)
        # validar tamano correcto de filas
        if any([len(r) != ncol for r in self.data]):
            raise Exception("Ejercicio 1: Las filas deben ser del mismo tamano. ¡Validador funcionando!")
    def say_hi(self):
        print("Ejercicio 1: say_hi() method")
    def __repr__(self):
        retval = "["
        for list in self.data:
            retval += "["
            for x in list:
                retval += str(x) + ", "
            retval += "], "
        retval = retval + "]"
        return retval.replace(", ]", "]")
    def __str__(self):
        return self.__repr__()
        #return "Ejercicio 1: print"
    def __getitem__(self, index):
        return(self.data[index[0]][index[1]])
    def __setitem__(self, index, newval):
        self.data[index[0]][index[1]] = newval
        return
Explanation: <span style="color: red"> EJERCICIO 1 </span>
Validador
End of explanation
Array([[1,2,3],[4,5]])
Explanation: Prueba de validador
End of explanation
vec = Array([1,2,3])
vec.data
Explanation: Prueba con vectores
End of explanation
X = Array([[1,2],[3,4]])
X[1,0]
Explanation: Index & Item Assignment
End of explanation
X[0,0] = 0
X[0,0]
X
Explanation: <span style="color: red"> EJERCICIO 2</span>
Método setter
End of explanation
np.zeros((3,6))
Explanation: Inicialización de una matriz en ceros con numpy
End of explanation
import re
import numpy as np
class zeros:
    "Clase para llenar una matriz en Ceros"
    data = list()
    shape = None
    def __init__(self, shape):
        "Constructor"
        self.data = list()
        print(shape)
        for i in range(0, shape[1]):
            self.data.append(list())
            for j in range(0, shape[0]):
                self.data[i].append(list())
                self.data[i][j] = 0.
                #self.data[i].append(list())
            #    self.data[i][j] = 0
        self.shape = shape
        #self.data = np.zeros(shape)
    def eye(self):
        if self.shape[0] != self.shape[1]:
            raise Exception("Ejercicio 3: las columnas y las filas deben ser de igual número n = m")
        for i in range(0,self.shape[1]):
            for j in range(0, self.shape[0]):
                if(i == j):
                    self.data[i][j] = 1.0
    def __repr__(self):
        retval = "[\n"
        for list in self.data:
            retval += "["
            for x in list:
                retval += str(x) + ", "
            retval += "], \n"
        retval = retval + "]"
        return retval.replace(", ]", "]")
    def __str__(self):
        return self.__repr__()
        #return "Ejercicio 1: print"
    def __getitem__(self, index):
        return(self.data[index[0]][index[1]])
    def __setitem__(self, index, newval):
        self.data[index[0]][index[1]] = newval
        return
X = zeros([3,4])
X
X.eye()
X
X = zeros((4, 4))
X.eye()
X
Explanation: <span style="color: red"> EJERCICIO 3 </span>
Función para crear arrays "vacíos" (en ceros)
End of explanation
np.array([[1,2,3],[4,5,6],[7,8,9]]).transpose()
Explanation: Transposición
End of explanation
import re
class transpose:
    "Clase para llenar una matriz en Ceros"
    data = list()
    shape = None
    def __init__(self, list_of_rows):
        "Constructor"
        # obtener dimensiones
        self.data = list_of_rows
        nrow = len(list_of_rows)
        #  ___caso vector: redimensionar correctamente
        if not isinstance(list_of_rows[0], list):
            nrow = 1
            self.data = [[x] for x in list_of_rows]
        # ahora las columnas deben estar bien aunque sea un vector
        ncol = len(self.data[0])
        self.shape = (nrow, ncol)
        # validar tamano correcto de filas
        if any([len(r) != ncol for r in self.data]):
            raise Exception("Las filas deben ser del mismo tamano")
    def transpose(self):
        transposed = list()
        for i in range(0, len(self.data[1])):
            transposed.append(list())
            for j in range(0, len(self.data[0])):
                transposed[i].append(list())
                transposed[i][j] = self.data[j][i]                
        print(transposed)
    def eye(self):
        if self.shape[0] != self.shape[1]:
            raise Exception("Ejercicio 3: las columnas y las filas deben ser de igual número n = m")
        for i in range(0,self.shape[1]):
            for j in range(0, self.shape[0]):
                if(i == j):
                    self.data[i][j] = 1.0
    def __repr__(self):
        retval = "[\n"
        for list in self.data:
            retval += "["
            for x in list:
                retval += str(x) + ", "
            retval += "], \n"
        retval = retval + "]"
        return retval.replace(", ]", "]")
    def __str__(self):
        return self.__repr__()
        #return "Ejercicio 1: print"
    def __getitem__(self, index):
        return(self.data[index[0]][index[1]])
    def __setitem__(self, index, newval):
        self.data[index[0]][index[1]] = newval
        return
    def __add__(self, other):
        "Hora de sumar"
        if isinstance(other, transpose):
            if self.shape != other.shape:
                raise Exception("Las dimensiones son distintas!")
            rows, cols = self.shape
            suma = transpose([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    suma.data[r][c] = self.data[r][c] + other.data[r][c]
            return suma
        elif isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos
    def __mul__(self, other):
        "Método de multiplicación"
        if isinstance(other, transpose):
            if self.shape[1] != other.shape[0]:
                raise Exception("Las dimensiones son distintas!")
            rows, cols = self.shape
            suma = transpose([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    suma.data[r][c] = self.data[r][c] + other.data[r][c]
            return suma
        elif isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos
X = transpose([[1,2,3],[4,5,6],[7,8,9]])
X.transpose()
Explanation: <span style="color: red"> EJERCICIO 4 </span>
Función para transponer arrays
End of explanation
np.array([[1,2,3],[4,5,6],[7,8,9]]) + np.array([[10,11,12],[13,14,15],[16,17,18]])
Y = transpose([[10,11,12],[13,14,15],[16,17,18]])
X + Y
Z = X + 10
Z
Z.data
transpose([[1,1],[1,1]]) + transpose([[2,2],[2,2]])
import re
class transpose:
    "Clase para llenar una matriz en Ceros"
    data = list()
    shape = None
    def __init__(self, list_of_rows):
        "Constructor"
        # obtener dimensiones
        self.data = list_of_rows
        nrow = len(list_of_rows)
        #  ___caso vector: redimensionar correctamente
        if not isinstance(list_of_rows[0], list):
            nrow = 1
            self.data = [[x] for x in list_of_rows]
        # ahora las columnas deben estar bien aunque sea un vector
        ncol = len(self.data[0])
        self.shape = (nrow, ncol)
        # validar tamano correcto de filas
        if any([len(r) != ncol for r in self.data]):
            raise Exception("Las filas deben ser del mismo tamano")
    def transpose(self):
        transposed = list()
        for i in range(0, len(self.data[1])):
            transposed.append(list())
            for j in range(0, len(self.data[0])):
                transposed[i].append(list())
                transposed[i][j] = self.data[j][i]                
        print(transposed)
    def eye(self):
        if self.shape[0] != self.shape[1]:
            raise Exception("Ejercicio 3: las columnas y las filas deben ser de igual número n = m")
        for i in range(0,self.shape[1]):
            for j in range(0, self.shape[0]):
                if(i == j):
                    self.data[i][j] = 1.0
    def __repr__(self):
        retval = "[\n"
        for list in self.data:
            retval += "["
            for x in list:
                retval += str(x) + ", "
            retval += "], \n"
        retval = retval + "]"
        return retval.replace(", ]", "]")
    def __str__(self):
        return self.__repr__()
        #return "Ejercicio 1: print"
    def __getitem__(self, index):
        return(self.data[index[0]][index[1]])
    def __setitem__(self, index, newval):
        self.data[index[0]][index[1]] = newval
        return
    def __add__(self, other):
        "Hora de sumar"
        if isinstance(other, transpose):
            if self.shape != other.shape:
                raise Exception("Las dimensiones son distintas!")
            rows, cols = self.shape
            suma = transpose([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    suma.data[r][c] = self.data[r][c] + other.data[r][c]
            return suma
        elif isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos
    def __rmul__(self, other):
        "Multiplicación escalar"
        if isinstance(2, (int, float, complex)): # en caso de que el lado derecho sea solo un numero
            rows, cols = self.shape
            newArray = transpose([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] * other
            return newArray
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos
    def __mul__(self, other):
        "Multiplicación vectorial"
        if isinstance(other, transpose):
            if self.shape[1] != other.shape[0] or self.shape[0] != other.shape[1]:
                raise Exception("Las dimensiones son distintas!")
            rows, cols = self.shape[0], other.shape[1]
            rowsL, colsL = other.shape[0], self.shape[1]
            retval = transpose([[0. for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    print("R(" + str(r) + ", " + str(c) + ") = ", end=" ")
                    for i in range(colsL):
                        #for j in range(rowsL):
                        print("A("+str(c) + "," + str(i) + ") * B(" + str(r) + "," + str(c)+")",end=" + ")
                    print("")
                            #retval.data[r][c] += self.data[i][j] * other.data[i][j]
                    #print(str(r) + ", " + str(c) + " = ")
            return retval
        else:
            return NotImplemented # es un tipo de error particular usado en estos metodos
transpose([[1,1,1],[1,1,1]])  * transpose([[2,2],[2,2],[2,2]])
np.matmul(np.array([[1,1,1],[1,1,1]]), np.array([[2,2,2],[2,2,2],[2,2,2]]))
Explanation: Suma
End of explanation
class Vector(transpose): 
    "clase de Vectores Array"
    def __init__(self, list_of_numbers):
        self.vdata = list_of_numbers
        list_of_rows = [[x] for x in list_of_numbers]
        return transpose.__init__(self, list_of_rows)
    def __repr__(self):
        return "Vector(" + str(self.vdata) + ")"
    def __str__(self):
        return str(self.vdata)
    def __add__(self, other):
        if type(other) is Vector:
            new_arr = transpose.__add__(self, other)
        else:
            "Suma escalar"
            rows, cols = self.shape
            new_arr = transpose([0 for r in range(rows)])
            for r in range(rows):
                new_arr.data[r][0] = self.data[r][0] + 10
            print(new_arr.__dict__)
        return Vector([x[0] for x in new_arr.data])
Vector([1,2,3]).__dict__
Vector([1,2,3])
Vector([1,2,3]) + Vector([4,5,6])
Explanation: <span style = "color: red"> EJERCICIO 5:</span> Vectores
End of explanation
Vector([1,2,3]) + 10
Explanation: <span style = "color: red"> EJERCICIO 6</span>
End of explanation
<END_TASK>