python-046Đọc toàn bộ đề miễn phí

Tối ưu hóa Bộ nhớ DataFrame Triệt để bằng Downcasting & Categorical Dtype

Khi nạp các tệp CSV dung lượng lớn (hàng triệu bản ghi) vào bộ nhớ, pandas mặc định phân bổ int64 (8 bytes) cho số nguyên, float64 (8 bytes) cho số thực và object (con trỏ Python t…

PythonTrung bình25 phút

Tiến độ của tôi ở bài này

Điểm được lưu vào tài khoản sau khi chấm bài.

Đang tải điểm của bạn…

Kiến thức và chủ đề

pandasmemory optimizationdowncastingcategory dtypedeep memory usage

Kiến thức tiên quyết: memory usage deep, to numeric downcast, category conversion.

Nội dung đề bài

Mục tiêu kiến thức

  • Đo lường chính xác mức tiêu thụ bộ nhớ RAM thực tế của pandas.DataFrame bằng memory_usage(deep=True).
  • Ép kiểu giảm cấp (Downcasting) các cột số nguyên (int64 → int8, int16, int32) và số thực (float64 → float32).
  • Nhận diện và chuyển đổi các cột chuỗi ký tự (object) có độ đa dạng thấp (low cardinality) sang kiểu category.
  • Lập báo cáo thống kê tỷ lệ phần trăm bộ nhớ tiết kiệm được.

Mô tả bài toán

Khi nạp các tệp CSV dung lượng lớn (hàng triệu bản ghi) vào bộ nhớ, pandas mặc định phân bổ int64 (8 bytes) cho số nguyên, float64 (8 bytes) cho số thực và object (con trỏ Python tốn kém) cho chuỗi. Điều này khiến máy chủ phân tích dễ rơi vào tình trạng quá tải bộ nhớ (Out-Of-Memory - OOM).

Hãy viết hàm: optimize_dataframe_memory(df: pd.DataFrame, category_threshold: float = 0.5) -> tuple[pd.DataFrame, dict]

Yêu cầu thực hiện:

  • Kiểm tra đầu vào:
  • Nếu df rỗng (len(df) == 0), trả về (df.copy(), {"initial_bytes": 0, "optimized_bytes": 0, "savings_pct": 0.0, "dtypes": {}}).
  • category_threshold phải nằm trong khoảng (0.0, 1.0].
  • Đo lường dung lượng ban đầu:
  • Tính tổng dung lượng RAM thực tế: initial_bytes = int(df.memory_usage(deep=True).sum()).
  • Thực hiện Tối ưu hóa trên bản sao:
  • Tạo bản sao opt_df = df.copy().
  • Duyệt qua từng cột:
  • Cột số nguyên (integer): Sử dụng pd.to_numeric(opt_df[col], downcast='integer').
  • Cột số thực (float): Sử dụng pd.to_numeric(opt_df[col], downcast='float') để chuyển về float32.
  • Cột chuỗi (object hoặc string):
  • Tính tỷ lệ giá trị duy nhất: ratio = len(opt_df[col].unique())len(opt_df[col]).
  • Nếu ratio < categorythreshold, chuyển đổi cột sang kiểu: opt_df[col] = opt_df[col].astype('category').
  • Đo lường dung lượng sau tối ưu & Báo cáo:
  • optimized_bytes = int(opt_df.memory_usage(deep=True).sum()).
  • Tính tỷ lệ phần trăm tiết kiệm:

savings_pct = round(initial_bytes - optimized_bytesinitial_bytes × 100, 2).

  • Tạo bản đồ kiểu dữ liệu: dtypes = {col: str(opt_df[col].dtype) for col in opt_df.columns}.
  • Đầu ra:
  • Trả về tuple gồm:

(opt_df, {"initial_bytes": initial_bytes, "optimized_bytes": optimized_bytes, "savings_pct": savings_pct, "dtypes": dtypes}).

Input

  • Các tham số truyền vào hàm/lớp optimize_dataframe_memory hoặc dữ liệu đầu vào theo định dạng mô tả.

Output

  • Kết quả trả về của hàm/lớp optimize_dataframe_memory hoặc dữ liệu in ra màn hình theo đúng đặc tả.

Ràng buộc

  • Số dòng dữ liệu: 0 ≤ N ≤ 105.
  • Không làm thay đổi DataFrame df gốc.

Ví dụ 1

Input

optimize_dataframe_memory(data={'small_int': [10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50, 10, 20, 30, 40, 50], 'float_col': [1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5, 1.5, 2.5, 3.5, 4.5, 5.5], 'status': ['active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive', 'active', 'inactive']}, category_threshold=0.5)

Output

{'small_int': 'int8', 'float_col': 'float32', 'status': 'category'}

Giải thích

Hàm được gọi với các tham số mẫu trên và trả về kết quả chính xác theo yêu cầu.

Ví dụ 2

Input

optimize_dataframe_memory(data={'unique_id': ['ID_0', 'ID_1', 'ID_2', 'ID_3', 'ID_4', 'ID_5', 'ID_6', 'ID_7', 'ID_8', 'ID_9']}, category_threshold=0.5)

Output

{'unique_id': 'object'}

Giải thích

Hàm được gọi với bộ tham số thứ hai và trả về kết quả tương ứng theo thiết kế.

3 cấp độ gợi ýMở dần khi bạn thật sự cần hỗ trợ.
Phân tích lời giảiGiải thích hướng tư duy và thuật toán.
Code tham khảoDùng để đối chiếu sau khi tự làm.

Gợi ý và lời giải chỉ mở sau khi bạn bấm Nộp bài. Giáo viên và quản trị viên mở được ngay.