preditc_nhansu_phase2/create_buoc1_csv_v2.py

257 lines
10 KiB
Python

import json
import os
import csv
from collections import defaultdict
def extract_valid_positions_from_json(file_path):
"""Trích xuất chỉ các vị trí hợp lệ từ file JSON"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
valid_records = []
skipped_positions = []
# Lấy mã tòa nhà từ tên file (bỏ đuôi .json)
ma_toa_nha = os.path.basename(file_path).replace('.json', '')
# Duyệt qua từng vị trí trong Thong_tin_nhan_su
for nhan_su_item in data.get('Thong_tin_nhan_su', []):
ten_vi_tri = nhan_su_item.get('Tên vị trí', '')
khu_vuc = nhan_su_item.get('Khu Vực làm sạch', '')
# Kiểm tra Ca_lam_viec
ca_lam_viec_list = nhan_su_item.get('Ca_lam_viec', [])
if not ca_lam_viec_list:
skipped_positions.append(f"{ten_vi_tri}: Thiếu Ca_lam_viec")
continue
# Kiểm tra Chi_tiet_vi_tri
chi_tiet = data.get('Chi_tiet_vi_tri', {}).get(ten_vi_tri, {})
if not chi_tiet:
skipped_positions.append(f"{ten_vi_tri}: Không có trong Chi_tiet_vi_tri")
continue
# Kiểm tra Công việc thường
cong_viec_thuong = chi_tiet.get('Công việc thường', [])
if not cong_viec_thuong:
skipped_positions.append(f"{ten_vi_tri}: Thiếu/rỗng Công việc thường")
continue
# Nếu vị trí hợp lệ, trích xuất dữ liệu
for ca_item in ca_lam_viec_list:
ten_ca = ca_item.get('Ten_ca', '')
gio = ca_item.get('Gio', '')
so_nhan_su = ca_item.get('So_nhan_su', 0)
# Lấy all_task
all_tasks = []
for cv in cong_viec_thuong:
noi_dung = cv.get('Nội dung công việc', '').strip()
if noi_dung:
all_tasks.append(noi_dung)
if not all_tasks:
skipped_positions.append(f"{ten_vi_tri}: Không có nội dung công việc")
continue
all_task_str = ' / '.join(all_tasks)
valid_records.append({
'ma_toa_nha': ma_toa_nha,
'Khu_vuc_lam_sach': khu_vuc.strip(),
'gio': gio.strip(),
'So_nhan_su': so_nhan_su,
'Ten_ca': ten_ca.strip(),
'all_task': all_task_str,
'file_source': os.path.basename(file_path),
'vi_tri': ten_vi_tri
})
return valid_records, skipped_positions
except Exception as e:
return [], [f"Lỗi: {e}"]
def main():
success_folder = r"c:\Users\tainl\Documents\testHM\data\data-hoanmy\converters\output\sodonhansu\success"
null_folder = r"c:\Users\tainl\Documents\testHM\data\data-hoanmy\converters\output\sodonhansu\null"
output_csv = r"c:\Users\tainl\Documents\testHM\data\data-hoanmy\buoc1.csv"
# Lấy danh sách file từ cả 2 folder
success_files = [(os.path.join(success_folder, f), f, 'success') for f in os.listdir(success_folder) if f.endswith('.json')]
null_files = [(os.path.join(null_folder, f), f, 'null') for f in os.listdir(null_folder) if f.endswith('.json')]
all_file_paths = success_files + null_files
print(f"Đang xử lý files từ 2 folders...")
print(f" - Folder success: {len(success_files)} files")
print(f" - Folder null: {len(null_files)} files")
print(f" - Tổng: {len(all_file_paths)} files")
print("=" * 100)
# Trích xuất các vị trí hợp lệ từ tất cả các file
all_valid_records = []
file_stats = []
total_skipped = 0
print(f"\nĐang trích xuất các vị trí hợp lệ...")
for idx, (file_path, file_name, folder_type) in enumerate(all_file_paths, 1):
if idx % 50 == 0:
print(f" Đã xử lý {idx}/{len(all_file_paths)} files...")
valid_records, skipped_positions = extract_valid_positions_from_json(file_path)
if valid_records:
all_valid_records.extend(valid_records)
if skipped_positions:
total_skipped += len(skipped_positions)
file_stats.append({
'file': file_name,
'folder': folder_type,
'valid': len(valid_records),
'skipped': len(skipped_positions),
'skipped_reasons': skipped_positions[:3]
})
print(f"\n✅ Trích xuất được {len(all_valid_records)} vị trí hợp lệ từ {len(all_file_paths)} files")
print(f"⚠️ Đã bỏ qua {total_skipped} vị trí không hợp lệ")
# Thống kê theo folder
success_records = [r for r in all_valid_records if r['file_source'] in [f[1] for f in success_files]]
null_records = [r for r in all_valid_records if r['file_source'] in [f[1] for f in null_files]]
print(f"\n📊 Chi tiết:")
print(f" - Từ folder success: {len(success_records)} vị trí hợp lệ")
print(f" - Từ folder null: {len(null_records)} vị trí hợp lệ")
# Hiển thị một số file có vị trí bị bỏ qua
if file_stats:
print(f"\n📝 Ví dụ các file có vị trí bị bỏ qua (10 files đầu):")
for stat in file_stats[:10]:
print(f" - {stat['file']} ({stat['folder']}): {stat['valid']} hợp lệ, {stat['skipped']} bỏ qua")
for reason in stat['skipped_reasons']:
print(f"{reason}")
# Gộp các record có cùng MÃ TÒA NHÀ và KHU VỰC LÀM SẠCH
print(f"\n{'=' * 100}")
print(f"Đang gộp các record có cùng tòa nhà và khu vực...")
grouped_data = defaultdict(lambda: {
'So_nhan_su': 0,
'all_task': [],
'gio': '',
'Ten_ca': '',
'ma_toa_nha': '',
'Khu_vuc_lam_sach': ''
})
for record in all_valid_records:
# Key = (mã tòa nhà, khu vực làm sạch)
key = (record['ma_toa_nha'], record['Khu_vuc_lam_sach'])
grouped_data[key]['So_nhan_su'] += record['So_nhan_su']
# Gộp all_task
if record['all_task']:
grouped_data[key]['all_task'].append(record['all_task'])
# Lưu thông tin tòa nhà và khu vực
grouped_data[key]['ma_toa_nha'] = record['ma_toa_nha']
grouped_data[key]['Khu_vuc_lam_sach'] = record['Khu_vuc_lam_sach']
# Lấy thông tin ca đầu tiên
if not grouped_data[key]['gio']:
grouped_data[key]['gio'] = record['gio']
grouped_data[key]['Ten_ca'] = record['Ten_ca']
# Tạo danh sách final và lọc các record có giờ null/rỗng
final_records = []
skipped_null_gio = 0
for (ma_toa_nha, khu_vuc), info in grouped_data.items():
if not khu_vuc:
continue
# Loại bỏ các record có giờ rỗng/null
if not info['gio'] or info['gio'].strip() == '':
skipped_null_gio += 1
continue
all_task_combined = ' / '.join(info['all_task'])
final_records.append({
'ma_toa_nha': info['ma_toa_nha'],
'Khu_vuc_lam_sach': info['Khu_vuc_lam_sach'],
'gio': info['gio'],
'So_nhan_su': info['So_nhan_su'],
'Ten_ca': info['Ten_ca'],
'all_task': all_task_combined
})
# Sắp xếp theo Mã tòa nhà, rồi đến Khu vực
final_records.sort(key=lambda x: (x['ma_toa_nha'], x['Khu_vuc_lam_sach']))
print(f"✅ Sau khi gộp: {len(final_records)} records duy nhất")
if skipped_null_gio > 0:
print(f"⚠️ Đã loại bỏ thêm {skipped_null_gio} records có giờ null/rỗng")
# Xuất ra CSV
with open(output_csv, 'w', encoding='utf-8-sig', newline='') as f:
fieldnames = ['ma_toa_nha', 'Khu_vuc_lam_sach', 'gio', 'So_nhan_su', 'Ten_ca', 'all_task']
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(final_records)
print(f"\n{'=' * 100}")
print(f"✅ ĐÃ TẠO FILE: {output_csv}")
print(f"{'=' * 100}")
print(f"\n📊 TỔNG KẾT:")
print(f" - Tổng files xử lý: {len(all_file_paths)} (success: {len(success_files)}, null: {len(null_files)})")
print(f" - Vị trí hợp lệ: {len(all_valid_records)} (success: {len(success_records)}, null: {len(null_records)})")
print(f" - Vị trí bị bỏ qua: {total_skipped}")
print(f" - Records sau gộp: {len(final_records)}")
print(f" - Số nhân sự tổng: {sum(r['So_nhan_su'] for r in final_records)}")
# Hiển thị mẫu
print(f"\n📝 MẪU DỮ LIỆU (5 records đầu):")
for idx, record in enumerate(final_records[:5], 1):
print(f"\n{idx}. Mã tòa nhà: {record['ma_toa_nha']}")
print(f" Khu vực: {record['Khu_vuc_lam_sach'][:60]}...")
print(f" Ca: {record['Ten_ca']} | Giờ: {record['gio']} | Số NS: {record['So_nhan_su']}")
print(f" Tasks: {record['all_task'][:100]}...")
# Kiểm tra vấn đề
print(f"\n{'=' * 100}")
print(f"🔍 KIỂM TRA VẤN ĐỀ:")
empty_khu_vuc = [r for r in final_records if not r['Khu_vuc_lam_sach']]
empty_gio = [r for r in final_records if not r['gio'] or r['gio'].strip() == '']
empty_tasks = [r for r in final_records if not r['all_task']]
zero_nhan_su = [r for r in final_records if r['So_nhan_su'] == 0]
empty_ma_toa = [r for r in final_records if not r['ma_toa_nha']]
if empty_khu_vuc:
print(f" ⚠️ {len(empty_khu_vuc)} records có Khu vực rỗng")
if empty_gio:
print(f" ⚠️ {len(empty_gio)} records có Giờ rỗng/null")
if empty_tasks:
print(f" ⚠️ {len(empty_tasks)} records có all_task rỗng")
if zero_nhan_su:
print(f" ⚠️ {len(zero_nhan_su)} records có số nhân sự = 0")
if empty_ma_toa:
print(f" ⚠️ {len(empty_ma_toa)} records có mã tòa nhà rỗng")
if not (empty_khu_vuc or empty_gio or empty_tasks or zero_nhan_su or empty_ma_toa):
print(f" ✅ Không phát hiện vấn đề về dữ liệu!")
if __name__ == "__main__":
main()