296 lines
11 KiB
Python
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()
|