SKILL.md
Experimental Design Guide
A skill for designing rigorous experiments using formal Design of Experiments (DOE) methodology. Covers factorial designs, fractional factorials, response surface methods, and optimal design strategies for scientific research.
Fundamental Principles
Fisher's Three Principles
- Randomization: Assign experimental units to treatments randomly to eliminate systematic bias
- Replication: Include enough replicates to estimate experimental error and ensure statistical power
- Blocking: Group similar experimental units to reduce nuisance variability
Sample Size and Power Analysis
from scipy import stats
import numpy as np
def power_analysis_ttest(effect_size: float, alpha: float = 0.05,
power: float = 0.80, ratio: float = 1.0) -> dict:
"""
Calculate required sample size for a two-sample t-test.
Args:
effect_size: Cohen's d (expected effect size)
alpha: Significance level
power: Desired statistical power
ratio: Ratio of n2/n1 (for unequal groups)
"""
from statsmodels.stats.power import TTestIndPower
analysis = TTestIndPower()
n1 = analysis.solve_power(
effect_size=effect_size,
alpha=alpha,
power=power,
ratio=ratio,
alternative='two-sided'
)
return {
'n_per_group': int(np.ceil(n1)),
'total_n': int(np.ceil(n1) + np.ceil(n1 * ratio)),
'effect_size_d': effect_size,
'alpha': alpha,
'power': power,
'interpretation': (
f"Need {int(np.ceil(n1))} per group "
f"(total N = {int(np.ceil(n1) + np.ceil(n1 * ratio))}) "
f"to detect d = {effect_size} with {power*100:.0f}% power."
)
}
# Example: medium effect size
result = power_analysis_ttest(effect_size=0.5, alpha=0.05, power=0.80)
print(result['interpretation'])
Full Factorial Designs
2^k Factorial Design
import itertools
import pandas as pd
def create_factorial_design(factors: dict, replicates: int = 3) -> pd.DataFrame:
"""
Create a full factorial experimental design.
Args:
factors: Dict mapping factor names to lists of levels
e.g., {'Temperature': [60, 80], 'Pressure': [1, 2], 'Catalyst': ['A', 'B']}
replicates: Number of replicates per combination
"""
factor_names = list(factors.keys())
factor_levels = list(factors.values())
# Generate all combinations
combinations = list(itertools.product(*factor_levels))
# Create design matrix with replicates
rows = []
run_order = 0
for rep in range(replicates):
for combo in combinations:
run_order += 1
row = {'Run': run_order, 'Replicate': rep + 1}
for name, value in zip(factor_names, combo):
row[name] = value
row['Response'] = None # To be filled with experimental data
rows.append(row)
design = pd.DataFrame(rows)
# Randomize run order
design = design.sample(frac=1, random_state=42).reset_index(drop=True)
design['RandomizedRun'] = range(1, len(design) + 1)
print(f"Design summary:")
print(f" Factors: {len(factors)}")
print(f" Levels per factor: {[len(v) for v in factors.values()]}")
print(f" Total treatments: {len(combinations)}")
print(f" Replicates: {replicates}")
print(f" Total runs: {len(design)}")
return design
# Example: 2^3 factorial
design = create_factorial_design({
'Temperature': [60, 80],
'Pressure': [1, 2],
'Catalyst': ['A', 'B']
}, replicates=3)
