Skip to content

🧠 Case Study — Python Basics

Từ click chuột thủ công đến script tự động — Python cơ bản thay đổi cách Data Analyst làm việc như thế nào?

Tổng quan

Trong Buổi 7, bạn đã học các nền tảng Python: data types (int, float, str, list, dict), control flow (if/else, for loop), functions, và file handling (CSV, JSON). Đây là những khái niệm "nhỏ" nhưng tạo nên sức mạnh lớn — mỗi script tự động hóa, mỗi pipeline ETL, mỗi hệ thống báo cáo đều được xây dựng từ chính những building blocks này.

Ba case study dưới đây minh họa cách Python cơ bản được áp dụng ở 3 quy mô khác nhau — từ một DA tự động hóa báo cáo cá nhân, một team DA tại tập đoàn công nghệ lớn nhất Việt Nam xây ETL pipeline, đến startup chuyển đổi từ Google Sheets sang Python pipeline. Mỗi case trả lời 3 câu hỏi: (1) Vấn đề dữ liệu gì cần giải quyết? (2) Python cơ bản giải quyết bằng cách nào? (3) Kết quả đo lường được là gì?

#Case StudyVấn đềPython Concepts chính
1Automate the Boring StuffBáo cáo Excel thủ công mất 30 phút/ngàyCSV reading, functions, list, for loop
2FPT SoftwareETL từ 20+ nguồn dữ liệu cho 50 dự ánFile handling (CSV, JSON, Excel), dict, loop, functions
3Startup Việt Nam (DataMart)Google Sheets + copy-paste thủ công → pipelineFunctions, automation, list/dict, control flow

Case Study 1: Automate the Boring Stuff — Tự động hóa báo cáo KPI hàng ngày

🏷️ Thông tin

Tiêu chíChi tiết
Bối cảnhCông ty FMCG (Fast-Moving Consumer Goods) tại TP.HCM, ~500 nhân viên
NgànhBán lẻ — Hàng tiêu dùng nhanh
Quy mô dữ liệu~2,000–5,000 dòng giao dịch/ngày từ 15 cửa hàng
Nhân vậtMinh — Junior Data Analyst, mới vào nghề 6 tháng
Chủ đề DACSV file reading, functions, list operations, for loop, basic calculations

📋 Bối cảnh

Minh là Junior DA tại một công ty FMCG có 15 cửa hàng tại TP.HCM và Hà Nội. Mỗi sáng, hệ thống POS (Point of Sale) xuất file CSV chứa toàn bộ giao dịch ngày hôm trước — mỗi dòng gồm: mã giao dịch, cửa hàng, sản phẩm, số lượng, đơn giá, thời gian mua. Nhiệm vụ của Minh: tổng hợp file CSV này thành báo cáo KPI hàng ngày gửi cho quản lý trước 9h sáng.

⚡ Vấn đề

Quy trình cũ hoàn toàn thủ công:

  1. Mở file CSV bằng Excel (~2 phút chờ load 5,000 dòng)
  2. Tạo PivotTable tính tổng doanh thu theo cửa hàng (~5 phút)
  3. Tính các KPI: tổng doanh thu, số đơn hàng, giá trị đơn trung bình (AOV), top 5 sản phẩm bán chạy (~8 phút)
  4. So sánh với ngày hôm trước (mở thêm 1 file cũ, copy số liệu) (~5 phút)
  5. Format bảng đẹp, copy vào email gửi sếp (~10 phút)

Tổng: ~30 phút mỗi sáng — lặp lại 365 ngày/năm. Nếu sai 1 ô PivotTable → sai cả báo cáo → sếp mất niềm tin.

⚠️ Pain Points

  • Tốn thời gian: 30 phút × 250 ngày làm việc = 125 giờ/năm chỉ cho 1 báo cáo
  • Dễ sai sót: Copy-paste sai ô, quên filter, PivotTable chọn nhầm range
  • Không scale: Nếu thêm 5 cửa hàng mới → phải sửa lại PivotTable thủ công
  • Không version control: Không biết ai sửa gì, lúc nào

🛠️ Giải pháp

Minh học Python cơ bản trong 2 tuần và viết script tự động hóa toàn bộ quy trình.

Bước 1: Đọc file CSV bằng Python

python
import csv

def doc_du_lieu_csv(file_path):
    """Đọc file CSV và trả về list of dictionaries"""
    du_lieu = []
    with open(file_path, mode='r', encoding='utf-8') as file:
        reader = csv.DictReader(file)
        for dong in reader:
            # Chuyển đổi kiểu dữ liệu
            dong['so_luong'] = int(dong['so_luong'])
            dong['don_gia'] = float(dong['don_gia'])
            dong['thanh_tien'] = dong['so_luong'] * dong['don_gia']
            du_lieu.append(dong)
    return du_lieu

# Sử dụng
giao_dich = doc_du_lieu_csv('sales_2026-02-17.csv')
print(f"Tổng số giao dịch: {len(giao_dich)}")
# Output: Tổng số giao dịch: 4,832

🔍 Python Basics tại đây

  • Function (def doc_du_lieu_csv): Đóng gói logic thành khối tái sử dụng
  • List (du_lieu = []): Lưu trữ tất cả giao dịch
  • Dictionary (dong — mỗi dòng CSV là 1 dict với key là tên cột): Truy cập dữ liệu bằng tên cột thay vì index
  • For loop (for dong in reader): Duyệt qua từng dòng dữ liệu
  • Type conversion: int(), float() — chuyển đổi string sang số

Bước 2: Tính KPI bằng functions

python
def tinh_kpi(giao_dich):
    """Tính các KPI chính từ danh sách giao dịch"""
    tong_doanh_thu = 0
    doanh_thu_theo_cua_hang = {}
    san_pham_count = {}

    for gd in giao_dich:
        # Tổng doanh thu
        tong_doanh_thu += gd['thanh_tien']

        # Doanh thu theo cửa hàng — dùng dict
        cua_hang = gd['cua_hang']
        if cua_hang not in doanh_thu_theo_cua_hang:
            doanh_thu_theo_cua_hang[cua_hang] = 0
        doanh_thu_theo_cua_hang[cua_hang] += gd['thanh_tien']

        # Đếm số lượng bán theo sản phẩm
        sp = gd['san_pham']
        if sp not in san_pham_count:
            san_pham_count[sp] = 0
        san_pham_count[sp] += gd['so_luong']

    # Tính AOV (Average Order Value)
    so_don = len(giao_dich)
    aov = tong_doanh_thu / so_don if so_don > 0 else 0

    # Top 5 sản phẩm bán chạy — sort dict by value
    top_5_sp = sorted(san_pham_count.items(),
                      key=lambda x: x[1], reverse=True)[:5]

    return {
        'tong_doanh_thu': tong_doanh_thu,
        'so_don_hang': so_don,
        'aov': round(aov, 0),
        'doanh_thu_cua_hang': doanh_thu_theo_cua_hang,
        'top_5_san_pham': top_5_sp
    }

kpi = tinh_kpi(giao_dich)
print(f"Tổng doanh thu: {kpi['tong_doanh_thu']:,.0f} VNĐ")
print(f"Số đơn hàng: {kpi['so_don_hang']}")
print(f"AOV: {kpi['aov']:,.0f} VNĐ")
# Output:
# Tổng doanh thu: 892,450,000 VNĐ
# Số đơn hàng: 4,832
# AOV: 184,720 VNĐ

Bước 3: So sánh với ngày hôm trước

python
def so_sanh_ngay(kpi_hom_nay, kpi_hom_qua):
    """So sánh KPI hôm nay vs hôm qua, trả về % thay đổi"""
    thay_doi = {}
    for key in ['tong_doanh_thu', 'so_don_hang', 'aov']:
        gia_tri_nay = kpi_hom_nay[key]
        gia_tri_qua = kpi_hom_qua[key]
        if gia_tri_qua > 0:
            phan_tram = ((gia_tri_nay - gia_tri_qua) / gia_tri_qua) * 100
            thay_doi[key] = round(phan_tram, 1)
        else:
            thay_doi[key] = 0
    return thay_doi

# So sánh
giao_dich_hom_qua = doc_du_lieu_csv('sales_2026-02-16.csv')
kpi_hom_qua = tinh_kpi(giao_dich_hom_qua)
thay_doi = so_sanh_ngay(kpi, kpi_hom_qua)

print(f"Doanh thu thay đổi: {thay_doi['tong_doanh_thu']:+.1f}%")
# Output: Doanh thu thay đổi: +12.3%

📊 Kết quả

Chỉ sốTrước (thủ công)Sau (Python script)Cải thiện
Thời gian/báo cáo30 phút3 phút (chạy script)-90%
Thời gian/năm125 giờ12.5 giờTiết kiệm 112.5 giờ/năm
Tỷ lệ lỗi~5% (sai ô, nhầm filter)~0% (logic cố định)Gần như loại bỏ lỗi
Mở rộng cửa hàng mớiSửa PivotTable 15 phút0 phút (tự động detect)100% tự động
ConsistencyTùy ngày (mệt = sai)100% nhất quán

💡 Bài học quan trọng

Script chỉ dùng 4 khái niệm Python cơ bản: đọc CSV, for loop, dictionary, function. Không cần Pandas, không cần thư viện phức tạp. Đây là "80/20 rule" — 20% kiến thức Python giải quyết 80% vấn đề lặp đi lặp lại.

🎓 Bài học cho DA

  1. Bắt đầu từ pain point nhỏ: Đừng cố tự động hóa mọi thứ cùng lúc. Minh chỉ tự động 1 báo cáo — nhưng tiết kiệm 112.5 giờ/năm.
  2. Function = tái sử dụng: Hàm tinh_kpi() có thể dùng cho bất kỳ file CSV nào cùng format — hôm nay, tuần trước, tháng trước.
  3. Dictionary là cấu trúc dữ liệu core cho DA: Gom nhóm theo cửa hàng, đếm theo sản phẩm — dict làm được tất cả.
  4. Script > spreadsheet khi dữ liệu lặp lại: Nếu bạn làm cùng 1 thao tác > 3 lần → viết script.

Case Study 2: FPT Software — Python ETL từ 20+ nguồn dữ liệu

🏷️ Thông tin

Tiêu chíChi tiết
Công tyFPT Software — công ty công nghệ lớn nhất Việt Nam
NgànhIT Services & Outsourcing
Quy mô30,000+ nhân viên, doanh thu >$1 tỷ (2025), hoạt động tại 30+ quốc gia
TeamData Analytics Center of Excellence — 15 DA/DE phục vụ 50+ dự án nội bộ
Chủ đề DAFile handling (CSV, JSON, Excel), dictionary, nested loops, functions, error handling

📋 Bối cảnh

FPT Software có hơn 50 dự án phần mềm chạy song song cho khách hàng toàn cầu (Nhật Bản, Mỹ, Châu Âu). Mỗi dự án tạo ra dữ liệu từ nhiều hệ thống khác nhau: Jira (quản lý task), GitLab (source code), Confluence (tài liệu), Timesheet (chấm công), HR system (nhân sự), Finance (chi phí dự án). Ban lãnh đạo cần báo cáo tổng hợp hiệu suất dự án hàng tuần — nhưng dữ liệu nằm rải rác ở 20+ nguồn, mỗi nguồn 1 format khác nhau.

Team Data Analytics Center of Excellence (DA CoE) gồm 15 người chịu trách nhiệm thu thập, chuẩn hóa và phân tích dữ liệu từ tất cả nguồn. Trước khi dùng Python, mọi thứ là thủ công: download file, mở Excel, copy-paste, chỉnh format, ghép lại.

⚡ Vấn đề

20+ nguồn dữ liệu, mỗi nguồn 1 format:

NguồnFormatTần suấtDữ liệu
Jira CloudJSON (API response)Real-timeTasks, bugs, story points
GitLabJSONDaily exportCommits, merge requests
TimesheetCSVWeekly exportGiờ làm việc theo dự án
HR SystemExcel (.xlsx)MonthlyNhân sự, phòng ban, level
FinanceCSVMonthlyBudget, actual cost
Client SurveyExcelQuarterlyCSAT scores

Quy trình cũ: 1 DA mất 2 ngày (16 giờ) mỗi tuần chỉ để thu thập và chuẩn hóa dữ liệu từ 20 nguồn. Còn chưa kể lỗi: nhầm format ngày (MM/DD vs DD/MM), encoding UTF-8 bị lỗi tiếng Việt, cột bị lệch khi copy-paste giữa các file.

❌ Hậu quả của ETL thủ công

  • 32 giờ/tháng (2 ngày/tuần × 4 tuần) chỉ cho data collection
  • Trung bình 3 lỗi dữ liệu/tuần (nhầm format, thiếu dòng, sai encoding)
  • Báo cáo trễ deadline 40% thời gian vì phụ thuộc vào 1 người
  • Không reproducible: Nếu DA nghỉ phép → không ai biết các bước thủ công

🛠️ Giải pháp

Team DA CoE xây dựng bộ Python scripts sử dụng kiến thức Python cơ bản — không dùng Pandas trong phase đầu, chỉ dùng csv, json modules có sẵn trong Python.

Script 1: Đọc và chuẩn hóa nhiều loại file

python
import csv
import json

def doc_csv(file_path):
    """Đọc file CSV, trả về list of dict"""
    ket_qua = []
    with open(file_path, mode='r', encoding='utf-8') as f:
        reader = csv.DictReader(f)
        for dong in reader:
            ket_qua.append(dong)
    return ket_qua

def doc_json(file_path):
    """Đọc file JSON, trả về list hoặc dict"""
    with open(file_path, mode='r', encoding='utf-8') as f:
        du_lieu = json.load(f)
    return du_lieu

def chuan_hoa_ngay(ngay_str):
    """Chuẩn hóa các format ngày khác nhau về DD/MM/YYYY"""
    # Xử lý các format: 2026-02-17, 02/17/2026, 17-02-2026
    if '-' in ngay_str and len(ngay_str.split('-')[0]) == 4:
        # Format: YYYY-MM-DD (từ Jira, GitLab)
        parts = ngay_str.split('-')
        return f"{parts[2]}/{parts[1]}/{parts[0]}"
    elif '/' in ngay_str and len(ngay_str.split('/')[2]) == 4:
        # Format: MM/DD/YYYY (từ hệ thống Mỹ)
        parts = ngay_str.split('/')
        return f"{parts[1]}/{parts[0]}/{parts[2]}"
    return ngay_str  # Đã đúng format DD/MM/YYYY

# Sử dụng
timesheet = doc_csv('exports/timesheet_week07.csv')
jira_tasks = doc_json('exports/jira_sprint_42.json')
print(f"Timesheet: {len(timesheet)} records")
print(f"Jira tasks: {len(jira_tasks)} records")
# Output:
# Timesheet: 3,240 records
# Jira tasks: 1,856 records

Script 2: Gom dữ liệu từ nhiều nguồn vào 1 cấu trúc thống nhất

python
def tao_bao_cao_du_an(jira_tasks, timesheet_data, hr_data):
    """
    Gom dữ liệu từ 3 nguồn thành báo cáo theo dự án.
    Dùng dict để gom nhóm — key là mã dự án.
    """
    du_an = {}

    # Gom task từ Jira (JSON) — đếm theo trạng thái
    for task in jira_tasks:
        ma_da = task['project_key']
        if ma_da not in du_an:
            du_an[ma_da] = {
                'ten_du_an': task['project_name'],
                'tasks_done': 0,
                'tasks_in_progress': 0,
                'tasks_todo': 0,
                'total_story_points': 0,
                'tong_gio_lam': 0,
                'so_nhan_su': 0
            }
        # Đếm task theo trạng thái
        trang_thai = task['status'].lower()
        if trang_thai == 'done':
            du_an[ma_da]['tasks_done'] += 1
        elif trang_thai == 'in progress':
            du_an[ma_da]['tasks_in_progress'] += 1
        else:
            du_an[ma_da]['tasks_todo'] += 1
        du_an[ma_da]['total_story_points'] += int(task.get('story_points', 0))

    # Gom giờ làm từ Timesheet (CSV)
    for ts in timesheet_data:
        ma_da = ts['project_code']
        if ma_da in du_an:
            du_an[ma_da]['tong_gio_lam'] += float(ts['hours'])

    # Đếm nhân sự từ HR Data
    nhan_su_theo_da = {}
    for nv in hr_data:
        ma_da = nv['project_code']
        if ma_da not in nhan_su_theo_da:
            nhan_su_theo_da[ma_da] = set()
        nhan_su_theo_da[ma_da].add(nv['employee_id'])

    for ma_da in du_an:
        if ma_da in nhan_su_theo_da:
            du_an[ma_da]['so_nhan_su'] = len(nhan_su_theo_da[ma_da])

    return du_an

# Chạy gom dữ liệu
hr_data = doc_csv('exports/hr_assignment.csv')
bao_cao = tao_bao_cao_du_an(jira_tasks, timesheet, hr_data)

# In kết quả
for ma, info in bao_cao.items():
    ti_le_done = 0
    tong_task = info['tasks_done'] + info['tasks_in_progress'] + info['tasks_todo']
    if tong_task > 0:
        ti_le_done = round(info['tasks_done'] / tong_task * 100, 1)
    print(f"[{ma}] {info['ten_du_an']}: "
          f"{ti_le_done}% done, "
          f"{info['tong_gio_lam']:.0f}h logged, "
          f"{info['so_nhan_su']} members")

Kết quả ví dụ:

[FPT-JP01] Toyota Connected Platform: 78.5% done, 2,840h logged, 45 members
[FPT-US03] Healthcare Analytics: 65.2% done, 1,560h logged, 28 members
[FPT-EU07] Banking Data Migration: 42.8% done, 3,200h logged, 52 members

Script 3: Ghi kết quả ra file CSV tổng hợp

python
def xuat_bao_cao_csv(du_an_dict, output_path):
    """Ghi báo cáo tổng hợp ra file CSV"""
    headers = ['ma_du_an', 'ten_du_an', 'tasks_done', 'tasks_in_progress',
               'tasks_todo', 'ti_le_hoan_thanh', 'tong_gio_lam', 'so_nhan_su']

    with open(output_path, mode='w', encoding='utf-8', newline='') as f:
        writer = csv.DictWriter(f, fieldnames=headers)
        writer.writeheader()

        for ma, info in du_an_dict.items():
            tong_task = info['tasks_done'] + info['tasks_in_progress'] + info['tasks_todo']
            ti_le = round(info['tasks_done'] / tong_task * 100, 1) if tong_task > 0 else 0

            writer.writerow({
                'ma_du_an': ma,
                'ten_du_an': info['ten_du_an'],
                'tasks_done': info['tasks_done'],
                'tasks_in_progress': info['tasks_in_progress'],
                'tasks_todo': info['tasks_todo'],
                'ti_le_hoan_thanh': f"{ti_le}%",
                'tong_gio_lam': info['tong_gio_lam'],
                'so_nhan_su': info['so_nhan_su']
            })

    print(f"✅ Đã xuất báo cáo: {output_path}")

xuat_bao_cao_csv(bao_cao, 'reports/weekly_report_2026_W07.csv')
# Output: ✅ Đã xuất báo cáo: reports/weekly_report_2026_W07.csv

🔍 Python Basics tại đây

  • File handling đa format: csv.DictReader cho CSV, json.load() cho JSON — cùng trả về list/dict
  • Nested dictionary: du_an[ma_da] — mỗi dự án là 1 dict chứa nhiều KPI
  • Nested loops: Loop qua tasks → loop qua timesheet → gom vào cùng dict theo project_key
  • Functions làm building blocks: Mỗi function xử lý 1 nguồn dữ liệu → ghép lại thành pipeline
  • set(): Đếm unique employees — tránh trùng khi 1 nhân sự log timesheet nhiều lần

📊 Kết quả

Chỉ sốTrước (thủ công)Sau (Python scripts)Cải thiện
Thời gian ETL/tuần16 giờ (2 ngày)2 giờ (chạy scripts + review)-87.5%
Lỗi dữ liệu/tuần~3 lỗi (format, encoding, thiếu dòng)< 0.5 lỗi (chỉ edge case)-83%
Số nguồn xử lý được8 nguồn (giới hạn sức người)20+ nguồn (thêm nguồn = thêm function)+150%
Bus factor1 người (nghỉ = tê liệt)Bất kỳ ai chạy script đượcLoại bỏ rủi ro
Tổng tiết kiệm/năm728 giờ/năm (14h × 52 tuần)~$15,000 giá trị nhân lực

🎓 Bài học cho DA

  1. Python cơ bản đủ để xây ETL pipeline: Chỉ dùng csv, json — 2 modules có sẵn trong Python, không cần install thêm gì.
  2. Dictionary là trung tâm của data aggregation: Gom nhóm theo project, đếm theo trạng thái, merge nhiều nguồn — tất cả dùng dict.
  3. Mỗi function = 1 data source: Thiết kế doc_csv(), doc_json() riêng biệt → dễ maintain, dễ test, dễ thêm nguồn mới.
  4. Chuẩn hóa dữ liệu trước khi gom: Hàm chuan_hoa_ngay() giải quyết vấn đề format ngày khác nhau giữa các hệ thống — bước nhỏ nhưng critical.

Case Study 3: DataMart (Startup VN) — Từ Google Sheets + Manual đến Python Pipeline

🏷️ Thông tin

Tiêu chíChi tiết
Công tyDataMart — startup SaaS quản lý bán hàng đa kênh tại Việt Nam
NgànhE-commerce SaaS — Nền tảng quản lý bán hàng
Quy mô12 nhân sự, 500+ merchants sử dụng platform, Series A (~$2M)
Team Data2 người: 1 DA (Linh) + 1 backend dev hỗ trợ part-time
Chủ đề DAFunctions, list/dict processing, control flow (if/else), automation, CSV/JSON

📋 Bối cảnh

DataMart là startup Việt Nam cung cấp SaaS cho các shop bán hàng trên Shopee, Lazada, TikTok Shop. Platform giúp merchants quản lý đơn hàng, tồn kho, và khách hàng từ nhiều sàn TMĐT trên một giao diện. Có 500+ merchants đang sử dụng, tổng ~150,000 đơn hàng/tháng.

Linh — DA duy nhất của DataMart — chịu trách nhiệm tạo báo cáo cho CEO, investors, và đội Sales. Vì startup nhỏ, không có Data Engineer, không có data warehouse — mọi dữ liệu nằm trong Google Sheetsdatabase exports (CSV).

⚡ Vấn đề

Quy trình "data analysis" cũ tại DataMart:

  1. Export dữ liệu từ database admin → file CSV (~5 phút)
  2. Import vào Google Sheets → chờ load (~3 phút nếu >50,000 dòng)
  3. Copy-paste dữ liệu từ 3 sheets (đơn hàng, merchants, sản phẩm) vào 1 sheet tổng hợp (~15 phút)
  4. Viết VLOOKUP ghép thông tin merchant vào đơn hàng (~10 phút)
  5. Tạo charts trong Google Sheets (~10 phút)
  6. Copy charts vào Google Slides cho meeting (~5 phút)

Tổng: ~48 phút cho 1 báo cáo. Linh phải làm 3 báo cáo/tuần: (1) Weekly Metrics cho CEO, (2) Monthly Cohort cho Investors, (3) Sales Performance cho team Sales.

⚠️ Giới hạn Google Sheets

  • 10 triệu ô limit: Với 150,000 đơn/tháng × 15 cột = 2.25 triệu ô/tháng → chỉ lưu được ~4 tháng lịch sử
  • Chậm khi >50,000 dòng: VLOOKUP trên 100,000 dòng → Sheets đơ 30 giây
  • Không version control: "Sheet tổng hợp v2 FINAL (copy)" — rất quen thuộc
  • Không tự động: Mỗi tuần lặp lại y hệt — nhưng phải làm tay

🛠️ Giải pháp

Linh dành 3 tuần cuối tuần học Python cơ bản (theo đúng nội dung Buổi 7), sau đó bắt đầu chuyển đổi dần từ Google Sheets sang Python scripts.

Script 1: Đọc và ghép dữ liệu từ nhiều file CSV (thay thế VLOOKUP)

python
import csv

def doc_csv_thanh_dict(file_path, key_field):
    """
    Đọc CSV và tạo lookup dictionary — thay thế VLOOKUP.
    Key: giá trị của cột key_field
    Value: toàn bộ dòng (dict)
    """
    lookup = {}
    with open(file_path, mode='r', encoding='utf-8') as f:
        reader = csv.DictReader(f)
        for dong in reader:
            key = dong[key_field]
            lookup[key] = dong
    return lookup

def ghep_du_lieu(don_hang_list, merchant_lookup, san_pham_lookup):
    """
    Ghép 3 nguồn dữ liệu: đơn hàng + merchant + sản phẩm.
    Tương đương VLOOKUP trong Google Sheets — nhưng nhanh hơn 100x.
    """
    ket_qua = []
    loi_khong_tim_thay = 0

    for don in don_hang_list:
        merchant_id = don['merchant_id']
        product_id = don['product_id']

        # Lookup merchant info
        merchant = merchant_lookup.get(merchant_id, None)
        san_pham = san_pham_lookup.get(product_id, None)

        if merchant is None or san_pham is None:
            loi_khong_tim_thay += 1
            continue  # Skip nếu không tìm thấy

        # Ghép dữ liệu thành 1 record hoàn chỉnh
        record = {
            'order_id': don['order_id'],
            'ngay_dat': don['order_date'],
            'kenh_ban': don['channel'],       # shopee, lazada, tiktok
            'merchant_name': merchant['name'],
            'merchant_tier': merchant['tier'], # gold, silver, bronze
            'san_pham': san_pham['product_name'],
            'danh_muc': san_pham['category'],
            'so_luong': int(don['quantity']),
            'doanh_thu': float(don['revenue']),
            'trang_thai': don['status']
        }
        ket_qua.append(record)

    print(f"✅ Ghép thành công: {len(ket_qua)} records")
    if loi_khong_tim_thay > 0:
        print(f"⚠️ Không tìm thấy: {loi_khong_tim_thay} records")
    return ket_qua

# Chạy pipeline
don_hang = doc_csv_thanh_dict('data/orders_feb2026.csv', 'order_id')
merchant_lookup = doc_csv_thanh_dict('data/merchants.csv', 'merchant_id')
san_pham_lookup = doc_csv_thanh_dict('data/products.csv', 'product_id')

don_hang_list = list(don_hang.values())
du_lieu_ghep = ghep_du_lieu(don_hang_list, merchant_lookup, san_pham_lookup)
# Output:
# ✅ Ghép thành công: 148,523 records
# ⚠️ Không tìm thấy: 1,477 records

Script 2: Tính metrics theo kênh bán hàng và tier merchant

python
def tinh_metrics_theo_nhom(du_lieu, group_field):
    """
    Tính tổng doanh thu và số đơn theo 1 trường phân nhóm.
    Linh hoạt: group theo 'kenh_ban', 'merchant_tier', 'danh_muc', v.v.
    """
    nhom = {}

    for record in du_lieu:
        key = record[group_field]

        if key not in nhom:
            nhom[key] = {
                'so_don': 0,
                'doanh_thu': 0,
                'san_pham_list': []
            }

        if record['trang_thai'] == 'completed':
            nhom[key]['so_don'] += 1
            nhom[key]['doanh_thu'] += record['doanh_thu']
            nhom[key]['san_pham_list'].append(record['san_pham'])

    # Tính AOV cho mỗi nhóm
    for key in nhom:
        so_don = nhom[key]['so_don']
        nhom[key]['aov'] = round(nhom[key]['doanh_thu'] / so_don, 0) if so_don > 0 else 0
        # Đếm unique sản phẩm
        nhom[key]['unique_products'] = len(set(nhom[key]['san_pham_list']))
        del nhom[key]['san_pham_list']  # Giải phóng memory

    return nhom

# Phân tích theo kênh bán hàng
metrics_kenh = tinh_metrics_theo_nhom(du_lieu_ghep, 'kenh_ban')
for kenh, data in sorted(metrics_kenh.items(),
                          key=lambda x: x[1]['doanh_thu'], reverse=True):
    print(f"{kenh:12s} | {data['so_don']:>8,} đơn | "
          f"{data['doanh_thu']:>15,.0f} VNĐ | AOV: {data['aov']:>10,.0f}")

Kết quả:

shopee       |   72,450 đơn | 38,520,000,000 VNĐ | AOV:    531,677
lazada       |   41,280 đơn | 25,180,000,000 VNĐ | AOV:    610,078
tiktok_shop  |   34,793 đơn | 15,240,000,000 VNĐ | AOV:    438,003

Script 3: Tự động detect anomalies

python
def detect_anomaly(du_lieu, nguong_phan_tram=50):
    """
    Phát hiện merchants có doanh thu giảm đột ngột.
    So sánh tuần này vs tuần trước — nếu giảm > ngưỡng → cảnh báo.
    """
    canh_bao = []

    # Gom doanh thu theo merchant + tuần
    merchant_weekly = {}
    for record in du_lieu:
        m_name = record['merchant_name']
        tuan = record['ngay_dat'][:7]  # YYYY-MM (demo đơn giản)

        if m_name not in merchant_weekly:
            merchant_weekly[m_name] = {}
        if tuan not in merchant_weekly[m_name]:
            merchant_weekly[m_name][tuan] = 0
        merchant_weekly[m_name][tuan] += record['doanh_thu']

    # So sánh 2 tuần gần nhất
    for merchant, tuan_data in merchant_weekly.items():
        cac_tuan = sorted(tuan_data.keys())
        if len(cac_tuan) >= 2:
            tuan_truoc = tuan_data[cac_tuan[-2]]
            tuan_nay = tuan_data[cac_tuan[-1]]

            if tuan_truoc > 0:
                phan_tram_thay_doi = ((tuan_nay - tuan_truoc) / tuan_truoc) * 100

                if phan_tram_thay_doi < -nguong_phan_tram:
                    canh_bao.append({
                        'merchant': merchant,
                        'tuan_truoc': tuan_truoc,
                        'tuan_nay': tuan_nay,
                        'thay_doi': round(phan_tram_thay_doi, 1)
                    })

    return canh_bao

alerts = detect_anomaly(du_lieu_ghep, nguong_phan_tram=40)
for alert in alerts:
    print(f"🚨 {alert['merchant']}: {alert['thay_doi']}% "
          f"({alert['tuan_truoc']:,.0f}{alert['tuan_nay']:,.0f})")
# Output:
# 🚨 ShopTrangSuc99: -62.3% (45,200,000 → 17,050,000)
# 🚨 MayTinhPhuKien: -48.1% (28,400,000 → 14,740,000)
🔍 Python Basics trong toàn bộ pipeline
ConceptSử dụngVí dụ
FunctionMỗi bước pipeline là 1 function riêngghep_du_lieu(), tinh_metrics_theo_nhom()
DictionaryLookup table (thay VLOOKUP), gom nhómmerchant_lookup, nhom[key]
ListLưu danh sách records, sản phẩmdu_lieu_ghep, san_pham_list
For loopDuyệt qua mỗi đơn hàng, mỗi merchantfor record in du_lieu
If/elseFilter trạng thái, detect anomalyif record['trang_thai'] == 'completed'
CSV moduleĐọc/ghi file dữ liệucsv.DictReader, csv.DictWriter
set()Đếm unique productslen(set(san_pham_list))
String methodsParse ngày, format outputngay[:7], f-string formatting

📊 Kết quả

Chỉ sốTrước (Google Sheets)Sau (Python pipeline)Cải thiện
Thời gian/báo cáo48 phút (thủ công)5 phút (chạy script)-90%
Tổng thời gian/tuần2.4 giờ (3 báo cáo)15 phút-90%
Dung lượng dữ liệu xử lý50,000 dòng (Sheets lag)500,000+ dòng (không giới hạn)10x
Lịch sử dữ liệu~4 tháng (limit ô Sheets)Không giới hạn (file-based)
Anomaly detectionKhông có (nhìn bằng mắt)Tự động alert khi giảm >40%Mới hoàn toàn
Reproducibility0% (thủ công)100% (script = tài liệu)

💡 Growth Story

Sau 3 tháng dùng Python pipeline, Linh có thời gian phân tích sâu hơn thay vì chỉ tổng hợp số liệu. Linh phát hiện pattern: merchants tier Gold trên Shopee có AOV cao hơn 40% so với TikTok Shop → CEO điều chỉnh pricing strategy → tăng 18% revenue Q2/2026. Insight này không thể có nếu Linh vẫn dành 7+ giờ/tuần copy-paste trên Google Sheets.

🎓 Bài học cho DA

  1. Google Sheets tốt cho prototype, Python tốt cho production: Khi dữ liệu > 50,000 dòng hoặc quy trình lặp > 3 lần/tuần → chuyển sang Python.
  2. Dictionary thay thế VLOOKUP hoàn hảo: merchant_lookup.get(id) nhanh hơn VLOOKUP trên 100,000 dòng hàng trăm lần — và không bao giờ sai.
  3. Function = reusable logic: Hàm tinh_metrics_theo_nhom(du_lieu, group_field) dùng cho bất kỳ field nào — kênh bán, merchant tier, danh mục — không cần viết lại.
  4. Script = documentation: Code Python chính là tài liệu — ai đọc cũng hiểu quy trình. Google Sheets workflow chỉ nằm trong đầu 1 người.

So sánh & Tổng hợp

Tiêu chíCase 1: Automate the Boring StuffCase 2: FPT SoftwareCase 3: DataMart Startup
Quy mô1 người, 1 báo cáo15 người, 50+ dự án2 người, 500+ merchants
Vấn đề chínhBáo cáo thủ công lặp lạiETL từ 20+ nguồn đa formatGoogle Sheets bottleneck
Python conceptsCSV, function, loopCSV + JSON, nested dict/loopDict lookup, if/else, functions
Thời gian tiết kiệm90% (30→3 phút)87.5% (16→2 giờ)90% (48→5 phút)
Dữ liệu xử lý5,000 dòng/ngày20+ nguồn, 100,000+ records150,000 đơn/tháng
Skill level cầnBeginner (1-2 tuần học)Intermediate (team collab)Beginner-Intermediate
ROI112.5 giờ/năm728 giờ/năm (~$15,000)~100 giờ/năm + revenue insight

📌 Pattern chung

Cả 3 case study đều chứng minh 1 điều: Python cơ bản (data types, loops, functions, file handling) đủ để giải quyết phần lớn vấn đề dữ liệu thực tế. Bạn không cần Pandas, không cần Machine Learning, không cần framework phức tạp — chỉ cần hiểu rõ list, dict, for, def, csv, json.

Progression:

  • Case 1: 1 file → 1 báo cáo (automation đơn giản)
  • Case 2: 20+ files × nhiều format → 1 báo cáo tổng hợp (ETL pipeline)
  • Case 3: Multi-source → metrics + anomaly detection (full analytics pipeline)

Bài tập tư duy

Câu 1: Áp dụng vào công việc hiện tại

Hãy nghĩ về công việc hiện tại (hoặc công việc mong muốn) của bạn:

  • Bạn có quy trình nào lặp đi lặp lại mỗi ngày/tuần mà đang làm thủ công (Excel, Google Sheets)?
  • Ước tính: mỗi lần mất bao nhiêu phút? Bao nhiêu lần/tuần?
  • Nếu viết Python script, bạn cần những concepts nào (CSV reading? dictionary? loop? function?)?
  • Tính ROI: tiết kiệm bao nhiêu giờ/năm?

Câu 2: Thiết kế mini pipeline

Giả sử bạn là DA tại một chuỗi cafe có 10 cửa hàng. Mỗi ngày bạn nhận file CSV giao dịch từ mỗi cửa hàng (10 files). Hãy thiết kế pipeline bằng Python cơ bản:

  1. Đọc 10 file CSV → gộp thành 1 list
  2. Tính KPI: tổng doanh thu, số đơn hàng, AOV — theo từng cửa hàng (dùng dict)
  3. Tìm cửa hàng có doanh thu cao nhất và thấp nhất
  4. Ghi kết quả ra file CSV tổng hợp

Gợi ý: Bạn cần dùng for loop (duyệt 10 files), dictionary (gom theo cửa hàng), function (tái sử dụng), csv module (đọc/ghi).

Câu 3: So sánh công cụ

So sánh 3 công cụ cho cùng 1 tác vụ — "tính tổng doanh thu theo khu vực từ file 100,000 dòng":

Tiêu chíExcel/Google SheetsSQLPython (csv + dict)
Tốc độ setup???
Xử lý 100K dòng???
Tự động chạy lại???
Kết hợp nhiều nguồn???
Sharing kết quả???

Hãy điền và giải thích — không có công cụ nào "tốt nhất" cho mọi tình huống. Khi nào nên dùng công cụ nào?