mcpField
W
workforce-scheduling

workforce-scheduling

github.com/kishorkukrejaその他8483 回インストール3 週間前に更新
リポジトリ

workforce-scheduling について

倉庫やサプライチェーン運営向けの人員配置スキルです。需要、人件費、従業員の勤務可能時間、スキル、コンプライアンス上の制約を考慮したシフト計画を支援します。

主な機能

  1. 01労働需要と人員供給の評価
  2. 02シフト設計方式の比較
  3. 03配置目標と制約の定式化
  4. 04貪欲法や整数計画法の活用
  5. 05希望条件とリアルタイム変更への対応
  6. 06シフト・コスト・指標のレポート作成

活用シーン

  1. 01需要が変動する倉庫のシフト計画
  2. 02通常勤務・残業・臨時雇用の調整
  3. 03勤務可能時間・スキル・休息規則の考慮
  4. 04欠勤や需要急増への対応

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/kishorkukreja/awesome-supply-chain --skill workforce-scheduling

インストール後、Claude Code で/workforce-schedulingを入力して読み込まれたか確認します。

詳細

労働力のシフトスケジューリング

倉庫およびサプライチェーン業務における労働力のシフトスケジューリングと労働力の最適化の専門家です。労働力の供給を需要に合わせ、コストを最小限に抑え、コンプライアンスを確保し、従業員の満足度を高める最適なシフトスケジュールの作成を支援します。

初期評価

労働力のシフトスケジューリングを最適化する前に、次の項目を把握します。

  1. 労働需要

    • 日次/週次の注文量のパターンはどのようになっていますか?
    • 繁忙期や季節性はありますか?
    • 実施する作業(ピッキング、梱包、入荷処理)は何ですか?
    • 必要なスキルや資格は何ですか?
    • サービスレベルの目標(納期どおりの出荷)は何ですか?
  2. 労働力の供給

    • 労働力の総人数(フルタイム、パートタイム、臨時)は何人ですか?
    • 従業員の勤務可能時間や希望はどのようになっていますか?
    • スキルレベルやクロストレーニングの状況はどうなっていますか?
    • 希望するシフトの長さ(8時間、10時間、12時間)はどれですか?
    • 労働組合の規則や労働協約はありますか?
  3. 業務上の制約

    • 稼働時間(週5日24時間、週7日24時間、日勤のみ)はどのようになっていますか?
    • 最低必要人員数は何人ですか?
    • 連続勤務日数の上限はありますか?
    • 残業の規則とコストはどのようになっていますか?
    • 休憩や食事時間に関する要件はありますか?
    • 週末や祝日の人員配置は必要ですか?
  4. 現状

    • 現在のスケジュール作成方法(手作業、ソフトウェア)は何ですか?
    • 現在の労務費(通常勤務+残業)はいくらですか?
    • 労働力の稼働率はどのくらいですか?
    • 従業員は現在のスケジュールに満足していますか?
    • スケジュールの変更頻度はどのくらいですか?

労働力のシフトスケジューリングの枠組み

スケジューリングの目標

主な目標:

  1. 需要への適合:予測される業務量に対して十分な労働力を確保します
  2. コストの最小化:通常勤務時間、残業、臨時従業員の構成を最適化します
  3. 稼働率の最大化:待機時間や過剰人員を削減します
  4. 従業員の満足度:希望、公平性、ワークライフバランスを考慮します
  5. コンプライアンス:労働法、労働組合の規則、会社の方針を遵守します

主な指標:

  • 単位あたりの労務費(注文あたりのドル額、ピッキングした明細行あたりのドル額)
  • 労働力の稼働率(%)(生産的な時間/スケジュール上の時間)
  • スケジュール効率(実績と計画の労働時間の比較)
  • 従業員の離職率と欠勤率
  • 残業率(残業時間/総労働時間)
シフト設計の戦略

1. 固定シフト

  • 毎週同じスケジュール
  • メリット:予定が立てやすく、生活設計がしやすい
  • デメリット:柔軟性がなく、需要に合わない場合があります
  • 用途:需要が安定している場合、労働組合のある職場

2. ローテーションシフト

  • 従業員が異なるシフトを順番に担当します
  • メリット:好ましくないシフトを公平に分担できます
  • デメリット:概日リズムを乱し、従業員の負担が増えます
  • 用途:24時間365日の業務、公平性を重視する場合

3. 柔軟/変動シフト

  • シフトの開始時刻や長さが変動します
  • メリット:需要に合わせ、コストを削減できます
  • デメリット:従業員にとって予定が立てにくく、スケジュール作成も難しくなります
  • 用途:需要が変動する場合、労務費への感度が高い場合

4. 圧縮労働週

  • 週5日8時間の代わりに、週4日10時間または週3日12時間勤務にします
  • メリット:勤務日数が少なく、従業員に好まれ、必要な人員を確保できます
  • デメリット:疲労が蓄積し、割増賃金が必要になる場合があります
  • 用途:継続的な業務、従業員の定着

5. オンコール/フレックス人員

  • 必要に応じて労働時間を変動させます
  • メリット:柔軟性が最大限に高く、コスト効率に優れています
  • デメリット:従業員が予定を立てにくく、離職率が上がる場合があります
  • 用途:繁忙期、予備要員の確保

数理的な定式化

最適化問題としての労働力スケジューリング

決定変数:

  • x[i,s,d] = 従業員 i が日 d にシフト s で勤務する場合は 1、それ以外は 0
  • y[s,d] = 日 d のシフト s に配置する従業員数
  • o[i,d] = 従業員 i の日 d の残業時間

パラメーター:

  • D[s,d] = 日 d のシフト s に必要な労働時間
  • C_reg = 通常勤務の時給
  • C_ot = 残業の時給(通常は通常勤務の時給の1.5倍)
  • C_temp = 臨時従業員の時給
  • A[i,s,d] = 従業員 i が日 d のシフト s に勤務できるかどうか(0 または 1)
  • H[s] = シフト s の長さ(時間)
  • Max_hours[i] = 従業員 i の週あたりの最大勤務時間
  • Min_rest = シフト間に必要な最小休息時間

目的関数:

Minimize:
  Total Labor Cost = Regular + Overtime + Temp + Penalties

Formally:
  Σ Σ Σ (C_reg × H[s] × x[i,s,d])  # Regular time
  + Σ Σ (C_ot × o[i,d])  # Overtime
  + Σ Σ (C_temp × temp_hours[s,d])  # Temporary workers
  + α × (Σ schedule_disruption_penalty)  # Preference violations
  + β × (Σ understaffing_penalty)  # Demand shortfall

制約条件:

# 1. Meet demand (with possible understaffing penalty)
for s in shifts:
    for d in days:
        Σ (H[s] × x[i,s,d]) + temp_hours[s,d] >= D[s,d]

# 2. Each employee works at most one shift per day
for i in employees:
    for d in days:
        Σ x[i,s,d] <= 1  for all s

# 3. Respect employee availability
for i in employees:
    for s in shifts:
        for d in days:
            x[i,s,d] <= A[i,s,d]

# 4. Maximum hours per week
for i in employees:
    for week in weeks:
        Σ Σ (H[s] × x[i,s,d]) <= Max_hours[i]  for d in week, s in shifts

# 5. Minimum rest between shifts
for i in employees:
    for d in days[:-1]:
        if x[i, evening_shift, d] = 1:
            x[i, morning_shift, d+1] = 0  # Example: no evening then morning

# 6. Maximum consecutive working days
for i in employees:
    for d in days:
        Σ x[i,s,d'] <= 6  for d' in [d...d+6], s in shifts

# 7. Minimum employees per shift (coverage)
for s in shifts:
    for d in days:
        Σ x[i,s,d] >= Min_coverage[s,d]  for all i

# 8. Skill requirements
for s in shifts:
    for d in days:
        Σ x[i,s,d] × skill[i,k] >= required_skill[k,s,d]
          for all i, k in skills

スケジューリングアルゴリズム

貪欲法による需要主導型スケジューリング
import pandas as pd
import numpy as np
from datetime import datetime, timedelta

def greedy_workforce_scheduling(demand, employees, shifts, days):
    """
    Greedy heuristic for workforce scheduling

    Algorithm:
    1. Sort days by demand (highest first)
    2. For each day, assign employees to meet demand
    3. Prioritize employees with availability and low weekly hours

    Parameters:
    -----------
    demand : dict
        {(shift, day): required_hours}
    employees : DataFrame
        Columns: employee_id, max_hours_per_week, availability
    shifts : list
        Shift identifiers
    days : list
        Day identifiers (e.g., dates)

    Returns:
    --------
    Schedule assignments
    """

    # Initialize schedule
    schedule = []
    employee_hours = {emp['employee_id']: 0 for _, emp in employees.iterrows()}

    # Sort (shift, day) pairs by demand
    demand_sorted = sorted(demand.items(), key=lambda x: x[1], reverse=True)

    for (shift, day), required_hours in demand_sorted:
        assigned_hours = 0

        # Get available employees for this shift/day
        available_employees = employees[
            employees['availability'].apply(lambda x: (shift, day) in x)
        ].copy()

        # Sort by current hours worked (assign to those with fewer hours first)
        available_employees['current_hours'] = available_employees['employee_id'].map(employee_hours)
        available_employees = available_employees.sort_values('current_hours')

        # Assign employees until demand met
        for idx, emp in available_employees.iterrows():
            emp_id = emp['employee_id']
            shift_length = 8  # Assume 8-hour shifts

            # Check if employee can work (not exceeding max hours)
            if employee_hours[emp_id] + shift_length <= emp['max_hours_per_week']:
                # Assign employee
                schedule.append({
                    'employee_id': emp_id,
                    'shift': shift,
                    'day': day,
                    'hours': shift_length
                })

                employee_hours[emp_id] += shift_length
                assigned_hours += shift_length

                if assigned_hours >= required_hours:
                    break

        # Check if demand met
        if assigned_hours < required_hours:
            print(f"Warning: Understaffed on {day}, shift {shift} "
                  f"({assigned_hours}/{required_hours} hours)")

    return pd.DataFrame(schedule)


# Example usage
employees = pd.DataFrame({
    'employee_id': [f'EMP{i:03d}' for i in range(1, 21)],
    'max_hours_per_week': [40] * 15 + [20] * 5,  # 15 full-time, 5 part-time
    'availability': [
        [(s, d) for s in ['morning', 'afternoon', 'evening']
         for d in range(7)]  # Available all shifts/days
        for _ in range(20)
    ]
})

shifts = ['morning', 'afternoon', 'evening']
days = list(range(7))  # Monday=0, Sunday=6

# Demand varies by day and shift
demand = {
    (shift, day): np.random.randint(40, 120)
    for shift in shifts for day in days
}

# Higher demand on weekdays, mornings and afternoons
for day in range(5):  # Mon-Fri
    demand[('morning', day)] *= 1.5
    demand[('afternoon', day)] *= 1.3

schedule = greedy_workforce_scheduling(demand, employees, shifts, days)

print("Workforce Schedule:")
print(f"Total Scheduled Hours: {schedule['hours'].sum()}")
print(f"Employees Scheduled: {schedule['employee_id'].nunique()}")
print(f"\nSchedule by Shift:")
print(schedule.groupby('shift')['hours'].sum())
整数計画モデル
from pulp import *

def optimize_workforce_schedule(demand, employees, shifts, days,
                                cost_regular=20, cost_overtime=30):
    """
    Optimal workforce scheduling using MIP

    Parameters:
    -----------
    demand : dict
        {(shift, day): hours_needed}
    employees : DataFrame
        Employee data with availability and constraints
    shifts : list
        Available shifts
    days : list
        Days to schedule
    cost_regular : float
        Regular hourly cost
    cost_overtime : float
        Overtime hourly cost

    Returns:
    --------
    Optimal schedule
    """

    prob = LpProblem("Workforce_Scheduling", LpMinimize)

    # Decision variables
    # x[emp, shift, day] = 1 if employee works this shift on this day
    x = LpVariable.dicts("assign",
                        [(emp['employee_id'], shift, day)
                         for _, emp in employees.iterrows()
                         for shift in shifts
                         for day in days],
                        cat='Binary')

    # Overtime hours variables
    overtime = LpVariable.dicts("overtime",
                               [(emp['employee_id'], day)
                                for _, emp in employees.iterrows()
                                for day in days],
                               lowBound=0,
                               cat='Continuous')

    # Understaffing variables (soft constraint)
    understaffed = LpVariable.dicts("understaffed",
                                   [(shift, day) for shift in shifts for day in days],
                                   lowBound=0,
                                   cat='Continuous')

    # Objective: minimize cost
    shift_hours = 8  # Assume 8-hour shifts

    prob += (
        # Regular time cost
        cost_regular * shift_hours * lpSum([
            x[emp['employee_id'], shift, day]
            for _, emp in employees.iterrows()
            for shift in shifts
            for day in days
        ]) +

        # Overtime cost
        cost_overtime * lpSum([
            overtime[emp['employee_id'], day]
            for _, emp in employees.iterrows()
            for day in days
        ]) +

        # Understaffing penalty (high cost)
        1000 * lpSum([
            understaffed[shift, day]
            for shift in shifts
            for day in days
        ])
    ), "Total_Cost"

    # Constraints

    # 1. Meet demand (with possible understaffing)
    for shift in shifts:
        for day in days:
            prob += (
                lpSum([
                    shift_hours * x[emp['employee_id'], shift, day]
                    for _, emp in employees.iterrows()
                ]) + understaffed[shift, day] >= demand.get((shift, day), 0)
            ), f"Demand_{shift}_{day}"

    # 2. Each employee works at most one shift per day
    for _, emp in employees.iterrows():
        for day in days:
            prob += lpSum([
                x[emp['employee_id'], shift, day]
                for shift in shifts
            ]) <= 1, f"OneShift_{emp['employee_id']}_{day}"

    # 3. Maximum 40 hours per week for full-time (simplified to 5 shifts)
    for _, emp in employees.iterrows():
        max_shifts = emp['max_hours_per_week'] // shift_hours

        prob += lpSum([
            x[emp['employee_id'], shift, day]
            for shift in shifts
            for day in days
        ]) <= max_shifts, f"MaxHours_{emp['employee_id']}"

    # 4. Calculate overtime (hours beyond 40)
    for _, emp in employees.iterrows():
        total_hours = lpSum([
            shift_hours * x[emp['employee_id'], shift, day]
            for shift in shifts
            for day in days
        ])

        prob += (
            overtime[emp['employee_id'], days[0]] >= total_hours - emp['max_hours_per_week']
        ), f"Overtime_{emp['employee_id']}"

    # Solve
    prob.solve(PULP_CBC_CMD(msg=0))

    # Extract solution
    schedule = []
    for _, emp in employees.iterrows():
        for shift in shifts:
            for day in days:
                if x[emp['employee_id'], shift, day].varValue > 0.5:
                    schedule.append({
                        'employee_id': emp['employee_id'],
                        'shift': shift,
                        'day': day,
                        'hours': shift_hours
                    })

    return {
        'status': LpStatus[prob.status],
        'total_cost': value(prob.objective),
        'schedule': pd.DataFrame(schedule)
    }


result = optimize_workforce_schedule(demand, employees, shifts, days)

print(f"\nOptimization Status: {result['status']}")
print(f"Total Cost: ${result['total_cost']:,.2f}")
print(f"\nSchedule Summary:")
print(result['schedule'].groupby('shift').size())

高度なスケジューリング手法

シフト入札と希望に基づくスケジューリング
class PreferenceBasedScheduler:
    """
    Schedule based on employee preferences and seniority
    """

    def __init__(self, employees, shifts, days):
        self.employees = employees
        self.shifts = shifts
        self.days = days
        self.schedule = []

    def collect_preferences(self):
        """
        Collect employee shift preferences (1-10 scale)

        In practice, would come from employee input system
        """

        preferences = {}

        for _, emp in self.employees.iterrows():
            emp_id = emp['employee_id']
            preferences[emp_id] = {}

            for shift in self.shifts:
                for day in self.days:
                    # Simulate: random preference score
                    # Higher = more preferred
                    preferences[emp_id][(shift, day)] = np.random.randint(1, 11)

        return preferences

    def schedule_with_preferences(self, demand, preferences, seniority):
        """
        Create schedule considering preferences and seniority

        Algorithm:
        1. Sort employees by seniority
        2. Senior employees pick preferred shifts first
        3. Fill remaining shifts with junior employees
        4. Balance to meet demand

        Parameters:
        -----------
        demand : dict
            Required staffing
        preferences : dict
            {employee_id: {(shift, day): preference_score}}
        seniority : dict
            {employee_id: years_of_service}

        Returns:
        --------
        Schedule with preference satisfaction
        """

        # Sort employees by seniority
        employees_sorted = sorted(
            self.employees['employee_id'],
            key=lambda emp_id: seniority.get(emp_id, 0),
            reverse=True
        )

        remaining_demand = demand.copy()
        employee_assignments = {emp: 0 for emp in employees_sorted}

        schedule = []

        # Round 1: Senior employees pick top preferences
        for emp_id in employees_sorted:
            emp_prefs = preferences[emp_id]

            # Get top 5 preferred shifts
            top_prefs = sorted(emp_prefs.items(),
                             key=lambda x: x[1],
                             reverse=True)[:5]

            for (shift, day), pref_score in top_prefs:
                # Check if this slot still needs staffing
                if remaining_demand.get((shift, day), 0) > 0:
                    # Check if employee hasn't exceeded weekly hours
                    if employee_assignments[emp_id] < 5:  # Max 5 shifts/week
                        schedule.append({
                            'employee_id': emp_id,
                            'shift': shift,
                            'day': day,
                            'hours': 8,
                            'preference_score': pref_score
                        })

                        employee_assignments[emp_id] += 1
                        remaining_demand[(shift, day)] -= 8

                        break  # Move to next employee

        # Round 2: Fill remaining demand with available employees
        for (shift, day), needed_hours in remaining_demand.items():
            if needed_hours > 0:
                # Find employees not yet at capacity
                available = [
                    emp for emp in employees_sorted
                    if employee_assignments[emp] < 5
                ]

                for emp_id in available:
                    if needed_hours <= 0:
                        break

                    schedule.append({
                        'employee_id': emp_id,
                        'shift': shift,
                        'day': day,
                        'hours': 8,
                        'preference_score': preferences[emp_id].get((shift, day), 0)
                    })

                    employee_assignments[emp_id] += 1
                    needed_hours -= 8

        schedule_df = pd.DataFrame(schedule)

        # Calculate satisfaction metrics
        avg_preference = schedule_df['preference_score'].mean()
        pref_above_7 = (schedule_df['preference_score'] >= 7).sum() / len(schedule_df) * 100

        return {
            'schedule': schedule_df,
            'avg_preference_score': avg_preference,
            'percent_preferred_shifts': pref_above_7
        }


# Example
scheduler = PreferenceBasedScheduler(employees, shifts, days)
preferences = scheduler.collect_preferences()
seniority = {f'EMP{i:03d}': np.random.randint(1, 15) for i in range(1, 21)}

result_pref = scheduler.schedule_with_preferences(demand, preferences, seniority)

print("\nPreference-Based Scheduling:")
print(f"Average Preference Score: {result_pref['avg_preference_score']:.2f}/10")
print(f"Preferred Shifts (7+): {result_pref['percent_preferred_shifts']:.1f}%")
リアルタイム調整による動的スケジューリング
class DynamicScheduleManager:
    """
    Manage real-time schedule adjustments

    Handle call-outs, demand surges, schedule swaps
    """

    def __init__(self, base_schedule, employee_pool):
        self.base_schedule = base_schedule
        self.employee_pool = employee_pool
        self.adjustments = []

    def handle_callout(self, employee_id, shift, day):
        """
        Handle employee call-out and find replacement

        Priority:
        1. Overtime for already-scheduled employees
        2. On-call employees
        3. Temporary workers
        """

        print(f"Call-out: {employee_id} for {shift} on day {day}")

        # Option 1: Ask already-scheduled employees if they can extend/add shift
        same_day_workers = self.base_schedule[
            (self.base_schedule['day'] == day) &
            (self.base_schedule['employee_id'] != employee_id)
        ]

        if len(same_day_workers) > 0:
            # Offer overtime to current workers
            replacement = same_day_workers.iloc[0]['employee_id']
            print(f"  Replacement: {replacement} (overtime)")

            self.adjustments.append({
                'type': 'replacement',
                'original': employee_id,
                'replacement': replacement,
                'shift': shift,
                'day': day,
                'cost': 'overtime'
            })

            return replacement

        # Option 2: Call on-call employee
        on_call = self.employee_pool[self.employee_pool['type'] == 'on_call']

        if len(on_call) > 0:
            replacement = on_call.iloc[0]['employee_id']
            print(f"  Replacement: {replacement} (on-call)")

            self.adjustments.append({
                'type': 'replacement',
                'original': employee_id,
                'replacement': replacement,
                'shift': shift,
                'day': day,
                'cost': 'regular'
            })

            return replacement

        # Option 3: Hire temp worker
        print(f"  Replacement: TEMP (temporary agency)")

        self.adjustments.append({
            'type': 'replacement',
            'original': employee_id,
            'replacement': 'TEMP',
            'shift': shift,
            'day': day,
            'cost': 'temp_agency'
        })

        return 'TEMP'

    def handle_demand_surge(self, shift, day, additional_hours_needed):
        """
        Handle unexpected demand increase

        Options:
        1. Extend shifts (overtime)
        2. Call in off-duty employees
        3. Hire temps
        """

        print(f"Demand surge: +{additional_hours_needed} hours needed for {shift} on day {day}")

        # Option 1: Extend current shift
        current_workers = self.base_schedule[
            (self.base_schedule['shift'] == shift) &
            (self.base_schedule['day'] == day)
        ]

        if len(current_workers) > 0:
            # Ask workers to extend shift
            overtime_per_worker = additional_hours_needed / len(current_workers)

            print(f"  Solution: Extend shift for {len(current_workers)} workers "
                  f"({overtime_per_worker:.1f} OT hours each)")

            self.adjustments.append({
                'type': 'overtime',
                'shift': shift,
                'day': day,
                'employees': current_workers['employee_id'].tolist(),
                'ot_hours': overtime_per_worker
            })

            return 'overtime'

        # Option 2: Call in off-duty
        # (implementation similar to call-out)

        return 'temp'


# Example usage
manager = DynamicScheduleManager(schedule, employees)

# Simulate call-out
manager.handle_callout('EMP005', 'morning', 2)

# Simulate demand surge
manager.handle_demand_surge('afternoon', 3, 24)

print(f"\nTotal Adjustments: {len(manager.adjustments)}")

ツールとライブラリ

要員スケジューリングソフトウェア

専門的なスケジューリング:

  • Workforce Software (Kronos):エンタープライズ向けスケジューリングと勤怠管理
  • ADP Workforce Now:人事とスケジューリングの統合
  • Shiftboard:シフトスケジューリングと労務管理
  • When I Work:従業員向けスケジューリングアプリ
  • Deputy:要員管理プラットフォーム
  • 7shifts:飲食店・小売店向けスケジューリング
  • Humanity (TCP):従業員のスケジューリングと勤怠管理

労務管理機能を備えたWMS:

  • Manhattan WMS:労務管理システム(LMS)
  • Blue Yonder (JDA) WMS:労務計画とスケジューリング
  • SAP EWM:統合された労務管理
  • HighJump WMS:標準作業時間を設定したLMSモジュール
Pythonライブラリ
# Optimization
from pulp import *
from ortools.sat.python import cp_model

# Scheduling
import pandas as pd
import numpy as np
from datetime import datetime, timedelta

# Constraint Programming
from constraint import Problem, AllDifferentConstraint

よくある課題と解決策

課題:予測できない需要

問題:

  • 1日の注文量が±30%変動する
  • 必要な要員数を正確に予測できない
  • 過剰人員(コストの無駄)または人員不足(出荷漏れ)が発生する

解決策:

  • 柔軟な要員体制(中核要員+柔軟要員プール)
  • オンコール従業員(4時間前の通知)
  • 複数の業務を担当できるようにクロストレーニングする
  • 動的スケジューリング(勤務中に調整)
  • 残業を緩衝策として活用する(費用は高いものの効果的)
  • 派遣会社と提携する(迅速に人員を増やせる)
課題:従業員の勤務可能時間の制約

問題:

  • 学生は夕方や週末のみ勤務可能
  • 親は特定の時間帯(送迎)を必要とする
  • 副業によって勤務可能時間が限られる
  • 勤務不可の希望が多い

解決策:

  • セルフサービスのシフト入札システム
  • パートタイム従業員を採用して要員数を増やす
  • 人気の低いシフトには割増賃金を支払う
  • スケジュールを事前に通知する(2週間以上前)
  • シフト交換を認める(従業員同士)
  • 最適化に勤務可能時間の制約を反映する
課題:公平性と士気

問題:

  • いつも週末が休みの従業員がいる
  • 勤続年数の長い従業員が好条件のシフトを得る
  • えこひいきだと受け取られる
  • 士気の低下が生産性に影響する

解決策:

  • スケジューリングのルールを透明化する
  • 人気の低いシフトを公平にローテーションする
  • 勤続年数に基づくシフト入札(公平な手続き)
  • 週末シフトを均等に割り当てる
  • 公平性の指標を追跡し、公表する
  • スケジューリングに関する匿名のフィードバックを募る
課題:必要なスキル構成

問題:

  • すべての従業員がすべての業務を担当できるわけではない
  • フォークリフトの認定オペレーターが必要
  • 品質管理には経験豊富な作業員が必要
  • 勤務可能時間だけを基準にスケジュールを組めない

解決策:

  • 従業員データベースでスキルを管理する
  • 最適化にスキルの制約を含める
  • シフトごとに必要な有資格者の最低人数を設定する
  • クロストレーニングプログラムを実施する(スキルの幅を広げる)
  • 重要なスキルには手当を支給する
  • 資格の取得状況と更新を管理する
課題:直前の変更

問題:

  • 急な欠勤(病気、緊急事態)
  • 需要の急増(予期しない大口注文)
  • 設備の故障(追加の人員が必要)
  • スケジュールが実情に合わなくなる

解決策:

  • オンコール要員のプール(要員の10〜15%)
  • 欠勤時の自動通知
  • 派遣会社との継続契約
  • 残業の承認ルール
  • リアルタイムでスケジュールを調整するアプリ
  • 5〜10%の欠勤率を想定する

出力形式

従業員スケジュールレポート

週間スケジュール - 2024年1月15日~21日の週

スケジュールの概要:

曜日シフト従業員数合計時間需要(時間)稼働率
月午前12969296%
月午後10807898%
月夜間6484594%
火午前11888597%
..................

従業員の割り当て:

Employee: EMP001 (John Smith)
  Mon: Morning (6:00-14:00)
  Tue: Morning (6:00-14:00)
  Wed: Morning (6:00-14:00)
  Thu: Morning (6:00-14:00)
  Fri: Afternoon (14:00-22:00)
  Total: 40 hours

Employee: EMP002 (Jane Doe)
  Mon: Afternoon (14:00-22:00)
  Wed: Afternoon (14:00-22:00)
  Thu: Evening (22:00-6:00)
  Sat: Morning (6:00-14:00)
  Total: 32 hours (Part-time)

...

コスト分析:

区分時間時給コスト
通常勤務1,520$20/hr$30,400
残業85$30/hr$2,550
臨時雇用40$25/hr$1,000
合計1,645-$33,950

パフォーマンス指標:

  • 平均稼働率:95%
  • 残業の割合:5.2%
  • 従業員満足度(希望):8.2/10
  • 配置率:100%(人員不足のシフトなし)
  • 1時間あたりのコスト:$20.64

スケジュールの遵守状況:

  • ✓ すべてのシフトで最低人員数を満たしています
  • ✓ 通常勤務時間が40時間を超える従業員はいません
  • ✓ シフト間に最低11時間の休息時間があります
  • ✓ 連続勤務日数が6日を超える従業員はいません
  • ✓ スキル要件を満たしています(フォークリフト、QC)

確認事項

さらに詳しい情報が必要な場合は、以下をご確認ください。

  1. 営業時間とシフト体制はどのようになっていますか?
  2. 従業員数(フルタイム、パートタイム)はどれくらいですか?
  3. 需要はどのように変動しますか(日次、週次、季節ごと)?
  4. どのようなスケジュール上の制約がありますか(労働組合、残業規則)?
  5. 現在、どのような方法でスケジュールを作成していますか?
  6. 人件費の内訳はどのようになっていますか(通常勤務、残業、臨時雇用)?
  7. 従業員に勤務可能時間の制約や希望はありますか?
  8. スキルや資格の要件はありますか?

関連スキル

  • task-assignment-problem:作業者を特定のタスクに割り当てる場合
  • capacity-planning:長期的な人員計画を立てる場合
  • wave-planning-optimization:人員を考慮してピッキングのウェーブを計画する場合
  • demand-forecasting:人員需要を予測する場合
  • constraint-programming:複雑なスケジュール制約を扱う場合
  • optimization-modeling:数学的なスケジュールモデルを作成する場合
  • production-scheduling:製造業の人員スケジュールを作成する場合

コメント