Ciencia de datos, Python

Fundamentos de Machine Learning: Resolución de problemas


Introducción

En Ingdustrial Pro Academy queremos entregarte herramientas que permitan aumentar tu desarrollo académico y profesional en el área de los datos, por eso, hemos creado este blog que junto a un canal en YouTube, más el material y cursos disponibles en esta plataforma, podrás complementar tu aprendizaje. A continuación, nos embarcaremos en la resolución de problemas de Machine Learning, haremos un repaso de los fundamentos como cálculo deferencial, integral, álgebra lineal, probabilidad y estadística, porque no solo es importante saber implementar usando las librerías existentes en Python, para un científico de datos es fundamental conocer el trasfondo matemático, nuestra intención al impartir esta serie, es presentar las técnicas matemáticas y estadísticas básicas necesarias para comprender algunos de los algoritmos de Machine Learning más populares como: regresión, clasificación, agrupamiento, proyección, etc. Al final, tendrás el conocimiento y la confianza para poder explorar la literatura sobre Machine Learning, para buscar y entender métodos mas sofisticados que se adapten mejor a tus necesidades.

Background

1. Matemáticas y métodos estadísticas

Esta parte abarcará cálculo deferencial, integral, álgebra lineal, probabilidad y estadística en una y varias variables, como mencionamos anteriormente, es imposible cubrir en pocas líneas siquiera un tema de dichas disciplinas, pero haremos nuestro mejor esfuerzo exponiendo los principales teoremas y propiedades que debemos dominar para entender los problemas que resolveremos, la forma en como haremos esto será, presentando problemas donde se pueda aplicar toda la maquinaria matemática y métodos necesarios.

1.1 Escalares, Vectores y Matrices

Los escalares son letras minúsculas \(x, y, z, α, β\) γ o letras latinas mayúsculas \(N, M, T\). Estas últimas se utilizan normalmente para indicar un recuento (número de ejemplos, características, intervalos de tiempo) y suelen ir acompañadas de un índice correspondiente \(n, m, t\) (ejemplo actual, característica, intervalo de tiempo). Los vectores son letras minúsculas en negrita \(\mathbf{x} = [x_1, x_2,…, x_M]^{T}\) y normalmente se supone que son vectores columna. Cuando se escribe a mano, un vector se indica con una flecha superpuesta \(\overrightarrow{x}= [x_1, x_2,…, x_M]^{T}\). Las matrices son letras mayúsculas en negrita:
$$\mathbf{U}=\begin{pmatrix}
U_{11} & U_{12} & \cdots & U_{1m} \\
U_{21} & U_{22} & \cdots & U_{2m} \\
\vdots & \vdots & \ddots & \vdots \\
U_{n1} & U_{n2} & \cdots & U_{nm}
\end{pmatrix}
$$
Como en el ejemplo anterior, los subíndices se utilizan como índices en objetos estructurados, como vectores o matrices.

1.2 Conjuntos

Los conjuntos se representan mediante letras mayúsculas caligráficas \(\mathcal{X,Y,D}\). A menudo indexamos un conjunto mediante etiquetas en superíndices entre paréntesis: \( \mathcal{S}=\{ s^{(1)},s^{(2)},s^{(3)},…,s^{(S)} \} \), donde \(\mathcal{S}= |\mathcal{S}|\). Una abreviatura para esto define de manera equivalente \(\mathcal{S}=\{ s^{(s)} \}_{s=1}^{\mathcal{S}}\). Esta abreviatura, es conveniente cuando se define un conjunto de ejemplos de entrenamiento: \( \mathcal{S}=\{\left ( x^{(1)},y^{(1)} \right ),\left ( x^{(2)},y^{(2)} \right ),…, \left ( x^{(N)},y^{(N)} \right )\} \), es equivalente a \( \mathcal{S}=\{ \left ( x^{(n)},y^{(n)} \right ) \}_{n=1}^{N} \).

1.3 Variables Aleatorias

Las variables aleatorias también son letras latinas mayúsculas \(X, Y, Z\), pero su uso suele ser evidente a partir del contexto. Cuando una variable aleatoria \(X_i\) y un escalar \(x_i\) son versiones en mayúsculas/minúsculas una de la otra, normalmente queremos decir que el escalar es un valor tomado por la variable aleatoria. Cuando es posible, tratamos de reservar las letras griegas para los parámetros \(\theta\), \(\phi \) o los hiperparámetros \(\alpha, \beta, \gamma\).

Para una variable aleatoria \(X\) escribimos \(X \sim \text{Gaussian}(\mu, \sigma^2)\) o también \( X \sim\mathcal{N}(\mu, \sigma^2) \) para indicar que \(X\) sigue una distribución gaussiana/Normal unidimensional (1D) con media \(\mu\) y varianza \(\sigma^2\). Escribimos \(x \sim \text{Gaussian}(\mu, \sigma^2)\) para decir que \(x\) es una muestra de la misma distribución.

Una distribución de probabilidad condicional sobre la variable aleatoria \(X\) dadas \(Y\) y \(Z\) se escribe \(P(X|Y, Z)\) y su función de masa de probabilidad (pmf: probability mass function) o función de densidad de probabilidad (pdf: probability density function) es \(p(x|y, z)\). Si la distribución de probabilidad tiene parámetros \(\alpha\), \(\beta\), podemos escribir su pmf/pdf de al menos tres formas equivalentes:

  • Un estadístico podría preferir \(p(x|y, z; \alpha, \beta)\) para delimitar claramente los parámetros.
  • Un experto en modelos gráficos preferiría \(p(x|y, z, \alpha, \beta)\) ya que dichos parámetros son realmente solo variables aleatorias adicionales.
  • Un tipógrafo podría preferir ahorrar tinta escribiendo \(p_{\alpha, \beta}(x|y, z)\).

Nos referiremos a esta pmf/pdf como: \(p_{\alpha, \beta}(\cdot | y,z)\). Usando nuestra notación \(\sim\) de arriba, podríamos escribir que \(X\) sigue la distribución \(X \sim p_{\alpha, \beta}(\cdot | y, z)\) y \(x\) es una muestra de: \(x \sim p_{\alpha, \beta}(\cdot | y, z)\).

La esperanza de una variable aleatoria \(X\) es \(\mathbb{E}[X]\). Cuando se trabaja con cantidades aleatorias para las cuales la distribución generadora puede no estar clara, podemos denotarla en la esperanza. Por ejemplo, \(\mathbb{E}_{{x \sim p_{\alpha, \beta}(\cdot | y, z)}}[f(x,y,z)]\) es la esperanza de \(f(x, y, z)\) para alguna función \(f\) donde \(x\) se toma de la distribución \(p_{\alpha, \beta}(\cdot |y, z)\) e \(y\) y \(z\) son constantes para la evaluación de esta esperanza.

1.4 Funciones y Derivadas

Supongamos que tenemos una función \(f(x)\) escribimos su derivada parcial con respecto a \(x\) como \( \frac{\partial f(x)}{\partial x} \).
También denotamos su primera derivada como \(f'(x)\) conocida como notación de Lagrange. Para una función multivariable \(f(\mathbf{x}) = f(x_1,…,x_M)\), escribimos su gradiente con respecto a \(x\) como \(∇_{x}f(x)\) y con frecuencia omitimos el subíndice, es decir, \(∇f(x)\), cuando resulta claro a partir del contexto, puede que no lo sea para un gradiente como \(∇_{y}g(x, y)\) ya que no seria obvio con respecto a que se estará derivando, si con respecto a \(x\) o con respecto a \(y\) una vez omitamos el subíndice.

1.5 Notación/Convenciones

Tabla 1 (habrá una segunda parte) de las convenciones respecto a la notación que usaremos de aquí en adelante:

PROBLEMAS

PROBLEMA 1
Encuentra: \(\frac{\partial }{\partial w_j}\left ( x^T{w} \right )\) donde \(x\) y \(w\) son vectores de valores reales de dimensión \(M\) y \(1 ≤ j ≤ M\).

Solución (Haz clic aquí)

Debemos recordar que la expresión \(x^T{w}\) es equivalente a: \(x \cdot {w}\), es decir:
$$x^Tw = x \cdot w$$
La igualdad anterior es el producto punto, no olvidemos su definición:

Esta definición nos indica que el producto punto(escalar o interno) es la multiplicación de dos vectores que dan como resultado un número real, esto nos permite justificar la transpuesta de \(x\) ya que \(x \cdot w\) no es un real, y para lograrlo se transpone \(x\), así se obtendrá una matriz fila, en este caso \(x\) (por ejemplo dimensión \(1\times n\)) por una matriz columna, en este caso \(w\) (por ejemplo de dimensión \(n\times 1\)) y su multiplicación si resultaría en un numero real, una vez entendido este concepto fundamental, procedemos a resolver:
$$ \frac{\partial }{\partial w_j}\left ( x^T{w} \right )=\frac{\partial }{\partial w_j}\left (\sum_{i=1}^{M}x_i\cdot w_i \right )=\frac{\partial }{\partial w_j}\left ( x_1\cdot w_1 + x_2\cdot w_2+x_3\cdot w_3+… + x_M\cdot w_M\right )$$ $$ = x_1\cdot \frac{\partial }{\partial w_j}(w_1)+x_2\cdot \frac{\partial }{\partial w_j}(w_2)+x_3\cdot \frac{\partial }{\partial w_j}(w_3)+…+ x_M\cdot \frac{\partial }{\partial w_j}(w_M)$$
Debemos notar que \(w_j\) no depende de \(w_i\), \(\forall i\neq j\), por lo que, se cumple:
$$ \frac{\partial w_i}{\partial w_j} = \left\{\begin{array}{ll} 0 & \text{si } i \neq j \\ 1 & \text{si } i =j\end{array} \right. $$
Como \(1 ≤ j ≤ M\), se cumple \(w_1 ≤ w_j ≤ w_M\), por lo tanto: $$ x_1\cdot \frac{\partial }{\partial w_j}(w_1)+x_2\cdot \frac{\partial }{\partial w_j}(w_2)+x_3\cdot \frac{\partial }{\partial w_j}(w_3)+…+ x_M\cdot \frac{\partial }{\partial w_j}(w_M) = x_1\cdot \frac{\partial }{\partial w_1}(w_1)+x_2\cdot \frac{\partial }{\partial w_2}(w_2)+x_3\cdot \frac{\partial }{\partial w_3}(w_3)+…+ x_M\cdot \frac{\partial }{\partial w_M}(w_M)$$ $$ = x_1 \cdot 1 +x_2 \cdot 1+x_3 \cdot 1+…+x_M \cdot 1 $$
Finalmente se cumpliría: $$ \frac{\partial }{\partial w_j}\left ( x^T{w} \right ) = x_j $$

PROBLEMA 2
La función Gamma esta definida por:
$$ \Gamma(x) = \int_{0}^{\infty} u^{x-1}e^{-u}du $$
Usando integración por partes demuestre la relación: \(\Gamma(x+1) =x\Gamma(x)\). Demuestre también que \(\Gamma(1) =1\) y, por lo tanto, que \(\Gamma(x+1) =x!\) cuando \(x \in \mathbb{Z^{+}}\).

Solución (Haz clic aquí)

Recordando la integración por partes:
$$\int zdv= zv-\int vdz $$
Queremos obtener:
$$ \Gamma(x+1) = \int_{0}^{\infty} u^{x}e^{-u}du =$$
Ahora, tenemos que igualar: \(\Gamma(x+1) = \int_{0}^{\infty} u^{x}e^{-u}du=\int zdv\), donde:
$$z=u^x \to dz = xu^{x-1}$$ $$dv=e^{-u}du \to v=\int e^{-u}du=-e^{-u}$$
Así, obtenemos:
$$\Gamma(x+1)=-u^xe^{-u}|_{0}^{+\infty}+x\int_{0}^{\infty}e^{-u}u^{x-1}du$$
$$ = (\displaystyle \underbrace{\lim_{ u\to +\infty}-u^xe^{-u}}_{\textrm{indeterminado}}+\underbrace{\displaystyle \lim_{ u\to 0}u^xe^{-u})}_{0}+x\Gamma(x)$$
Notamos que el primer límite es indeterminado (\(\frac{\infty}{\infty}\)) y el segundo limite es 0 (\(\frac{0^{x}}{e^{0}}=\frac{0}{1}=0\))
Ahora, el paso donde toda la literatura elemental, canales en Youtube, blogs, etc, rehúye y no justifica 😅, debemos calcular: \(\lim_{ u\to +\infty}-u^xe^{-u}\), para que, así, se justifiquen todos nuestros pasos y el aprendizaje sea completo. De hecho, la decisión de usar este ejercicio se justifica, no porque no exista una explicación extensa, si no, que en toda esas interminables explicaciones en la web, ninguna se dio el trabajo de justificar el limite mencionado y creemos es importante agregar este truco a nuestra lista. Así que, ahora debemos decidir cual método es el mas conveniente, quizás algunos opten por acotar, otros usen series de Taylor, en nuestro caso nos la jugaremos por la Regla de la L’Hôpital (L’H), por lo que, al usar por primera vez L’H obtenemos: \(\frac{xu^{x-1}}{e^{u}}\), que al evaluar su limite en infinito sigue dando indeterminado, al aplicar L’H por segunda vez, se obtiene: \(\frac{x(x-1)u^{x-2}}{e^{u}}\), dando el mismo resultado que su expresión anterior al evaluar su limite en infinito, como no existe una regla de cuanto es el máximo de veces que se puede aplicar la regla L’H , debemos estar atentos a las expresiones que se forman una vez aplicadas unas cuantas veces, por lo que, podríamos decir que a medida que se aplica L’H el numerador se va transformando en un polinomio o también a la expresión de factorial, si justificamos que el numerador tiende a comportarse como un polinomio debemos notar que la función exponencial \(e^{u}\) crece mucho mas rápido que un polinomio, en otras palabras, seria lo mismo justificar que el denominador se hace grande mas rápidamente que el numerador(ambas estarían correctas) así que, el resultado del límite seria 0, ahora si se justifica o aproxima el numerador a \(x!\) ocurriría exactamente lo mismo, por que al expandir el factorial se formarían polinomios, por lo tanto, el límite aproximadamente es:
$$\lim_{ u\to +\infty}-u^xe^{-u}=\lim_{ u\to +\infty}-x! \cdot e^{-u}=0$$
Ahora podemos decir con toda tranquilidad que se cumple:
$$\Gamma(x+1)=x\Gamma(x)$$
Por último, tenemos que probar que se cumple \(\Gamma(1) =1\) y con este resultado demostrar \(\Gamma(x+1) =x!\) cuando \(x \in \mathbb{Z^{+}}\)
$$\Gamma(1) =\int_{0}^{\infty}e^{-u}u^{0}du=\int_{0}^{\infty}e^{-u}du=-e^{-u}|_{0}^{\infty}$$
Calculamos los limites:
$$ -e^{-u}|_{0}^{\infty}=-\displaystyle \lim_{b \to +\infty}e^{-b} + \displaystyle \lim_{b \to 0}e^{-b}=-\frac{1}{\infty}+\frac{1}{e^{0}}=-0+1=1$$
Usamos la igualdad demostrada anteriormente:
$$ \Gamma(x+1)=x\Gamma(x)=x(x-1)\Gamma(x-1)=x(x-1)(x-2)\Gamma(x-2)=x(x-1)(x-2)(x-3)\cdot … \cdot 1 \cdot \Gamma(1)=x!$$
Por lo tanto:
$$ \Gamma(x+1)=x!$$

PROBLEMA 3
Resuelva:
$$\sum_{j=3}^{5}\prod_{k=2}^{j}\left ( \frac{2^{k}}{k+1} \right )$$

Solución (Haz clic aquí)

$$\prod_{k=2}^{j}\left ( \frac{2^{k}}{k+1} \right )=\left ( \frac{2^{2}}{3} \right )\cdot \left ( \frac{2^{3}}{4} \right )\cdot \left ( \frac{2^{4}}{5} \right )\cdot …\cdot \left ( \frac{2^{j-1}}{j} \right )\cdot \left ( \frac{2^{j}}{j+1} \right )=\frac{2^{2+3+4+…+(j-1)+j}}{3\cdot 4\cdot 5\cdot …\cdot j\cdot (j+1)}=\frac{2^{\sum_{k=2}^{j}k}}{(j+1)!}$$
Veamos como se llego a que el denominador es \((j+1)!\). No olvidemos la definición de factorial:
$$n!=1\cdot 2\cdot 3\cdot …\cdot (n-2)\cdot (n-1)\cdot n$$ Entonces se cumple:
$$(n+1)!= 2\cdot 3\cdot 4\cdot …\cdot (n-1)\cdot n\cdot (n+1)$$
Así, es fácil darnos cuenta, por ejemplo: \(4!=4 \cdot 3 \cdot 2 \cdot 1\), entonces, se cumple: \((n+1)n!=(n+1)!\)
Ahora, necesitamos encontrar: \(\sum_{k=2}^{j}k\)
Existe una expresión útil para estos casos:
$$\sum_{i=m}^{n}i=\frac{1}{2}\left ( n^{2}-m^{2}+n+m \right )$$
Considerando \(i=k ; m=2 ; n=j\), reemplazamos y resolvemos:
$$\sum_{i=m}^{n}i=\frac{1}{2}\left ( n^{2}-m^{2}+n+m \right )=\sum_{k=2}^{j}k=\frac{1}{2}\left ( j^{2}-2^{2}+j+2 \right )=\frac{1}{2}\left ( j^{2}+j-2 \right )=\frac{1}{2}\left ( j+2 \right )\left ( j-1 \right )$$
Solo nos queda reemplazar:
$$\sum_{j=3}^{5}\prod_{k=2}^{j}\left ( \frac{2^{k}}{k+1} \right )=\sum_{j=3}^{5}\frac{2^{\sum_{k=2}^{j}k}}{(j+1)!}=\sum_{j=3}^{5}\frac{2^{\frac{1}{2}\left ( j+2 \right )\left ( j-1 \right )}}{(j+1)!}=\frac{2^{5}}{4!}+\frac{2^{9}}{5!}+\frac{2^{14}}{6!}=\frac{1276}{45}=28.35$$

Árbol de Decisión

Un árbol de decisión es un modelo de aprendizaje automático que representa una serie de decisiones secuenciales para predecir un resultado o clasificar un dato. Se trata de un gráfico en forma de árbol que muestra las posibles decisiones y sus consecuencias. Cada nodo del árbol representa una característica o atributo del dato que se está analizando, y cada rama representa una decisión basada en el valor de esa característica. El nodo final del árbol representa la predicción o clasificación del dato.

Terminologías de árboles de decisión:

Un árbol de decisión es un diagrama de flujo dirigido, dibujado en una estructura similar a la de un árbol. La estructura del árbol comprende nodos raíz (root nodes), ramas (branches), nodos internos (internal nodes) y nodos hoja (leaf nodes).


Existen términos especializados asociados con los árboles de decisión que denotan varios componentes y facetas de la estructura del árbol y el procedimiento de toma de decisiones. :

Nodo raíz/Root Node: el nodo raíz de un árbol de decisión, que representa la opción o característica original a partir de la cual se ramifica el árbol, es el nodo más alto.

Nodos internos/Internal Nodes (Nodos de Decisión): nodos en el árbol cuyas opciones están determinadas por los valores de atributos particulares. Hay ramas en estos nodos que van a otros nodos.

Nodos hoja/Leaf Nodes (Nodos terminales): los extremos de las ramas, cuando se deciden las opciones o los pronósticos. No hay más ramas en los nodos hoja.

Ramas/Branches (Bordes): vínculos entre nodos que muestran cómo se toman las decisiones en respuesta a circunstancias particulares.

División/Splitting: el proceso de dividir un nodo en dos o más subnodos según un criterio de decisión. Implica seleccionar una característica y un umbral para crear subconjuntos de datos.

Nodo padre/Parent Node: un nodo que se divide en nodos secundarios. Nodo original a partir del cual se origina una división.

Nodo hijo/Child Node: nodos creados como resultado de una división a partir de un nodo primario.

Criterio de decisión: regla o condición utilizada para determinar cómo se deben dividir los datos en un nodo de decisión. Implica comparar los valores de las características con un umbral.

Poda/Pruning: proceso de eliminación de ramas o nodos de un árbol de decisión para mejorar su generalización y evitar el sobreajuste.

Ecuaciones Útiles

Información Mutua (Mutual Information)

La información mutua es una medida de la cantidad de información que una variable aleatoria contiene sobre otra variable aleatoria. En el contexto de los árboles de decisión, la información mutua se utiliza para determinar la importancia de cada característica en la predicción del resultado.
La ecuación de información mutua se define como:

$$I(X|Y)=H(Y)-H(Y|X)$$

donde:

  • \(I(X|Y)\) es la información mutua entre las variables \(X\) e \(Y\).
  • \(H(Y)\) es la entropía de la variable \(Y\).
  • \(H(Y|X)\) es la entropía condicional de la variable \(Y\) dada la variable \(X\).

Ligando las ecuaciones de información mutua con los árboles de decisión

En los árboles de decisión, la información mutua se utiliza para seleccionar la característica más importante para dividir el conjunto de datos en cada nodo. La característica con la mayor información mutua con la variable objetivo se selecciona como la característica para dividir el conjunto de datos.

La información mutua se calcula para cada característica y se utiliza para determinar la ganancia de información que se obtiene al dividir el conjunto de datos según esa característica. La característica con la mayor ganancia de información se selecciona como la característica para dividir el conjunto de datos.

En resumen, la información mutua es una medida de la cantidad de información que una variable aleatoria contiene sobre otra variable aleatoria, y se utiliza en los árboles de decisión para seleccionar la característica más importante para dividir el conjunto de datos en cada nodo.

Entropía

La entropía es una medida de la cantidad de incertidumbre o aleatoriedad en una variable aleatoria. En el contexto de la información mutua, la entropía se utiliza para medir la cantidad de información que una variable aleatoria contiene sobre otra variable aleatoria.
La entropía de una variable aleatoria X se define como:

$$H(X) = – ∑ p(x) log_{2} p(x)$$

donde:

  • \(H(X)\) es la entropía de la variable \(X\).
  • \(p(x)\) es la probabilidad de cada valor de la variable \(X\).
  • \(log_{2} \) es el logaritmo en base \(2\).

Tipos de entropía

Hay varios tipos de entropía que se utilizan en el contexto de la información mutua:

  • Entropía de Shannon: es la entropía definida anteriormente, que mide la cantidad de información que una variable aleatoria contiene sobre sí misma.
  • Entropía condicional: Supóngase que \(X\) es una variable aleatoria sobre un espacio de probabilidad \( \Omega\) y \(A\subset \Omega\) sea un evento. Si \(X\) toma valores sobre un conjunto finito \( \{ a_i | 1\leq i \leq m \} \), se define de manera natural la entropia condicional de \(X\) dado \(A\) como:

$$ H(X|A)=\sum_{k=1}^{m}P(X=a_k|A)\ln(P(X=a_k|A) $$

Otra forma alternativa que se usa con logaritmo base 2, es:

$$ H(Y|X=x)=-\sum_{y \in \mathcal{Y}}P(Y=y|X=x)log_{2}P(Y=y|X=x) $$

De la misma manera, si \(Y\) es otra variable que toma valores \(b_k\) se define la entropía condicional \(H(X|Y)\) como:

$$ H(X|A)=\sum_{j}H(X|Y=b_j)P(Y=b_j) $$

Relación entre entropía e información mutua

La entropía y la información mutua están estrechamente relacionadas. La información mutua entre dos variables aleatorias \(X\) e \(Y\) se puede expresar en términos de la entropía de \(X\) e \(Y\), y la entropía condicional de \(X\) dado \(Y\).

$$I(X|Y) = H(X) – H(X|Y)$$

Esta ecuación muestra que la información mutua entre \(X\) e \(Y\) es igual a la entropía de \(X\) menos la entropía condicional de \(X\) dada \(Y\). Esto significa que la información mutua es una medida de la cantidad de información que se comparte entre \(X\) e \(Y\), y que se puede calcular utilizando la entropía y la entropía condicional.

PROBLEMA 4 (Árbol de Decisión | NIVEL: \(\star\))

Usaremos el conjunto de datos a continuación para aprender un árbol de decisiones que predice si las personas aprueban el curso de Fundamentos de Machine Learning (Sí o No), en función de su GPA anterior (alto (H), medio(M)o bajo(L)) y si estudiaron o no.

Para este problema, puedes escribir tus respuestas usando \(log_{2}\), pero puede ser útil tener en cuenta que \(log_{2} 3 ≈ 1.6\)

  1. ¿Cuál es la entropía H(APROBÓ)?
  2. ¿Cuál es la entropía H(APROBÓ | GPA)?
  3. ¿Cuál es la entropía H(APROBÓ | ESTUDIÓ)?
  4. Dibuje el árbol de decisiones completo que se aprendería para este conjunto de datos.
Solución (Haz clic aquí)

Complementaremos este blog con nuestro canal en Youtube: https://www.youtube.com/@INGDUSTRIALPROACADEMY
Subiremos resoluciones de ejercicios interesantes, así que:
¡Suscríbete y mantente al tanto de nuestras últimas novedades! ☺️


Si quieres aprender más, revisa nuestros modelos de exámenes.
Aprovecha el descuento: 65% en el Examen de Ciencia de Datos.