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()