Chapter 20: Key Takeaways - Recruiting Analytics
Quick Reference Summary
This chapter covered applying analytics to college football recruiting, from prospect evaluation to program efficiency measurement.
Core Concepts
Star Rating Distributions
| Star Rating | National Count/Year | Historical Starter Rate | Draft Rate |
|---|---|---|---|
| 5-star | ~30 | 85% | 55% |
| 4-star | ~320 | 65% | 22% |
| 3-star | ~1,800 | 35% | 6% |
| 2-star | ~5,000 | 12% | 1.5% |
Key Metrics
| Metric | Definition | Typical Range |
|---|---|---|
| Composite Rating | Combined rating (0.8-1.0) | 0.8500-0.9999 |
| Blue Chip Ratio | (4★ + 5★) / Total Roster | 20-60% |
| Development Efficiency | Actual Outcomes / Expected | 0.5-1.5 |
| Class Points | Sum of recruit ratings × 100 | 150-350 per class |
Essential Formulas
Reliability Weight for Ratings
reliability = seasons_of_college_data / (seasons + 2)
Example: After 2 seasons
reliability = 2 / (2 + 2) = 0.5
Expected Starters from Class
expected_starters = Σ(recruits_by_star × starter_rate_by_star)
Example: 2 five-stars, 10 four-stars, 12 three-stars
expected = 2×0.85 + 10×0.65 + 12×0.35 = 12.4 starters
Development Efficiency
efficiency = actual_outcomes / expected_outcomes
efficiency > 1.0: Outperforming
efficiency < 1.0: Underperforming
Competition-Adjusted Statistics
adjusted_stat = raw_stat × (base_factor + adjustment × competition_factor)
Example: Y/C from smaller state
adjusted_ypc = 8.0 × (0.70 + 0.30 × 0.85) = 7.64
Code Patterns
Basic Prospect Evaluation
def evaluate_prospect(measurables: dict,
rating: float,
position: str) -> dict:
"""Evaluate a prospect."""
# Physical score (position-specific)
physical_score = calculate_physical_fit(measurables, position)
# Rating score (normalized to 0-100)
rating_score = (rating - 0.80) * 500
# Composite
composite = 0.35 * rating_score + 0.65 * physical_score
return {
'composite_score': composite,
'physical_score': physical_score,
'rating_score': rating_score,
'projection': get_projection(composite)
}
Position Needs Analysis
def analyze_needs(roster: pd.DataFrame,
targets: dict) -> dict:
"""Analyze roster needs by position."""
needs = {}
for position, target in targets.items():
current = roster[roster['position'] == position]
departing = current[current['class_year'] == 'SR']
returning = len(current) - len(departing)
if returning < target['min']:
needs[position] = 'critical'
elif returning < target['max']:
needs[position] = 'moderate'
else:
needs[position] = 'low'
return needs
Efficiency Calculation
def calculate_efficiency(recruits: pd.DataFrame) -> float:
"""Calculate development efficiency."""
# Expected outcomes by star rating
expected_rates = {5: 0.85, 4: 0.65, 3: 0.35, 2: 0.12}
expected = sum(
expected_rates.get(int(r['star_rating']), 0.20)
for _, r in recruits.iterrows()
)
actual = recruits['became_starter'].sum()
return actual / expected if expected > 0 else 1.0
Position-Specific Guidelines
Physical Profile Standards
| Position | Height Range | Weight Range | 40-Time Range |
|---|---|---|---|
| QB | 6'2"-6'6" | 210-240 | 4.5-5.0 |
| RB | 5'8"-6'1" | 195-225 | 4.35-4.6 |
| WR | 5'10"-6'4" | 180-220 | 4.30-4.55 |
| OT | 6'4"-6'8" | 290-330 | 5.0-5.4 |
| EDGE | 6'2"-6'6" | 240-275 | 4.5-4.8 |
| CB | 5'9"-6'2" | 180-205 | 4.3-4.5 |
Development Timelines
| Position | Typical Start Year | Notes |
|---|---|---|
| RB/WR | Year 1-2 | Earliest contributors |
| CB/S | Year 2 | Scheme learning |
| LB | Year 2-3 | Physical development |
| OL | Year 2-3 | Technique intensive |
| QB | Year 2-3 | System mastery |
| DL | Year 2-3 | Strength requirements |
Common Pitfalls
1. Over-Relying on Star Ratings
Wrong: Only recruiting 4-5 star players
# BAD - stars only
targets = recruits[recruits['star_rating'] >= 4]
Right: Consider efficiency and fit
# GOOD - rating + fit + need
targets = recruits[
(recruits['composite_rating'] >= 0.88) &
(recruits['position'].isin(critical_needs)) &
(recruits['fit_score'] >= 70)
]
2. Ignoring Competition Level
Wrong: Raw stat comparison
# BAD - raw stats
best_rb = prospects.sort_values('ypc', ascending=False)
Right: Adjusted comparison
# GOOD - adjusted for competition
prospects['adj_ypc'] = prospects.apply(
lambda x: adjust_for_competition(x['ypc'], x['classification']),
axis=1
)
best_rb = prospects.sort_values('adj_ypc', ascending=False)
3. Neglecting Position Needs
Wrong: BPA without balance
# BAD - pure BPA
class_selection = top_available[:25]
Right: Needs-aware selection
# GOOD - balanced approach
class_selection = optimize_class(
available,
position_needs,
scholarship_limit=25
)
Evaluation Checklist
Before Recruiting
- [ ] Analyze current roster composition
- [ ] Identify position needs by urgency
- [ ] Set target class composition
- [ ] Establish evaluation criteria
Prospect Evaluation
- [ ] Verify measurables from multiple sources
- [ ] Adjust statistics for competition
- [ ] Evaluate physical fit for position
- [ ] Consider development timeline
- [ ] Assess scheme fit
Class Analysis
- [ ] Calculate total class points
- [ ] Verify position distribution
- [ ] Project class impact by year
- [ ] Compare to historical classes
Post-Signing
- [ ] Track development against projections
- [ ] Calculate efficiency metrics
- [ ] Identify evaluation improvements
- [ ] Update models with outcomes
Quick Reference Tables
Recruiting Class Size Guidelines
| Situation | Target Size | Notes |
|---|---|---|
| Stable roster | 20-22 | Replace normal attrition |
| Rebuilding | 25 | Maximum allowed |
| Post-sanctions | 15-18 | Scholarship limits |
| Strong retention | 18-20 | Less replacement needed |
Commit Probability Benchmarks
| Stage | Typical Probability |
|---|---|
| Offered | 5-15% |
| Unofficial visit | 15-25% |
| Official visit | 30-50% |
| Crystal ball leader | 50-70% |
| Soft commit | 70-85% |
| Hard commit | 85-95% |
Efficiency Interpretation
| Efficiency Score | Interpretation |
|---|---|
| > 1.30 | Elite development program |
| 1.10 - 1.30 | Above average |
| 0.90 - 1.10 | Average |
| 0.70 - 0.90 | Below average |
| < 0.70 | Development concerns |
Red Flags
Warning signs in recruiting evaluation:
- Self-reported measurables only: Verify at camps
- No verified film: Limited evaluation basis
- Single-season production: Small sample size
- Weak competition: Inflated statistics
- Multiple transfers: Fit concerns
- Academic issues: Eligibility risk
- Character concerns: Program fit
Next Steps
After mastering recruiting analytics, proceed to: - Chapter 21: Win Probability Models - Chapter 22: Machine Learning Applications - Chapter 23: Network Analysis in Football