Skip to content

🧠 Case Study — EDA: Khám phá dữ liệu trong thực tế

Trong buổi học này, chúng ta đã nắm được quy trình EDA hoàn chỉnh: univariate → bivariate → multivariate, sử dụng Pandas, Matplotlib, và Seaborn. Bây giờ hãy xem các kỹ năng đó được áp dụng trong thực tế như thế nào — từ việc Airbnb phát hiện pricing anomalies trên toàn cầu, đến Shopee phân tích hành vi người dùng để tối ưu conversion, và cuối cùng là best practices từ top Kaggle notebooks.


Case Study 1: Airbnb — EDA trên Listing Data phát hiện Pricing Patterns & Host Behavior

Bối cảnh

Airbnb công khai dữ liệu listing thông qua chương trình Inside Airbnb — một project thu thập và chia sẻ dữ liệu từ hàng triệu listing trên toàn thế giới. Dataset phổ biến nhất là New York City listings với khoảng 37.000 listings, chứa thông tin: giá/đêm, loại phòng, khu vực, số reviews, availability, host info, và nhiều features khác.

Team Data Analytics của một OTA (Online Travel Agency) tại Việt Nam nhận nhiệm vụ: phân tích thị trường Airbnb NYC để benchmark cho sản phẩm homestay nội địa. Họ cần hiểu pricing patterns, host behavior, và demand distribution trước khi đề xuất chiến lược giá.

Vấn đề

Khi nhận dataset, team thấy dữ liệu "có vẻ đầy đủ" — 37.000 dòng, 18 cột, missing values < 5%. Một thành viên junior đề xuất: "Tính mean price theo khu vực rồi làm báo cáo thôi."

Nhưng Senior DA trong team kiên quyết: "EDA trước. Mọi thứ khác sau."

Giải pháp — EDA Pipeline

Bước 1 — Overview & Distribution Analysis:

python
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

df = pd.read_csv('airbnb_nyc_listings.csv')
print(f"Shape: {df.shape}")         # (36,905, 18)
print(df.describe())

# Phân phối giá — univariate EDA
fig, axes = plt.subplots(1, 2, figsize=(14, 5))

# Histogram cho thấy extreme right skew
axes[0].hist(df['price'], bins=100, edgecolor='black', alpha=0.7)
axes[0].set_title('Phân phối giá Airbnb NYC (raw)')
axes[0].set_xlabel('Giá / đêm ($)')

# Boxplot phát hiện outliers
axes[1].boxplot(df['price'], vert=True)
axes[1].set_title('Boxplot — Giá / đêm')

plt.tight_layout()
plt.show()

Kết quả ngay lập tức cho thấy vấn đề: price có min = $0 và max = $10.000/đêm. Mean = $153 nhưng median = $106 — phân phối bị skew mạnh. Nếu team tính trung bình mà không nhìn phân phối, con số $153 sẽ không đại diện cho đa số listings.

Phát hiện Pricing Anomalies bằng EDA

Airbnb NYC có listings giá $0 (host quên set giá hoặc listing test) và $10.000/đêm (luxury penthouses hoặc data error). EDA phát hiện điều này trong 30 giây nhờ df.describe() + histogram. Nếu bỏ qua, mọi phân tích giá trung bình sẽ bị sai lệch nghiêm trọng.

Bước 2 — Bivariate: Giá theo khu vực và loại phòng:

python
# Lọc outliers hợp lý (giá từ $10 đến $1000)
df_clean = df[(df['price'] > 10) & (df['price'] < 1000)]

# Giá theo neighbourhood_group (5 boroughs NYC)
fig, axes = plt.subplots(1, 2, figsize=(16, 6))

# Boxplot giá theo borough
sns.boxplot(data=df_clean, x='neighbourhood_group', y='price',
            order=['Manhattan', 'Brooklyn', 'Queens', 'Bronx', 'Staten Island'],
            ax=axes[0], palette='Set2')
axes[0].set_title('Giá Airbnb theo Borough')
axes[0].set_xlabel('Borough')
axes[0].set_ylabel('Giá / đêm ($)')

# Countplot — số lượng listing theo room type
sns.countplot(data=df_clean, x='room_type', hue='neighbourhood_group',
              ax=axes[1], palette='Set2')
axes[1].set_title('Số lượng listing theo Loại phòng & Borough')
axes[1].legend(title='Borough', fontsize=8)

plt.tight_layout()
plt.show()

EDA cho thấy: Manhattan chiếm 44% listings với giá trung vị $150/đêm, trong khi Bronx chỉ chiếm 2.5% với giá trung vị $65. Nhưng điều bất ngờ: Private Room ở Brooklyn có giá ngang với Entire Apartment ở Bronx — insight này team chưa bao giờ nghĩ tới nếu không vẽ biểu đồ.

Bước 3 — Host Behavior Analysis:

python
# Host behavior: số listing trung bình mỗi host
host_listing_counts = df.groupby('host_id')['id'].count().reset_index()
host_listing_counts.columns = ['host_id', 'listing_count']

print(f"Tổng hosts: {host_listing_counts.shape[0]:,}")
print(f"Hosts có 1 listing: {(host_listing_counts['listing_count'] == 1).sum():,}")
print(f"Hosts có > 10 listings: {(host_listing_counts['listing_count'] > 10).sum():,}")

# Top 10 hosts
top_hosts = host_listing_counts.nlargest(10, 'listing_count')
print("\nTop 10 hosts theo số listing:")
print(top_hosts)

Phát hiện bất ngờ: top 1% hosts sở hữu 25% tổng listings — đây không phải "cá nhân cho thuê phòng thừa" mà là professional property managers. Pattern này ảnh hưởng trực tiếp đến chiến lược giá: professional hosts thường set giá cạnh tranh hơn, response nhanh hơn, và có nhiều reviews hơn.

Kết quả

Phát hiện từ EDAImpact
Pricing outliers ($0 và $10K+)Cần filter trước khi tính statistics — tránh sai lệch mean
Manhattan premium 2-3x vs outer boroughsBenchmark giá homestay nội địa cần phân theo vùng
Professional hosts chiếm 25% listingsModel pricing cần phân biệt individual vs professional host
Private Room Brooklyn ≈ Entire Apt BronxLocation premium quan trọng hơn room type

Bài học từ Airbnb EDA

  1. Luôn check distribution trước khi tính mean — dùng histogram + boxplot.
  2. Outlier lọc theo domain knowledge — $0/đêm rõ ràng sai, nhưng $500/đêm ở Manhattan là bình thường.
  3. Bivariate analysis phát hiện insight mà univariate bỏ lỡ — giá trung bình chung không có nghĩa bằng giá theo segment.

Bài học cho DA

  1. EDA phải đi trước mọi business recommendation — nếu team kết luận giá trung bình $153 mà không EDA, họ sẽ đề xuất pricing sai.
  2. df.describe() là dòng code đầu tiên — min, max, mean, median cho bạn overview trong 1 giây.
  3. Visualization là công cụ phát hiện chính — bảng số khó thấy skewness, nhưng histogram hiện ngay lập tức.
  4. Host behavior analysis mở ra góc nhìn hoàn toàn mới — không chỉ phân tích listing, mà phân tích người tạo listing.

Case Study 2: Shopee — EDA User Behavior Data: Session Time, Click Patterns, Conversion

Bối cảnh

Shopee là sàn thương mại điện tử lớn nhất Đông Nam Á, với hơn 340 triệu lượt truy cập/tháng tại Việt Nam. Team Growth Analytics gồm 8 người chịu trách nhiệm phân tích user behavior — từ lúc user mở app đến khi hoàn tất (hoặc bỏ dở) đơn hàng.

Quý 4/2025, conversion rate (CR) trên mobile app giảm từ 3.8% xuống 3.2% mà team chưa xác định được nguyên nhân. VP of Product yêu cầu: "Cho tôi biết tại sao CR giảm — và giảm ở đâu."

Team có dataset user behavior gồm 5 triệu sessions trong 3 tháng, mỗi session chứa: session_id, user_id, device_type, session_duration_sec, page_views, search_count, add_to_cart, checkout_initiated, order_completed, traffic_source, user_segment (new/returning).

Vấn đề

Một cách tiếp cận phổ biến nhưng sai: "CR giảm 0.6% point, vậy nhân với traffic sẽ ra số đơn mất, xong." Nhưng Senior DA hỏi: "CR giảm đều trên mọi segment hay chỉ giảm ở một nhóm cụ thể? Session behavior có thay đổi gì không?"

Câu trả lời chỉ có EDA mới tìm được.

Giải pháp — EDA theo Funnel

Bước 1 — Funnel Overview:

python
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

df = pd.read_csv('shopee_sessions_q4.csv')

# Funnel metrics tổng quan
funnel = {
    'Sessions': len(df),
    'Search': (df['search_count'] > 0).sum(),
    'Add to Cart': (df['add_to_cart'] > 0).sum(),
    'Checkout': (df['checkout_initiated'] == 1).sum(),
    'Order': (df['order_completed'] == 1).sum()
}

funnel_df = pd.DataFrame(list(funnel.items()), columns=['Step', 'Count'])
funnel_df['Rate'] = funnel_df['Count'] / funnel_df['Count'].iloc[0] * 100
funnel_df['Drop_off'] = funnel_df['Rate'].diff().fillna(0)

print(funnel_df.to_string(index=False))

Kết quả cho thấy: drop-off lớn nhất ở bước "Add to Cart → Checkout" (giảm 68%). Đây là nút thắt — nhưng câu hỏi tiếp theo: nút thắt này có phải mới không, hay đã tồn tại từ trước?

Bước 2 — Segment Breakdown (New vs Returning):

python
# So sánh CR theo user segment
segment_cr = df.groupby('user_segment').agg(
    sessions=('session_id', 'count'),
    orders=('order_completed', 'sum'),
    avg_session_duration=('session_duration_sec', 'median'),
    avg_page_views=('page_views', 'median')
)
segment_cr['conversion_rate'] = segment_cr['orders'] / segment_cr['sessions'] * 100

print("\n=== Conversion Rate theo Segment ===")
print(segment_cr)

# Visualization
fig, axes = plt.subplots(1, 3, figsize=(18, 5))

# CR by segment
segment_cr['conversion_rate'].plot(kind='bar', ax=axes[0], color=['#3498db', '#e74c3c'])
axes[0].set_title('CR theo User Segment')
axes[0].set_ylabel('Conversion Rate (%)')

# Session duration distribution
for seg in df['user_segment'].unique():
    axes[1].hist(df[df['user_segment'] == seg]['session_duration_sec'],
                 bins=50, alpha=0.5, label=seg)
axes[1].set_title('Phân phối Session Duration')
axes[1].set_xlabel('Duration (giây)')
axes[1].legend()

# Page views distribution
sns.boxplot(data=df, x='user_segment', y='page_views', ax=axes[2])
axes[2].set_title('Page Views theo Segment')

plt.tight_layout()
plt.show()

Phát hiện quan trọng

EDA cho thấy: CR của Returning Users giữ nguyên 4.5%, nhưng CR của New Users giảm từ 2.8% xuống 1.9%. Đồng thời, tỷ lệ New Users trong tổng traffic tăng từ 35% lên 48% — do chiến dịch marketing mùa sale thu hút nhiều user mới chất lượng thấp (session duration trung vị chỉ 45 giây vs 180 giây của returning users). CR tổng giảm không phải vì sản phẩm tệ hơn — mà vì traffic mix thay đổi.

Bước 3 — Device & Traffic Source Deep Dive:

python
# CR theo device type và traffic source
pivot_cr = df.pivot_table(
    values='order_completed',
    index='device_type',
    columns='traffic_source',
    aggfunc='mean'
) * 100

print("\n=== CR (%) theo Device × Traffic Source ===")
print(pivot_cr.round(2))

# Heatmap
plt.figure(figsize=(10, 6))
sns.heatmap(pivot_cr, annot=True, fmt='.2f', cmap='YlOrRd',
            linewidths=0.5, cbar_kws={'label': 'Conversion Rate (%)'})
plt.title('Heatmap: CR theo Device × Traffic Source')
plt.tight_layout()
plt.show()

Heatmap tiết lộ thêm: traffic từ TikTok Ads trên Android có CR chỉ 0.8% — thấp nhất toàn bộ matrix. Đây là nguồn traffic chiếm 22% New Users nhưng gần như không convert. Team Marketing đang đổ budget vào channel có ROI thấp nhất.

Bước 4 — Click Pattern Anomaly:

python
# Session behavior: search → add_to_cart → checkout correlation
behavior_cols = ['search_count', 'page_views', 'add_to_cart',
                 'session_duration_sec', 'order_completed']
corr = df[behavior_cols].corr()

plt.figure(figsize=(8, 6))
sns.heatmap(corr, annot=True, cmap='RdBu_r', center=0,
            fmt='.2f', square=True)
plt.title('Correlation: Session Behavior Metrics')
plt.tight_layout()
plt.show()

Insight: search_count có tương quan dương mạnh (+0.38) với order_completed, nhưng page_views lại tương quan yếu (+0.08). Nghĩa là: user tìm kiếm nhiều thì mua nhiều, nhưng user xem nhiều trang chưa chắc mua. Nhóm "window shoppers" (page_views cao, search thấp) hầu như không convert — chiếm 30% sessions nhưng chỉ đóng góp 4% orders.

Kết quả

Insight từ EDAAction được đề xuất
CR giảm do traffic mix thay đổi, không do product issueĐiều chỉnh KPI: tách CR theo new/returning
TikTok Ads Android: CR = 0.8%, chiếm 22% new usersGiảm budget TikTok Ads hoặc optimize landing page
Search-driven users convert 3x vs browse-only usersPrioritize search UX improvement
Drop-off lớn nhất ở Cart → CheckoutA/B test simplified checkout flow cho new users

Bài học cho DA

  1. Không bao giờ chỉ nhìn metric tổng — CR tổng giảm che giấu sự thật: returning CR ổn định, new CR giảm mạnh.
  2. Pivot table + heatmap là combo mạnh nhất cho bivariate analysis — nhanh chóng phát hiện "ô vuông" nào đang có vấn đề.
  3. Correlation giữa behavior metrics cho biết hành vi nào thực sự dẫn đến conversion — không phải tất cả engagement đều có giá trị.
  4. EDA thay đổi câu hỏi — từ "tại sao CR giảm?" thành "CR giảm ở segment nào, từ nguồn nào, trên device nào?" — giúp đi đến root cause nhanh hơn.

Case Study 3: Kaggle — Top Notebooks EDA: Pattern và Best Practices

Bối cảnh

Kaggle là nền tảng Data Science lớn nhất thế giới với hơn 15 triệu users. Mỗi competition thu hút hàng nghìn notebooks — và có một quan sát thú vị: top-voted notebooks hầu hết là EDA notebooks, không phải modeling notebooks. Trong competition "House Prices" (hơn 80.000 teams), notebook được vote nhiều nhất là "Comprehensive data exploration with Python" — một EDA notebook thuần túy.

Điều này nói lên: cộng đồng Data Science đánh giá EDA cao ngang, thậm chí hơn, modeling. Tại sao?

Phân tích: Pattern chung của Top EDA Notebooks

Team nghiên cứu phân tích 50 top-voted EDA notebooks từ 5 competitions lớn nhất trên Kaggle: Titanic, House Prices, Credit Card Fraud, Airbnb NYC, và Store Sales Forecasting. Họ tìm ra một EDA framework chung mà hầu hết top notebooks đều tuân theo.

Pattern 1 — Structure nhất quán với 5 phần:

Hầu hết top EDA notebooks tuân theo cấu trúc 5 phần:

PhầnNội dungTỷ lệ notebooks áp dụng
1. Data Overviewshape, dtypes, head, describe, missing values98%
2. Univariate AnalysisDistribution của từng feature quan trọng94%
3. Bivariate AnalysisRelationships giữa features và target88%
4. Multivariate AnalysisCorrelation matrix, pair plots82%
5. Summary & InsightsTóm tắt findings, đề xuất next steps76%

Công thức EDA 5 bước — áp dụng cho mọi dataset

Bất kể dataset là gì — sales, healthcare, finance, marketing — 5 bước trên luôn áp dụng được. Đây là "checklist khám tổng quát" mà top Kagglers đều tuân theo.

Pattern 2 — Visualization-first approach:

Top notebooks dành 60-70% nội dung cho visualization, chỉ 30-40% cho code giải thích. Mỗi biểu đồ đều kèm narrative — giải thích insight, không chỉ show hình.

python
# Pattern từ top Kaggle EDA notebooks: LUÔN kèm narrative
# Ví dụ với House Prices dataset
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

df = pd.read_csv('house_prices.csv')

# Phân phối target variable (SalePrice)
fig, axes = plt.subplots(1, 3, figsize=(18, 5))

# 1. Histogram — xem shape
axes[0].hist(df['SalePrice'], bins=50, edgecolor='black', alpha=0.7)
axes[0].set_title('SalePrice Distribution')
axes[0].axvline(df['SalePrice'].mean(), color='r', linestyle='--', label=f"Mean: ${df['SalePrice'].mean():,.0f}")
axes[0].axvline(df['SalePrice'].median(), color='g', linestyle='--', label=f"Median: ${df['SalePrice'].median():,.0f}")
axes[0].legend()

# 2. Log-transformed — xem nếu transform có normalize không
axes[1].hist(df['SalePrice'].apply(lambda x: x if x > 0 else 1).apply('log'),
             bins=50, edgecolor='black', alpha=0.7, color='orange')
axes[1].set_title('Log(SalePrice) — Gần normal hơn')

# 3. QQ-plot style: sorted values
axes[2].scatter(range(len(df)), df['SalePrice'].sort_values().values, alpha=0.3, s=5)
axes[2].set_title('Sorted SalePrice — Phát hiện khoảng nhảy')

plt.tight_layout()
plt.show()

# NARRATIVE (pattern bắt buộc trong top notebooks):
print("""
INSIGHT: SalePrice bị right-skewed (skewness = 1.88).
- Mean ($180K) > Median ($163K) → nhóm nhà đắt kéo mean lên.
- Log transform giúp normalize → nên dùng log(SalePrice) khi modeling.
- Sorted plot cho thấy "bậc thang" ở top 5% → luxury segment tách biệt rõ.
""")

Pattern 3 — Missing Values Analysis sâu:

Top notebooks không chỉ đếm missing values — họ phân tích lý dovisualize missing pattern:

python
# Missing values analysis — best practice từ Kaggle
missing = df.isnull().sum()
missing_pct = (missing / len(df) * 100).sort_values(ascending=False)
missing_df = pd.DataFrame({
    'Missing Count': missing,
    'Missing %': missing_pct
}).query('`Missing Count` > 0')

print("=== Missing Values Summary ===")
print(missing_df)

# Visualize missing pattern
plt.figure(figsize=(12, 6))
missing_df['Missing %'].plot(kind='bar', color='coral', edgecolor='black')
plt.axhline(y=50, color='red', linestyle='--', label='50% threshold')
plt.title('Missing Values theo Feature')
plt.ylabel('% Missing')
plt.legend()
plt.xticks(rotation=45, ha='right')
plt.tight_layout()
plt.show()

Best Practice: Missing Values Decision Framework

Top Kaggle notebooks phân loại missing values theo 3 nhóm:

  • MCAR (Missing Completely At Random): thiếu ngẫu nhiên → safe to drop or impute
  • MAR (Missing At Random): thiếu phụ thuộc vào biến khác → cần impute có điều kiện
  • MNAR (Missing Not At Random): thiếu vì chính giá trị đó (e.g., income cao thì không khai) → cần domain knowledge

Hiểu loại missing giúp chọn đúng chiến lược xử lý — đây là điều phân biệt EDA amateur và professional.

Pattern 4 — Correlation với domain knowledge:

python
# Correlation analysis — top notebook pattern
# Không show toàn bộ matrix, chỉ show top correlations với target

target_corr = df.select_dtypes(include='number').corr()['SalePrice'].drop('SalePrice')
target_corr = target_corr.abs().sort_values(ascending=False)

# Top 10 features tương quan mạnh nhất với SalePrice
print("=== Top 10 Features tương quan với SalePrice ===")
print(target_corr.head(10))

# Scatter plots cho top 4 features
top_features = target_corr.head(4).index.tolist()
fig, axes = plt.subplots(1, 4, figsize=(20, 5))

for i, feat in enumerate(top_features):
    axes[i].scatter(df[feat], df['SalePrice'], alpha=0.3, s=10)
    axes[i].set_xlabel(feat)
    axes[i].set_ylabel('SalePrice')
    corr_val = df[feat].corr(df['SalePrice'])
    axes[i].set_title(f'{feat}\n(r = {corr_val:.2f})')

plt.tight_layout()
plt.show()

Kết quả — Framework đúc kết từ 50 Top Notebooks

Best PracticeTần suất áp dụngTại sao quan trọng
Bắt đầu bằng df.shape, df.info(), df.describe()98%Tạo mental model về dataset trước khi dive deep
Histogram + boxplot cho mọi numeric feature94%Phát hiện skewness, outliers ngay lập tức
Missing values heatmap/bar chart88%Quyết định chiến lược imputation
Correlation matrix chỉ show top features82%Tránh cognitive overload, focus vào features quan trọng
Narrative text sau mỗi visualization76%Biến chart thành insight — đây là điều tạo nên sự khác biệt
Log transform test cho skewed features68%Cải thiện model performance đáng kể

Bài học cho DA

  1. EDA tốt = kể chuyện với data — top notebooks không chỉ show biểu đồ, họ giải thích: "biểu đồ này cho thấy X, điều này có nghĩa Y, nên chúng ta cần làm Z."
  2. Structure nhất quán — tuân theo 5 bước (Overview → Univariate → Bivariate → Multivariate → Summary) giúp không bỏ sót và dễ reproduce.
  3. Missing values analysis là nghệ thuật — không phải cứ missing là drop; hiểu lý do missing quan trọng hơn đếm số missing.
  4. Focus > Completeness — top notebooks không phân tích tất cả features; họ chọn top 10-15 features quan trọng nhất và phân tích sâu.

So sánh & Tổng hợp

Tiêu chíAirbnbShopeeKaggle Best Practices
Dataset37K listings, 18 features5M sessions, 12 featuresVaries (1K - 300K rows)
EDA FocusPricing distribution & host segmentationFunnel analysis & behavior patternsComprehensive feature exploration
Key TechniqueHistogram + boxplot cho outlier detectionPivot table + heatmap cho segment CRCorrelation + scatter cho feature selection
Biggest InsightMean price misleading do outliers; professional hosts dominateCR drop do traffic mix, not product issueEDA structure determines analysis quality
Business ImpactPricing strategy benchmark chính xác hơnReallocate marketing budget, save costHigher model accuracy, better reproducibility
LessonFilter outliers bằng domain knowledgeSegment trước khi concludeFollow 5-step framework consistently

Nguyên tắc chung từ 3 Case Studies

  1. EDA TRƯỚC, kết luận SAU — cả 3 case đều cho thấy: nhảy vào tính toán mà không EDA sẽ dẫn đến kết luận sai.
  2. Distribution > Mean — trung bình nói dối, phân phối nói thật. Luôn vẽ histogram/boxplot trước khi tính mean.
  3. Segment analysis phát hiện insight ẩn — tổng thể che giấu chi tiết. Chia nhỏ theo segment là cách tìm root cause nhanh nhất.
  4. Visualization + Narrative — biểu đồ không có giải thích chỉ là hình đẹp. Insight nằm ở câu chuyện bạn kể từ biểu đồ.

Bài tập tư duy

Câu hỏi thảo luận

  1. Airbnb Context: Nếu bạn EDA dataset Airbnb Việt Nam (Đà Nẵng, Hội An, Phú Quốc), bạn dự đoán pricing distribution sẽ khác NYC như thế nào? Những yếu tố nào sẽ ảnh hưởng đến giá mà NYC không có (ví dụ: mùa du lịch, proximity to beach)?

  2. Shopee Context: Giả sử bạn phát hiện CR trên iOS cao gấp đôi Android. Trước khi kết luận "iOS users convert tốt hơn", bạn cần EDA thêm những gì để tránh kết luận sai? (Gợi ý: income level, device price, demographic biases)

  3. Kaggle Context: Tại sao top-voted notebooks trên Kaggle thường là EDA notebooks chứ không phải modeling notebooks? Điều này nói gì về giá trị của EDA trong Data Science workflow?

  4. Cross-case: Cả 3 case studies đều cho thấy "trung bình nói dối." Hãy nghĩ về 1 tình huống trong công việc hoặc cuộc sống hàng ngày mà con số trung bình che giấu sự thật. Bạn sẽ dùng kỹ thuật EDA nào để phát hiện?

Bài tập thực hành

Bài tập: EDA Mini-Project

Dataset: Tải Airbnb NYC dataset từ Inside Airbnb hoặc Kaggle.

Yêu cầu:

  1. Thực hiện 5 bước EDA (Overview → Univariate → Bivariate → Multivariate → Summary)
  2. Tạo ít nhất 5 visualizations có narrative giải thích
  3. Viết EDA Summary gồm: dataset overview, key distributions, segment insights, top correlations, recommendations
  4. Trả lời: "Nếu bạn muốn mở Airbnb ở NYC, bạn nên chọn borough nào, room type nào, và đặt giá bao nhiêu?"

Tiêu chí đánh giá:

  • Có follow 5-step framework không?
  • Visualization có kèm narrative không?
  • Insight có actionable không (dẫn đến recommendation cụ thể)?