|
import streamlit as st |
|
import pandas as pd |
|
import numpy as np |
|
import matplotlib.pyplot as plt |
|
import seaborn as sns |
|
from sklearn.cluster import KMeans |
|
from sklearn.preprocessing import StandardScaler |
|
from sklearn.decomposition import PCA |
|
from datasets import load_dataset |
|
|
|
|
|
st.title("Ứng dụng Phân Cụm Dữ Liệu Không Giám Sát") |
|
|
|
|
|
with st.expander("Giới thiệu về Ứng dụng"): |
|
st.write( |
|
"Ứng dụng này cho phép bạn tải lên bất kỳ loại tập dữ liệu không nhãn nào " |
|
"và tự động phân cụm dữ liệu bằng thuật toán K-means. " |
|
"Nó sẽ trực quan hóa các cụm bằng phương pháp PCA và cung cấp biểu đồ chuỗi thời gian cũng như phân phối cụm " |
|
"giúp bạn nhận diện các mô hình và nhóm trong dữ liệu." |
|
) |
|
|
|
|
|
uploaded_file = st.file_uploader("Tải lên tập tin CSV", type=["csv"]) |
|
|
|
|
|
if st.button("Dùng thử với bộ dữ liệu mẫu"): |
|
dataset = load_dataset('kheejay88/country_data', split='train') |
|
df = pd.DataFrame(dataset) |
|
st.success("Đã tải thành công bộ dữ liệu mẫu từ Hugging Face.") |
|
|
|
|
|
with st.expander("Các Cột Dữ Liệu"): |
|
st.write(""" |
|
**country** – Tên quốc gia\n |
|
**child_mort** – Tỷ lệ tử vong trẻ em dưới 5 tuổi trên 1000 ca sinh sống\n |
|
**exports** – Xuất khẩu hàng hóa và dịch vụ trên đầu người (tính theo phần trăm GDP)\n |
|
**health** – Chi tiêu y tế trên đầu người (tính theo phần trăm GDP)\n |
|
**imports** – Nhập khẩu hàng hóa và dịch vụ trên đầu người (tính theo phần trăm GDP)\n |
|
**income** – Thu nhập ròng trên đầu người\n |
|
**inflation** – Tỷ lệ lạm phát hàng năm (phần trăm)\n |
|
**life_expec** – Tuổi thọ trung bình khi sinh (năm)\n |
|
**total_fer** – Tổng tỷ suất sinh (số con trung bình mỗi phụ nữ)\n |
|
**gdpp** – GDP trên đầu người\n |
|
""") |
|
|
|
if uploaded_file is not None: |
|
df = pd.read_csv(uploaded_file) |
|
|
|
if 'df' in locals(): |
|
|
|
categorical_cols = df.select_dtypes(include=['object', 'category']).columns.tolist() |
|
df.drop(columns=categorical_cols, inplace=True) |
|
st.write("### Dữ liệu thô:") |
|
st.write(df.head()) |
|
|
|
|
|
scaler = StandardScaler() |
|
scaled_data = scaler.fit_transform(df) |
|
|
|
|
|
num_clusters = st.slider("Chọn số lượng cụm", min_value=2, max_value=10, value=3) |
|
|
|
|
|
kmeans = KMeans(n_clusters=num_clusters, random_state=42) |
|
clusters = kmeans.fit_predict(scaled_data) |
|
df['Cụm'] = clusters |
|
|
|
|
|
pca = PCA(n_components=2) |
|
pca_data = pca.fit_transform(scaled_data) |
|
df['PCA1'] = pca_data[:, 0] |
|
df['PCA2'] = pca_data[:, 1] |
|
|
|
|
|
st.write("### Biểu đồ Phân Cụm:") |
|
fig, ax = plt.subplots() |
|
sns.scatterplot(x='PCA1', y='PCA2', hue='Cụm', data=df, palette='viridis', ax=ax) |
|
st.pyplot(fig) |
|
|
|
|
|
numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist() |
|
if len(numeric_cols) >= 2: |
|
selected_col = st.selectbox("Chọn cột để vẽ biểu đồ chuỗi thời gian", numeric_cols) |
|
st.write("### Biểu đồ Chuỗi Thời Gian:") |
|
fig, ax = plt.subplots() |
|
for cluster in df['Cụm'].unique(): |
|
cluster_data = df[df['Cụm'] == cluster] |
|
ax.plot(cluster_data.index, cluster_data[selected_col], label=f'Cụm {cluster}') |
|
ax.legend() |
|
st.pyplot(fig) |
|
|
|
|
|
st.write("### Phân phối Cụm:") |
|
fig, ax = plt.subplots() |
|
sns.countplot(x='Cụm', data=df, palette='viridis', ax=ax) |
|
st.pyplot(fig) |
|
|
|
st.markdown("---") |
|
st.markdown("**Cảm ơn bạn!**") |