Summary
This experiment investigates kefir grain cultivation. Fractional factorial screening of milk fat content, fermentation time, grain-to-milk ratio, temperature, and agitation for probiotic count and taste.
The design varies 5 factors: fat pct (%), ranging from 0.5 to 4.0, ferm hrs (hrs), ranging from 12 to 48, grain ratio pct (%), ranging from 3 to 15, temp c (C), ranging from 18 to 28, and agitation (per_day), ranging from 0 to 3. The goal is to optimize 2 responses: probiotic score (pts) (maximize) and taste score (pts) (maximize). Fixed conditions held constant across all runs include milk type = whole_cow, vessel = glass_jar.
A fractional factorial design reduces the number of runs from 32 to 8 by deliberately confounding higher-order interactions. This is ideal for screening — identifying which of the 5 factors matter most before investing in a full study.
Key Findings
For probiotic score, the most influential factors were agitation (41.9%), fat pct (20.9%), temp c (18.6%). The best observed value was 8.6 (at fat pct = 4.0, ferm hrs = 12, grain ratio pct = 3).
For taste score, the most influential factors were ferm hrs (45.0%), temp c (32.1%), fat pct (15.6%). The best observed value was 7.2 (at fat pct = 4.0, ferm hrs = 48, grain ratio pct = 15).
Recommended Next Steps
- Follow up with a response surface design (CCD or Box-Behnken) on the top 3–4 factors to model curvature and find the true optimum.
- Consider whether any fixed factors should be varied in a future study.
- The screening results can guide factor reduction — drop factors contributing less than 5% and re-run with a smaller, more focused design.
Experimental Setup
Factors
| Factor | Low | High | Unit |
fat_pct | 0.5 | 4.0 | % |
ferm_hrs | 12 | 48 | hrs |
grain_ratio_pct | 3 | 15 | % |
temp_c | 18 | 28 | C |
agitation | 0 | 3 | per_day |
Fixed: milk_type = whole_cow, vessel = glass_jar
Responses
| Response | Direction | Unit |
probiotic_score | ↑ maximize | pts |
taste_score | ↑ maximize | pts |
Configuration
{
"metadata": {
"name": "Kefir Grain Cultivation",
"description": "Fractional factorial screening of milk fat content, fermentation time, grain-to-milk ratio, temperature, and agitation for probiotic count and taste"
},
"factors": [
{
"name": "fat_pct",
"levels": [
"0.5",
"4.0"
],
"type": "continuous",
"unit": "%"
},
{
"name": "ferm_hrs",
"levels": [
"12",
"48"
],
"type": "continuous",
"unit": "hrs"
},
{
"name": "grain_ratio_pct",
"levels": [
"3",
"15"
],
"type": "continuous",
"unit": "%"
},
{
"name": "temp_c",
"levels": [
"18",
"28"
],
"type": "continuous",
"unit": "C"
},
{
"name": "agitation",
"levels": [
"0",
"3"
],
"type": "continuous",
"unit": "per_day"
}
],
"fixed_factors": {
"milk_type": "whole_cow",
"vessel": "glass_jar"
},
"responses": [
{
"name": "probiotic_score",
"optimize": "maximize",
"unit": "pts"
},
{
"name": "taste_score",
"optimize": "maximize",
"unit": "pts"
}
],
"settings": {
"operation": "fractional_factorial",
"test_script": "use_cases/246_kefir_grains/sim.sh"
}
}
Experimental Matrix
The Fractional Factorial Design produces 8 runs. Each row is one experiment with specific factor settings.
| Run | fat_pct | ferm_hrs | grain_ratio_pct | temp_c | agitation |
| 1 | 0.5 | 48 | 15 | 18 | 0 |
| 2 | 4.0 | 12 | 3 | 18 | 0 |
| 3 | 4.0 | 48 | 3 | 28 | 0 |
| 4 | 4.0 | 48 | 15 | 28 | 3 |
| 5 | 0.5 | 48 | 3 | 18 | 3 |
| 6 | 4.0 | 12 | 15 | 18 | 3 |
| 7 | 0.5 | 12 | 3 | 28 | 3 |
| 8 | 0.5 | 12 | 15 | 28 | 0 |
Step-by-Step Workflow
1
Preview the design
$ doe info --config use_cases/246_kefir_grains/config.json
2
Generate the runner script
$ doe generate --config use_cases/246_kefir_grains/config.json \
--output use_cases/246_kefir_grains/results/run.sh --seed 42
3
Execute the experiments
$ bash use_cases/246_kefir_grains/results/run.sh
4
Analyze results
$ doe analyze --config use_cases/246_kefir_grains/config.json
5
Get optimization recommendations
$ doe optimize --config use_cases/246_kefir_grains/config.json
6
Multi-objective optimization
With 2 competing responses, use --multi to find the best compromise via Derringer–Suich desirability.
$ doe optimize --config use_cases/246_kefir_grains/config.json --multi
7
Generate the HTML report
$ doe report --config use_cases/246_kefir_grains/config.json \
--output use_cases/246_kefir_grains/results/report.html
Features Exercised
| Feature | Value |
| Design type | fractional_factorial |
| Factor types | continuous (all 5) |
| Arg style | double-dash |
| Responses | 2 (probiotic_score ↑, taste_score ↑) |
| Total runs | 8 |
Analysis Results
Generated from actual experiment runs using the DOE Helper Tool.
Response: probiotic_score
Top factors: agitation (41.9%), fat_pct (20.9%), temp_c (18.6%).
ANOVA
| Source | DF | SS | MS | F | p-value |
| Source | DF | SS | MS | F | p-value |
| fat_pct | 1 | 1.6200 | 1.6200 | 1.102 | 0.3419 |
| ferm_hrs | 1 | 0.0800 | 0.0800 | 0.054 | 0.8248 |
| grain_ratio_pct | 1 | 0.7200 | 0.7200 | 0.490 | 0.5152 |
| temp_c | 1 | 1.2800 | 1.2800 | 0.871 | 0.3936 |
| agitation | 1 | 6.4800 | 6.4800 | 4.408 | 0.0898 |
| fat_pct*ferm_hrs | 1 | 1.2800 | 1.2800 | 0.871 | 0.3936 |
| fat_pct*grain_ratio_pct | 1 | 6.4800 | 6.4800 | 4.408 | 0.0898 |
| fat_pct*temp_c | 1 | 0.0800 | 0.0800 | 0.054 | 0.8248 |
| fat_pct*agitation | 1 | 0.7200 | 0.7200 | 0.490 | 0.5152 |
| ferm_hrs*grain_ratio_pct | 1 | 0.9800 | 0.9800 | 0.667 | 0.4513 |
| ferm_hrs*temp_c | 1 | 1.6200 | 1.6200 | 1.102 | 0.3419 |
| ferm_hrs*agitation | 1 | 0.5000 | 0.5000 | 0.340 | 0.5851 |
| grain_ratio_pct*temp_c | 1 | 0.5000 | 0.5000 | 0.340 | 0.5851 |
| grain_ratio_pct*agitation | 1 | 1.6200 | 1.6200 | 1.102 | 0.3419 |
| temp_c*agitation | 1 | 0.9800 | 0.9800 | 0.667 | 0.4513 |
| Error | (Lenth | PSE) | 5 | 7.3500 | 1.4700 |
| Total | 7 | 11.6600 | 1.6657 | | |
Pareto Chart
Main Effects Plot
Normal Probability Plot of Effects
Half-Normal Plot of Effects
Model Diagnostics
Response: taste_score
Top factors: ferm_hrs (45.0%), temp_c (32.1%), fat_pct (15.6%).
ANOVA
| Source | DF | SS | MS | F | p-value |
| Source | DF | SS | MS | F | p-value |
| fat_pct | 1 | 0.3612 | 0.3612 | 2.379 | 0.1836 |
| ferm_hrs | 1 | 3.0012 | 3.0012 | 19.761 | 0.0067 |
| grain_ratio_pct | 1 | 0.0113 | 0.0113 | 0.074 | 0.7964 |
| temp_c | 1 | 1.5312 | 1.5312 | 10.082 | 0.0247 |
| agitation | 1 | 0.0312 | 0.0312 | 0.206 | 0.6691 |
| fat_pct*ferm_hrs | 1 | 1.5313 | 1.5313 | 10.082 | 0.0247 |
| fat_pct*grain_ratio_pct | 1 | 0.0312 | 0.0312 | 0.206 | 0.6691 |
| fat_pct*temp_c | 1 | 3.0012 | 3.0012 | 19.761 | 0.0067 |
| fat_pct*agitation | 1 | 0.0113 | 0.0113 | 0.074 | 0.7964 |
| ferm_hrs*grain_ratio_pct | 1 | 0.7812 | 0.7812 | 5.144 | 0.0726 |
| ferm_hrs*temp_c | 1 | 0.3613 | 0.3613 | 2.379 | 0.1836 |
| ferm_hrs*agitation | 1 | 0.1013 | 0.1013 | 0.667 | 0.4513 |
| grain_ratio_pct*temp_c | 1 | 0.1012 | 0.1012 | 0.667 | 0.4513 |
| grain_ratio_pct*agitation | 1 | 0.3612 | 0.3612 | 2.379 | 0.1836 |
| temp_c*agitation | 1 | 0.7812 | 0.7812 | 5.144 | 0.0726 |
| Error | (Lenth | PSE) | 5 | 0.7594 | 0.1519 |
| Total | 7 | 5.8187 | 0.8312 | | |
Pareto Chart
Main Effects Plot
Normal Probability Plot of Effects
Half-Normal Plot of Effects
Model Diagnostics
Response Surface Plots
3D surfaces fitted with quadratic RSM. Red dots are observed data points.
probiotic score fat pct vs agitation
probiotic score fat pct vs ferm hrs
probiotic score fat pct vs grain ratio pct
probiotic score fat pct vs temp c
probiotic score ferm hrs vs agitation
probiotic score ferm hrs vs grain ratio pct
probiotic score ferm hrs vs temp c
probiotic score grain ratio pct vs agitation
probiotic score grain ratio pct vs temp c
probiotic score temp c vs agitation
taste score fat pct vs agitation
taste score fat pct vs ferm hrs
taste score fat pct vs grain ratio pct
taste score fat pct vs temp c
taste score ferm hrs vs agitation
taste score ferm hrs vs grain ratio pct
taste score ferm hrs vs temp c
taste score grain ratio pct vs agitation
taste score grain ratio pct vs temp c
taste score temp c vs agitation
Multi-Objective Optimization
When responses compete, Derringer–Suich desirability finds the best compromise.
Each response is scaled to a 0–1 desirability, then combined via a weighted geometric mean.
Overall Desirability
D = 0.7510
Per-Response Desirability
| Response | Weight | Desirability | Predicted | Dir |
probiotic_score |
1.5 |
|
8.60 0.9545 8.60 pts |
↑ |
taste_score |
1.5 |
|
6.20 0.5909 6.20 pts |
↑ |
Recommended Settings
| Factor | Value |
fat_pct | 0.5 % |
ferm_hrs | 48 hrs |
grain_ratio_pct | 3 % |
temp_c | 18 C |
agitation | 3 per_day |
Source: from observed run #4
Trade-off Summary
Sacrifice = how much worse than single-objective best.
| Response | Predicted | Best Observed | Sacrifice |
taste_score | 6.20 | 7.20 | +1.00 |
Top 3 Runs by Desirability
| Run | D | Factor Settings |
| #3 | 0.6492 | fat_pct=4.0, ferm_hrs=48, grain_ratio_pct=15, temp_c=28, agitation=3 |
| #6 | 0.5102 | fat_pct=0.5, ferm_hrs=48, grain_ratio_pct=15, temp_c=18, agitation=0 |
Model Quality
| Response | R² | Type |
taste_score | 0.9515 | linear |
Full Multi-Objective Output
============================================================
MULTI-OBJECTIVE OPTIMIZATION
Method: Derringer-Suich Desirability Function
============================================================
Overall desirability: D = 0.7510
Response Weight Desirability Predicted Direction
---------------------------------------------------------------------
probiotic_score 1.5 0.9545 8.60 pts ↑
taste_score 1.5 0.5909 6.20 pts ↑
Recommended settings:
fat_pct = 0.5 %
ferm_hrs = 48 hrs
grain_ratio_pct = 3 %
temp_c = 18 C
agitation = 3 per_day
(from observed run #4)
Trade-off summary:
probiotic_score: 8.60 (best observed: 8.60, sacrifice: +0.00)
taste_score: 6.20 (best observed: 7.20, sacrifice: +1.00)
Model quality:
probiotic_score: R² = 0.8885 (linear)
taste_score: R² = 0.9515 (linear)
Top 3 observed runs by overall desirability:
1. Run #4 (D=0.7510): fat_pct=0.5, ferm_hrs=48, grain_ratio_pct=3, temp_c=18, agitation=3
2. Run #3 (D=0.6492): fat_pct=4.0, ferm_hrs=48, grain_ratio_pct=15, temp_c=28, agitation=3
3. Run #6 (D=0.5102): fat_pct=0.5, ferm_hrs=48, grain_ratio_pct=15, temp_c=18, agitation=0
Full Analysis Output
=== Main Effects: probiotic_score ===
Factor Effect Std Error % Contribution
--------------------------------------------------------------
agitation 1.8000 0.4563 41.9%
fat_pct -0.9000 0.4563 20.9%
temp_c -0.8000 0.4563 18.6%
grain_ratio_pct 0.6000 0.4563 14.0%
ferm_hrs -0.2000 0.4563 4.7%
=== ANOVA Table: probiotic_score ===
Source DF SS MS F p-value
-----------------------------------------------------------------------------
fat_pct 1 1.6200 1.6200 1.102 0.3419
ferm_hrs 1 0.0800 0.0800 0.054 0.8248
grain_ratio_pct 1 0.7200 0.7200 0.490 0.5152
temp_c 1 1.2800 1.2800 0.871 0.3936
agitation 1 6.4800 6.4800 4.408 0.0898
fat_pct*ferm_hrs 1 1.2800 1.2800 0.871 0.3936
fat_pct*grain_ratio_pct 1 6.4800 6.4800 4.408 0.0898
fat_pct*temp_c 1 0.0800 0.0800 0.054 0.8248
fat_pct*agitation 1 0.7200 0.7200 0.490 0.5152
ferm_hrs*grain_ratio_pct 1 0.9800 0.9800 0.667 0.4513
ferm_hrs*temp_c 1 1.6200 1.6200 1.102 0.3419
ferm_hrs*agitation 1 0.5000 0.5000 0.340 0.5851
grain_ratio_pct*temp_c 1 0.5000 0.5000 0.340 0.5851
grain_ratio_pct*agitation 1 1.6200 1.6200 1.102 0.3419
temp_c*agitation 1 0.9800 0.9800 0.667 0.4513
Error (Lenth PSE) 5 7.3500 1.4700
Total 7 11.6600 1.6657
Note: Error estimated using Lenth's pseudo-standard-error (unreplicated design)
=== Interaction Effects: probiotic_score ===
Factor A Factor B Interaction % Contribution
------------------------------------------------------------------------
fat_pct grain_ratio_pct -1.8000 23.7%
ferm_hrs temp_c -0.9000 11.8%
grain_ratio_pct agitation 0.9000 11.8%
fat_pct ferm_hrs -0.8000 10.5%
ferm_hrs grain_ratio_pct 0.7000 9.2%
temp_c agitation -0.7000 9.2%
fat_pct agitation -0.6000 7.9%
ferm_hrs agitation 0.5000 6.6%
grain_ratio_pct temp_c -0.5000 6.6%
fat_pct temp_c -0.2000 2.6%
=== Summary Statistics: probiotic_score ===
fat_pct:
Level N Mean Std Min Max
------------------------------------------------------------
0.5 4 6.5000 1.5875 5.0000 8.6000
4.0 4 5.6000 0.9092 4.6000 6.8000
ferm_hrs:
Level N Mean Std Min Max
------------------------------------------------------------
12 4 6.1500 0.7550 5.4000 6.8000
48 4 5.9500 1.8138 4.6000 8.6000
grain_ratio_pct:
Level N Mean Std Min Max
------------------------------------------------------------
15 4 5.7500 0.7550 5.0000 6.8000
3 4 6.3500 1.7540 4.6000 8.6000
temp_c:
Level N Mean Std Min Max
------------------------------------------------------------
18 4 6.4500 1.6279 5.0000 8.6000
28 4 5.6500 0.9000 4.6000 6.8000
agitation:
Level N Mean Std Min Max
------------------------------------------------------------
0 4 5.1500 0.4435 4.6000 5.6000
3 4 6.9500 1.2369 5.6000 8.6000
=== Main Effects: taste_score ===
Factor Effect Std Error % Contribution
--------------------------------------------------------------
ferm_hrs 1.2250 0.3223 45.0%
temp_c 0.8750 0.3223 32.1%
fat_pct -0.4250 0.3223 15.6%
agitation -0.1250 0.3223 4.6%
grain_ratio_pct 0.0750 0.3223 2.8%
=== ANOVA Table: taste_score ===
Source DF SS MS F p-value
-----------------------------------------------------------------------------
fat_pct 1 0.3612 0.3612 2.379 0.1836
ferm_hrs 1 3.0012 3.0012 19.761 0.0067
grain_ratio_pct 1 0.0113 0.0113 0.074 0.7964
temp_c 1 1.5312 1.5312 10.082 0.0247
agitation 1 0.0312 0.0312 0.206 0.6691
fat_pct*ferm_hrs 1 1.5313 1.5313 10.082 0.0247
fat_pct*grain_ratio_pct 1 0.0312 0.0312 0.206 0.6691
fat_pct*temp_c 1 3.0012 3.0012 19.761 0.0067
fat_pct*agitation 1 0.0113 0.0113 0.074 0.7964
ferm_hrs*grain_ratio_pct 1 0.7812 0.7812 5.144 0.0726
ferm_hrs*temp_c 1 0.3613 0.3613 2.379 0.1836
ferm_hrs*agitation 1 0.1013 0.1013 0.667 0.4513
grain_ratio_pct*temp_c 1 0.1012 0.1012 0.667 0.4513
grain_ratio_pct*agitation 1 0.3612 0.3612 2.379 0.1836
temp_c*agitation 1 0.7812 0.7812 5.144 0.0726
Error (Lenth PSE) 5 0.7594 0.1519
Total 7 5.8187 0.8312
Note: Error estimated using Lenth's pseudo-standard-error (unreplicated design)
=== Interaction Effects: taste_score ===
Factor A Factor B Interaction % Contribution
------------------------------------------------------------------------
fat_pct temp_c 1.2250 25.3%
fat_pct ferm_hrs 0.8750 18.0%
ferm_hrs grain_ratio_pct -0.6250 12.9%
temp_c agitation 0.6250 12.9%
ferm_hrs temp_c -0.4250 8.8%
grain_ratio_pct agitation 0.4250 8.8%
ferm_hrs agitation -0.2250 4.6%
grain_ratio_pct temp_c 0.2250 4.6%
fat_pct grain_ratio_pct 0.1250 2.6%
fat_pct agitation -0.0750 1.5%
=== Summary Statistics: taste_score ===
fat_pct:
Level N Mean Std Min Max
------------------------------------------------------------
0.5 4 6.4750 0.5315 5.9000 7.1000
4.0 4 6.0500 1.2396 4.7000 7.2000
ferm_hrs:
Level N Mean Std Min Max
------------------------------------------------------------
12 4 5.6500 0.8544 4.7000 6.7000
48 4 6.8750 0.4573 6.2000 7.2000
grain_ratio_pct:
Level N Mean Std Min Max
------------------------------------------------------------
15 4 6.2250 1.1758 4.7000 7.2000
3 4 6.3000 0.7439 5.3000 7.0000
temp_c:
Level N Mean Std Min Max
------------------------------------------------------------
18 4 5.8250 1.0500 4.7000 7.1000
28 4 6.7000 0.5715 5.9000 7.2000
agitation:
Level N Mean Std Min Max
------------------------------------------------------------
0 4 6.3250 0.8732 5.3000 7.1000
3 4 6.2000 1.0801 4.7000 7.2000
Optimization Recommendations
=== Optimization: probiotic_score ===
Direction: maximize
Best observed run: #4
fat_pct = 4.0
ferm_hrs = 12
grain_ratio_pct = 3
temp_c = 18
agitation = 0
Value: 8.6
RSM Model (linear, R² = 0.8182, Adj R² = 0.3636):
Coefficients:
intercept +6.0500
fat_pct +0.3500
ferm_hrs -0.4500
grain_ratio_pct +0.1500
temp_c -0.8500
agitation -0.3500
Predicted optimum (from linear model, at observed points):
fat_pct = 4.0
ferm_hrs = 12
grain_ratio_pct = 3
temp_c = 18
agitation = 0
Predicted value: 7.9000
Surface optimum (via L-BFGS-B, linear model):
fat_pct = 4
ferm_hrs = 12
grain_ratio_pct = 15
temp_c = 18
agitation = 0
Predicted value: 8.2000
Model quality: Good fit — general trends are captured, some noise remains.
Factor importance:
1. temp_c (effect: -1.7, contribution: 39.5%)
2. ferm_hrs (effect: -0.9, contribution: 20.9%)
3. fat_pct (effect: 0.7, contribution: 16.3%)
4. agitation (effect: -0.7, contribution: 16.3%)
5. grain_ratio_pct (effect: -0.3, contribution: 7.0%)
=== Optimization: taste_score ===
Direction: maximize
Best observed run: #6
fat_pct = 4.0
ferm_hrs = 48
grain_ratio_pct = 15
temp_c = 28
agitation = 3
Value: 7.2
RSM Model (linear, R² = 0.9807, Adj R² = 0.9323):
Coefficients:
intercept +6.2625
fat_pct +0.5125
ferm_hrs -0.2125
grain_ratio_pct -0.1375
temp_c +0.5375
agitation +0.3125
Predicted optimum (from linear model, at observed points):
fat_pct = 4.0
ferm_hrs = 48
grain_ratio_pct = 15
temp_c = 28
agitation = 3
Predicted value: 7.2750
Surface optimum (via L-BFGS-B, linear model):
fat_pct = 4
ferm_hrs = 12
grain_ratio_pct = 3
temp_c = 28
agitation = 3
Predicted value: 7.9750
Model quality: Excellent fit — surface predictions are reliable.
Factor importance:
1. temp_c (effect: 1.1, contribution: 31.4%)
2. fat_pct (effect: 1.0, contribution: 29.9%)
3. agitation (effect: 0.6, contribution: 18.2%)
4. ferm_hrs (effect: -0.4, contribution: 12.4%)
5. grain_ratio_pct (effect: 0.3, contribution: 8.0%)