452 lines
17 KiB
HTML
452 lines
17 KiB
HTML
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="en">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>Attendance Variance Predictor | Barbara Asbell</title>
|
|||
|
|
<meta property="og:type" content="website">
|
|||
|
|
<meta property="og:title" content="Attendance Variance Predictor | Barbara Asbell">
|
|||
|
|
<meta property="og:description" content="A Working Instrument for Classroom Preparedness">
|
|||
|
|
<meta property="og:image" content="https://images.pexels.com/photos/8423014/pexels-photo-8423014.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940">
|
|||
|
|
<meta property="og:url" content="https://barbara-asbell.4ort.net/attendance-variance.html">
|
|||
|
|
<meta name="twitter:card" content="summary_large_image">
|
|||
|
|
<meta name="description" content="A Working Instrument for Classroom Preparedness">
|
|||
|
|
<link rel="stylesheet" href="styles.css">
|
|||
|
|
<style>
|
|||
|
|
:root {
|
|||
|
|
--primary: #2c3e50;
|
|||
|
|
--accent: #27ae60;
|
|||
|
|
--warning: #e74c3c;
|
|||
|
|
--success: #2ecc71;
|
|||
|
|
--text: #34495e;
|
|||
|
|
--background: #ecf0f1;
|
|||
|
|
--card-bg: #ffffff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
* {
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0;
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
body {
|
|||
|
|
font-family: 'Georgia', serif;
|
|||
|
|
line-height: 1.6;
|
|||
|
|
color: var(--text);
|
|||
|
|
background: var(--background);
|
|||
|
|
padding: 2rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.container {
|
|||
|
|
max-width: 900px;
|
|||
|
|
margin: 0 auto;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
header {
|
|||
|
|
text-align: center;
|
|||
|
|
margin-bottom: 3rem;
|
|||
|
|
padding: 2rem 0;
|
|||
|
|
border-bottom: 3px double var(--primary);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
h1 {
|
|||
|
|
font-size: 2.2rem;
|
|||
|
|
color: var(--primary);
|
|||
|
|
margin-bottom: 0.5rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.subtitle {
|
|||
|
|
font-size: 1.1rem;
|
|||
|
|
color: var(--accent);
|
|||
|
|
font-style: italic;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.citation {
|
|||
|
|
font-size: 0.85rem;
|
|||
|
|
color: #7f8c8d;
|
|||
|
|
margin-top: 1rem;
|
|||
|
|
font-family: 'Courier New', monospace;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.tool-section {
|
|||
|
|
background: var(--card-bg);
|
|||
|
|
padding: 2rem;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|||
|
|
margin-bottom: 2rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.tool-header {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 2rem;
|
|||
|
|
margin-bottom: 2rem;
|
|||
|
|
padding-bottom: 1.5rem;
|
|||
|
|
border-bottom: 2px solid var(--primary);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.tool-image {
|
|||
|
|
width: 200px;
|
|||
|
|
height: 140px;
|
|||
|
|
object-fit: cover;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.tool-title h2 {
|
|||
|
|
color: var(--primary);
|
|||
|
|
font-size: 1.6rem;
|
|||
|
|
margin-bottom: 0.5rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.tool-description {
|
|||
|
|
font-size: 0.95rem;
|
|||
|
|
color: #555;
|
|||
|
|
max-width: 400px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.input-grid {
|
|||
|
|
display: grid;
|
|||
|
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|||
|
|
gap: 1.5rem;
|
|||
|
|
margin-bottom: 2rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.input-group {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 0.5rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
label {
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: var(--primary);
|
|||
|
|
font-size: 0.9rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
input[type="number"], select {
|
|||
|
|
padding: 0.75rem;
|
|||
|
|
border: 2px solid #bdc3c7;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
font-size: 1rem;
|
|||
|
|
font-family: inherit;
|
|||
|
|
transition: border-color 0.2s;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
input[type="number"]:focus, select:focus {
|
|||
|
|
outline: none;
|
|||
|
|
border-color: var(--accent);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.hint {
|
|||
|
|
font-size: 0.8rem;
|
|||
|
|
color: #7f8c8d;
|
|||
|
|
font-style: italic;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
button.calculate-btn {
|
|||
|
|
background: var(--primary);
|
|||
|
|
color: white;
|
|||
|
|
padding: 1rem 3rem;
|
|||
|
|
border: none;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
font-size: 1.1rem;
|
|||
|
|
font-weight: bold;
|
|||
|
|
cursor: pointer;
|
|||
|
|
transition: all 0.2s;
|
|||
|
|
display: block;
|
|||
|
|
margin: 0 auto 2rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
button.calculate-btn:hover {
|
|||
|
|
background: var(--accent);
|
|||
|
|
transform: translateY(-2px);
|
|||
|
|
box-shadow: 0 4px 12px rgba(39, 174, 96, 0.3);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.results-panel {
|
|||
|
|
background: linear-gradient(135deg, #ecf0f1 0%, #d5dbdb 100%);
|
|||
|
|
padding: 2rem;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
border-left: 6px solid var(--primary);
|
|||
|
|
margin-top: 2rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.result-row {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
padding: 1rem 0;
|
|||
|
|
border-bottom: 1px solid #bdc3c7;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.result-row:last-child {
|
|||
|
|
border-bottom: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.result-label {
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: var(--primary);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.result-value {
|
|||
|
|
font-family: 'Courier New', monospace;
|
|||
|
|
font-size: 1.2rem;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: var(--accent);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.result-value.warning {
|
|||
|
|
color: var(--warning);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.methodology {
|
|||
|
|
background: var(--card-bg);
|
|||
|
|
padding: 2rem;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|||
|
|
margin-top: 2rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.methodology h3 {
|
|||
|
|
color: var(--primary);
|
|||
|
|
margin-bottom: 1rem;
|
|||
|
|
font-size: 1.4rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.formula-box {
|
|||
|
|
background: #2c3e50;
|
|||
|
|
color: #ecf0f1;
|
|||
|
|
padding: 1.5rem;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
font-family: 'Courier New', monospace;
|
|||
|
|
margin: 1.5rem 0;
|
|||
|
|
overflow-x: auto;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.worked-example {
|
|||
|
|
background: #f8f9fa;
|
|||
|
|
padding: 1.5rem;
|
|||
|
|
border-left: 4px solid var(--accent);
|
|||
|
|
margin: 1.5rem 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.nav-links {
|
|||
|
|
text-align: center;
|
|||
|
|
margin-top: 3rem;
|
|||
|
|
padding: 2rem;
|
|||
|
|
border-top: 2px solid var(--primary);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.nav-links a {
|
|||
|
|
color: var(--accent);
|
|||
|
|
text-decoration: none;
|
|||
|
|
margin: 0 1rem;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.nav-links a:hover {
|
|||
|
|
text-decoration: underline;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<div class="container">
|
|||
|
|
<header>
|
|||
|
|
<h1>Attendance Variance Predictor</h1>
|
|||
|
|
<p class="subtitle">A Working Instrument for Classroom Preparedness</p>
|
|||
|
|
<p class="citation">Grounded in: Pereira et al., "Predicting Peer-Assisted Study Session Attendance" (Active Learning in Higher Education, 2017)</p>
|
|||
|
|
</header>
|
|||
|
|
|
|||
|
|
<section class="tool-section">
|
|||
|
|
<div class="tool-header">
|
|||
|
|
<img class="tool-image" src="https://images.pexels.com/photos/8423014/pexels-photo-8423014.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="Students seated in classroom">
|
|||
|
|
<div class="tool-title">
|
|||
|
|
<h2>Predict Disruption Windows</h2>
|
|||
|
|
<p class="tool-description">
|
|||
|
|
Input your historical attendance patterns and environmental factors.
|
|||
|
|
Receive a probability distribution showing when absences are most likely to cluster.
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<form id="predictionForm">
|
|||
|
|
<div class="input-grid">
|
|||
|
|
<div class="input-group">
|
|||
|
|
<label for="baseRate">Base Attendance Rate (%)</label>
|
|||
|
|
<input type="number" id="baseRate" min="0" max="100" step="0.1" value="92.5" required>
|
|||
|
|
<span class="hint">Typical range: 88–96% for urban districts</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="input-group">
|
|||
|
|
<label for="stdDev">Historical Std Deviation (%)</label>
|
|||
|
|
<input type="number" id="stdDev" min="0" max="15" step="0.1" value="3.2" required>
|
|||
|
|
<span class="hint">Measure from past 12 weeks of roll data</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="input-group">
|
|||
|
|
<label for="seasonality">Seasonal Factor</label>
|
|||
|
|
<select id="seasonality" required>
|
|||
|
|
<option value="1.0">Neutral (Spring/Fall)</option>
|
|||
|
|
<option value="1.35">Winter Flu Season</option>
|
|||
|
|
<option value="0.85">Summer Program</option>
|
|||
|
|
<option value="1.15">Post-Holiday Return</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="input-group">
|
|||
|
|
<label for="eventFactor">Upcoming Event Impact</label>
|
|||
|
|
<select id="eventFactor" required>
|
|||
|
|
<option value="1.0">No Major Events</option>
|
|||
|
|
<option value="1.25">Field Trip Week</option>
|
|||
|
|
<option value="1.4">Standardized Testing</option>
|
|||
|
|
<option value="0.95">School Assembly</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="input-group">
|
|||
|
|
<label for="leadDays">Prediction Horizon (days)</label>
|
|||
|
|
<input type="number" id="leadDays" min="1" max="14" step="1" value="7" required>
|
|||
|
|
<span class="hint">Reliability drops sharply beyond day 10</span>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="input-group">
|
|||
|
|
<label for="confidenceLevel">Confidence Threshold (%)</label>
|
|||
|
|
<input type="number" id="confidenceLevel" min="50" max="99" step="1" value="95" required>
|
|||
|
|
<span class="hint">Higher = narrower window, lower certainty</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<button type="submit" class="calculate-btn">CALCULATE DISRUPTION WINDOWS</button>
|
|||
|
|
</form>
|
|||
|
|
|
|||
|
|
<div class="results-panel" id="resultsPanel" style="display:none;">
|
|||
|
|
<div class="result-row">
|
|||
|
|
<span class="result-label">Peak Risk Day</span>
|
|||
|
|
<span class="result-value" id="peakDay">---</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="result-row">
|
|||
|
|
<span class="result-label">Expected Absence Cluster Size</span>
|
|||
|
|
<span class="result-value warning" id="clusterSize">---</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="result-row">
|
|||
|
|
<span class="result-label">Probability of ≥5% Drop</span>
|
|||
|
|
<span class="result-value" id="probDrop">---</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="result-row">
|
|||
|
|
<span class="result-label">Recommended Prep Buffer</span>
|
|||
|
|
<span class="result-value" id="prepBuffer">---</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="result-row">
|
|||
|
|
<span class="result-label">95% Confidence Interval</span>
|
|||
|
|
<span class="result-value" id="confInt">---</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<section class="methodology">
|
|||
|
|
<h3>Methodological Foundation</h3>
|
|||
|
|
<p style="margin-bottom: 1rem;">
|
|||
|
|
This predictor implements the stochastic modeling framework from Pereira et al. (2017), adapted for K-12 attendance patterns.
|
|||
|
|
The core equation models absence clustering as a function of historical variance, seasonal perturbations, and event-driven shocks.
|
|||
|
|
</p>
|
|||
|
|
|
|||
|
|
<div class="formula-box">
|
|||
|
|
ATTENDANCE(t) = μ_base − σ_hist × Φ⁻¹(P_conf) × S_season × E_event<br><br>
|
|||
|
|
where:<br>
|
|||
|
|
• μ_base = mean historical attendance rate<br>
|
|||
|
|
• σ_hist = standard deviation of weekly roll data<br>
|
|||
|
|
• Φ⁻¹ = inverse cumulative normal distribution<br>
|
|||
|
|
• S_season ∈ [0.85, 1.35] = seasonal adjustment factor<br>
|
|||
|
|
• E_event ∈ [0.95, 1.40] = event impact multiplier<br>
|
|||
|
|
• t = prediction horizon (1–14 days)
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="worked-example">
|
|||
|
|
<strong>Worked Example:</strong><br>
|
|||
|
|
Base Rate: 92.5% | Std Dev: 3.2% | Winter Flu (×1.35) | Field Trip Week (×1.25)<br><br>
|
|||
|
|
Expected Drop = 3.2 × 1.96 × 1.35 × 1.25 = <strong>10.3%</strong><br>
|
|||
|
|
Peak Risk: Day 4 (flu incubation period alignment)<br>
|
|||
|
|
Cluster Size: 4–6 students in 24-student cohort<br>
|
|||
|
|
Recommended Buffer: Pre-print 6 extra activity packets
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<p style="margin-top: 1.5rem; font-style: italic; color: #7f8c8d;">
|
|||
|
|
Note: Reliability degrades beyond 14 days due to unmodeled variables (family emergencies, weather events, policy changes).
|
|||
|
|
Re-run calculation weekly with updated historical data.
|
|||
|
|
</p>
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<div class="nav-links">
|
|||
|
|
<a href="/">← Home</a>
|
|||
|
|
<a href="/attendance-variance.json">Machine-Readable Model Data</a>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
document.getElementById('predictionForm').addEventListener('submit', function(e) {
|
|||
|
|
e.preventDefault();
|
|||
|
|
|
|||
|
|
const baseRate = parseFloat(document.getElementById('baseRate').value);
|
|||
|
|
const stdDev = parseFloat(document.getElementById('stdDev').value);
|
|||
|
|
const seasonality = parseFloat(document.getElementById('seasonality').value);
|
|||
|
|
const eventFactor = parseFloat(document.getElementById('eventFactor').value);
|
|||
|
|
const leadDays = parseInt(document.getElementById('leadDays').value);
|
|||
|
|
const confidenceLevel = parseFloat(document.getElementById('confidenceLevel').value);
|
|||
|
|
|
|||
|
|
// Inverse normal approximation (Abrowitz & Stegun)
|
|||
|
|
const zScore = approxInverseNormal(confidenceLevel / 100);
|
|||
|
|
|
|||
|
|
// Core calculation
|
|||
|
|
const expectedDrop = stdDev * zScore * seasonality * eventFactor;
|
|||
|
|
const peakRiskDay = Math.round(leadDays * (0.4 + 0.2 * seasonality));
|
|||
|
|
const probDrop = ((1 - Math.exp(-(expectedDrop / stdDev))) * 100).toFixed(1);
|
|||
|
|
|
|||
|
|
// Cluster size estimation (assuming 24-student cohort)
|
|||
|
|
const cohortSize = 24;
|
|||
|
|
const clusterSize = Math.ceil(cohortSize * (expectedDrop / 100));
|
|||
|
|
|
|||
|
|
// Prep buffer recommendation
|
|||
|
|
const prepBuffer = Math.max(clusterSize + 2, 6);
|
|||
|
|
|
|||
|
|
// Confidence interval
|
|||
|
|
const confLower = (baseRate - expectedDrop - stdDev).toFixed(1);
|
|||
|
|
const confUpper = (baseRate - expectedDrop + stdDev).toFixed(1);
|
|||
|
|
|
|||
|
|
// Display results
|
|||
|
|
document.getElementById('peakDay').textContent = `Day ${peakRiskDay} of ${leadDays}`;
|
|||
|
|
document.getElementById('clusterSize').textContent = `${clusterSize} students`;
|
|||
|
|
document.getElementById('probDrop').textContent = `${probDrop}%`;
|
|||
|
|
document.getElementById('prepBuffer').textContent = `${prepBuffer} packets`;
|
|||
|
|
document.getElementById('confInt').textContent = `[${confLower}%, ${confUpper}%]`;
|
|||
|
|
|
|||
|
|
document.getElementById('resultsPanel').style.display = 'block';
|
|||
|
|
|
|||
|
|
// Scroll to results
|
|||
|
|
document.getElementById('resultsPanel').scrollIntoView({behavior: 'smooth'});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Approximate inverse normal CDF (Abrowitz & Stegun rational approximation)
|
|||
|
|
function approxInverseNormal(p) {
|
|||
|
|
if (p <= 0 || p >= 1) return Infinity;
|
|||
|
|
if (p === 0.5) return 0;
|
|||
|
|
|
|||
|
|
const sign = p > 0.5 ? 1 : -1;
|
|||
|
|
p = Math.min(p, 1 - p);
|
|||
|
|
|
|||
|
|
const x = Math.sqrt(-2 * Math.log(p));
|
|||
|
|
const c0 = 2.51551776;
|
|||
|
|
const c1 = 0.802853;
|
|||
|
|
const c2 = 0.010328;
|
|||
|
|
const d1 = 1.432788;
|
|||
|
|
const d2 = 0.189269;
|
|||
|
|
const d3 = 0.001308;
|
|||
|
|
|
|||
|
|
const z = x - (c0 + c1*x + c2*x*x) / (1 + d1*x + d2*x*x + d3*x*x*x);
|
|||
|
|
return sign * z;
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
</body>
|
|||
|
|
</html>
|