preditc_nhansu_phase2/calculate_area.py

297 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import csv
import re
from collections import defaultdict
# Đọc file JSON - thông tin diện tích
json_file = r"c:\Users\tainl\Documents\testHM\data\data-hoanmy\workload_converter\output_files\Link LLV 2025 For Dev.json"
csv_input = r"c:\Users\tainl\Documents\testHM\data\data-hoanmy\buoc1.csv"
csv_output = r"c:\Users\tainl\Documents\testHM\data\data-hoanmy\buoc2_with_area_v3.csv"
print("Đang đọc dữ liệu...")
print("=" * 100)
# Đọc JSON
with open(json_file, 'r', encoding='utf-8') as f:
dien_tich_data = json.load(f)
# Tạo index theo mã địa điểm
area_index = defaultdict(list)
for record in dien_tich_data:
ma_dd = record.get('Mã địa điểm', '')
if ma_dd:
area_index[ma_dd].append(record)
print(f"✅ Đọc được {len(dien_tich_data)} records từ JSON")
print(f"✅ Có {len(area_index)} mã địa điểm duy nhất")
# Đọc CSV
with open(csv_input, 'r', encoding='utf-8-sig') as f:
reader = csv.DictReader(f)
csv_records = list(reader)
print(f"✅ Đọc được {len(csv_records)} records từ CSV")
# Lọc các record có mã tòa trong JSON
filtered_records = []
skipped_records = []
for record in csv_records:
ma_toa = record['ma_toa_nha']
if ma_toa in area_index:
filtered_records.append(record)
else:
skipped_records.append(ma_toa)
print(f"\n{'=' * 100}")
print(f"📊 LỌC DỮ LIỆU:")
print(f"{'=' * 100}")
print(f"Records giữ lại: {len(filtered_records)}")
print(f"Records bỏ qua: {len(skipped_records)}")
if skipped_records:
unique_skipped = set(skipped_records)
print(f"\n⚠️ Các mã tòa bị loại bỏ ({len(unique_skipped)} mã):")
for ma in list(unique_skipped)[:20]:
print(f" - {ma}")
# Hàm trích xuất tầng từ text
def extract_floors(text):
"""Trích xuất số tầng từ text"""
floors = set()
text = text.lower()
# Pattern: "tầng 1", "T2", "tầng 3-5", "tầng 1,2,3", "từ tầng 2-5"
patterns = [
r'từ\s+tầng\s+(\d+)\s*[-]\s*(\d+)', # Range với "từ"
r'tầng\s+(\d+)\s*[-đến]+\s*(\d+)', # Range
r'tầng\s+(\d+)', # Single
r't\s*(\d+)', # T2, T3
r'(\d+)\s*tầng', # 5 tầng
]
for pattern in patterns:
matches = re.findall(pattern, text)
for match in matches:
if isinstance(match, tuple) and len(match) == 2:
# Range case
try:
start, end = int(match[0]), int(match[1])
if start <= end and end - start <= 20: # Reasonable range
floors.update(range(start, end + 1))
except:
pass
else:
# Single floor
try:
num = int(match) if isinstance(match, str) else match
if 0 <= num <= 100: # Reasonable floor number
floors.add(num)
except:
pass
return sorted(floors)
# Hàm trích xuất loại khu vực
def extract_area_types(text):
"""Trích xuất các loại khu vực từ text"""
text = text.lower()
area_types = []
# Keywords mapping - thêm nhiều từ đồng nghĩa
keywords = {
'sảnh': ['sảnh', 'lobby', 'sanh'],
'hành lang': ['hành lang', 'hanh lang', 'hàng lang', 'hang lang', 'coridol'],
'wc': ['wc', 'nhà vệ sinh', 'toilet', 'vệ sinh', 've sinh', 'vs'],
'văn phòng': ['văn phòng', 'van phong', 'vp ', 'office'],
'phòng bệnh': ['phòng bệnh', 'phong benh', 'giường bệnh', 'giuong benh'],
'phòng': ['phòng', 'phong'],
'ngoại cảnh': ['ngoại cảnh', 'ngoai canh', 'sân', 'san', 'vườn', 'vuon', 'ngoài trời'],
'thang máy': ['thang máy', 'thang may', 'lift'],
'cầu thang': ['cầu thang', 'cau thang', 'thang bộ', 'tang bo'],
'nhà ăn': ['nhà ăn', 'nha an', 'phòng ăn', 'canteen'],
'phòng mổ': ['phòng mổ', 'phong mo', 'phẫu thuật', 'phau thuat'],
'phòng khám': ['phòng khám', 'phong kham', 'khám bệnh'],
'kho': ['kho', 'warehouse'],
'nhà máy': ['nhà máy', 'nha may', 'factory', 'xưởng', 'xuong'],
}
for area_type, patterns in keywords.items():
for pattern in patterns:
if pattern in text:
area_types.append(area_type)
break
return area_types
# Hàm tính diện tích
def calculate_area(ma_toa, khu_vuc_text):
"""Tính tổng diện tích dựa vào mã tòa và text khu vực"""
if ma_toa not in area_index:
return 0, "Không tìm thấy trong JSON"
# Trích xuất thông tin từ text
floors = extract_floors(khu_vuc_text)
area_types = extract_area_types(khu_vuc_text)
total_area = 0
details = []
# Lấy tất cả records của tòa nhà
toa_records = area_index[ma_toa]
# LOGIC CẢI THIỆN: Fallback thông minh
if floors and area_types:
# Trường hợp 1: Có CẢ tầng VÀ khu vực → Match chặt chẽ (AND)
for rec in toa_records:
tang_str = str(rec.get('Tầng', '')).lower()
khu_vuc_str = str(rec.get('Khu vực', '')).lower()
# Kiểm tra tầng
tang_match = False
for floor in floors:
if f'tầng {floor}' in tang_str or f't{floor}' in tang_str or str(floor) == tang_str:
tang_match = True
break
# Kiểm tra khu vực
khu_vuc_match = False
for area_type in area_types:
if area_type in khu_vuc_str or area_type in tang_str:
khu_vuc_match = True
break
if tang_match and khu_vuc_match:
area_added = 0
for key, value in rec.items():
if key.startswith('Sàn') and isinstance(value, (int, float)) and value > 0:
area_added += value
total_area += value
if area_added > 0:
details.append(f"{rec.get('Tầng', 'N/A')} - {rec.get('Khu vực', 'N/A')}: {area_added}")
if total_area > 0:
detail_str = " | ".join(details[:3]) if details else ""
return total_area, f"Match tầng+khu vực: {detail_str}" if detail_str else "Match tầng+khu vực"
# Trường hợp 2: CHỈ có tầng (không parse được khu vực) → Lấy TẤT CẢ diện tích của tầng đó
if floors and not area_types:
for rec in toa_records:
tang_str = str(rec.get('Tầng', '')).lower()
tang_match = False
for floor in floors:
if f'tầng {floor}' in tang_str or f't{floor}' in tang_str or str(floor) == tang_str:
tang_match = True
break
if tang_match:
area_added = 0
for key, value in rec.items():
if key.startswith('Sàn') and isinstance(value, (int, float)) and value > 0:
area_added += value
total_area += value
if area_added > 0:
details.append(f"{rec.get('Tầng', 'N/A')}: {area_added}")
if total_area > 0:
return total_area, f"Tầng {','.join(map(str, floors))}"
# Trường hợp 3: CHỈ có khu vực (không parse được tầng) → Lấy khu vực đó trên TẤT CẢ tầng
if not floors and area_types:
for rec in toa_records:
khu_vuc_str = str(rec.get('Khu vực', '')).lower()
khu_vuc_match = False
for area_type in area_types:
if area_type in khu_vuc_str:
khu_vuc_match = True
break
if khu_vuc_match:
area_added = 0
for key, value in rec.items():
if key.startswith('Sàn') and isinstance(value, (int, float)) and value > 0:
area_added += value
total_area += value
if area_added > 0:
details.append(f"{rec.get('Khu vực', 'N/A')}: {area_added}")
if total_area > 0:
return total_area, f"Khu vực: {','.join(area_types)}"
# Trường hợp 4: Không parse được GÌ → Tính tổng toàn bộ
for rec in toa_records:
for key, value in rec.items():
if key.startswith('Sàn') and isinstance(value, (int, float)) and value > 0:
total_area += value
return total_area, "Tổng toàn bộ tòa (không parse được)"
# Tính diện tích cho từng record
print(f"\n{'=' * 100}")
print(f"🔢 ĐANG TÍNH DIỆN TÍCH...")
print(f"{'=' * 100}")
results = []
stats = {
'co_dien_tich': 0,
'khong_dien_tich': 0,
'tong_dien_tich': 0
}
for idx, record in enumerate(filtered_records, 1):
if idx % 100 == 0:
print(f" Đã xử lý {idx}/{len(filtered_records)} records...")
ma_toa = record['ma_toa_nha']
khu_vuc = record['Khu_vuc_lam_sach']
area, detail = calculate_area(ma_toa, khu_vuc)
if area > 0:
stats['co_dien_tich'] += 1
stats['tong_dien_tich'] += area
else:
stats['khong_dien_tich'] += 1
results.append({
**record,
'dien_tich_m2': round(area, 2),
'chi_tiet_tinh': detail
})
# Xuất ra CSV
with open(csv_output, 'w', encoding='utf-8-sig', newline='') as f:
fieldnames = ['ma_toa_nha', 'Khu_vuc_lam_sach', 'gio', 'So_nhan_su', 'Ten_ca', 'dien_tich_m2', 'chi_tiet_tinh', 'all_task']
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(results)
print(f"\n{'=' * 100}")
print(f"✅ ĐÃ TẠO FILE: {csv_output}")
print(f"{'=' * 100}")
print(f"\n📊 THỐNG KÊ:")
print(f" - Records đầu ra: {len(results)}")
print(f" - Records có diện tích > 0: {stats['co_dien_tich']} ({stats['co_dien_tich']*100//len(results)}%)")
print(f" - Records diện tích = 0: {stats['khong_dien_tich']} ({stats['khong_dien_tich']*100//len(results)}%)")
print(f" - Tổng diện tích: {stats['tong_dien_tich']:,.0f}")
# Hiển thị mẫu
print(f"\n📝 MẪU DỮ LIỆU (10 records đầu):")
for idx, rec in enumerate(results[:10], 1):
print(f"\n{idx}. Mã: {rec['ma_toa_nha']} | DT: {rec['dien_tich_m2']}")
print(f" Khu vực: {rec['Khu_vuc_lam_sach'][:60]}...")
print(f" Chi tiết: {rec['chi_tiet_tinh'][:80]}...")
print(f"\n{'=' * 100}")
print(f"💡 LƯU Ý:")
print(f" - Logic phân tích text còn đơn giản, có thể chưa chính xác 100%")
print(f" - Cần review các records có diện tích = 0 để cải thiện logic")
print(f"{'=' * 100}")