Trong bài https://ngocminhtran.com/2020/04/20/tensorflow-js-thu-vien-machine-learning-cho-web-developer/ chúng ta đã làm quen với thư viện TensorFlow.js – một thư viện Machine Learning (và Deep Learning) dành cho “dân” sử dụng JavaScript. Và trong bài này, chúng ta sẽ làm quen với một thư viện được tích hợp trong TensorFlow.js dùng để trực quan hóa dữ liệu.
Trực quan hóa dữ liệu là một kỹ thuật rất quan trọng trong lĩnh vực Machine Learning(ML) giúp chúng ta thấy rõ sự thay đổi của dữ liệu để từ đó đưa ra những dự đoán và những điều chỉnh mô hình ML sao cho hiệu quả nhất. Những ai tiếp cận ML với ngôn ngữ Python đều biết đến thư viện https://matplotlib.org/ và với ngôn ngữ JavaScript chúng ta cũng sẽ dùng một thư viện tương tự là tfjs-vis
Thư viện tfjs-vis
Trong bài trước, để sử dụng TensorFlow.js chúng ta cần khai báo
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js"></script>
Hay chúng ta có thể khai báo tương đương
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest"></script>
Khai báo bên dưới giúp chúng liên kết đến thư viện TensorFlow.js phiên bản mới nhất.
Mặc dù được tích hợp trong TensorFlow.js nhưng tfjs-vis là một thư viện riêng biệt và để sử dụng chúng ta cần khai báo như sau:
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-vis@latest"> </script>
Các dự án ML với JavaScript thường phải khai báo cả hai thư viện này.
Trực quan dữ liệu
Dữ liệu có thể được trực quan thành các dạng biểu đồ khác nhau và tfjs-vis sử dụng các hàm từ namespace tfvis.render tương ứng với các dạng biểu đồ như sau:
- Biểu đồ dạng đường (Line chart): tfvis.render.linechart()
- Biểu đồ dạng phân tán (Scatter plot): tfvis.render.scatterplot()
- Biểu đồ dạng cột (Bar chart): tfvis.render.barchart()
- Biểu đồ tần suất (Histogram chart): tfvis.render.histogram ()
- Sơ đồ nhiệt (heatmap): tfvis.render.heatmap()
***Một lưu ý là bài viết không trình bày ý nghĩa các kiểu biểu đồ một cách chi tiết. Có thể tham khảo về các biểu đồ từ các nguồn khác.
Trước khi tìm hiểu từng dạng biểu đồ, chúng ta cần chuẩn bị sẵn tập tin plot.html có nội dung như sau:
<html> <head> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-vis@latest"> </script> </head> <body> <div id="plot"></div> </body> <script> <!-- Đoạn mã biểu đồ được đặt ở đây--> </script> <html>
Chúng ta cũng có thể thực thi mã trên https://codepen.io/
Biểu đồ dạng đường (Line chart)
Biểu đồ dạng đường là loại biểu đồ thể hiện mức dao động gữa hai đại lượng dưới dạng một đường liền nét. Đoạn mã sau đây sẽ minh họa dùng hàm linechart() biểu diễn mối quan hệ giữa các điểm tọa độ x và y như sau:
let values = [{x: 1, y: 20}, {x: 2, y: 30},{x: 3, y: 70}, {x: 4, y: 50}]; tfvis.render.linechart(document.getElementById('plot'), {values}, {width: 400});
Một vài lưu ý về đoạn mã trên:
- Biến values là một mảng chứa mảng các đối tượng biểu diễn dưới dạng các cặp (x,y). Các đối tượng này là dạng đơn giản nhất trong JavaScript (gọi là plain old JavaScript object (POJO) https://en.wikipedia.org/wiki/Plain_old_Java_object ). Tham khảo thêm về đối tượng trong JS tại https://ngocminhtran.com/object-doi-tuong-trong-javascript/
- Hàm linechart() có 3 tham số: tham số thứ nhất là vị trí chúng ta sẽ thể hiện biểu đồ và trong ví dụ trên là vị trí phần tử HTML có id là plot; tham số thứ hai là một đối tượng với một vài trường hay thuộc tính (field) và trong ví dụ trên chỉ có một trường là mảng values; tham số thứ 3 cũng là các đối tượng chứa các thuộc tính mô tả kích cỡ của biểu đồ với width là chiều rộng và height (trong ví dụ trên không dùng) là chiều cao và các thuộc tính XLabel thay thế nhãn trục ngang và Ylabel thay thế nhãn trục dọc.
Nếu chúng ta thực thi trên trình duyệt sẽ có kết quả như sau:
Nếu chúng ta không khai báo gì thêm (tức là chỉ dùng đoạn mã như trên) thì các trục của biểu đồ được gán các nhãn mặc định là x (trục ngang) và y (trục dọc). Mỗi một đường cong được gọi là một series với nhãn mặc định là Series 1 cho đường thứ nhất, Series 2 cho đường thứ 2 và cứ thế. Để hiểu hơn, giả sử chúng ta thêm một mảng khác đến values như sau:
let values = [ [{x: 1, y: 20}, {x: 2, y: 30},{x: 3, y: 70}, {x: 4, y: 50}], // mảng 1 [{x: 1, y: 5}, {x: 2, y: 70},{x: 3, y: 45}, {x: 4, y: 10}] // mảng 2 ];
Thực thi lại trên trình duyệt
Tất nhiên là chúng ta không dễ dàng chấp nhận với các mặc định và các nhãn mặc định như x, y, Series 1 và Series 2 có thể dễ dàng được thay đổi phù hợp với nội dung dữ liệu trực quan của chúng ta. Thay đổi một ít từ ví dụ trên:
let values = [ [{x: 1, y: 20}, {x: 2, y: 30},{x: 3, y: 70}, {x: 4, y: 50}], [{x: 1, y: 5}, {x: 2, y: 70},{x: 3, y: 45}, {x: 4, y: 10}] ]; let series = ["My series 1", "My series 2"]; tfvis.render.linechart(document.getElementById('plot'), {values,series}, {width: 400, xLabel:"My X Label", yLabel:"My Y Label"});
Kết quả:
Chúng ta thêm mảng series đến đối tượng là tham số thứ hai, thêm XLabel và Ylabel đến đối tượng tham số thứ ba của hàm linechart().
Biểu đồ dạng phân tán (Scatter plot)
Biểu đồ tán xạ dùng để biểu diễn mối quan hệ giữa hai biến định lượng. Đoạn mã sau đây sẽ minh họa dùng hàm scatterplot() biểu diễn mối quan hệ giữa các điểm tọa độ x và y như sau:
let values = [ [{x: 20, y: 40}, {x: 32, y: 0}, {x: 5, y: 52}, {x: 12, y: -6}], [{x: 15, y: 35}, {x: 0, y: 9}, {x: 7, y: 28}, {x: 16, y: 8}] ]; let series = ["My series 1", "My series 2"]; tfvis.render.scatterplot(document.getElementById('plot'), {values,series}, {width: 400, xLabel:"My X Label", yLabel:"My Y Label"});
Các tham số hàm scatterplot() hoàn toàn tương tự hàm linechart(), chỉ khác hàm linechart() hiển thị các đường trong khi đó scatterplot() hiển thị các điểm rời rạc
Biểu đồ dạng cột (Bar chart)
Là dạng biểu đồ phổ biến nhất thể hiện sự thay đổi giữa hai biến định lượng
const data = [{index: '2015', value: 300},{index: '2016', value: 250}, {index: '2017', value: 360}, {index: "2018", value: 400} ]; tfvis.render.barchart(document.getElementById('plot'), data, { yLabel: "Sinh viên tốt nghiệp", xLabel:"Năm", width: 400, });
Một số thay đổi cần lưu ý:
- Biến data là một biến mảng chứa các đối tượng chứ không phải là một biến mảng chứa các mảng giống biến values trong các ví dụ trên.
- Các đối tượng trong data là các cặp index và value thay vì x và y. index có thể nhận các giá trị kiểu số hay kiểuchuỗi (như ví dụ trên) trong khi x chỉ nhận số.
- Tham số thứ hai của hàm barchart() là một mảng đối tượng thông thường chứ không phải là một đối tượng giống hàm linechart() và scatterplot().
Kết quả ví dụ khi thực thi
Biểu đồ tần suất (Histogram chart)
Là một dạng biểu đồ cột cho thấy bằng hình ảnh sự thay đổi, biến động của một tập hợp các dữ liệu theo những hình dạng nhất định.
Một histogram gán các giá trị trong các đơn vị gọi là bin. Một bin là một dãy giá trị liên tục với cận trên (giá trị lớn nhất) và cận dưới (giá trị nhỏ nhất). Các bin thường được chọn kề nhau để có thể bao trùm hết các giá trị khả dĩ. Để hiểu hơn chúng ta xét ví dụ tạo biểu đồ tần suất dùng hàm histogram() như sau:
const data = [1, 5, 5, 5, 5, 10, -3, -3]; tfvis.render.histogram(document.getElementById('plot'), data, { width: 400 });
Chúng ta chỉ dùng biến mảng data để lưu các giá trị số và ý nghĩa các tham số hàm histogram() tương tự hàm barchart(). Thực thi đoạn mã trên:
Trong histogram này chúng ta gán các giá trị đến 5 bins: bin thứ nhất chứa giá trị từ -4 đến -2, bin thứ hai chứa giá trị từ 0 đến 2, bin thứ 3 chứa giá trị từ 4 đến 6 và bin cuối cùng chứa giá trị từ 8 đến 10. Mỗi cột là tần suất (hay số lần xuất hiện của một giá trị) cao nhất trong mỗi bin. Ví dụ giá trị 5 trong tập data xuất hiện 4 lần nên bin thứ 3 sẽ có cột như hình trên.
Số lượng bin có thể được điều chỉnh trong hàm histogram() với thuộc tính maxBins trong tham số thứ ba cảu hàm này như sau:
const data = [1, 5, 5, 5, 5, 10, -3, -3]; tfvis.render.histogram(document.getElementById('plot'), data, { width: 400, maxBins:3 });
Kết quả
Nếu muốn chúng ta cũng có thể thay đổi các nhãn của hai trục tọa độ như các hàm trên.
Sơ đồ nhiệt (Heatmap)
Là một dạng biểu đồ cho thấy sự thay đổi, biến động của một tập hợp các dữ liệu. Heatmap thể hiện một mảng 2D các số giống như một lưới các ô màu. Đoạn mã sau mô tả một ví dụ về heatmap:
let values = [[1, 0, 0], [0, 0.3, 0.7], [0, 0.7, 0.3]]; tfvis.render.heatmap(document.getElementById('plot'), {values}, { width: 500, height: 300, colorMap: 'blues' });
Các tham số hàm heatmap() tương tự hàm linechart() ở trên. Thực thi đoạn mã:
Màu sắc thay đổi từ đậm đến nhạt tương ứng giá trị lớn nhất là 1 đến giá trị bé nhất là 0. Có thể thấy các ô tương ứng các giá trị của ma trận values. Các nhãn mặc định cho các hàng hay các cột của heatmap là 0, 1, 2, … và chúng ta có thể thay đổi bằng cách dùng các thuộc tính xTickLabels và yTickLabels trong tham số đối tượng thứ hai của hàm heatmap():
{values, xTickLabels: ['Apple', 'Orange', 'Tangerine'], yTickLabels: ['Apple', 'Orange', 'Tangerine']}
Kết quả thực thi
Có thể thêm nhãn cho hai trục ngang và dọc dùng các thuộc tính xLabel và yLabel trong tham số đối tượng thứ ba của hàm heatmap() tương tự các hàm chúng ta đã tìm hiểu ở trên.
Giá trị của thuộc tính colorMap có thể là blues (như hình trên) hay greyscale
Hay viridian
Lời cuối
Trong bài viết này chúng ta đã tìm hiểu một cách tổng quan các dạng biểu đồ phổ biến trong quá trình trực quan hóa dữ liệu. Mỗi dạng biểu đồ tương ứng với một hàm từ namespace tfvis.render mà chúng ta cũng đã tìm hiểu thông qua phân tích các ví dụ mỗi dạng biểu đồ. Các bài sau sẽ tìm hiểu việc áp dụng trực quan dữ liệu trong các bài toán ML lớn hơn.
Ý kiến bài viết