MinAI - Về trang chủ
Thực hành
9/152 giờ
Đang tải...

Thực Hành Trực Quan Hóa Dữ Liệu

Bài tập thực hành Matplotlib, Seaborn, Plotly trên dataset thực tế

0

🎯 Mục tiêu bài học

TB5 min

Sau bài thực hành này, bạn sẽ:

✅ Tạo dashboard phân tích hoàn chỉnh bằng Seaborn

✅ Chọn đúng loại biểu đồ cho từng câu hỏi phân tích

✅ Customize biểu đồ chuyên nghiệp (colors, labels, annotations)

✅ Tạo interactive visualization với Plotly

Thời gian: 2 giờ | Độ khó: Beginner → Hard | Yêu cầu: Hoàn thành Bài 8 (Visualization)

1

🟢 Phần 1: Basic Charts (Easy)

TB5 min

Ôn lại lý thuyết (Bài 8):

  • Matplotlib: Core library, fig, ax = plt.subplots()
  • Seaborn: High-level, built on Matplotlib, themes + palettes
  • Plotly: Interactive charts, px.scatter(), px.line(), px.bar()
  • Chart types: Line (xu hướng), Bar (so sánh), Scatter (tương quan), Box (phân phối)

Bài 1.1: Tạo dataset và biểu đồ cơ bản

Python
1import matplotlib.pyplot as plt
2import seaborn as sns
3import plotly.express as px
4import pandas as pd
5import numpy as np
6
7np.random.seed(42)
8sns.set_theme(style="whitegrid")
9
10# Dataset: Doanh thu 12 tháng theo 3 khu vực
11months = pd.date_range("2024-01-01", periods=12, freq="ME")
12df = pd.DataFrame({
13 "month": list(months) * 3,
14 "region": ["Bắc"] * 12 + ["Trung"] * 12 + ["Nam"] * 12,
15 "revenue": np.concatenate([
16 np.random.normal(500, 50, 12).cumsum(),
17 np.random.normal(400, 60, 12).cumsum(),
18 np.random.normal(600, 40, 12).cumsum()
19 ]).round(0)
20})

Bài 1.2: Line Chart — Xu hướng doanh thu

Đề bài: Vẽ line chart doanh thu theo tháng, mỗi khu vực 1 đường
Python
1fig, ax = plt.subplots(figsize=(12, 6))
2
3for region in df['region'].unique():
4 data = df[df['region'] == region]
5 ax.plot(data['month'], data['revenue'], marker='o', label=region)
6
7ax.set_title("Doanh Thu Theo Tháng Theo Khu Vực", fontsize=14, fontweight='bold')
8ax.set_xlabel("Tháng")
9ax.set_ylabel("Doanh thu (triệu VNĐ)")
10ax.legend(title="Khu vực")
11ax.tick_params(axis='x', rotation=45)
12plt.tight_layout()
13plt.show()

Bài 1.3: Bar Chart — So sánh tổng doanh thu

Đề bài: Bar chart tổng doanh thu mỗi khu vực
Python
1totals = df.groupby('region')['revenue'].sum().sort_values(ascending=False)
2
3fig, ax = plt.subplots(figsize=(8, 5))
4colors = ['#FF6B6B', '#4ECDC4', '#45B7D1']
5bars = ax.bar(totals.index, totals.values, color=colors, edgecolor='black')
6
7# Thêm số trên mỗi bar
8for bar in bars:
9 height = bar.get_height()
10 ax.text(bar.get_x() + bar.get_width()/2, height + 50,
11 f'{height:,.0f}', ha='center', fontweight='bold')
12
13ax.set_title("Tổng Doanh Thu Theo Khu Vực", fontsize=14, fontweight='bold')
14ax.set_ylabel("Doanh thu (triệu VNĐ)")
15plt.tight_layout()
16plt.show()

Checkpoint

Bạn đã thêm title, labels, legend cho biểu đồ chưa? Biểu đồ không có label là biểu đồ vô nghĩa!

2

🟡 Phần 2: Seaborn Statistical Plots (Medium)

TB5 min

Ôn lại lý thuyết (Bài 8):

  • Distribution plots: histplot (KDE), boxplot (quartiles), violinplot (density + box)
  • Categorical: barplot (mean + CI), countplot (count), stripplot (điểm rải)
  • Correlation: heatmap (ma trận tương quan), regplot (scatter + regression)
  • Subplots: fig, axes = plt.subplots(2, 2) rồi dùng ax=axes[i,j]
  • melt(): Chuyển wide → long format cho Seaborn

Bài 2.1: Distribution Analysis

Đề bài: Phân tích phân phối điểm thi của 500 sinh viên
Python
1np.random.seed(42)
2scores = pd.DataFrame({
3 "math": np.random.normal(72, 12, 500).clip(0, 100),
4 "physics": np.random.normal(68, 15, 500).clip(0, 100),
5 "chemistry": np.random.normal(75, 10, 500).clip(0, 100),
6 "gender": np.random.choice(["Nam", "Nữ"], 500)
7})
8
9fig, axes = plt.subplots(2, 2, figsize=(14, 10))
10
11# (a) Histogram + KDE cho Toán
12sns.histplot(scores, x="math", kde=True, ax=axes[0,0], color="steelblue")
13axes[0,0].axvline(scores['math'].mean(), color='red', linestyle='--', label='Mean')
14axes[0,0].legend()
15axes[0,0].set_title("Phân phối điểm Toán")
16
17# (b) Box plot 3 môn
18scores_melted = scores.melt(id_vars='gender', value_vars=['math','physics','chemistry'],
19 var_name='subject', value_name='score')
20sns.boxplot(data=scores_melted, x='subject', y='score', hue='gender', ax=axes[0,1])
21axes[0,1].set_title("Điểm theo Môn và Giới tính")
22
23# (c) Violin plot
24sns.violinplot(data=scores_melted, x='subject', y='score',
25 hue='gender', split=True, ax=axes[1,0])
26axes[1,0].set_title("Violin Plot")
27
28# (d) Correlation heatmap
29corr = scores[['math','physics','chemistry']].corr()
30sns.heatmap(corr, annot=True, cmap='coolwarm', center=0, ax=axes[1,1], fmt='.2f')
31axes[1,1].set_title("Tương quan giữa các môn")
32
33plt.suptitle("Phân Tích Điểm Thi Sinh Viên", fontsize=16, fontweight='bold')
34plt.tight_layout()
35plt.show()

Bài 2.2: Categorical Analysis

Đề bài: Phân tích dữ liệu tips (dataset mẫu Seaborn)
Python
1tips = sns.load_dataset("tips")
2
3fig, axes = plt.subplots(1, 3, figsize=(18, 5))
4
5# (a) Mean tip by day + smoker
6sns.barplot(data=tips, x="day", y="tip", hue="smoker",
7 errorbar="sd", ax=axes[0], palette="Set2")
8axes[0].set_title("Tip TB theo Ngày")
9
10# (b) Count by day and time
11sns.countplot(data=tips, x="day", hue="time", ax=axes[1], palette="Pastel1")
12axes[1].set_title("Số lượng theo Ngày & Buổi")
13
14# (c) Scatter: bill vs tip with regression
15sns.regplot(data=tips, x="total_bill", y="tip", ax=axes[2],
16 scatter_kws={'alpha': 0.5}, color="coral")
17axes[2].set_title("Bill vs Tip (Regression)")
18
19plt.tight_layout()
20plt.show()

Checkpoint

Bạn đã biết khi nào dùng histplot vs boxplot vs violinplot chưa?

3

🟡 Phần 3: Plotly Interactive (Medium)

TB5 min

Ôn lại lý thuyết (Bài 8):

  • Plotly Express: px.scatter(), px.line(), px.bar(), px.pie()
  • Interactive features: Zoom, pan, hover tooltip, filter legends
  • Animation: animation_frame="year" tạo slider thời gian
  • Customization: color, size, hover_name, log_x, range_x
  • Advanced: px.sunburst(), px.treemap() cho hierarchical data

Bài 3.1: Interactive Dashboard

Đề bài: Tạo các biểu đồ interactive với Plotly
Python
1# Dataset: Gapminder
2df = px.data.gapminder()
3
4# (a) Scatter: GDP vs Life Expectancy (2007) — hover country, size pop
5fig = px.scatter(df.query("year == 2007"),
6 x="gdpPercap", y="lifeExp",
7 color="continent", size="pop",
8 hover_name="country", log_x=True,
9 size_max=60,
10 title="GDP vs Tuổi Thọ — 2007")
11fig.show()
12
13# (b) Animated scatter qua các năm
14fig = px.scatter(df, x="gdpPercap", y="lifeExp",
15 animation_frame="year",
16 animation_group="country",
17 size="pop", color="continent",
18 hover_name="country",
19 log_x=True, size_max=55,
20 range_x=[100, 100000], range_y=[25, 90],
21 title="Gapminder Animation")
22fig.show()
23
24# (c) Vietnam vs neighbors
25countries = ['Vietnam', 'Thailand', 'Indonesia', 'Philippines', 'Malaysia']
26df_sea = df[df['country'].isin(countries)]
27
28fig = px.line(df_sea, x="year", y="gdpPercap",
29 color="country", markers=True,
30 title="GDP Per Capita — Southeast Asia")
31fig.show()

Bài 3.2: Business Charts

Đề bài: Biểu đồ kinh doanh interactive
Python
1# Pie chart: Market share
2market = pd.DataFrame({
3 "company": ["Apple", "Samsung", "Xiaomi", "OPPO", "Others"],
4 "share": [27, 21, 14, 10, 28]
5})
6fig = px.pie(market, values="share", names="company",
7 title="Thị phần Smartphone 2024",
8 hole=0.4) # Donut
9fig.show()
10
11# Sunburst: Hierarchical
12tips = px.data.tips()
13fig = px.sunburst(tips, path=["day", "time", "sex"],
14 values="total_bill",
15 title="Revenue Breakdown")
16fig.show()

Checkpoint

Plotly animation là tính năng rất ấn tượng trong presentation. Bạn đã tạo animation thành công chưa?

4

🔴 Phần 4: Complete Analysis Report (Hard)

TB5 min

Bài này kết hợp tất cả kỹ năng EDA:

  • Chọn đúng chart cho từng câu hỏi (pie, bar, hist, box, heatmap)
  • Layout subplot rõ ràng (3x2 grid)
  • Color palette nhất quán
  • Title, labels đầy đủ
  • Lưu xuất PNG resolution cao (dpi=300)

Tip: Xem solution rồi tự build dashboard cho dataset khác (housing, salary, etc.)

Bài 4.1: Full EDA Dashboard

Đề bài: Tạo báo cáo phân tích hoàn chỉnh cho dataset Titanic
Python
1# Load data
2titanic = sns.load_dataset("titanic")
3print(titanic.shape)
4print(titanic.head())
5
6fig, axes = plt.subplots(3, 2, figsize=(14, 16))
7
8# 1. Survival rate
9survival = titanic['survived'].value_counts()
10axes[0,0].pie(survival.values, labels=['Không sống sót', 'Sống sót'],
11 autopct='%1.1f%%', colors=['#FF6B6B', '#4ECDC4'])
12axes[0,0].set_title("Tỷ lệ sống sót")
13
14# 2. Survival by class
15sns.barplot(data=titanic, x='class', y='survived', hue='sex',
16 ax=axes[0,1], palette='Set2')
17axes[0,1].set_title("Tỷ lệ sống sót theo Hạng & Giới tính")
18axes[0,1].set_ylabel("Tỷ lệ sống sót")
19
20# 3. Age distribution by survival
21sns.histplot(data=titanic, x='age', hue='survived', kde=True,
22 ax=axes[1,0], palette={0: '#FF6B6B', 1: '#4ECDC4'})
23axes[1,0].set_title("Phân phối tuổi theo Sống sót")
24
25# 4. Fare distribution by class
26sns.boxplot(data=titanic, x='class', y='fare', ax=axes[1,1], palette='Set3')
27axes[1,1].set_title("Giá vé theo Hạng")
28
29# 5. Embarkation port
30sns.countplot(data=titanic, x='embark_town', hue='survived',
31 ax=axes[2,0], palette={0: '#FF6B6B', 1: '#4ECDC4'})
32axes[2,0].set_title("Cảng lên tàu & Sống sót")
33
34# 6. Correlation
35numeric = titanic.select_dtypes(include=[np.number])
36sns.heatmap(numeric.corr(), annot=True, cmap='RdYlGn', center=0,
37 ax=axes[2,1], fmt='.2f')
38axes[2,1].set_title("Ma trận tương quan")
39
40plt.suptitle("🚢 TITANIC — PHÂN TÍCH DỮ LIỆU TOÀN DIỆN",
41 fontsize=18, fontweight='bold', y=1.01)
42plt.tight_layout()
43plt.savefig("titanic_analysis.png", dpi=300, bbox_inches='tight')
44plt.show()

Template EDA Dashboard ở trên là pattern bạn sẽ dùng đi dùng lại trong mọi dự án Data Science. Hãy lưu lại làm template!

Checkpoint

Bạn đã tạo được dashboard 6 biểu đồ trên Titanic chưa? Kết luận gì về yếu tố ảnh hưởng sống sót?

5

📝 Tổng Kết

TB5 min

Câu hỏi tự kiểm tra

  1. Khi tạo EDA Dashboard, những loại biểu đồ nào nên có để phân tích toàn diện?
  2. sns.pairplot() giúp bạn khám phá điều gì về dữ liệu? Khi nào nên sử dụng?
  3. Plotly Express khác Matplotlib ở điểm nào khi tạo biểu đồ tương tác?
  4. Tại sao nên lưu biểu đồ với dpi=300 thay vì giá trị mặc định?

✅ Checklist hoàn thành

  • 🟢 Phần 1 (Easy): Line chart, bar chart — xong?
  • 🟡 Phần 2 (Medium): Seaborn statistical plots — xong?
  • 🟡 Phần 3 (Medium): Plotly interactive — xong?
  • 🔴 Phần 4 (Hard): Full EDA dashboard — xong?

Visualization Cheat Sheet

Python
1# Seaborn (static, statistical)
2sns.histplot(df, x="col", kde=True)
3sns.boxplot(df, x="cat", y="num")
4sns.scatterplot(df, x="x", y="y", hue="cat")
5sns.heatmap(corr, annot=True)
6
7# Plotly (interactive)
8px.scatter(df, x="x", y="y", color="cat", size="val")
9px.bar(df, x="cat", y="val")
10px.line(df, x="time", y="val", color="cat")
11px.pie(df, values="val", names="cat")

Bài tiếp theo: Data Cleaning — Xử lý dữ liệu bẩn, bước quan trọng nhất trong Data Science! 🧹