Khi khai phá dữ liệu đa chiều không quá phức tạp, một cách tiếp cận hữu ích là vẽ nhiều đối tượng con khác nhau của tập dữ liệu cần khai phá trên cùng một hình vẽ. Kỹ thuật này đôi khi được gọi là “Trellis plotting”. Nó cho phép người xem nhanh chóng trích xuất một lượng lớn thông tin từ dữ liệu phức tạp. Matplotlib cung cấp hỗ trợ tốt cho việc tạo ra các hình khối với nhiều trục; Seaborn được xây dựng từ các API của Matplotlib để trực tiếp liên kết cấu trúc của Seaborn với cấu trúc của bộ dữ liệu. Để sử dụng các tính năng này, dữ liệu của bạn phải ở dạng pandas dataframe.
Kĩ thuật “Trellis plotting” được hỗ trợ rất tốt qua lớp FacetGrid và PairGrid và nó cũng là thành phần cấu thành các chức năng đã được nhắc đến ở các bài trước đó trong seaborn như: lmplot(), factorplot() và pairplot().
FacetGrid: Nó rất hữu ích khi bạn muốn biểu diễn sự phân bố của một biến hoặc mối quan hệ giữa nhiều biến riêng biệt trong các tập con của bộ dữ liệu. Một FacetGrid có thể được vẽ với tối đa ba chiều: col, row, và hue. Hai chiều đầu tiên có sự tương ứng rõ ràng với mảng kết quả của các trục; tuy nhiên biến hue như là một chiều thứ ba dọc theo một trục chiều sâu (Z), trong đó các level/classes khác nhau của biến được vẽ với màu sắc khác nhau. Các biến này nên là categorical hoặc rời rạc, và sau đó dữ liệu ở mỗi level/class của biến sẽ được sử dụng cho một mặt (facet) dọc theo trục đó. Chúng ta sẽ lần lượt tìm hiểu giá trị của lớp FacetGrid qua các ví dụ sau.
Để thuận tiện cho bài, trước hết ta sẽ import đủ các gói sau và load dữ liệu:
import numpy as np
import pandas as pd
import seaborn as sns
from scipy import stats
import matplotlib as mpl
import matplotlib.pyplot as plt
sns.set(style="ticks")
np.random.seed(sum(map(ord, "axis_grids")))
tips = sns.load_dataset("tips")
Khởi tạo lớp FacetGrid
Lớp được sử dụng bằng cách khởi tạo một đối tượng FacetGrid với một dataframe và tên các biến sẽ tạo thành các chiều row, col hoặc hue của lưới. Khởi tạo lưới là thiết lập các con số về matplotlib figure và axes, nhưng không vẽ ra bất cứ điều gì trên chúng. Ví dụ chúng tôi muốn kiểm tra sự khác biệt giữa bữa trưa và bữa tối trong bộ tips data.
g = sns.FacetGrid(tips, col="time")
plt.show()
Plotting với FacetGrid.map()
Để vẽ các hình lên lưới ta sử dụng phương thức map() trong lớp FacetGrid. Hàm đó cung cấp một giao diện giúp ta có thể truyền vào hàm đảm nhiệm vẽ hình ( plot function) và tên của các biến trong dataframe. Về kía cạnh plot function truyền vào map(), ngoài việc truyền vào các hàm vẽ đã xây dựng sẵn trong seaborn hay matplotlib ta còn có thể truyền vào một hàm vẽ tự định nghĩa, tôi gọi đó là custom function, miễn là nó thỏa mãn một số rules sau:
Nó phải vẽ trên trục đang làm việc (“currently active” matplotlib Axes). Điều này luôn đúng nếu dùng các hàm vẽ thuộc matplotlib.pyplot namespace, và chúng ta có thể nhận được Axes hiện tại qua việc gọi hàm plt.gca().
Nó phải chấp nhận kiểu dữ liệu được truyền vào qua map() thuộc FacetGrid. Để thỏa mãn điều này, chúng ta có thể tiến hành tiền xử lý trước dữ liệu hoặc để giải quyết xung đột và giúp cho việc tương thích ngược giữa các plot functions.
Nó phải có khả năng chấp nhận các đối số color và label keyword, và lý tưởng là nó sẽ làm một cái gì đó hữu ích với chúng. Để thỏa mãn điều này, chúng ta có thể tiến hành tiền xử lý trước để giải quyết xung đột và giúp cho việc tương thích ngược giữa các plot functions.
Nhắc lại một số hàm dựng sẵn như: plt.hist, plt.scatter, sns.regplot, sns.barplot, sns.boxplot, sns.distplot …
Ví dụ: Làm tiếp ví dụ phía trên vẽ phân phối tiền tip dựa vào thời gian, sử dụng histogram.
g = sns.FacetGrid(tips, col="time")
g.map(plt.hist, "tip");
plt.show()
Các hàm khác sẽ được kết hợp trong các ví dụ khác về mô tả cách tùy chỉnh các hình vẽ với FacetGrid.
Để tạo ra một hình vẽ quan hệ, chỉ cần chuyển nhiều tên biến. Bạn cũng có thể cung cấp đối số từ khóa, sẽ được chuyển đến chức năng vẽ để hiệu chỉnh hình vẽ.
g = sns.FacetGrid(tips, col="sex", hue="smoker")
g.map(plt.scatter, "total_bill", "tip", alpha=.7)
g.add_legend();
plt.show()
Nhắc lại: alpha là đối số mà plt.scatter phải có thể nhận biết và xử lý. Để rõ hơn ta đi đến ví dụ sau khi dùng plot function là sns.regplot. Các bạn chú ý đến cách truyền các đối số như color, fit_reg, x_jitter cho regplot.
g = sns.FacetGrid(tips, row="smoker", col="time", margin_titles=True)
g.map(sns.regplot, "size", "total_bill", color=".3", fit_reg=False, x_jitter=.1);
plt.show()
Bạn có thể muốn điều chỉnh một số khía cạnh của hình vẽ. Còn có một số phương thức thuộc FacetGrid để thao tác với hình vẽ. Phổ biến nhất là FacetGrid.set (), và còn có các phương thức chuyên dụng hơn khác như FacetGrid.set_axis_labels(), thiết lập nhãn cho trục. Ví dụ:
with sns.axes_style("white"):
g = sns.FacetGrid(tips, row="sex", col="smoker", margin_titles=True, size=2.5)
g.map(plt.scatter, "total_bill", "tip", color="#334488", edgecolor="white", lw=.5);
g.set_axis_labels("Total bill (US Dollars)", "Tip");
g.set(xticks=[10, 30, 50], yticks=[2, 6, 10]);
g.fig.subplots_adjust(wspace=.02, hspace=.02);
plt.show()
Để có thể tùy chỉnh nhiều hơn, bạn có thể làm việc trực tiếp với các đối tượng Figure và Axes, được lưu trữ dưới dạng thuộc tính thành viên ở fig và axes (mảng hai chiều), tương ứng. Khi tạo một hình không có cạnh bên cạnh hàng hoặc cột, bạn cũng có thể sử dụng thuộc tính ax để truy cập trực tiếp vào các trục đơn. Ví dụ:
g = sns.FacetGrid(tips, col="smoker", margin_titles=True, size=4)
g.map(plt.scatter, "total_bill", "tip", color="#338844", edgecolor="white", s=50, lw=1)
for ax in g.axes.flat:
ax.plot((0, 50), (0, .2 * 50), c=".2", ls="--")
g.set(xlim=(0, 60), ylim=(0, 14));
plt.show()
PairGrid: Nó cũng cho phép bạn nhanh chóng vẽ một lưới các subplot cùng loại hình để biểu diễn dữ liệu trong. Trong một PairGrid, mỗi hàng và cột được gán cho một biến khác, do đó, kết quả của hình vẽ cho thấy mỗi mối quan hệ giữa các cặp biến trong tập dữ liệu. Kiểu hình vẽ này đôi khi được gọi là “scatterplot matrix”, vì đây là cách phổ biến nhất để hiển thị từng mối quan hệ, nhưng PairGrid không giới hạn ở hình vẽ kiểu scatterplots. Sử dụng PairGrid có thể cung cấp cho bạn bản tóm tắt ngắn gọn mà nhanh chóng về các mối quan hệ thú vị trong tập dữ liệu của bạn.
Cách tiếp cận sử dụng PariGrid cũng giống như với FacetGrid, cũng cần khởi tạo đến việc truyền vào hàm vẽ (plot function) và nó cũng trả về một đối tượng PairGrid mà ta có thể tùy biến thoải mái qua các phương thức sẵn có trong PairGird hay qua các đối tượng thuộc matplotlib.
Sử dụng bộ dữ liệu “iris”
iris = sns.load_dataset("iris")
Ta sẽ đi qua ví dụ sau để có được cái nhìn tổng quan trong về ý nghĩa cũng như cách dùng của PairGrid.
g = sns.PairGrid(iris, hue="species")
g.map_diag(plt.hist)
g.map_offdiag(plt.scatter)
g.add_legend();
plt.show()
Yêu cầu: Các bạn có thể tự thử biểu diễn dữ liệu với nhiều kiểu plot khác nhau, thêm nhiều chiều vào PairGrid qua col, row, hoặc hue và tùy chỉnh trục, figure, legend để có thể thành thạo và hiểu sâu hơn về cách dùng của PairGrid.
Nếu như FaceGrid miêu tả mối quan hệ giống nhau ở các mức (level/class) của các biến khác nhau trên mỗi mặt, thì PairGrid lại miêu tả mối quan hệ khác nhau.
Kết Luận
Qua bài học này người đọc có thể học được cách vẽ nhanh nhiều subplot theo cặp để biểu diễn tương quan của dữ liệu qua các lớp của Seaborn như PairGrid và FaceGrid. Việc sử dụng này vô cùng đơn giản, và hữu ích khi chúng ta muốn nhanh tìm ra insight của dữ liệu. Qua một loạt các bài về seaborn, chúng ta có thể dễ nhận thấy Seaborn vô cùng hữu ích và mạnh mẽ đúng không các bạn.