# 🏢 Dự Đoán Nhân Sự Ca Làm Việc

> **Hệ thống Machine Learning dự đoán số lượng nhân sự cần thiết cho mỗi ca làm việc dựa trên đặc điểm tòa nhà và công việc**

---

## 📋 Mục Lục

- [Tổng Quan](#-tổng-quan)
- [Cấu Trúc Dữ Liệu](#-cấu-trúc-dữ-liệu)
- [Các File Chính](#-các-file-chính)
- [Pipeline Dự Đoán](#-pipeline-dự-đoán)
- [Hướng Dẫn Sử Dụng](#-hướng-dẫn-sử-dụng)

---

## 🎯 Tổng Quan

Dự án này sử dụng Machine Learning để tự động dự đoán số lượng nhân sự cần thiết cho mỗi ca làm việc tại các tòa nhà, dựa trên:
- Đặc điểm vật lý của tòa nhà (diện tích, số tầng, số WC, v.v.)
- Loại công việc và nội dung công việc (text features)
- Thông tin ca làm việc (ca sáng, chiều, tối, đêm)

---

## 📊 Cấu Trúc Dữ Liệu

### 🗂️ Dữ Liệu Gốc (`data_raw/`)

#### 1. **`Link LLV 1_5_2025.json`**
📌 **Mục đích:** Chứa thông tin về các ca làm việc

**Nội dung:**
- Danh sách các ca làm việc của từng tòa nhà
- Thời gian làm việc (ca sáng, chiều, tối, đêm)
- Công việc thường (`all_task_normal`)
- Công việc định kỳ (`all_task_dinhky`)
- Số nhân sự thực tế cho mỗi ca

**Vai trò:** Cung cấp dữ liệu về **phân ca** và **nội dung công việc** cho model

---

#### 2. **`Link LLV 2025_clean.json`**
📌 **Mục đích:** Chứa thông tin về đặc điểm vật lý của các tòa nhà

**Nội dung:**
- Diện tích từng tầng của mỗi tòa nhà
- Số lượng WC, phòng, v.v.
- Thông tin cơ sở hạ tầng

**⚠️ LƯU Ý QUAN TRỌNG:**
> **Các trường liên quan đến diện tích trong `final_2.csv` là TỔNG diện tích của TẤT CẢ các tầng trong mỗi tòa nhà**, không phải diện tích trung bình hay diện tích một tầng!
> 
> Ví dụ: Nếu tòa nhà có 10 tầng, mỗi tầng 500m², thì `tong_dien_tich = 5000m²`

---

### 📈 Dữ Liệu Training

#### **`final_2.csv`** (hoặc `final_2.xlsx`)
📌 **Mục đích:** Dataset chính để huấn luyện model

**Nguồn dữ liệu:**
- **Thông tin ca làm việc** ← từ `data_raw/Link LLV 1_5_2025.json`
- **Thông tin diện tích tòa nhà** ← từ `data_raw/Link LLV 2025_clean.json` (TỔNG diện tích các tầng)

**Các nhóm features chính:**

| Nhóm Features | Nguồn | Ví dụ |
|---------------|-------|-------|
| **Thông tin ca** | Link LLV | `ca_sang`, `ca_chieu`, `ca_toi`, `ca_dem` |
| **Diện tích** | Link LLV 2025 | `tong_dien_tich`, `dien_tich_wc`, `dien_tich_hanh_lang` |
| **Cơ sở vật chất** | Link LLV 2025 | `so_tang`, `so_wc`, `so_phong` |
| **Text features** | Sinh ra từ tasks | `num_cleaning_tasks`, `cleaning_ratio`, `area_diversity` |
| **Target** | Link LLV | `so_nhan_su` (số nhân sự thực tế) |

---

## 📁 Các File Chính

### 1. 📓 **`All_feature_Readme.ipynb`**
> **Notebook giải thích chi tiết về Text Features**

**Nội dung:**
- 📖 Giải thích từng loại text feature được trích xuất từ công việc
- 🔍 Các keyword được sử dụng để nhận diện công việc
- 📊 Ví dụ minh họa cho từng feature
- 📈 Phân tích tầm quan trọng của các features

**Khi nào đọc:** Khi bạn muốn hiểu cách hệ thống trích xuất thông tin từ đoạn text công việc

---

### 2. 🤖 **`artifacts/`**
> **Thư mục chứa các model đã được huấn luyện**

**Các file trong thư mục:**

```
artifacts/
├── extratrees_log1p.joblib           # Model chính (Extra Trees với log transform)
├── extratrees_staff_model.joblib     # Model dự đoán nhân sự
├── model_meta.joblib                 # Metadata của model (params, metrics)
└── X_proc_columns.joblib             # Danh sách features và thứ tự columns
```

**Định dạng:** Joblib (compressed pickle format)

**Cách load:**
```python
import joblib
model = joblib.load('artifacts/extratrees_log1p.joblib')
```

---

### 3. 📄 **`input.json`**
> **File input mẫu để dự đoán cho MỘT ca làm việc của MỘT tòa nhà**

**Cấu trúc:**
```json
{
  "ma_dia_diem": "TD-001",
  "loai_ca": "Hành chính",
  "bat_dau": "07:00:00",
  "ket_thuc": "15:00:00",
  "tong_gio_lam": 8.0,
  "so_ca_cua_toa": 3,
  "all_task_normal": "Lau sàn hành lang; Thu gom rác WC; Vệ sinh sảnh chính; Lau kính thang máy",
  "all_task_dinhky": "Cọ bồn cầu WC tầng 2; Đánh sàn lobby; Trực phát sinh",
  "so_tang": 12,
  "so_cua_thang_may": 4,
  "dien_tich_ngoai_canh": 350.0,
  "dien_tich_sanh": 220.0,
  "dien_tich_hanh_lang": 1800.0,
  "dien_tich_wc": 420.0,
  "dien_tich_phong": 2600.0,
  "dien_tich_tham": 800.0,
  "dien_tich_kinh": 560.0,
  "doc_ham": 1,
  "vien_phan_quang": 0,
  "op_tuong": 1,
  "op_chan_tuong": 1,
  "ranh_thoat_nuoc": 1
}
```

#### 📝 Giải Thích Chi Tiết Các Trường:

**🏢 Thông tin tòa nhà & ca:**
- `ma_dia_diem`: Mã định danh tòa nhà
- `loai_ca`: Loại ca làm việc (Hành chính / Ca sáng / Ca chiều / Ca tối / Ca đêm)
- `bat_dau`, `ket_thuc`: Thời gian bắt đầu và kết thúc ca (HH:MM:SS)
- `tong_gio_lam`: Tổng số giờ làm việc trong ca
- `so_ca_cua_toa`: Tổng số ca làm việc trong ngày của tòa nhà

**📋 Công việc - 2 loại quan trọng:**

> **⭐ `all_task_normal` - CÔNG VIỆC HẰNG NGÀY:**
> - Các task được thực hiện **MỖI NGÀY** trong ca này
> - Ví dụ: Lau sàn, Thu rác, Vệ sinh WC (mỗi ngày đều phải làm)
> - **Tần suất:** Ngày nào cũng làm, ca nào cũng làm
> - **Format:** Các task cách nhau bởi dấu chấm phẩy (`;`)

> **⭐ `all_task_dinhky` - CÔNG VIỆC ĐỊNH KỲ (TUẦN/THÁNG):**
> - Các task được thực hiện **THEO TUẦN** hoặc **THEO THÁNG**
> - Ví dụ: Cọ bồn cầu (1 tuần/lần), Đánh sàn (1 tháng/lần), Trực phát sinh
> - **Tần suất:** Không làm hàng ngày, chỉ làm định kỳ
> - **Format:** Các task cách nhau bởi dấu chấm phẩy (`;`)

**Sự khác biệt:**
| | `all_task_normal` | `all_task_dinhky` |
|---|---|---|
| **Tần suất** | Hằng ngày | Theo tuần/tháng |
| **Ví dụ** | Lau sàn, Thu rác | Cọ rửa, Đánh sàn |
| **Khối lượng** | Công việc nhẹ, lặp lại | Công việc nặng, ít lần |

**🏗️ Đặc điểm vật lý:**
- `so_tang`: Tổng số tầng
- `so_cua_thang_may`: Số cửa thang máy

**📏 Diện tích (m²) - ⚠️ TỔNG TẤT CẢ CÁC TẦNG:**
- `dien_tich_ngoai_canh`: Khu vực ngoại cảnh (sân, vỉa hè)
- `dien_tich_sanh`: Sảnh, lobby
- `dien_tich_hanh_lang`: Hành lang, lối đi
- `dien_tich_wc`: WC, toilet
- `dien_tich_phong`: Các phòng (văn phòng, phòng họp)
- `dien_tich_tham`: Sàn có thảm
- `dien_tich_kinh`: Kính cần lau

> **⚠️ CHÚ Ý:** Tất cả diện tích là TỔNG của TẤT CẢ các tầng!
> 
> Ví dụ: Tòa 12 tầng, mỗi tầng 150m² hành lang → `dien_tich_hanh_lang = 1800m²`

**🔧 Đặc điểm bề mặt (1=Có, 0=Không):**
- `doc_ham`: Có tầng hầm
- `vien_phan_quang`: Có viền phản quang
- `op_tuong`: Có ốp tường
- `op_chan_tuong`: Có ốp chân tường
- `ranh_thoat_nuoc`: Có rãnh thoát nước

---

### 4. 🎯 **`all_predict.py`**
> **Script chính để chạy dự đoán**

**Chức năng:**
1. 📖 Đọc file `input.json`
2. 🔄 Trích xuất text features từ công việc
3. 🏗️ Xây dựng feature vector đầy đủ
4. 🤖 Load model từ `artifacts/`
5. 📊 Dự đoán số nhân sú cần thiết
6. 💾 Xuất kết quả

**Cách chạy:**
```bash
python all_predict.py
```

**Output:** Số nhân sự dự đoán cho ca làm việc trong `input.json`

---

### 5. 🔧 **`predict.py`**
> **Module chứa hàm trích xuất text features từ công việc**

**Hàm chính:**
```python
extract_text_features_to_json(task_normal: str, task_dinhky: str) -> str
```

**Input:**
- `task_normal`: Text công việc **HẰNG NGÀY** (các task làm mỗi ngày)
- `task_dinhky`: Text công việc **ĐỊNH KỲ TUẦN/THÁNG** (các task làm định kỳ)

**Output:** JSON string chứa 18 text features:
- `task_counts` (7 features): Số lượng từng loại công việc
- `area_coverage` (7 features): Số công việc theo khu vực
- `ratios_and_diversity` (4 features): Tỷ lệ và độ đa dạng

**Ví dụ sử dụng:**
```python
from predict import extract_text_features_to_json

# Công việc hằng ngày
task_normal = "Lau sàn WC; Thu gom rác; Vệ sinh sảnh"

# Công việc định kỳ (tuần/tháng)
task_dinhky = "Cọ bồn cầu; Đánh sàn; Trực phát sinh"

# Trích xuất features
json_features = extract_text_features_to_json(task_normal, task_dinhky)
print(json_features)
```

**Kết quả trả về:**
```json
{
  "task_counts": {
    "num_tasks": 6,
    "num_cleaning_tasks": 3,
    "num_trash_collection_tasks": 1,
    "num_monitoring_tasks": 1,
    "num_deep_cleaning_tasks": 2,
    "num_support_tasks": 0,
    "num_other_tasks": 0
  },
  "area_coverage": {
    "num_wc_tasks": 2,
    "num_hallway_tasks": 0,
    "num_lobby_tasks": 1,
    ...
  },
  ...
}
```

---

## 🔄 Pipeline Dự Đoán

```mermaid
graph LR
    A[input.json] --> B[all_predict.py]
    B --> C[predict.py<br/>Text Features]
    C --> D[Feature Vector]
    D --> E[Model<br/>artifacts/]
    E --> F[Dự đoán<br/>Số nhân sự]
```

### Chi tiết từng bước:

1. **Input** 📥
   - Đọc `input.json` chứa thông tin ca làm việc
   - Bao gồm 2 loại công việc: `all_task_normal` (hằng ngày) và `all_task_dinhky` (định kỳ)
   
2. **Text Feature Extraction** 🔤
   - `predict.py` trích xuất 18 features từ text công việc
   - **Gộp cả 2 loại công việc** (normal + dinhky) để phân tích
   - Phân loại công việc: cleaning, trash, monitoring, deep cleaning, support, other
   - Phân vùng khu vực: WC, hallway, lobby, outdoor, elevator, medical, office
   
3. **Feature Engineering** 🏗️
   - Kết hợp text features với building features (diện tích, số tầng, v.v.)
   - Chuẩn hóa dữ liệu theo chuẩn của training set
   
4. **Model Prediction** 🤖
   - Load model đã được train từ `artifacts/`
   - Dự đoán số nhân sự dựa trên toàn bộ features
   
5. **Output** 📤
   - Trả về số nhân sự cần thiết cho ca đó

---

## 🚀 Hướng Dẫn Sử Dụng

### Yêu cầu hệ thống
```bash
pip install pandas numpy scikit-learn joblib openpyxl
```

### 1. Dự đoán cho MỘT ca làm việc

**Bước 1:** Chuẩn bị `input.json`
```json
{
  "ma_dia_diem": "TD-001",
  "loai_ca": "Hành chính",
  "bat_dau": "07:00:00",
  "ket_thuc": "15:00:00",
  "tong_gio_lam": 8.0,
  "so_ca_cua_toa": 3,
  "all_task_normal": "Lau sàn hành lang; Thu gom rác WC; Vệ sinh sảnh",
  "all_task_dinhky": "Cọ bồn cầu WC; Đánh sàn lobby; Trực phát sinh",
  "so_tang": 12,
  "so_cua_thang_may": 4,
  "dien_tich_hanh_lang": 1800.0,
  "dien_tich_wc": 420.0,
  ...
}
```

> **💡 Lưu ý về 2 trường công việc:**
> - `all_task_normal`: Các task làm **MỖI NGÀY** (lau sàn, thu rác hàng ngày)
> - `all_task_dinhky`: Các task làm **THEO TUẦN/THÁNG** (cọ rửa định kỳ, đánh sàn định kỳ)

**Bước 2:** Chạy prediction
```bash
python all_predict.py
```

**Bước 3:** Xem kết quả
```
📊 Dự đoán số nhân sự: 8 người
```

---

### 2. Trích xuất Text Features riêng lẻ

```python
from predict import extract_text_features_to_json

# Công việc hằng ngày (daily tasks)
task_normal = "Lau sàn WC tầng 1; Thu gom rác hành lang; Vệ sinh sảnh"

# Công việc định kỳ (weekly/monthly tasks)
task_dinhky = "Cọ bồn cầu WC; Đánh sàn lobby; Trực phát sinh"

# Trích xuất features (sẽ gộp cả 2 loại công việc để phân tích)
features_json = extract_text_features_to_json(task_normal, task_dinhky)

# Parse JSON
import json
features = json.loads(features_json)

print(f"Tổng số tasks (cả normal + dinhky): {features['task_counts']['num_tasks']}")
print(f"Số tasks vệ sinh: {features['task_counts']['num_cleaning_tasks']}")
print(f"Số tasks cọ rửa (deep cleaning): {features['task_counts']['num_deep_cleaning_tasks']}")
print(f"Tỷ lệ vệ sinh: {features['ratios_and_diversity']['cleaning_ratio']}")
print(f"Số tasks vệ sinh: {features['task_counts']['num_cleaning_tasks']}")
print(f"Tỷ lệ vệ sinh: {features['ratios_and_diversity']['cleaning_ratio']}")
```

---

### 3. Training lại model (nếu cần)

**Bước 1:** Chuẩn bị data
- Đảm bảo `final_2.csv` có đủ features
- Đảm bảo diện tích là TỔNG các tầng

**Bước 2:** Chạy notebook training
```bash
jupyter notebook ML_Training_Pipeline_Complete.ipynb
```

**Bước 3:** Model mới sẽ được lưu vào `artifacts/`

---

## 📈 Text Features Chi Tiết

### Nhóm 1: Task Counts (7 features)
| Feature | Mô tả | Keywords |
|---------|-------|----------|
| `num_tasks` | Tổng số công việc | - |
| `num_cleaning_tasks` | Công việc vệ sinh | vệ sinh, lau, chùi, quét, hút |
| `num_trash_collection_tasks` | Thu gom rác | thu gom rác, thay rác, đổ rác |
| `num_monitoring_tasks` | Trực/giám sát | trực, kiểm tra, check, giám sát |
| `num_deep_cleaning_tasks` | Vệ sinh sâu | cọ rửa, cọ bồn cầu, đánh sàn |
| `num_support_tasks` | Hỗ trợ | giao ca, bàn giao, chụp ảnh, chuẩn bị |
| `num_other_tasks` | Công việc khác | (không match keywords trên) |

### Nhóm 2: Area Coverage (7 features)
| Feature | Mô tả | Keywords |
|---------|-------|----------|
| `num_wc_tasks` | WC/Toilet | wc, toilet, nhà vệ sinh, bồn cầu |
| `num_hallway_tasks` | Hành lang | hành lang, corridor, lối đi |
| `num_lobby_tasks` | Sảnh | sảnh, lobby, tiền sảnh |
| `num_outdoor_tasks` | Ngoại cảnh | ngoại cảnh, sân, vỉa hè, khuôn viên |
| `num_elevator_tasks` | Thang máy | thang máy, elevator, cầu thang |
| `num_medical_tasks_total` | Khu vực y tế | phòng bệnh, phòng khám, phòng mổ, xét nghiệm |
| `num_indoor_room_tasks` | Phòng văn phòng | phòng họp, văn phòng, phòng giám đốc |

### Nhóm 3: Ratios & Diversity (4 features)
| Feature | Mô tả | Công thức |
|---------|-------|-----------|
| `cleaning_ratio` | Tỷ lệ vệ sinh | cleaning_tasks / total_tasks |
| `trash_collection_ratio` | Tỷ lệ thu rác | trash_tasks / total_tasks |
| `monitoring_ratio` | Tỷ lệ trực | monitoring_tasks / total_tasks |
| `area_diversity` | Độ đa dạng khu vực | Số khu vực có ít nhất 1 task |

---

## 📝 Lưu Ý Quan Trọng

### ⚠️ Về 2 Loại Công Việc

> **📋 `all_task_normal` - CÔNG VIỆC HẰNG NGÀY:**
> - Các task thực hiện **MỖI NGÀY** trong ca
> - Ví dụ: Lau sàn, Thu rác, Vệ sinh WC
> - Đặc điểm: Công việc nhẹ, lặp lại hàng ngày
> - Tần suất: **Ngày nào cũng làm**

> **📋 `all_task_dinhky` - CÔNG VIỆC ĐỊNH KỲ:**
> - Các task thực hiện **THEO TUẦN** hoặc **THEO THÁNG**
> - Ví dụ: Cọ bồn cầu (1 tuần/lần), Đánh sàn (1 tháng/lần)
> - Đặc điểm: Công việc nặng hơn, không làm hàng ngày
> - Tần suất: **Định kỳ (weekly/monthly)**

**Cách xử lý trong model:**
- Hệ thống sẽ **GỘP CẢ 2 LOẠI** công việc để phân tích
- Trích xuất features từ tổng hợp: `all_task_normal + all_task_dinhky`
- Điều này giúp model hiểu được **TOÀN BỘ KHỐI LƯỢNG CÔNG VIỆC** của ca đó

---

### ⚠️ Về Diện Tích
> **TỔNG diện tích trong `final_2.csv` và `input.json` là tổng của TẤT CẢ các tầng trong tòa nhà!**
> 
> Ví dụ:
> - Tòa nhà 15 tầng, mỗi tầng 300m² hành lang
> - → `dien_tich_hanh_lang = 15 × 300 = 4500m²`
> - KHÔNG PHẢI 300m²!
> 
> Công thức: `dien_tich_X = so_tang × dien_tich_X_moi_tang`

---

### 📌 Về Ca Làm Việc
- Mỗi `input.json` chỉ đại diện cho **MỘT ca** của **MỘT tòa nhà**
- Loại ca: Hành chính, Ca sáng, Ca chiều, Ca tối, Ca đêm
- Bao gồm thông tin thời gian: `bat_dau`, `ket_thuc`, `tong_gio_lam`

---

### 🔤 Về Text Format
- Text công việc phải bằng **tiếng Việt** (có dấu hoặc không dấu đều được)
- Các công việc tách nhau bằng **dấu chấm phẩy (`;`)** hoặc `|` hoặc xuống dòng
- Hệ thống tự động lowercase và normalize
- **Nên viết rõ ràng:** "Lau sàn hành lang" thay vì "Lau sàn"
- **Nên có thông tin khu vực:** "Vệ sinh WC tầng 2" thay vì chỉ "Vệ sinh"


<div align="center">


</div>
