Ejercicio 1

1. En el campo de la genética, se busca identificar los genes asociados a una enfermedad específica. En un estudio reciente se encontró que un conjunto de 22 genes está fuertemente relacionado con la aparición de diabetes tipo 2. El equipo de investigación ahora se pregunta ¿cuántos conjuntos de 22 genes se tendrían que evaluar para identificar todos los genes relacionados con la diabetes tipo 2? Suponga que el genoma humano consta de 25.000 genes.

Además, si se propusiera un algoritmo de búsqueda basado en fuerza bruta que evalúa cada combinación de 22 genes para determinar su relación con la diabetes tipo 2 en 1 nanosegundo,
- ¿Cuánto tiempo se necesitaría para evaluar todas las combinaciones?
- ¿Qué sugerencia haría desde el punto de vista computacional?
- Contextualice su respuesta para el problema.

Solución:

Análisis inicial:
Si son 25.000 genes en total y la verificación de cada gen se hiciese de manera individual, se necesitaría un igual número de verificaciones que de genes, es decir, 25.000 verificaciones individuales para 25.000 genes.Sin embargo, al agruparlos en conjuntos de 22 genes, necesitamos calcular las posibles combinaciones o permutaciones correspondientes.
Esto es, si la composición de cada grupo de 22 genes resulta relevante para determinar la relación del conjunto de genes con la aparición de diabetes tipo 2, pero su orden no tiene relevancia, entonces podemos considerar todas las posibles combinaciones de grupos de 22 genes: \[ Combinaciones= \begin{equation} \frac{25000!}{22!(25000 - 22)!} \end{equation} \] Sin embargo, al intentar calcular 25000!, el número es demasiado grande para el cómputo de este problema en un computador de nivel domiciliario.

factorial(25000)/(factorial(22)*factorial(25000-22))
## [1] NaN

Obtenemos como resultado NaN que significa Not a number.

Por otro lado, si el orden de de la cadena de genes es relevante para la determinación de si un conjunto puede estar vinculado a la aparición de diabetes tipo 2, entonces estamos frente a una permutación. Para este caso, la fórmula sería: \[ Permutaciones= \begin{equation} \frac{25000!}{(25000 - 22)!} \end{equation} \]

factorial(25000)/(factorial(25000-22))
## [1] NaN

Tal como ocurre en el caso anterior, factorial de 25 mil es un número demasiado grande para ser calculado computacionalmente con la tecnología actual de un sistema computacional no profesional, por lo que las permutaciones no pueden ser calculadas. Consideremos además que la operación del número total de permutaciones sería un número aún más grande que el de combinaciones.

Estrategia de resolución
Podemos calcular factoriales demasiado grandes para ser procesador de manera tradicional, utilizando el paquete gmp.

Combinaciones

# Cargamos el paquete "gmp"
library(gmp)
## 
## Attaching package: 'gmp'
## The following objects are masked from 'package:base':
## 
##     %*%, apply, crossprod, matrix, tcrossprod
# Definimos n y k
n <- as.bigz(25000)
k <- as.bigz(22)

# Cálculo de combinaciones
combinaciones <- chooseZ(n, k)

# Combinaciones
print(combinaciones)
## Big Integer ('bigz') :
## [1] 5010713441141501787577547676827449801905335389570753182333600600985237925000

Permutaciones

# Cálculo del numerador 25.000!
numerador <- as.bigz(25000)
numerador_factorial <- factorialZ(numerador)

# Cálculo del denominador (25.000 - 22)!
denominador <- as.bigz(25000 - 22)
denominador_factorial <- factorialZ(denominador)

# Cálculo de permutaciones -> 25.000!  /  (25.000 - 22)!
permutaciones <- numerador_factorial / denominador_factorial

# Permutaciones
print(permutaciones)
## Big Rational ('bigq') :
## [1] 5632045554528088973219822914385244299964785963832422226786540210002092493346708052107264000000000


Tiempo de cálculo:
Si cada comprobación toma 1 nanosegundo, podemos multiplicar el total de combinaciones por 1 nanosegundo y obtendremos el tiempo total en nanosegundos. Luego, pasamos de nanosegundos a segundos dividiendo el total de nanosegundos en 1.000.000.000 para obtener el tiempo en segundos.
\[ Tiempo\ Total \ [s]= \begin{equation} \frac{(Combinaciones\ o \ Permutaciones) \cdot 1\ nanosegundo}{1\ 000\ 000\ 000} \end{equation} \]

Para calcular el tiempo, tomaré el resultado de combinaciones. De manera que:

segundos = combinaciones/1000000000
print(segundos)
## Big Rational ('bigq') :
## [1] 200428537645660071503101907073097992076213415582830127293344024039409517/40000
horas = segundos/3600
print(horas)
## Big Rational ('bigq') :
## [1] 200428537645660071503101907073097992076213415582830127293344024039409517/144000000
dias = horas/24
print(dias)
## Big Rational ('bigq') :
## [1] 200428537645660071503101907073097992076213415582830127293344024039409517/3456000000
años = dias/365
print(años)
## Big Rational ('bigq') :
## [1] 200428537645660071503101907073097992076213415582830127293344024039409517/1261440000000
milenios = años/1000
print(milenios)
## Big Rational ('bigq') :
## [1] 200428537645660071503101907073097992076213415582830127293344024039409517/1261440000000000

Incluso exagerando el cálculo, al estimar milenios, el tiempo es extremadamente grande y resulta inmanejable para nuestra realidad humana.

Si calculamos las permutaciones el tiempo resultante es aún mayor:

segundos_p = permutaciones/1000000000
print(segundos_p)
## Big Rational ('bigq') :
## [1] 5632045554528088973219822914385244299964785963832422226786540210002092493346708052107264
horas_p = segundos_p/3600
print(horas_p)
## Big Rational ('bigq') :
## [1] 39111427462000617869582103572119752083088791415502932130462084791681197870463250361856/25
dias_p = horas/24
print(dias_p)
## Big Rational ('bigq') :
## [1] 200428537645660071503101907073097992076213415582830127293344024039409517/3456000000
años_p = dias_p/365
print(años_p)
## Big Rational ('bigq') :
## [1] 200428537645660071503101907073097992076213415582830127293344024039409517/1261440000000
milenios_p = años_p/1000
print(milenios_p)
## Big Rational ('bigq') :
## [1] 200428537645660071503101907073097992076213415582830127293344024039409517/1261440000000000


Sugerencia estratégica desde la óptica computacional:

i. Disminuir el espacio total de búsqueda definiendo candidatos de interés
Antes de implementar una solución computacional que involucre algún tipo de verificación o búsqueda dentro de un conjunto, es esencial determina exactamente qué es lo que se busca.

En este sentido, es esencial que previo a cualquier diseño de implementación computacional se identifique algún tipo de indicador genético que advierta qué patrones o características existen al momento de determinar si un gen podría estar relacionado con la diabetes tipo 2 para así identificar posibles candidatos y priorizar la verificación de los grupos que contengan a aquellos candidatos. Para ello se puede analizar en profundidad el estudio y los resultados del hallazgo inicial que plantea el problema del grupo original de 22 genes. Por ejemplo,
- ¿Hay elementos en común entre estos genes?
- ¿Existen características diferenciadoras en este grupo respecto de otros genes?
- ¿Por qué 22 y no otro número?
- ¿Hay alguna característica especial en la composición de este grupo de genes?

Responder este tipo de preguntas y más puede ayudarnos a formar un perfil de candidato(s) en donde prioricemos la búsqueda de acuerdo a criterios de probabilidad, descartando en el proceso candidatos débiles y priorizando aquellos grupos que sí tengan mayor probabilidad. Esta labor puede realizarse de manera manual en términos generales o bien haciendo uso de los avances en Inteligencia Artificial para buscar patrones diferenciadores o características en común en el grupo inicial de 22 genes que da origen a este problema.
Una vez identificado un grupo más acotado de candidatos, la búsqueda puede ser más eficiente. Aún así, un algoritmo de fuerza bruta no es la estrategia más recomendada para buscar coincidencias en un conjunto de elementos grande de cualquier tipo.

ii. Apoyo de especialistas en la materia y revisión de precedentes
En este caso y respecto de las especificidades del problema, sería conveniente consultar avances en bioinformática para saber qué avances y estrategias se están utilizando al momento de enfrentar problemas computacionales de tipo similar.

Del mismo modo, siendo la ciencia una disciplina que se construye y desarrolla en colectivo, el estudio de precedentes en investigación e ingeniería ayudará a descubrir si ya se ha realizado algún ejercicio similar y, en ese caso, consultar la documentación o pedir asesoramiento o colaboración a los autores puede significar un impulso y aceleración significativa respecto de la eficiencia en la elección y el despliegue de la estrategia computacional correcta.

Ejercicio 2

2. En el campo de la ingeniería aeroespacial, se sabe que los materiales utilizados en las alas de los aviones pueden sufrir de fatiga y eventualmente fallar. Se ha determinado que la vida útil de los materiales de las alas es de 20.000 horas de vuelo. Bajo este contexto:

a) ¿Cuál es la probabilidad de que las alas de un avión fallen antes de las 5,000 horas de vuelo?
b) ¿Cuál es la probabilidad de que las alas de un avión fallen antes de las 20,000 horas de vuelo?
c) ¿Cuál es la probabilidad de que las alas de un avión fallen después de las 30,000 horas de vuelo?
e) Indique y grafique la distribución asociada.

Solución:

Al trabajar sobre estimaciones de tiempo, estamos considerando variables continuas. En particular, este problema puede resolverse mediante distribución exponencial debido a que buscamos calcular la fiabilidad o durabilidad de un producto o material, en este caso se trata de las alas de un avión.
Sabemos por el enunciado que la vida útil de las alas es de 20.000 horas de vuelo, luego:

lambda = 20000

respuesta_a = pexp(5000, rate =1/lambda, lower.tail = T)
print(respuesta_a)
## [1] 0.2211992
respuesta_b = pexp(20000, rate =1/lambda, lower.tail = T)
print(respuesta_b)
## [1] 0.6321206
respuesta_c = pexp(30000, rate =1/lambda, lower.tail = F)
print(respuesta_c)
## [1] 0.2231302
# Gráfico
rango = seq(-10,40000)
distribucion = dexp(rango, rate =1/lambda)
datos=data.frame(rango,distribucion)
library("ggplot2")
grafico = ggplot(data=datos,aes(x=rango,y=distribucion))
grafico = grafico + geom_line(stat="identity",color="pink",linewidth = 0.5)
grafico = grafico + theme_bw() + ggtitle("Distribución de probabilidades: Distribución exponencial")
grafico = grafico + xlab("Horas de vuelo") + ylab("Probabilidad")
plot(grafico)


## Ejercicio 3
3. Se sabe que el tiempo que tarda un empleado en resolver un problema de soporte técnico en una empresa sigue una distribución normal de media 15 minutos y desviación estándar de 5 minutos. Con base en esta información:
a) ¿Cuál es la probabilidad de que un empleado resuelva un problema en exactamente 10 minutos? Argumente su respuesta.
b) Si seleccionamos aleatoriamente a 50 empleados, ¿cuál es la probabilidad de que el tiempo promedio que tardan en resolver un problema de soporte técnico sea menor a 12 minutos?
c) Indique y grafíque las distribuciones asociadas.

Solución:

  1. Por definición, el cálculo directo de un único punto exacto en la distribución normal no es posible, pues al tratarse de una variable continua debemos trabajar dentro de un rango. La probabilidad exacta de un valor particular en la distribución estándar es de cero.

Alternativamente, R nos permite calcular la densidad para un x = 10 minutos mediante la función dnorm:

dnorm(10,15,5)
## [1] 0.04839414

Y, también, podemos calcular la probabilidad de que el trabajador tarde menos de 10 minutos mediante la función pnorm:

pnorm(10,15,5)
## [1] 0.1586553
  1. En primer lugar, la probabilidad de que un empleado cualquiera resuelva el problema en menos de 12 minutos equivale a:
pnorm(12,15,5)
## [1] 0.2742531

Sin embargo, al tomar una muestra aleatoria de 50 empleados utilizando distribución binomial, tenemos que:

Sabemos que la probabilidad de que un empleado tarde menos de 12 minutos es de: 0.2742531, calculada mediante pnorm(12,15,5). Luego, utilizamos distribución binomial:

p = pnorm(12,15,5)
respuesta = dbinom(50, size = 50, p)
print(respuesta)
## [1] 8.083113e-29

Por lo tanto, al seleccionar 50 trabajadores aleatoriamente, la probabilidad de que tarden menos de 12 minutos en resolver un problema técnico es de: 8.083113e-29.

  1. Gráficos:
#Creación de la distribución
x=seq(0,35,by=0.1)
y=dnorm(seq(0,35,by=0.1),15,5)
z=y
datos=data.frame(x,y,z)
#Gráfico
library("ggplot2")
p = ggplot(data.frame(x = x, y = y)) + aes(x = x, y = y)
p = p+geom_line(color="darkblue") + labs(x = "Dist. normal", y = "Densidad")
p = p + theme_classic() + ggtitle("Distribución normal Ejercicio 3")
p = p + geom_area(data = datos, aes(x=x,y=z), fill="lightblue", alpha=0.4)
#Distribución normal con media de 15 minutos y desviación estándar de 5
plot(p)

library("Rlab")
## Rlab 4.0 attached.
## 
## Attaching package: 'Rlab'
## The following objects are masked from 'package:stats':
## 
##     dexp, dgamma, dweibull, pexp, pgamma, pweibull, qexp, qgamma,
##     qweibull, rexp, rgamma, rweibull
## The following object is masked from 'package:datasets':
## 
##     precip
rango = seq(0,30)
distribucion = dbinom(rango, size = 50,prob = 0.2742531)
datos=data.frame(rango,distribucion)
library("ggplot2")
grafico = ggplot(data=datos,aes(x=rango,y=distribucion))
grafico = grafico + geom_bar(stat="identity",fill="lightblue3")
grafico = grafico + theme_bw() + ggtitle("Distribución de probabilidades pregunta c)")
grafico = grafico + xlab("Rango") + ylab("Probabilidad")
plot(grafico)

Referencias