File size: 6,724 Bytes
a689c79 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# bioprocess_model.py
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.integrate import odeint
from scipy.optimize import curve_fit
from sklearn.metrics import mean_squared_error
import seaborn as sns
class BioprocessModel:
def __init__(self):
self.params = {}
self.r2 = {}
self.rmse = {}
self.datax = []
self.datas = []
self.datap = []
self.dataxp = []
self.datasp = []
self.datapp = []
self.datax_std = []
self.datas_std = []
self.datap_std = []
@staticmethod
def logistic(time, xo, xm, um):
return (xo * np.exp(um * time)) / (1 - (xo / xm) * (1 - np.exp(um * time)))
@staticmethod
def substrate(time, so, p, q, xo, xm, um):
return so - (p * xo * ((np.exp(um * time)) / (1 - (xo / xm) * (1 - np.exp(um * time))) - 1)) - \
(q * (xm / um) * np.log(1 - (xo / xm) * (1 - np.exp(um * time))))
@staticmethod
def product(time, po, alpha, beta, xo, xm, um):
return po + (alpha * xo * ((np.exp(um * time) / (1 - (xo / xm) * (1 - np.exp(um * time)))) - 1)) + \
(beta * (xm / um) * np.log(1 - (xo / xm) * (1 - np.exp(um * time))))
@staticmethod
def logistic_diff(X, t, params):
xo, xm, um = params
dXdt = um * X * (1 - X / xm)
return dXdt
def substrate_diff(self, S, t, params, biomass_params, X_func):
so, p, q = params
xo, xm, um = biomass_params
X_t = X_func(t)
dSdt = -p * (um * X_t * (1 - X_t / xm)) - q * X_t
return dSdt
def product_diff(self, P, t, params, biomass_params, X_func):
po, alpha, beta = params
xo, xm, um = biomass_params
X_t = X_func(t)
dPdt = alpha * (um * X_t * (1 - X_t / xm)) + beta * X_t
return dPdt
def process_data(self, df):
biomass_cols = [col for col in df.columns if 'Biomasa' in col]
substrate_cols = [col for col in df.columns if 'Sustrato' in col]
product_cols = [col for col in df.columns if 'Producto' in col]
time_col = [col for col in df.columns if 'Tiempo' in col][0]
time = df[time_col].values
data_biomass = np.array([df[col].values for col in biomass_cols])
self.datax.append(data_biomass)
self.dataxp.append(np.mean(data_biomass, axis=0))
self.datax_std.append(np.std(data_biomass, axis=0, ddof=1))
data_substrate = np.array([df[col].values for col in substrate_cols])
self.datas.append(data_substrate)
self.datasp.append(np.mean(data_substrate, axis=0))
self.datas_std.append(np.std(data_substrate, axis=0, ddof=1))
data_product = np.array([df[col].values for col in product_cols])
self.datap.append(data_product)
self.datapp.append(np.mean(data_product, axis=0))
self.datap_std.append(np.std(data_product, axis=0, ddof=1))
self.time = time
def fit_model(self, model_type='logistic'):
if model_type == 'logistic':
self.fit_biomass = self.fit_biomass_logistic
self.fit_substrate = self.fit_substrate_logistic
self.fit_product = self.fit_product_logistic
def fit_biomass_logistic(self, time, biomass, bounds):
popt, _ = curve_fit(self.logistic, time, biomass, bounds=bounds, maxfev=10000)
self.params['biomass'] = {'xo': popt[0], 'xm': popt[1], 'um': popt[2]}
y_pred = self.logistic(time, *popt)
self.r2['biomass'] = 1 - (np.sum((biomass - y_pred) ** 2) / np.sum((biomass - np.mean(biomass)) ** 2))
self.rmse['biomass'] = np.sqrt(mean_squared_error(biomass, y_pred))
return y_pred
def fit_substrate_logistic(self, time, substrate, biomass_params, bounds):
popt, _ = curve_fit(lambda t, so, p, q: self.substrate(t, so, p, q, *biomass_params.values()),
time, substrate, bounds=bounds)
self.params['substrate'] = {'so': popt[0], 'p': popt[1], 'q': popt[2]}
y_pred = self.substrate(time, *popt, *biomass_params.values())
self.r2['substrate'] = 1 - (np.sum((substrate - y_pred) ** 2) / np.sum((substrate - np.mean(substrate)) ** 2))
self.rmse['substrate'] = np.sqrt(mean_squared_error(substrate, y_pred))
return y_pred
def fit_product_logistic(self, time, product, biomass_params, bounds):
popt, _ = curve_fit(lambda t, po, alpha, beta: self.product(t, po, alpha, beta, *biomass_params.values()),
time, product, bounds=bounds)
self.params['product'] = {'po': popt[0], 'alpha': popt[1], 'beta': popt[2]}
y_pred = self.product(time, *popt, *biomass_params.values())
self.r2['product'] = 1 - (np.sum((product - y_pred) ** 2) / np.sum((product - np.mean(product)) ** 2))
self.rmse['product'] = np.sqrt(mean_squared_error(product, y_pred))
return y_pred
def plot_combined_results(self, time, biomass, substrate, product,
y_pred_biomass, y_pred_substrate, y_pred_product,
biomass_std=None, substrate_std=None, product_std=None,
experiment_name='', legend_position='best', params_position='upper right',
show_legend=True, show_params=True,
style='whitegrid', line_color='#0000FF', point_color='#000000',
line_style='-', marker_style='o'):
sns.set_style(style)
fig, ax1 = plt.subplots(figsize=(10, 7))
ax1.set_xlabel('Tiempo')
ax1.set_ylabel('Biomasa', color=line_color)
ax1.plot(time, biomass, marker=marker_style, linestyle='', color=point_color, label='Biomasa (Datos)')
ax1.plot(time, y_pred_biomass, linestyle=line_style, color=line_color, label='Biomasa (Modelo)')
ax1.tick_params(axis='y', labelcolor=line_color)
ax2 = ax1.twinx()
ax2.set_ylabel('Sustrato', color='green')
ax2.plot(time, substrate, marker=marker_style, linestyle='', color='green', label='Sustrato (Datos)')
ax2.plot(time, y_pred_substrate, linestyle=line_style, color='green', label='Sustrato (Modelo)')
ax2.tick_params(axis='y', labelcolor='green')
ax3 = ax1.twinx()
ax3.spines["right"].set_position(("axes", 1.1))
ax3.set_ylabel('Producto', color='red')
ax3.plot(time, product, marker=marker_style, linestyle='', color='red', label='Producto (Datos)')
ax3.plot(time, y_pred_product, linestyle=line_style, color='red', label='Producto (Modelo)')
ax3.tick_params(axis='y', labelcolor='red')
fig.tight_layout()
return fig
|