Skip to content
Back to skills

Bio Applied Enzyme Kinetics

ASecurity

Enzyme kinetics computational patterns — fitting Michaelis-Menten with scipy, bootstrap confidence intervals, inhibition type determination, allosteric cooperativity, and multi-substrate kinetics

  • 4 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 27, 2026
data-aipythongo

Works with

  • cli

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add Pavel-Kravchenko/Bioinformatics --skill bio-applied-enzyme-kinetics --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Bio Applied Enzyme Kinetics?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Bio Applied Enzyme Kinetics
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/pavel-kravchenko-bio-applied-enzyme-kinetics/badge)](https://www.skillsdirectory.com/skills/pavel-kravchenko-bio-applied-enzyme-kinetics)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: bio-applied-enzyme-kinetics
description: Enzyme kinetics computational patterns — fitting Michaelis-Menten with scipy, bootstrap confidence intervals, inhibition type determination, allosteric cooperativity, and multi-substrate kinetics
tool_type: python
primary_tool: NumPy
---

# Enzyme Kinetics: Computational Patterns

## Fitting Michaelis-Menten Parameters

```python
import numpy as np
from scipy.optimize import curve_fit

def michaelis_menten(S, vmax, km):
    return (vmax * S) / (km + S)

# Substrate concentrations should span 0.1*Km to 10*Km
substrate_uM = np.array([0.5, 1.0, 2.0, 3.0, 5.0, 7.5, 10.0, 15.0, 20.0, 30.0, 50.0])

popt, pcov = curve_fit(
    michaelis_menten, substrate_uM, observed_v,
    p0=[max(observed_v), substrate_uM[np.argmin(np.abs(observed_v - max(observed_v)/2))]],
    bounds=([0, 0], [np.inf, np.inf]),
    maxfev=5000
)
vmax_fit, km_fit = popt
perr = np.sqrt(np.diag(pcov))   # standard errors
ci95 = 1.96 * perr               # 95% confidence intervals

kcat = vmax_fit / enzyme_conc_uM                  # turnover number (s⁻¹)
catalytic_efficiency = kcat / km_fit              # M⁻¹s⁻¹ (if units in µM, multiply by 1e6)
```

## Parametric Bootstrap for Confidence Bands

```python
n_boot = 500
residuals = observed_v - michaelis_menten(substrate_uM, *popt)
residual_sd = np.std(residuals)
S_smooth = np.linspace(0, substrate_uM.max() * 1.1, 300)

boot_curves = np.zeros((n_boot, len(S_smooth)))
boot_params = np.zeros((n_boot, 2))

for i in range(n_boot):
    v_boot = michaelis_menten(substrate_uM, *popt) + np.random.normal(0, residual_sd, len(substrate_uM))
    v_boot = np.clip(v_boot, 0, None)
    try:
        p_boot, _ = curve_fit(michaelis_menten, substrate_uM, v_boot,
                               p0=popt, bounds=([0,0],[np.inf,np.inf]), maxfev=2000)
        boot_curves[i] = michaelis_menten(S_smooth, p_boot[0], p_boot[1])
        boot_params[i] = p_boot
    except RuntimeError:
        boot_curves[i] = np.nan

ci_low  = np.nanpercentile(boot_curves, 2.5, axis=0)
ci_high = np.nanpercentile(boot_curves, 97.5, axis=0)
```

## Inhibition Models and Identification

```python
def competitive(S, vmax, km, I, Ki):
    """Km increases; Vmax unchanged. Same lines in Eadie-Hofstee, different x-intercept in LB."""
    return (vmax * S) / (km * (1 + I/Ki) + S)

def uncompetitive(S, vmax, km, I, Ki):
    """Both Vmax and Km decrease by same factor alpha. Parallel lines in Lineweaver-Burk."""
    alpha = 1 + I/Ki
    return (vmax/alpha * S) / (km/alpha + S)

def noncompetitive(S, vmax, km, I, Ki):
    """Vmax decreases; Km unchanged. Lines intersect on x-axis in Lineweaver-Burk."""
    return (vmax/(1 + I/Ki) * S) / (km + S)

def mixed_inhibition(S, vmax, km, I, Ki, alpha):
    """General case: alpha=1 -> noncompetitive; alpha->inf -> competitive."""
    return (vmax * S) / (alpha * km * (1 + I/Ki) + S)
```

### Inhibition Type Identification

| Observation | Inhibition type |
|-------------|----------------|
| Vmax unchanged, Km increases | Competitive |
| Vmax decreases, Km unchanged | Noncompetitive |
| Both Vmax and Km decrease equally | Uncompetitive |
| Both change, different factors | Mixed |
| LB: parallel lines | Uncompetitive |
| LB: lines converge on x-axis | Noncompetitive |
| LB: lines converge left of y-axis | Competitive or mixed |

## Allosteric Cooperativity (Hill Equation)

```python
def hill_equation(S, vmax, K_half, n):
    """n > 1: positive cooperativity; n < 1: negative; n = 1: hyperbolic (MM)."""
    return (vmax * S**n) / (K_half**n + S**n)

popt_hill, _ = curve_fit(hill_equation, substrate_uM, observed_v,
                          p0=[max(observed_v), np.median(substrate_uM), 1.5],
                          bounds=([0, 0, 0.1], [np.inf, np.inf, 10]))
vmax_h, K05, n_hill = popt_hill
# K_half = [S] at half-maximal velocity (equivalent to Km when n=1)
```

## Multi-Substrate Kinetics (Ping-Pong vs Sequential)

```python
# Ping-pong (parallel lines in double reciprocal at varied [B])
def ping_pong(S_A, S_B, vmax, Km_A, Km_B):
    return vmax / (1 + Km_A/S_A + Km_B/S_B)

# Sequential (ternary complex, intersecting lines in double reciprocal)
def sequential(S_A, S_B, vmax, Km_A, Km_B, Ki_A):
    return (vmax * S_A * S_B) / (Ki_A*Km_B + Km_B*S_A + Km_A*S_B + S_A*S_B)
```

## Goodness of Fit

```python
from scipy.stats import chi2

# Residuals
residuals = observed_v - michaelis_menten(substrate_uM, *popt)
ss_res = np.sum(residuals**2)
ss_tot = np.sum((observed_v - observed_v.mean())**2)
r_squared = 1 - ss_res / ss_tot

# Chi-squared (if measurement variances are known)
chi2_stat = np.sum((residuals / measurement_sd)**2)
p_val = chi2.sf(chi2_stat, df=len(observed_v) - 2)

print(f"R² = {r_squared:.4f}")
print(f"Vmax = {vmax_fit:.2f} ± {ci95[0]:.2f} µM/s")
print(f"Km   = {km_fit:.2f} ± {ci95[1]:.2f} µM")
```

## Pitfalls

- **Bad initial guesses crash curve_fit**: estimate p0 from the data — Vmax ≈ max(observed_v) × 1.1, Km ≈ [S] where v ≈ Vmax/2; never use default p0=[1,1] for kinetic data
- **Bootstrap assumes residuals are homoscedastic**: enzyme kinetic noise is often proportional to velocity (heteroscedastic); in that case use weighted least squares (`sigma=observed_v`) in curve_fit
- **Hill n is sensitive to data range**: fitting the Hill equation requires data both below and above K_half; sparse data near inflection point gives unstable n estimates
- **Competitive vs mixed inhibition**: mixed inhibition with large alpha looks like competitive — measure at multiple inhibitor concentrations and use Dixon plot (1/v vs [I]) to distinguish
- **kcat requires total enzyme concentration**: convert Vmax to kcat only if [E]_total is accurately known from active-site titration, not total protein concentration (often contains inactive enzyme)
- **pcov returns inf when fit is underdetermined**: too few data points relative to parameters, or parameters are not independently identifiable from the data — add more substrate concentrations

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.