predict_caLamviec_nhansu/extract_shift_features.py

221 lines
7.7 KiB
Python

"""
EXTRACTION: SHIFT FEATURES FROM JSON FOR STAFF PREDICTION
Trích xuất features ca làm việc để predict số nhân sự
Created: January 5, 2026
"""
import pandas as pd
import json
from datetime import datetime
from typing import Dict, List
def parse_time_string(time_str):
"""Parse time string to extract hours"""
if pd.isna(time_str) or time_str == 0:
return 0.0
time_str = str(time_str)
# Handle datetime format: "2025-01-01 22:00:00"
if '2025' in time_str or '2024' in time_str:
try:
dt = pd.to_datetime(time_str)
return dt.hour + dt.minute/60.0
except:
pass
# Handle time format: "HH:MM:SS"
try:
parts = time_str.split(':')
if len(parts) >= 2:
hours = float(parts[0])
minutes = float(parts[1])
return hours + minutes/60.0
except:
pass
return 0.0
def extract_shift_features(json_file_path: str, output_excel_path: str):
"""
Trích xuất shift features từ JSON và tạo Excel file
Features:
- ma_dia_diem: Mã tòa nhà
- loai_ca: Loại ca làm việc
- bat_dau: Giờ bắt đầu ca
- ket_thuc: Giờ kết thúc ca
- tong_gio_lam: Tổng số giờ làm việc
- so_ca_cua_toa: Số lượng ca của tòa nhà xuất hiện trong file
- so_luong: Target variable - Số nhân sự trong ca (để predict)
Args:
json_file_path: Path đến file JSON
output_excel_path: Path output file Excel
"""
print("=" * 80)
print("🚀 TRÍCH XUẤT SHIFT FEATURES TỪ JSON")
print("=" * 80)
# 1. Đọc JSON file
print(f"\n📂 Đọc file: {json_file_path}")
with open(json_file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
print(f"✅ Đọc thành công: {len(data)} records")
# 2. Chuyển sang DataFrame
df = pd.DataFrame(data)
print(f"\n📊 Cấu trúc dữ liệu gốc:")
print(f" - Số dòng: {len(df)}")
print(f" - Số cột: {len(df.columns)}")
print(f" - Các cột: {list(df.columns)}")
# 3. Đếm số ca của mỗi tòa nhà
print(f"\n🔢 Đếm số ca của mỗi tòa nhà...")
shift_counts = df['Mã địa điểm'].value_counts().to_dict()
# Thống kê số ca
unique_buildings = len(shift_counts)
total_shifts = sum(shift_counts.values())
avg_shifts = total_shifts / unique_buildings if unique_buildings > 0 else 0
print(f" - Số tòa nhà unique: {unique_buildings}")
print(f" - Tổng số ca: {total_shifts}")
print(f" - Trung bình ca/tòa: {avg_shifts:.2f}")
# 4. Tạo features DataFrame
print(f"\n🔧 Trích xuất features...")
features_data = []
for idx, row in df.iterrows():
ma_dia_diem = row['Mã địa điểm']
# Feature: Số ca của tòa nhà
so_ca_cua_toa = shift_counts.get(ma_dia_diem, 0)
# Parse time strings
bat_dau_str = str(row['Bắt đầu'])
ket_thuc_str = str(row['Kết thúc'])
tong_gio_lam_str = str(row['Tổng giờ làm'])
# Parse tổng giờ làm
try:
if 'day' in tong_gio_lam_str:
# Format: "7 days, 12:00:00"
parts = tong_gio_lam_str.split(',')
days = int(parts[0].split()[0])
time_parts = parts[1].strip().split(':')
hours = days * 24 + int(time_parts[0])
minutes = int(time_parts[1])
tong_gio_lam = hours + minutes/60.0
else:
# Format: "8:00:00"
time_parts = tong_gio_lam_str.split(':')
tong_gio_lam = float(time_parts[0]) + float(time_parts[1])/60.0
except:
tong_gio_lam = 0.0
# Target variable
so_luong = row['Số lượng']
# Thêm vào list
features_data.append({
'ma_dia_diem': ma_dia_diem,
'loai_ca': row['Loại ca'],
'bat_dau': bat_dau_str,
'ket_thuc': ket_thuc_str,
'tong_gio_lam': round(tong_gio_lam, 2),
'so_ca_cua_toa': so_ca_cua_toa,
'so_luong': so_luong
})
# 5. Tạo DataFrame
features_df = pd.DataFrame(features_data)
print(f"✅ Trích xuất thành công {len(features_df)} shifts")
# 6. Thống kê
print(f"\n📈 THỐNG KÊ FEATURES:")
print(f"\n 🏢 Tòa nhà:")
print(f" - Số tòa unique: {features_df['ma_dia_diem'].nunique()}")
print(f"\n 🕐 Loại ca:")
for loai_ca, count in features_df['loai_ca'].value_counts().items():
print(f" - {loai_ca}: {count} ca ({count/len(features_df)*100:.1f}%)")
print(f"\n ⏱️ Tổng giờ làm:")
print(f" - Min: {features_df['tong_gio_lam'].min():.2f} giờ")
print(f" - Mean: {features_df['tong_gio_lam'].mean():.2f} giờ")
print(f" - Max: {features_df['tong_gio_lam'].max():.2f} giờ")
print(f"\n 📊 Số ca của tòa:")
print(f" - Min: {features_df['so_ca_cua_toa'].min()} ca")
print(f" - Mean: {features_df['so_ca_cua_toa'].mean():.2f} ca")
print(f" - Max: {features_df['so_ca_cua_toa'].max()} ca")
print(f"\n 👥 Số lượng nhân sự (TARGET):")
print(f" - Min: {features_df['so_luong'].min()} người")
print(f" - Mean: {features_df['so_luong'].mean():.2f} người")
print(f" - Median: {features_df['so_luong'].median():.0f} người")
print(f" - Max: {features_df['so_luong'].max()} người")
# Top 5 tòa có nhiều nhân sự nhất
print(f"\n 🏆 TOP 5 CA CÓ NHIỀU NHÂN SỰ NHẤT:")
top5 = features_df.nlargest(5, 'so_luong')[['ma_dia_diem', 'loai_ca', 'tong_gio_lam', 'so_luong']]
for idx, row in top5.iterrows():
print(f" - {row['ma_dia_diem']}: {row['loai_ca']} ({row['tong_gio_lam']:.1f}h) → {row['so_luong']} người")
# 7. Export sang Excel
print(f"\n💾 Xuất file Excel...")
features_df.to_excel(output_excel_path, index=False, engine='openpyxl')
print(f"✅ Đã tạo file: {output_excel_path}")
print(f" - Số dòng: {len(features_df)}")
print(f" - Số cột: {len(features_df.columns)}")
# 8. Tạo thêm CSV backup
csv_path = output_excel_path.replace('.xlsx', '.csv')
features_df.to_csv(csv_path, index=False, encoding='utf-8-sig')
print(f"✅ Đã tạo CSV backup: {csv_path}")
# 9. Summary statistics
print(f"\n📊 SUMMARY STATISTICS:")
print(features_df.describe())
print(f"\n" + "=" * 80)
print("✅ HOÀN THÀNH!")
print("=" * 80)
return features_df
if __name__ == "__main__":
# Paths
json_file = "Link LLV 2025.json"
output_excel = "shift_features_for_prediction.xlsx"
# Run extraction
df = extract_shift_features(json_file, output_excel)
print(f"\n📋 SAMPLE DATA (10 dòng đầu):")
print(df.head(10).to_string())
print(f"\n🎯 CÁC FILE ĐÃ TẠO:")
print(f" 1. {output_excel} - File Excel chính (để mở và xem)")
print(f" 2. shift_features_for_prediction.csv - File CSV backup")
print(f"\n🎯 CẤU TRÚC FILE:")
print(f" - ma_dia_diem: Mã tòa nhà")
print(f" - loai_ca: Loại ca (Hành chính, Ca sáng, Ca chiều, ...)")
print(f" - bat_dau: Giờ bắt đầu ca")
print(f" - ket_thuc: Giờ kết thúc ca")
print(f" - tong_gio_lam: Tổng số giờ làm việc")
print(f" - so_ca_cua_toa: Số ca của tòa nhà (feature)")
print(f" - so_luong: Số nhân sự (TARGET VARIABLE)")
print(f"\n✨ READY FOR MODELING!")