predict_caLamviec_nhansu/create_aggregate_buildings.py

296 lines
11 KiB
Python

import json
import pandas as pd
from pathlib import Path
from collections import defaultdict
def main():
# Đọc file JSON
json_file = Path(r'c:\Users\SLG PC\Documents\Predict_calamviecHM\Link LLV 2025_clean.json')
print("Đang đọc file JSON...")
with open(json_file, 'r', encoding='utf-8') as f:
json_data = json.load(f)
print(f"✓ Đã đọc {len(json_data)} records từ JSON")
# Danh sách các trường cần aggregate (khả năng ≥50%)
# Nhóm 1: Trường định danh (không aggregate, lấy giá trị đầu tiên)
identity_fields = ['Mã địa điểm', 'Loại hình']
# Nhóm 2: Các trường diện tích/số lượng cần SUM
sum_fields = [
'Sàn ngoại cảnh',
'Sàn Sảnh',
'Sàn Hành lang',
'Sàn WC',
'Sàn Phòng',
'Thảm',
'Dốc hầm',
'Viền phản quang',
'Ốp tường',
'Ốp chân tường',
'Rãnh thoát nước',
'Kính'
]
# Nhóm 3: Các trường cần xử lý đặc biệt
special_fields = {
'Tên Tòa Tháp': 'first', # Lấy tên tòa đầu tiên
'Tầng': 'count_distinct', # Đếm số tầng khác nhau
'Cửa thang máy': 'sum', # Tổng số cửa thang máy
'Mức độ Lưu lượng KH hoạt động trên mặt sàn giờ': 'first' # Lấy giá trị đầu tiên
}
# Aggregate dữ liệu theo Mã địa điểm
print("\nĐang aggregate dữ liệu theo Mã địa điểm...")
aggregated_data = defaultdict(lambda: {
'Mã địa điểm': '',
'Loại hình': '',
'Tên Tòa Tháp': '',
'Số tầng': 0,
'Tổng số cửa thang máy': 0,
'Mức độ Lưu lượng KH': '',
'Diện tích ngoại cảnh Tòa tháp (m2)': 0,
'Sàn Sảnh (m2)': 0,
'Sàn Hành lang (m2)': 0,
'Sàn WC (m2)': 0,
'Sàn Phòng (m2)': 0,
'Thảm (m2)': 0,
'Dốc hầm (m)': 0,
'Viền phản quang (m)': 0,
'Ốp tường (m2)': 0,
'Ốp chân tường (m2)': 0,
'Rãnh thoát nước (m)': 0,
'Kính (m2)': 0,
'tangs': set(), # Tập hợp các tầng (để đếm)
})
# Xử lý từng record
for record in json_data:
ma_dia_diem = record.get('Mã địa điểm', '')
if not ma_dia_diem:
continue
agg = aggregated_data[ma_dia_diem]
# Lấy thông tin định danh (lần đầu tiên)
if not agg['Mã địa điểm']:
agg['Mã địa điểm'] = ma_dia_diem
agg['Loại hình'] = record.get('Loại hình', '')
agg['Tên Tòa Tháp'] = record.get('Tên Tòa Tháp', '')
agg['Mức độ Lưu lượng KH'] = record.get('Mức độ Lưu lượng KH hoạt động trên mặt sàn giờ', '')
# Tập hợp các tầng
tang = record.get('Tầng', '')
if tang:
agg['tangs'].add(str(tang))
# SUM các trường diện tích - Hàm helper để convert an toàn
def safe_float(value):
try:
return float(value) if value else 0
except (ValueError, TypeError):
return 0
agg['Diện tích ngoại cảnh Tòa tháp (m2)'] += safe_float(record.get('Sàn ngoại cảnh', 0))
agg['Sàn Sảnh (m2)'] += safe_float(record.get('Sàn Sảnh', 0))
agg['Sàn Hành lang (m2)'] += safe_float(record.get('Sàn Hành lang', 0))
agg['Sàn WC (m2)'] += safe_float(record.get('Sàn WC', 0))
agg['Sàn Phòng (m2)'] += safe_float(record.get('Sàn Phòng', 0))
agg['Thảm (m2)'] += safe_float(record.get('Thảm', 0))
agg['Dốc hầm (m)'] += safe_float(record.get('Dốc hầm', 0))
agg['Viền phản quang (m)'] += safe_float(record.get('Viền phản quang', 0))
agg['Ốp tường (m2)'] += safe_float(record.get('Ốp tường', 0))
agg['Ốp chân tường (m2)'] += safe_float(record.get('Ốp chân tường', 0))
agg['Rãnh thoát nước (m)'] += safe_float(record.get('Rãnh thoát nước', 0))
agg['Kính (m2)'] += safe_float(record.get('Kính', 0))
agg['Tổng số cửa thang máy'] += safe_float(record.get('Cửa thang máy', 0))
# Tính số tầng và làm sạch dữ liệu
print("Đang xử lý dữ liệu cuối cùng...")
final_data = []
for ma_dia_diem, agg in aggregated_data.items():
agg['Số tầng'] = len(agg['tangs'])
del agg['tangs'] # Xóa trường tạm
final_data.append(agg)
# Tạo DataFrame
df = pd.DataFrame(final_data)
# Sắp xếp theo Mã địa điểm
df = df.sort_values('Mã địa điểm')
# Sắp xếp lại thứ tự cột
column_order = [
'Mã địa điểm',
'Loại hình',
'Tên Tòa Tháp',
'Mức độ Lưu lượng KH',
'Số tầng',
'Tổng số cửa thang máy',
'Diện tích ngoại cảnh Tòa tháp (m2)',
'Sàn Sảnh (m2)',
'Sàn Hành lang (m2)',
'Sàn WC (m2)',
'Sàn Phòng (m2)',
'Thảm (m2)',
'Dốc hầm (m)',
'Viền phản quang (m)',
'Ốp tường (m2)',
'Ốp chân tường (m2)',
'Rãnh thoát nước (m)',
'Kính (m2)',
]
df = df[column_order]
# Làm tròn số
numeric_columns = df.select_dtypes(include=['float64', 'int64']).columns
for col in numeric_columns:
if col not in ['Mã địa điểm', 'Loại hình']:
df[col] = df[col].round(2)
print(f"\n✓ Đã aggregate thành {len(df)} tòa nhà")
# Lọc bỏ các tòa có tất cả các trường số bằng 0
print("Đang lọc bỏ các tòa nhà có tất cả trường số = 0...")
numeric_cols_to_check = [col for col in numeric_columns if col not in ['Mã địa điểm', 'Loại hình']]
# Tìm các dòng có ít nhất một trường số khác 0
df_filtered = df[(df[numeric_cols_to_check] != 0).any(axis=1)]
removed_count = len(df) - len(df_filtered)
print(f"✓ Đã loại bỏ {removed_count} tòa nhà có tất cả trường số = 0")
print(f"✓ Còn lại {len(df_filtered)} tòa nhà có dữ liệu hợp lệ")
# Cập nhật df
df = df_filtered
# Xuất ra Excel
output_file = 'Du_Lieu_Toa_Nha_Aggregate.xlsx'
print(f"\nĐang xuất dữ liệu ra file Excel...")
with pd.ExcelWriter(output_file, engine='openpyxl') as writer:
# Sheet 1: Dữ liệu đầy đủ
df.to_excel(writer, sheet_name='Dữ liệu tòa nhà', index=False)
# Sheet 2: Thống kê
stats_data = {
'Chỉ số': [
'Tổng số tòa nhà',
'Tổng diện tích Sàn Sảnh (m2)',
'Tổng diện tích Sàn Hành lang (m2)',
'Tổng diện tích Sàn WC (m2)',
'Tổng diện tích Sàn Phòng (m2)',
'Tổng diện tích Thảm (m2)',
'Tổng diện tích Kính (m2)',
'Trung bình số tầng/tòa',
'Trung bình số cửa thang máy/tòa',
],
'Giá trị': [
len(df),
df['Sàn Sảnh (m2)'].sum(),
df['Sàn Hành lang (m2)'].sum(),
df['Sàn WC (m2)'].sum(),
df['Sàn Phòng (m2)'].sum(),
df['Thảm (m2)'].sum(),
df['Kính (m2)'].sum(),
df['Số tầng'].mean(),
df['Tổng số cửa thang máy'].mean(),
]
}
df_stats = pd.DataFrame(stats_data)
df_stats['Giá trị'] = df_stats['Giá trị'].round(2)
df_stats.to_excel(writer, sheet_name='Thống kê', index=False)
# Sheet 3: Danh sách các trường đã aggregate
field_info = {
'Tên trường': column_order,
'Cách xử lý': [
'Khóa chính',
'Giá trị đầu tiên',
'Giá trị đầu tiên',
'Giá trị đầu tiên',
'COUNT DISTINCT các tầng',
'SUM tất cả cửa thang máy',
'SUM tất cả diện tích',
'SUM tất cả diện tích',
'SUM tất cả diện tích',
'SUM tất cả diện tích',
'SUM tất cả diện tích',
'SUM tất cả diện tích',
'SUM tất cả độ dài',
'SUM tất cả độ dài',
'SUM tất cả diện tích',
'SUM tất cả diện tích',
'SUM tất cả độ dài',
'SUM tất cả diện tích',
],
'Nguồn JSON': [
'Mã địa điểm',
'Loại hình',
'Tên Tòa Tháp',
'Mức độ Lưu lượng KH hoạt động trên mặt sàn giờ',
'Tầng',
'Cửa thang máy',
'Sàn ngoại cảnh',
'Sàn Sảnh',
'Sàn Hành lang',
'Sàn WC',
'Sàn Phòng',
'Thảm',
'Dốc hầm',
'Viền phản quang',
'Ốp tường',
'Ốp chân tường',
'Rãnh thoát nước',
'Kính',
],
'Khả năng đáp ứng CSV': [
'✅ 100%',
'✅ 100%',
'🔶 40%',
'⚠️ 50%',
'🔶 40%',
'🔶 30%',
'✅ 100%',
'✅ 100%',
'✅ 100%',
'✅ 100%',
'✅ 100%',
'✅ 100%',
'✅ 100%',
'✅ 100%',
'✅ 100%',
'✅ 100%',
'✅ 100%',
'✅ 100%',
]
}
df_fields = pd.DataFrame(field_info)
df_fields.to_excel(writer, sheet_name='Thông tin các trường', index=False)
print(f"✅ ĐÃ HOÀN THÀNH!")
print("="*100)
print(f"\n📁 File xuất ra: {output_file}")
print(f"📊 Tổng số tòa nhà: {len(df)}")
print(f"📋 Số trường dữ liệu: {len(column_order)}")
print("\n📄 Nội dung file gồm 3 sheets:")
print(" 1. Dữ liệu tòa nhà - Bảng dữ liệu đầy đủ của tất cả tòa nhà")
print(" 2. Thống kê - Các chỉ số thống kê tổng hợp")
print(" 3. Thông tin các trường - Giải thích cách xử lý từng trường")
print("\n" + "="*100)
print("📊 MẪU DỮ LIỆU (5 tòa nhà đầu tiên):")
print("="*100)
print(df.head().to_string())
print("\n" + "="*100)
print("📈 THỐNG KÊ TỔNG QUAN:")
print("="*100)
print(df.describe().round(2).to_string())
print("\n" + "="*100)
if __name__ == "__main__":
main()