import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler, LabelEncoder from sklearn.cluster import KMeans from backend.config.setting import ( PRE_TELCO_CHURN_CSV, PRE_TEST_CUSTOMER_CSV, ) df1 = pd.read_csv(PRE_TELCO_CHURN_CSV) df2 = pd.read_csv(PRE_TEST_CUSTOMER_CSV) df = pd.concat([df1, df2], ignore_index=True) # Danh sách đầy đủ các feature bạn yêu cầu features_to_use = [ 'Customer ID', 'Age', 'Avg Monthly GB Download', 'Churn Score', 'Gender', 'Monthly Charge', 'CLTV', 'Contract', 'Streaming Movies', 'Streaming Music', 'Streaming TV', 'Satisfaction Score', 'Tenure in Months' ] # Chỉ giữ lại các cột có trong file existing_cols = [col for col in features_to_use if col in df.columns] df_final = df[existing_cols].copy() # Kiểm tra xem có đủ cột quan trọng không if 'Customer ID' not in df_final.columns: print(" Cảnh báo: Không tìm thấy cột Customer ID. Code vẫn chạy nhưng kết quả sẽ không có ID.") # ========================================== # 2. TIỀN XỬ LÝ (PRE-PROCESSING) # ========================================== # Tạo một bản sao để train model (không làm hỏng data gốc) X = df_final.copy() # Bỏ cột ID ra khỏi dữ liệu training (vì ID không có ý nghĩa phân cụm) if 'Customer ID' in X.columns: X = X.drop(columns=['Customer ID']) # --- 2.1 Xử lý dữ liệu dạng chữ (Encoding) --- # Xử lý Gender: Male/Female -> 0/1 le = LabelEncoder() if 'Gender' in X.columns: X['Gender'] = le.fit_transform(X['Gender'].astype(str)) # Xử lý Contract: Chuyển thành số theo thứ tự cam kết contract_map = {'Month-to-month': 0, 'One year': 1, 'Two year': 2} if 'Contract' in X.columns: # Nếu dữ liệu lạ không khớp map, gán là 0 X['Contract'] = X['Contract'].map(contract_map).fillna(0) # Xử lý các cột Streaming: Yes -> 1, No -> 0 streaming_cols = ['Streaming Movies', 'Streaming Music', 'Streaming TV'] for col in streaming_cols: if col in X.columns: # Xử lý cả trường hợp 'No internet service' -> coi là 0 X[col] = X[col].apply(lambda x: 1 if str(x).strip() == 'Yes' else 0) # --- 2.2 Xử lý dữ liệu trống (Missing Values) --- # Điền giá trị trung bình vào các ô trống (để tránh lỗi) X = X.fillna(X.mean()) # --- 2.3 Chuẩn hóa dữ liệu (Scaling) --- # Bước này CỰC KỲ QUAN TRỌNG khi dùng nhiều feature khác đơn vị (Tuổi, Tiền, GB...) scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # ========================================== # 3. PHÂN CỤM (CLUSTERING) # ========================================== print(" Đang tiến hành phân cụm K-Means với 3 nhóm...") # Sử dụng K-Means với k=3 kmeans = KMeans(n_clusters=3, random_state=42, n_init=10) clusters = kmeans.fit_predict(X_scaled) # Gán nhãn cụm (0, 1, 2) tạm thời vào dataframe df_final['Cluster_Temp'] = clusters # ========================================== # 4. ĐỊNH DANH NHÓM A, B, C (RANKING) # ========================================== # Logic: Nhóm nào có CLTV (Giá trị vòng đời) cao nhất sẽ là A (VIP) # Nếu không có CLTV, dùng Monthly Charge ranking_metric = 'CLTV' if 'CLTV' in df_final.columns else 'Monthly Charge' # Tính giá trị trung bình của metric xếp hạng cho từng cụm cluster_stats = df_final.groupby('Cluster_Temp')[ranking_metric].mean().sort_values(ascending=False) print("\n Thống kê trung bình nhóm (Dựa trên CLTV):") print(cluster_stats) # Tạo map: Cao nhất -> A, Nhì -> B, Thấp -> C labels_map = {} rank_names = ['A', 'B', 'C'] # A là xịn nhất for i, cluster_idx in enumerate(cluster_stats.index): labels_map[cluster_idx] = rank_names[i] # Áp dụng map để tạo cột Segment cuối cùng df_final['Segment'] = df_final['Cluster_Temp'].map(labels_map) # ========================================== # 5. XUẤT FILE KẾT QUẢ # ========================================== # Bỏ cột Cluster_Temp thừa đi output_df = df_final.drop(columns=['Cluster_Temp']) filename = "telco_customer_segmented_full_features.csv" output_df.to_csv(filename, index=False) print(f"\n THÀNH CÔNG! File kết quả đã lưu tại: {filename}") print("-" * 50) print("Mẫu dữ liệu 5 dòng đầu tiên:") print(output_df[['Customer ID', 'Segment', 'CLTV', 'Churn Score', 'Monthly Charge']].head()) # In ra đặc điểm trung bình của từng nhóm để bạn dễ hiểu Insight print("\n ĐẶC ĐIỂM TRUNG BÌNH CỦA 3 NHÓM KHÁCH HÀNG:") summary = output_df.groupby('Segment')[['CLTV', 'Monthly Charge', 'Churn Score', 'Avg Monthly GB Download']].mean() print(summary)