Jupyter Notebook sang văn bản thuần: lấy nội dung, bỏ giàn giáo
Văn bản thuần là đích đến đúng khi nơi nhận không có ý kiến gì về định dạng. Một pipeline grep, một bản diff, một chỉ mục tìm kiếm, một lượt kiểm tra đạo văn, một email thuần văn bản gửi đồng nghiệp không muốn nhận tệp đính kèm — không thứ nào trong số đó được lợi từ dấu backtick và dấu thăng, mà vài thứ còn tệ đi vì loại dấu có nghĩa với trình kết xuất và vô nghĩa với người đọc.
Bộ chuyển đổi này nhận một tệp .ipynb rồi trả lại phần chữ cùng phần mã, không thêm chút đánh dấu nào. Các ô cách nhau bằng dòng trống. Mã hiện ra là mã, không hàng rào. Kết quả in ra nằm ngay dưới ô đã sinh ra nó, dưới một nhãn Output: đơn giản. Mọi thứ mà định dạng JSON bọc quanh nội dung đó đều bị bỏ. Việc xử lý diễn ra trong tab trình duyệt này.
Chuyện token
Lý do phổ biến nhất để làm phẳng một notebook là ở phía sau có thứ tính tiền theo token, mà một tệp .ipynb thô là cách rất đắt đỏ để nói rất ít. Nên nói cụ thể về tỷ lệ.
Một notebook ba mươi ô, một nửa trong đó sinh ra biểu đồ, thường xuyên chiếm hai đến ba megabyte trên đĩa. Phần chữ và phần mã bên trong có khi chỉ tám kilobyte. Tất cả phần còn lại là dữ liệu ảnh base64, bản HTML nhân đôi của những kết quả vốn đã có ở dạng thuần văn bản, và sổ sách của từng ô. Đưa tệp thô cho mô hình không chỉ đắt hơn cả trăm lần mức đáng phải trả — nó thường hỏng hẳn, vì cửa sổ ngữ cảnh bị lấp đầy bằng những ký tự không mang thông tin.
Tệ hơn nữa, base64 tách token rất tệ. Tiếng Anh thông thường trung bình khoảng bốn ký tự một token. Một chuỗi base64 ngẫu nhiên không có chuỗi con lặp lại nào để từ vựng của tokenizer nén lại, nên nó rơi về gần một token cho hai ký tự. Phần vô dụng nhất của tệp cũng chính là phần có tỷ lệ token trên ký tự tệ nhất. Bộ đếm phía trên hiện số token của kết quả để bạn thấy mình thực sự đang gửi đi cái gì.
Cái gì sống sót sau khi làm phẳng
Bỏ cấu trúc không giống bỏ ý nghĩa, và ranh giới giữa hai chuyện đó là chỗ một công cụ kiểu này thành hay bại. Những thứ được giữ:
- Nội dung ô markdown, đúng như đã viết. Các ký tự
#và**giữ nguyên, vì trong một ô markdown chúng là chỉ dấu duy nhất của tác giả về nhấn mạnh và thứ bậc. Gỡ chúng đi là làm phẳng một tài liệu vốn đã là văn xuôi thành một khối chữ không phân biệt. - Mã, đúng như đã gõ. Thụt lề giữ nguyên, chú thích còn nguyên. Ý nghĩa của Python phụ thuộc vào khoảng trắng đầu dòng, nên đây không phải lựa chọn thẩm mỹ.
- Kết quả dạng chữ. Nội dung in ra, giá trị trả về, bản xem trước dataframe ở dạng thuần.
- Tên lỗi, thông điệp lỗi và traceback, đã gỡ mã màu của terminal.
- Ô raw, thứ thường chứa LaTeX hoặc reStructuredText mà tác giả muốn để yên.
Cái gì bị bỏ: dữ liệu ảnh và video, tệp PDF đính kèm, bản HTML sinh đôi của bất kỳ kết quả nào đã có ở dạng chữ, số lần thực thi, mã định danh ô, đối tượng metadata rỗng, và những ô chẳng có gì bên trong. Một ô chỉ chứa khoảng trắng và không có kết quả thì không phải thứ ai cần đọc.
Chuyện dòng đánh dấu chỗ biểu đồ
Khi một biểu đồ bị gỡ, hoặc phải có thứ gì đó đánh dấu chỗ trống, hoặc không. Đây là đánh đổi thật. Không để gì thì văn bản đọc trôi chảy, nhưng một câu kiểu “như biểu đồ phía trên cho thấy” bỗng chẳng trỏ vào đâu. Để lại dấu thì bạn thêm một dòng gần như không mang thông tin.
Mặc định là để lại một dòng ngắn nêu loại nội dung, và công tắc phía trên tắt nó đi. Có một chi tiết liên quan đáng biết: matplotlib xuất ra một biểu diễn dạng chữ đi kèm với ảnh, và nó luôn đại loại như <Figure size 640x480 with 1 Axes>. Giữ lại một cách máy móc thì bạn có dòng đó rồi đến dòng đánh dấu, cái nọ nối cái kia, nói cùng một điều hai lần. Khi một biểu đồ đã bị gỡ, đúng dòng chữ đó bị chặn lại.
Cắt từ giữa
Có kết quả dài vì nó nhiều thông tin, và có kết quả dài vì một vòng lặp in bên trong. Công cụ không phân biệt được, nên nó chặn độ dài mỗi kết quả và cắt từ giữa, giữ phần đầu với phần cuối rồi ghi rõ đã mất bao nhiêu ký tự.
Cắt giữa thắng phương án còn lại vì một lý do cụ thể: hai phần nhiều thông tin nhất của một kết quả dài gần như luôn là phần đầu, cho thấy hình dạng của thứ vừa được tạo ra, và phần cuối, cho thấy nó dừng ở đâu. Một dataframe bị cắt đuôi cho bạn xem những hàng đầu và giấu mất dòng tổng kết. Cắt đầu thì giấu tên cột. Cắt giữa giữ được cả hai đầu câu chuyện.
Notebook đã phẳng thì dùng vào việc gì
Bỏ được JSON đi thì vài việc dễ hẳn. So sánh hai phiên bản của một notebook ở dạng văn bản thuần cho bạn thấy phần phân tích đã đổi gì thay vì số lần thực thi nào vừa tăng — lý do nbdime tồn tại chính là vì git diff thông thường trên một tệp .ipynb không đọc nổi. Tìm trong một thư mục notebook cái hàm đã dựng ra biểu đồ trở thành một lệnh grep bình thường. Đếm chữ cho báo cáo, đưa notebook cho công cụ đọc thành tiếng, hay dán phần phương pháp vào một tài liệu không kết xuất Markdown — tất cả đều chạy được mà không phải dọn thêm.
Riêng tư, và vì sao ở đây đó là chuyện cấu trúc
Notebook là tài liệu làm việc, mà tài liệu làm việc thì tích tụ những thứ không ai định giữ: một token dán vào lúc gỡ lỗi một API, một chuỗi kết nối, hai mươi hàng dữ liệu khách hàng in ra để kiểm tra một phép merge. Đưa thứ đó cho một dịch vụ chuyển đổi là đưa luôn mọi thứ nằm trong đó.
Bộ phân tích ở đây là JavaScript chạy trong tab này. Tệp của bạn được trình duyệt đọc, chuyển đổi trong bộ nhớ, rồi hiện ra. Không có bước tải lên, nên không có chính sách lưu trữ nào phải tin và không có yêu cầu xóa nào phải gửi. Nếu bạn muốn khối mã có hàng rào cùng tiêu đề Markdown, thì bộ chuyển notebook sang Markdown làm đúng vậy với cùng một cam kết.