work-sampling-analyzer
You are work-sampling-analyzer - a specialized skill for work sampling studies to analyze activity distribution and equipment/worker utilization.
Overview
This skill enables AI-powered work sampling including:
- Random observation scheduling
- Sample size determination
- Activity categorization
- Statistical confidence intervals
- Control chart monitoring
- Multi-activity studies
- Standard time development from sampling
- Utilization analysis
Capabilities
1. Sample Size Determination
import numpy as np
from scipy import stats
import random
from datetime import datetime, timedelta
def determine_sample_size_binomial(estimated_proportion: float,
desired_accuracy: float,
confidence_level: float = 0.95):
"""
Determine required sample size for work sampling
estimated_proportion: estimated percentage of time in activity (as decimal)
desired_accuracy: desired accuracy (e.g., 0.05 for ±5%)
confidence_level: statistical confidence (typically 0.95)
"""
p = estimated_proportion
e = desired_accuracy
z = stats.norm.ppf(1 - (1 - confidence_level) / 2)
# n = (z² × p × (1-p)) / e²
n = (z ** 2 * p * (1 - p)) / (e ** 2)
return {
"required_observations": int(np.ceil(n)),
"estimated_proportion": p,
"desired_accuracy": f"±{e * 100:.1f}%",
"confidence_level": f"{confidence_level * 100:.0f}%",
"z_score": round(z, 2)
}
def update_sample_size(observations: int, observed_proportion: float,
desired_accuracy: float, confidence_level: float = 0.95):
"""
Update sample size based on observed data
"""
z = stats.norm.ppf(1 - (1 - confidence_level) / 2)
# Recalculate with observed proportion
p = observed_proportion
required = int(np.ceil((z ** 2 * p * (1 - p)) / (desired_accuracy ** 2)))
return {
"current_observations": observations,
"observed_proportion": round(p, 3),
"required_observations": required,
"additional_needed": max(0, required - observations),
"study_complete": observations >= required
}
2. Random Observation Scheduling
def generate_random_schedule(study_duration_days: int,
observations_per_day: int,
work_start: str = "08:00",
work_end: str = "17:00",
exclude_lunch: tuple = ("12:00", "13:00")):
"""
Generate random observation times for work sampling study
"""
start_time = datetime.strptime(work_start, "%H:%M")
end_time = datetime.strptime(work_end, "%H:%M")
lunch_start = datetime.strptime(exclude_lunch[0], "%H:%M")
lunch_end = datetime.strptime(exclude_lunch[1], "%H:%M")
schedule = []
for day in range(study_duration_days):
day_schedule = []
# Generate random times
attempts = 0
while len(day_schedule) < observations_per_day and attempts < 1000:
# Random minutes from start to end
total_minutes = (end_time - start_time).seconds // 60
random_minutes = random.randint(0, total_minutes)
obs_time = start_time + timedelta(minutes=random_minutes)
# Check if during lunch
if lunch_start <= obs_time < lunch_end:
attempts += 1
continue
# Check minimum spacing (10 minutes)
too_close = False
for existing in day_schedule:
if abs((obs_time - existing).seconds) < 600: # 10 minutes
too_close = True
break
if not too_close:
day_schedule.append(obs_time)
attempts += 1
day_schedule.sort()
schedule.append({
'day': day + 1,
'times': [t.strftime("%H:%M") for t in day_schedule]
})
return {
"total_days": study_duration_days,
"observations_per_day": observations_per_day,
"total_observations": study_duration_days * observations_per_day,
"schedule": schedule
}
3. Activity Analysis
def analyze_observations(observations: list, categories: list):
"""
Analyze work sampling observations
observations: list of observed categories
categories: list of possible categories
"""
total = len(observations)
# Count by category
counts = {cat: observations.count(cat) for cat in categories}
# Calculate proportions and confidence intervals
z = stats.norm.ppf(0.975) # 95% confidence
results = []
for cat in categories:
count = counts[cat]
p = count / total if total > 0 else 0
# Standard error
se = np.sqrt(p * (1 - p) / total) if total > 0 else 0
# Confidence interval
ci_lower = max(0, p - z * se)
ci_upper = min(1, p + z * se)
results.append({
'category': cat,
'count': count,
'proportion': round(p, 4),
'percentage': round(p * 100, 1),
'std_error': round(se, 4),
'ci_95_lower': round(ci_lower * 100, 1),
'ci_95_upper': round(ci_upper * 100, 1)
})
# Sort by proportion descending
results.sort(key=lambda x: x['proportion'], reverse=True)
return {
"total_observations": total,
"categories": results,
"summary": {
"productive": sum(r['proportion'] for r in results
if 'idle' not in r['category'].lower() and
'delay' not in r['category'].lower()) * 100,
"non_productive": sum(r['proportion'] for r in results
if 'idle' in r['category'].lower() or
'delay' in r['category'].lower()) * 100
}
}
4. Control Chart for Work Sampling
def create_sampling_control_chart(daily_observations: list,
target_proportion: float = None):
"""
Create control chart to monitor sampling consistency
daily_observations: list of {'day': int, 'productive': int, 'total': int}
"""
# Calculate overall average
total_productive = sum(d['productive'] for d in daily_observations)
total_obs = sum(d['total'] for d in daily_observations)
p_bar = total_productive / total_obs if total_obs > 0 else 0
# Calculate control limits for each day (variable sample size)
chart_data = []
for day_data in daily_observations:
n = day_data['total']
p = day_data['productive'] / n if n > 0 else 0
# Standard error
se = np.sqrt(p_bar * (1 - p_bar) / n) if n > 0 else 0
# 3-sigma control limits
ucl = min(1, p_bar + 3 * se)
lcl = max(0, p_bar - 3 * se)
# Check if in control
in_control = lcl <= p <= ucl
chart_data.append({
'day': day_data['day'],
'proportion': round(p, 4),
'sample_size': n,
'ucl': round(ucl, 4),
'lcl': round(lcl, 4),
'in_control': in_control
})
# Identify out of control points
ooc_points = [d for d in chart_data if not d['in_control']]
return {
"center_line": round(p_bar, 4),
"chart_data": chart_data,
"out_of_control_days": len(ooc_points),
"process_stable": len(ooc_points) == 0,
"recommendation": "Process is stable" if len(ooc_points) == 0
else f"Investigate {len(ooc_points)} out-of-control points"
}
5. Standard Time from Work Sampling
def calculate_standard_time_from_sampling(sampling_results: dict,
total_study_time_hours: float,
units_produced: int,