Kỹ thuật tô màu các hàng trong Pandas DataFrame bằng hàm tùy chỉnh

Giới thiệu về định dạng bảng trong Pandas

Trong quy trình xử lý và phân tích dữ liệu, việc trực quan hóa thông tin đóng vai trò then chốt giúp người dùng nắm bắt nhanh chóng các xu hướng tiềm ẩn. Bên cạnh biểu đồ, bảng dữ liệu được định dạng đẹp mắt cũng là công cụ hữu hiệu. Tuy nhiên, thư viện Pandas mặc định chỉ hiển thị dữ liệu thô. Để khắc phục điều này, chúng ta có thể sử dụng cơ chế Styler của Pandas kết hợp với các hàm tùy chỉnh để áp dụng màu sắc cho từng hàng dựa trên điều kiện cụ thể.

Nguyên lý hoạt động của việc tùy chỉnh giao diện

Mặc dù Pandas không hỗ trợ thay đổi màu sắc trực tiếp trên đối tượng DataFrame gốc cho mục đích lưu trữ, nhưng thuộc tính .style cung cấp một bộ công cụ mạnh mẽ để tạo ra bản xem trước HTML hoặc Jupyter Notebook tương tác. Chúng ta có thể truyền một hàm Python vào phương thức apply, hàm này sẽ nhận dữ liệu đầu vào và trả về chuỗi CSS tương ứng để áp dụng cho ô hoặc hàng.

Các phương pháp chính

  • Sử dụng apply(axis=1): Phù hợp để thao tác trên toàn bộ dòng dựa trên giá trị của nhiều cột.
  • Sử dụng applymap (hoặc map trong phiên bản mới): Tác động đến từng ô riêng lẻ nếu cần chi tiết hơn.
  • Kết hợp với thư viện vẽ: Sử dụng matplotlib để xuất ra ảnh tĩnh khi môi trường không hỗ trợ HTML.

Triển khai thực tế với mã nguồn Python

Dưới đây là các ví dụ minh họa cách thiết lập màu nền cho các hàng trong bảng dữ liệu theo các kịch bản khác nhau.

Ví dụ 1: Đánh dấu theo ngưỡng giá trị cố định

Bảng dưới đây chứa doanh thu bán hàng. Chúng ta sẽ làm nổi bật các sản phẩm có doanh số vượt mức 150 đơn vị.

import pandas as pd

# Khởi tạo dữ liệu mẫu
ten_san_pham = ['Alpha', 'Beta', 'Gamma', 'Delta']
doanh_so = [120, 180, 90, 200]
bap_an = pd.DataFrame({'Ten': ten_san_pham, 'DoanhSo': doanh_so})

def thiet_lap_mau_trong_ve_doi_cua_so(hang):
    """Hàm kiểm tra điều kiện và trả về định dạng CSS"""
    gia_tri = hang['DoanhSo']
    neu_tra_mau = 'background-color: #ffcccc'  # Màu đỏ nhạt
    mac_dinh = ''
    
    danh_sach_css = [mac_dinh] * len(hang)
    if gia_tri > 150:
        danh_sach_css = [neu_tra_mau] * len(hang)
        
    return danh_sach_css

ket_qua_nen = bap_an.style.apply(thiet_lap_mau_trong_ve_doi_cua_so, axis=1)
# ket_qua_nen  // Hiển thị trong Jupyter Notebook

Ví dụ 2: Phân loại theo thứ tự thống kê

Thay vì so sánh với con số cố định, ta có thể tô màu dựa trên giá trị lớn nhất và nhỏ nhất của tập dữ liệu hiện hành.

max_gia = bap_an['DoanhSo'].max()
min_gia = bap_an['DoanhSo'].min()

def canh_bao_cuoi_cung_va_dau_danh(hang):
    """Đánh dấu cực đại và cực tiểu"""
    mau_xanh = 'background-color: #ccffcc'
    mau_do = 'background-color: #ffcccc'
    trang = ''
    
    if hang['DoanhSo'] == max_gia:
        result = [mau_xanh] * len(hang)
    elif hang['DoanhSo'] == min_gia:
        result = [mau_do] * len(hang)
    else:
        result = [trang] * len(hang)
        
    return result

styled_table = bap_an.style.apply(can_bao_cuoi_cung_va_dau_danh, axis=1)
print(styled_table)

Ví dụ 3: Mã màu gradient động

Sử dụng colormap từ Matplotlib để gán màu độ sâu khác nhau tương ứng với mức độ cao thấp của dữ liệu liên tục.

import matplotlib.pyplot as plt
from matplotlib.cm import get_cmap
import numpy as np

chuoi_mau = get_cmap('plasma')

def tao_mau_theo_tiem_tuc(hang):
    """Tính toán tỷ lệ phần trăm và chuyển sang mã màu RGBA"""
    ds_min = bap_an['DoanhSo'].min()
    ds_max = bap_an['DoanhSo'].max()
    range_val = ds_max - ds_min
    
    normalized_val = (hang['DoanhSo'] - ds_min) / range_val
    # Lấy màu RGB từ colormap
    rgb_color = chuoi_mau(normalized_val)[:3]
    rgba_str = f"rgba({rgb_color[0]*255}, {rgb_color[1]*255}, {rgb_color[2]*255}, 1)"
    
    return [f'background-color: {rgba_str}'] * len(hang)

gradient_style = bap_an.style.apply(tao_mau_theo_tiem_tuc, axis=1)

Ví dụ 4: Thay đổi màu chữ dựa trên nội dung văn bản

Hướng dẫn cách thay đổi color của chữ thay vì nền, áp dụng khi tên sản phẩm chứa ký tự đặc biệt.

def bien_thanh_van_menh(mot_dong):
    """Kiểm tra chuỗi tên sản phẩm"""
    mau_chu_xanh_duong = 'color: blue; font-weight: bold'
    mau_chu_den = ''
    
    if 'Alpha' in mot_dong['Ten']:
        return [mau_chu_xanh_duong] * len(mot_dong)
    return [mau_chu_den] * len(mot_dong)

text_styled = bap_an.style.apply(bien_thanh_van_menh, axis=1)

Ví dụ 5: Vẽ bảng tĩnh bằng Matplotlib

Nếu bạn cần xuất file ảnh mà không phụ thuộc vào trình duyệt web, việc xây dựng bảng trực tiếp trên trục tọa độ đồ họa là giải pháp tối ưu.

fig, ax = plt.subplots(figsize=(5, 3))
ax.axis('tight')
ax.axis('off')

# Tạo đối tượng Table
tbl = ax.table(cellText=bap_an.values, colLabels=bap_an.columns, loc='center')

for i in range(len(bap_an)):
    for j in range(len(bap_an.columns)):
        if bap_an.iloc[i, 1] > 150:
            tbl[(i+1, j)].set_facecolor('#ffff00')
            
plt.show()

Ví dụ 6: Kết hợp nhiều tiêu chí phức tạp

Áp dụng logic AND/OR để lọc điều kiện trước khi gắn nhãn màu sắc.

def phan_loai_phuc_hop(row_data):
    """Kết hợp điều kiện doanh số và tên sản phẩm"""
    default_bg = ''
    
    # Điều kiện: Doanh số lớn nhưng tên chứa 'Beta'
    if row_data['DoanhSo'] >= 150 and 'Beta' in row_data['Ten']:
        default_bg = 'background-color: lightgreen'
    # Điều kiện: Doanh số thấp bất kể tên
    elif row_data['DoanhSo'] < 100:
        default_bg = 'background-color: lightcoral'
        
    return [default_bg] * len(row_data)

multi_condition_view = bap_an.style.apply(phan_loai_phuc_hop, axis=1)

Ví dụ 7: Sử dụng hàm chuẩn hóa Z-score

Dùng biến thiên thống kê để phát hiện ngoại lai (outliers).

mean_val = bap_an['DoanhSo'].mean()
std_val = bap_an['DoanhSo'].std()

def highlight_outliers(x):
    z_score = abs((x['DoanhSo'] - mean_val) / std_val)
    if z_score > 1.5:
        return ['background-color: yellow'] * len(x)
    return [''] * len(x)

stats_highlight = bap_an.style.apply(highlight_outliers, axis=1)

Ví dụ 8: Áp dụng Gradient Gradient sẵn có của Pandas

Pandas tích hợp sẵn hàm background_gradient giúp tiết kiệm代码 lượng viết tùy chỉnh nếu chỉ cần so sánh trong một cột.

# Chỉ tô màu cột doanh số dựa trên sự chênh lệch trong cột đó
simple_gradient = bap_an.style.background_gradient(cmap='Blues', subset=['DoanhSo'], axis=0)

Ví dụ 9: Thay đổi kiểu dáng bảng dựa trên ngày tháng

Giả sử dữ liệu có thêm cột thời gian, chúng ta có thể đánh dấu cuối tuần hoặc ngày lễ.

du_lieu_time = pd.DataFrame({
    'Ngay': pd.date_range('2023-01-01', periods=5),
    'Luu_Luong': [10, 20, 30, 40, 50]
})

def dinh_dang_thoi_gian(dt_row):
    weekday = dt_row['Ngay'].weekday()
    if weekday >= 5: # Cuối tuần là 5, 6
        return ['background-color: #eee'] * len(dt_row)
    return [''] * len(dt_row)

time_styled = du_lieu_time.style.apply(dinh_dang_thoi_gian, axis=1)

Ví dụ 10: Tùy chỉnh CSS nâng cao

Không chỉ màu nền, bạn có thể thay đổi viền, độ dày hay đường viền quanh ô.

def advanced_style(dong_data):
    # Đổi cả border và background
    css_rules = ['border: 1px solid black; padding: 10px; background-color: #f0f0f0']
    return css_rules * len(dong_data)

complex_border = du_lieu_time.style.apply(advanced_style, axis=1)

Thẻ: Pandas data-visualization python-styling dataframe css-conditional

Đăng vào ngày 5 tháng 6 lúc 03:51