# ¿Cómo podrían afectar los recortes a la propagación del virus del Ébola?

## Una simulación epidemiológica (simple) del virus del Ébola

*Autor: [CAChemE.org](http://CAChemE.org), original por [Charles Hill, No painers blog](http://nopaniers.calepin.co/a-simple-model-of-the-ebola-virus.html) - Licencia [CC-BY](http://creativecommons.org/licenses/by/2.0/) *

La propagación del virus del ébola en el África occidental sigue, por el momento, imparable. Los modelos epidemiológicos tratan de representar este comportamiento mediante fórmulas matématicas. Este documento intenta ejemplificar con un modelo muy simple, y por tanto aproximado, del impacto de variables como la facilidad de contagio y mortalidad del mismo.

## Disclaimer

Nuestra formación no es en el ámbito de la medicina ni estadística y los resultados aquí mostrados son un ejercicio aplicado de métodos numéricos de integración con el [lenguaje de programación Python](http://cacheme.org/curso-online-python-cientifico-ingenieros/). Por ello, cualquier mejora en el modelo es bienvenida :)

# El virus

Los datos que podemos consultar del Ébola en el África occidental son desesperanzadores:

*Fuente: [Charles Hill, No painers blog](http://nopaniers.calepin.co/a-simple-model-of-the-ebola-virus.html) - Datos más actualizados (a octubre de 2014) se pueden consultar en la [BBC](http://www.bbc.com/news/world-africa-28755033) y [Forbes](http://www.forbes.com/sites/jvchamary/2014/10/13/ebola-trends/).*

Este gráfico representa la cantidad total (acumulada) de los casos y muertes producidos por el virus en el África occidental. El eje vertical es logarítmico y, por tanto, la tendencia lineal que aparece a partir de junio indica que los números están creciendo exponencialmente.

> Ateniendo al gráfico, el número de casos y defunciones por Ébola se duplica cada mes.

Siendo más precisos, el nº de casos se se duplica cada 29 días. Si se mantuviera esa velocidad de propagación, en nueve meses tendríamos un millón de casos, y en dos años una fracción significativa de la población mudnial habrá tenido la enfermedad. Obviamente necesitamos un modelo mejor ya que el crecimiento exponencial no puede ser ilimitado y esto es sólo un primer intento.

## El modelo

Existen cuatro variables / categorías de personas en este modelo:

$S$ son personas susceptibles que no han contraído el virus todavía. Si entran en contacto con alguien que es infeccioso, podrían contraer el virus.

$E$ son personas expuestas que tienen el virus , pero que aún no presentan los síntomas y no son infecciosos.

$I$ son personas que han sido contagiados por Ébola, han pasado el tiempo de incubación y son infecciosas. Su cuerpo se encuentra en plena batalla contra el virus y sus síntomas.

$R$ son personas que han ganado la batalla y se han recuperado. Ellos ahora son inmunes al virus.

Si te fijas, el número total de personas aún con vida $N$ corresponde con la suma de todos ellos.

Así el modelo epidemiológico a seguir se llama [SEIR](http://en.wikipedia.org/wiki/Compartmental_models_in_epidemiology#The_SEIR_model) y puede ser definido por el siguiente sistema de [ecuaciones diferenciales](http://es.wikipedia.org/wiki/Ecuaci%C3%B3n_diferencial):

\begin{align}
\frac{dS} {dt} &= -\beta \frac{S}{N} I \\\\
\frac{dE}{dt}  &= +\beta \frac{S}{N} I -\sigma E \\\\
\frac{dI}{dt} &= +\sigma E - \gamma I \\\\
\frac{dR}{dt} &= (1-f) \gamma I
\end{align}

Para nuestro caso, consideraremos que hay una persona afectada únicamente ($E = 1$)

## Explicación del modelo:

En esta sección se da una explicación del modelo SEIR y los parámetros que se han elegido. Si quieres, puedes ir directamente a los resultados:

La disminución del número de personas sanas con el tiempo será proporcional a las personas infecciosas (I) y la cantidad (proporcional) de las mismas $S/N$. Además, definimos una factor de probabilidad por día, que llamaremos $\beta$, de infectar a otra persona.  La variación del nº personas expuestas ($E$), seguirá la misma relación pero aumentando su número (signo positivo). Esto, matemáticamente queda expresado como:

\begin{align}
\frac{dS} {dt} &= -\beta \frac{S}{N} I \\\\
\frac{dE}{dt}  &= +\beta \frac{S}{N} I \\\\
\end{align}

Una vez que una persona está infectada ($E$), es necesario un tiempo para mostrar los síntomas y llegar a ser infecciosa ($I$). Este tiempo depende de cada caso, pero en los brotes anteriores de Ebola, se estimó que se necesita alrededor de 9 días para ello. Vamos a modelar esto con una *velocidad* de pasar de $E$ a $I$ de $\sigma = 1/9$ por día:

$$
\begin{align}
\frac{dE}{dt} = -\sigma E \\\\
\frac{dI}{dt} = +\sigma E
\end{align}
$$

En este punto, la persona enferma puede recuperarse o fallecer. Una vez más, vamos a modelar esto con una *velocidad*, que se puede encontrar con los brotes anteriores, de $ \gamma =  1 / 8.5$ por día. La probabilidad de fallecer estimada por la OMS en estos momentos es del 50% ([Fuente: OMS](http://www.who.int/mediacentre/factsheets/fs103/en/)). Sin embargo, vamos a ser optimistas y considerar que esta tasa puede reducirse hasta un 40% ($f = 0.4$) si los recursos de los centros hospitalarios no se ven comprometidos y los síntomas del virus se tratan a tiempo. Así, la fracción de personas sobreviven es de $1-f = 0.6$ (personas que sobreviven).

$$
\begin{align}
\frac{dI}{dt} &= - \gamma I \\\\
\frac{dR}{dt} &= (1-f) \gamma I
\end{align}
$$

Aún no se ha definido el valor de $\beta$, el cual indica la velocidad de personas que se infectan. Para ello haremos uso de un parámetro importante: el número medio de personas que un paciente con ébola podría llegar a infectar $R_0$.

$$R_0 = \frac{\beta}{\gamma}$$

En brotes anteriores, estimaron $R_0$ estar entre 1.3 y 2.7, es decir, un paciente con ébola llega a infectar de 1 a 3 personas. Este parámetro difiere entre países y factores como:
* Costumbres locales/religiosas
* Comportamiento del paciente infectado en fase contagiosa
* Equipamiento de los hospitales y medidas de protección
* Formación adecuada del personal sanitario
* Cumplimiento de protocolos de seguridad

Para ver la importancia que tiene disminuir este factor $R_0$, vamos a interactuar con el modelo y considerar que a mayor nº de recortes en sanidad mayor es el nº de contagios que un paciente con ébola puede llegar a realizar antes de estar controlado, así  $ R_0 = recortes \: sanidad $.

## Resultados

El [ártículo original](http://nopaniers.calepin.co/a-simple-model-of-the-ebola-virus.html) en el que se basa este trabajo resolvió el sistema de ecuaciones diferenciale numéricamente con parámetros similares obteniendo una aproximación entre su modelo y los datos reales.

Como se puede ver, el modelo no coincide bien al principio (antes de mayo), pero una vez que la fase de crecimiento exponencial comienza, la simulación obtiene resultados similares. Definitivamente, el modelo captura la velocidad de aumento, la relación entre los casos y los fallecimientos.

Entonces, ¿qué impacto tienen los recortes en la velocidad de propagación del ébola? Veámoslo en este gráfico resuelto y obtenido con Python.

En España seguimos a la espera de comprobar cuantas personas llegaron a contagiarse, por lo que hemos variado el valor de $R_0 = recortes \: sanidad$ entre 1 y 2. A la vista de los resultados, no es de extrañar que expertos y personal sanitario estén pidiendo más medios y formación para evitar contagios durante el tratamiento de pacientes con ébola en hospitales.

## Código

Para interactuar con este documento de [IPython Notebook](http://ipython.org/)/[JuPyter](http://jupyter.org/), puedes descargar e instalar [Anaconda de Continuum](http://continuum.io/downloads) ([ver instalación](https://www.youtube.com/watch?v=kLuwGhvWJzE&index=16&list=PLGBbVX_WvN7bMwYe7wWV5TZt1a58jTggB)) u optar por distribuciones portables de Python como [Pyzo](http://www.pyzo.org/index.html#).

```
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
from scipy import integrate

from IPython.html.widgets import interact, interactive, fixed
from IPython.html import widgets

# Hasta ahora, hemos cargado nuestras bibliotecas favoritas de Python

# Pasamos a definir nuestro sistema de ec. diferenciales:

def DiffEqs(y, t, sigma, gamma, f, beta):
    """ Modelo simple epidemiológico para la
    propagacion del virus del Ébola"""

    # Recuperamos las variables dependientes de entrada
    S, E, I, R, D = y

    Nn = S+E+I+R # Total de personas vivas

    # Definimos las ecuaciones diferenciales
    dSdt = -beta*(S/Nn)*I
    dEdt = +beta*(S/Nn)*I - sigma*E
    dIdt = sigma*E - gamma*I
    dRdt = (1.0-f)*gamma*I
    dDdt = f*gamma*I
    return [dSdt, dEdt, dIdt, dRdt, dDdt]

def ebola(tiempo, recortes_sanidad):
    """ Solve the model and plot a basic graph of the results """

    tiempo_simulacion = tiempo # días
    t  = np.linspace(0., tiempo_simulacion, 1000)

    #------------------------------------------------------------------------------
    # Constantes del modelo
    #------------------------------------------------------------------------------

    sigma = 1./9  #  Velocidad convertirse en contagioso una vez expuesto
    gamma = 1./8.5 # Velocidad de recuperación o fallecimiento
    f = 0.4 # Fracción de gente que no supera la enfermedad (40%)

    # A mayor nº de recortes, mayor nº de personas contagiadas por infectado
    R_0 = recortes_sanidad

    beta = R_0*gamma # Velocidad con la que se propaga la infección

    # Condiciones iniciales

    N = 350 # Población total

    y0 = [N, 1, 0, 0, 0] # [S, E, I, R, D]

    # Llamamos al ode para resolver las eq. diferenciales

    solution = integrate.odeint(DiffEqs, y0, t, args=(sigma, gamma, f, beta))

    S = solution[:,0] #  S es el nº de personas sin infectar
    E = solution[:,1] #  E es el nº de portadores del virus no contagiosos (aún)
    I = solution[:,2] #  I es el nº de personas sintomáticas e infecciosas
    R = solution[:,3] #  R es el nº de personas recuperadas
    Ds = solution[:,4] #  D es el nº de personas fallecidas

    # Creamos la figura para representar los resultados

    fig = plt.figure(figsize=(10, 5))

    # Representamos las curvas de evolución con respecto al tiempo
    plt.plot(t, (E+I)/N*100 )
    plt.plot(t, I/N*100)
    plt.plot(t, R/N*100)
    plt.plot(t, Ds/N*100)
    plt.plot(t, S/N*100)

    # Añadimos leyenda a los datos
    plt.legend(["% infectados",
            "% infectados contagiosos",
            "% recuperados",
            "% fallecidos",
            u"% población sana "], loc=1)

    plt.suptitle(u'Variación de la velocidad de propagación del virus del Ébola:', fontsize=14, fontweight='bold')
    plt.title(u"Impacto de los recortes en el sistema sanitario.", fontsize = 12)

    plt.text(10, 50, u"A mayor nº de recortes, mayor \n nº de contagios (accidentales) \n y mayor velocidad de propagación.", style='italic',
        bbox={'facecolor':'red', 'alpha':0.5, 'pad':10})

    plt.xlabel(u"tiempo / días")
    plt.ylabel(u"porcentaje de población")

    plt.show()

```

```
interact(ebola, tiempo=(100,600), recortes_sanidad=(1,2,0.01))
```

```

```


Remaining Useful Life Prediction for Lithium-Ion Battery: LSTM Approach

 State Of Health

Generally, the remaining useful charge/discharge cycle life indicates battery’s SOH. To predict the remaining useful life (RUL)using data driven approach, the main advantage is that they do not require extensive knowledge on battery chemistry and failure mechanisms. Prognostic data are derived from measurable parameters such as voltage, current, and temperature.

In this project, we regard the degradation of the capacity as the indicator of the RUL.

Charge counting or current integration shown in equation is probably the most classical SOC calculation method:

\begin{equation}
 SOC= 1- \int_ \ \frac{I*dt}{C{n}} ...........................1
\end{equation}
where I is the current; Cn is the nominal capacity; t is the time.

 The capacity of battery is computed by integrating discharge current over time and it is given by

\begin{equation}
 Q= \int_ {t1}^{\ t2} \ {I*dt} ...............................2
\end{equation}
where I is the current; Q is the capacity; and t1 and t2 are start and end time of a discharge cycle.

During discharge a load was placed on the battery to draw a constant current of 0.5 C (0.45 A) until the voltage decreased to 2.7 V.

In this project, data was collected from discharge cycles of Li-ion batteries cycled under various conditions are analyzed. The battery cycling data is sourced from a publically available repository; provided by Prognostics Center of Excellence (PCoE) at Ames Research Center, NASA

The data repository contains capacity, voltage, current, temperature, current load and voltage load recorded for each discharge cycle of the batteries. Except the cell capacity.

```python
import pandas as pd
import numpy as np
#dataset_caharge=pd.read_csv("B0005_10_charge.csv")
dataset_discharge=pd.read_csv("B0005_10_discharge.csv")
data_set=pd.read_csv("B0005_discharge1.csv")

```

```python
#The data come from sensors are collected
#This the original data comes from NASA for B0005
feat=['Batt_name','cycle','voltage_battery','current_battery','time']
test=dataset_discharge[feat]
print(test.head(10))
print("Number of records are: "+str(len(test)))
```

        Batt_name  cycle  voltage_battery  current_battery     time
    0  'B0005_10'      1         4.191492        -0.004902    0.000
    1  'B0005_10'      1         4.190749        -0.001478   16.781
    2  'B0005_10'      1         3.974871        -2.012528   35.703
    3  'B0005_10'      1         3.951717        -2.013979   53.781
    4  'B0005_10'      1         3.934352        -2.011144   71.922
    5  'B0005_10'      1         3.920058        -2.013007   90.094
    6  'B0005_10'      1         3.907904        -2.014400  108.281
    7  'B0005_10'      1         3.897036        -2.011603  126.453
    8  'B0005_10'      1         3.887477        -2.018015  144.641
    9  'B0005_10'      1         3.878959        -2.013135  162.844
    Number of records are: 50285

Preprocessing the data

```python
#These Lists used for creating new dataframe
l1,l2,l3,l4,l5,l6,l7=[],[],[],[],[],[],[]
```

```python
#This function read each row form the dataset and finds the current battery when the voltage drop to vol
def get_list_C_T(dataset, vol):
    cycle=1
    check=True
    current=0
    time=0.0
    sum_discharge=[]
    time_dis=[]
    for j in range(len(dataset_discharge)):
        if cycle == dataset['cycle'][j]:
            if dataset['voltage_battery'][j]>= vol and check:
                current=dataset['current_battery'][j]
                time=dataset['time'][j]
            else:
                sum_discharge.append(current)
                time_dis.append(time)
                l1.append(cycle)
                l2.append(dataset['voltage_battery'][j])
                l3.append(dataset['time'][j])
                l4.append(dataset['temp_battery'][j])
                l5.append("B0005")
                l6.append(dataset['dateTime'][j])
                l7.append(dataset['amb_temp'][j])
                #check=False
        else:
            cycle=dataset_discharge['cycle'][j]
            current=0
    return sum_discharge,time_dis
```

```python
# This function do Calculation for Capcaity of all discharge cycle that store in the data
def Cap_Cal(dataset,ini_cap,time_dis):
    list_Cap=[]
    Cap=[]
    Cap.append(ini_cap)
    for i in range(len(dataset)):
        if i==0:
            dt=time_dis[0]
            currents=dataset[0]
            list_Cap.append(ini_cap)
        else:
            dt=(time_dis[i] -time_dis[i-1])
            currents=(dataset[i])#+ sum_discharge[i-1])/2
            Cap_0=list_Cap[i-1]
            list_Cap.append((Cap_0-((currents*dt))/(3600)))
    return list_Cap
```

```python
sum_discharge=[]
time_dis=[]
sum_discharge,time_dis=get_list_C_T(dataset_discharge,2.7)
print(len(sum_discharge))
```

    168

```python
dt=0.0
currents=0.0
SOC=[]
Cap=[]
res=[]
dt_ch=0.0
```

```python
Cap.append(data_set['Capacity'][0])
Caps=data_set['Capacity'][0]
res=Cap_Cal(sum_discharge,Caps,time_dis)
```

```python
#Create file that include the online capacity, after preprocessing in real time data,
#and we will use this file to build LSTM model for RUL.

#create new data frame contains fields: Batt_name,cycle, dateTime, amb_temp,
#voltage_battery,temp_battery, current_battery, time, Capacity_online
new_dataset=pd.DataFrame()
new_dataset['Batt_name']=l5
new_dataset['cycle']=l1
new_dataset['dateTime']=l6
new_dataset['amb_temp']=l7
new_dataset['voltage_battery']=l2
new_dataset['temp_battery']=l4
new_dataset['current_battery']=sum_discharge
new_dataset['time']=l3
new_dataset['Capacity_online']=res
```

```python
print(new_dataset.tail())
```

        Batt_name  cycle                dateTime  amb_temp  voltage_battery  \
    163     B0005    164   '2008-05-26 10:44:38'        24         2.668737
    164     B0005    165   '2008-05-26 15:30:43'        24         2.696396
    165     B0005    166   '2008-05-26 20:21:04'        24         2.679483
    166     B0005    167   '2008-05-27 15:52:41'        24         2.678714
    167     B0005    168   '2008-05-27 20:45:42'        24         2.655378

         temp_battery  current_battery      time  Capacity_online
    163     40.864674        -2.011053  2327.578         1.292325
    164     40.857545        -2.014212  2318.109         1.287053
    165     40.937025        -2.012752  2316.938         1.286416
    166     40.936092        -2.014447  2355.609         1.308020
    167     40.873909        -2.014372  2383.953         1.323923

```python
#Save the data frame into new file as frist step, after that if new discharge cycle begin for B0005 will
#be added to this file.
new_dataset.to_csv("Capacity_onlineB5.csv")
```

```python
data_set['Capacity_Cal']=res
#data_set.to_csv("Capacity_onlineB5.csv")
```

```python
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
plot_df = new_dataset.loc[(new_dataset['cycle']>=1),['cycle','Capacity_online']]
#plot_df1 = data_set.loc[(data_set['cycle']>=1),['cycle','Capacity']]

sns.set_style("darkgrid")
plt.figure(figsize=(12, 8))
plt.plot(plot_df['cycle'], plot_df['Capacity_online'],color='blue')
#plt.plot(plot_df1['cycle'], plot_df1['Capacity'],color='red')

#Draw threshold
plt.plot([0.,len(new_dataset)], [1.40, 1.40],color='red')
plt.ylabel('Capacity')
# make x-axis ticks legible
adf = plt.gca().get_xaxis().get_major_formatter()
plt.xlabel('cycle')
plt.title('Discharge B0005')
```

```python
#This code find the difference between the capacity measured onffline
#(by NASA) and capacity that calculated online.
test=['cycle','Capacity','Capacity_Cal']
new_data1=data_set[test]
difer=[]
for i in range(len(new_data1)):
    difer.append(new_data1['Capacity'][i]-new_data1['Capacity_Cal'][i])
new_data1['differ']=difer
print(new_data1.head())
sum_error=0
for i in range(len(new_data1)):
    sum_error=sum_error+ new_data1['differ'][i]
print("The avg of Error is "+str(sum_error/len(new_data1)))
```

       cycle  Capacity  Capacity_Cal    differ
    0      1  1.856487      1.856487  0.000000
    1      2  1.846327      1.846393 -0.000066
    2      3  1.835349      1.835524 -0.000175
    3      4  1.835263      1.835577 -0.000314
    4      5  1.834646      1.834502  0.000144
    The avg of Error is 0.0005989038535388082

    /home/khaled/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:8: SettingWithCopyWarning:
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead

    See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

```python
#Caculate SOH
test=['cycle','Capacity','Capacity_Cal']
new_data=data_set[test]
SOH=[]
init=new_data['Capacity_Cal'][0]
for i in range(len(new_data)):
    SOH.append(new_data['Capacity_Cal'][i]/2.0)
    #print(str(i) + "  "+str(new_data['Capacity_Cal'][i]/2.0))
new_data['SOH']=SOH

```

    /home/khaled/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:9: SettingWithCopyWarning:
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead

    See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
      if __name__ == '__main__':

```python
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
plot_df = new_data.loc[(new_data['cycle']>=1),['cycle','SOH']]
sns.set_style("darkgrid")
plt.figure(figsize=(12, 8))
plt.plot(plot_df['cycle'], plot_df['SOH'],color='blue')
#plt.plot(plot_df1['cycle'], plot_df1['Capacity'],color='red')

#Draw threshold
plt.plot([0.,len(new_data)], [0.70, 0.70],color='red')
plt.ylabel('SOH')
# make x-axis ticks legible
adf = plt.gca().get_xaxis().get_major_formatter()
plt.xlabel('cycle')
plt.title('Discharge B0005')
```

```python
print(new_data.head())
```

       cycle  Capacity  Capacity_Cal       SOH
    0      1  1.856487      1.856487  0.928244
    1      2  1.846327      1.846393  0.923197
    2      3  1.835349      1.835524  0.917762
    3      4  1.835263      1.835577  0.917788
    4      5  1.834646      1.834502  0.917251

```python
df = pd.read_csv('Coll_Cap_B56718.csv')
```

```python

%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
plot_df = df.loc[(df['cycle']>=1)&(df['Batt_name']==1),['cycle','Online_Capacity']]
plot_df1=df.loc[(df['cycle']>=1)&(df['Batt_name']==2),['cycle','Online_Capacity']]
plot_df2=df.loc[(df['cycle']>=1)&(df['Batt_name']==3),['cycle','Online_Capacity']]
plot_df3=df.loc[(df['cycle']>=1)&(df['Batt_name']==4),['cycle','Online_Capacity']]
sns.set_style("darkgrid")
plt.figure(figsize=(20, 8))
plt.plot(plot_df['cycle'], plot_df['Online_Capacity'], label="B0005", color='blue')
plt.plot(plot_df1['cycle'], plot_df1['Online_Capacity'], label="B0006", color='red')
plt.plot(plot_df2['cycle'], plot_df2['Online_Capacity'], label="B0007", color='green')
plt.plot(plot_df3['cycle'], plot_df3['Online_Capacity'], label="B0018", color='black')
#Draw threshold
plt.plot([0.,168], [1.38, 1.38])
plt.ylabel('Capacity')
# make x-axis ticks legible
plt.legend(loc='upper right', ncol=2,fontsize='xx-large')
adf = plt.gca().get_xaxis().get_major_formatter()
plt.xlabel('cycle')
plt.title('Discharge B0005')
```

```python

```