You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
493 lines
32 KiB
493 lines
32 KiB
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## **Phân tích âm nhạc Nigeria được thu thập từ Spotify**\n",
|
|
"\n",
|
|
"Clustering (phân cụm) là một loại [Học không giám sát](https://wikipedia.org/wiki/Unsupervised_learning) giả định rằng một tập dữ liệu không được gắn nhãn hoặc các đầu vào của nó không được ghép với các đầu ra được xác định trước. Nó sử dụng các thuật toán khác nhau để sắp xếp dữ liệu không gắn nhãn và cung cấp các nhóm dựa trên các mẫu mà nó nhận ra trong dữ liệu.\n",
|
|
"\n",
|
|
"[**Câu hỏi kiểm tra trước bài giảng**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/27/)\n",
|
|
"\n",
|
|
"### **Giới thiệu**\n",
|
|
"\n",
|
|
"[Phân cụm](https://link.springer.com/referenceworkentry/10.1007%2F978-0-387-30164-8_124) rất hữu ích trong việc khám phá dữ liệu. Hãy xem liệu nó có thể giúp khám phá các xu hướng và mẫu trong cách khán giả Nigeria tiêu thụ âm nhạc hay không.\n",
|
|
"\n",
|
|
"> ✅ Dành một phút để suy nghĩ về các ứng dụng của phân cụm. Trong đời sống thực, phân cụm xảy ra bất cứ khi nào bạn có một đống quần áo cần phân loại theo từng thành viên trong gia đình 🧦👕👖🩲. Trong khoa học dữ liệu, phân cụm xảy ra khi cố gắng phân tích sở thích của người dùng hoặc xác định các đặc điểm của bất kỳ tập dữ liệu không gắn nhãn nào. Phân cụm, theo một cách nào đó, giúp làm sáng tỏ sự hỗn loạn, giống như ngăn kéo đựng tất.\n",
|
|
"\n",
|
|
"Trong môi trường chuyên nghiệp, phân cụm có thể được sử dụng để xác định các phân khúc thị trường, ví dụ như xác định nhóm tuổi nào mua những mặt hàng nào. Một ứng dụng khác có thể là phát hiện bất thường, chẳng hạn để phát hiện gian lận từ một tập dữ liệu giao dịch thẻ tín dụng. Hoặc bạn có thể sử dụng phân cụm để xác định khối u trong một loạt các bản quét y tế.\n",
|
|
"\n",
|
|
"✅ Dành một phút để suy nghĩ về cách bạn có thể đã gặp phân cụm 'trong thực tế', trong ngân hàng, thương mại điện tử hoặc môi trường kinh doanh.\n",
|
|
"\n",
|
|
"> 🎓 Thật thú vị, phân tích cụm bắt nguồn từ các lĩnh vực Nhân học và Tâm lý học vào những năm 1930. Bạn có thể tưởng tượng nó đã được sử dụng như thế nào không?\n",
|
|
"\n",
|
|
"Ngoài ra, bạn có thể sử dụng nó để nhóm các kết quả tìm kiếm - ví dụ như theo liên kết mua sắm, hình ảnh hoặc đánh giá. Phân cụm rất hữu ích khi bạn có một tập dữ liệu lớn mà bạn muốn giảm bớt và thực hiện phân tích chi tiết hơn, vì vậy kỹ thuật này có thể được sử dụng để tìm hiểu về dữ liệu trước khi xây dựng các mô hình khác.\n",
|
|
"\n",
|
|
"✅ Khi dữ liệu của bạn được tổ chức thành các cụm, bạn gán cho nó một Id cụm, và kỹ thuật này có thể hữu ích khi bảo vệ quyền riêng tư của tập dữ liệu; bạn có thể thay thế việc tham chiếu đến một điểm dữ liệu bằng Id cụm của nó, thay vì bằng dữ liệu nhận dạng tiết lộ nhiều hơn. Bạn có thể nghĩ đến những lý do khác tại sao bạn lại tham chiếu đến Id cụm thay vì các yếu tố khác của cụm để xác định nó không?\n",
|
|
"\n",
|
|
"### Bắt đầu với phân cụm\n",
|
|
"\n",
|
|
"> 🎓 Cách chúng ta tạo cụm phụ thuộc rất nhiều vào cách chúng ta nhóm các điểm dữ liệu thành các nhóm. Hãy cùng tìm hiểu một số thuật ngữ:\n",
|
|
">\n",
|
|
"> 🎓 ['Transductive' vs. 'inductive'](https://wikipedia.org/wiki/Transduction_(machine_learning))\n",
|
|
">\n",
|
|
"> Suy diễn truyền dẫn (transductive inference) được rút ra từ các trường hợp huấn luyện quan sát được ánh xạ đến các trường hợp kiểm tra cụ thể. Suy diễn quy nạp (inductive inference) được rút ra từ các trường hợp huấn luyện ánh xạ đến các quy tắc chung, sau đó mới được áp dụng cho các trường hợp kiểm tra.\n",
|
|
">\n",
|
|
"> Một ví dụ: Hãy tưởng tượng bạn có một tập dữ liệu chỉ được gắn nhãn một phần. Một số là 'đĩa nhạc', một số là 'cd', và một số để trống. Nhiệm vụ của bạn là cung cấp nhãn cho các mục trống. Nếu bạn chọn cách tiếp cận quy nạp, bạn sẽ huấn luyện một mô hình tìm kiếm 'đĩa nhạc' và 'cd', và áp dụng các nhãn đó cho dữ liệu chưa được gắn nhãn. Cách tiếp cận này sẽ gặp khó khăn trong việc phân loại những thứ thực sự là 'băng cassette'. Một cách tiếp cận truyền dẫn, mặt khác, xử lý dữ liệu chưa biết này hiệu quả hơn vì nó hoạt động để nhóm các mục tương tự lại với nhau và sau đó áp dụng một nhãn cho một nhóm. Trong trường hợp này, các cụm có thể phản ánh 'những thứ âm nhạc hình tròn' và 'những thứ âm nhạc hình vuông'.\n",
|
|
">\n",
|
|
"> 🎓 ['Non-flat' vs. 'flat' geometry](https://datascience.stackexchange.com/questions/52260/terminology-flat-geometry-in-the-context-of-clustering)\n",
|
|
">\n",
|
|
"> Được lấy từ thuật ngữ toán học, hình học không phẳng (non-flat) và phẳng (flat) đề cập đến cách đo khoảng cách giữa các điểm bằng các phương pháp hình học 'phẳng' ([Euclidean](https://wikipedia.org/wiki/Euclidean_geometry)) hoặc 'không phẳng' (phi Euclid).\n",
|
|
">\n",
|
|
"> 'Phẳng' trong ngữ cảnh này đề cập đến hình học Euclid (một phần được dạy như hình học 'mặt phẳng'), và không phẳng đề cập đến hình học phi Euclid. Hình học có liên quan gì đến học máy? Vâng, vì cả hai lĩnh vực đều bắt nguồn từ toán học, nên phải có một cách chung để đo khoảng cách giữa các điểm trong các cụm, và điều đó có thể được thực hiện theo cách 'phẳng' hoặc 'không phẳng', tùy thuộc vào bản chất của dữ liệu. [Khoảng cách Euclid](https://wikipedia.org/wiki/Euclidean_distance) được đo bằng độ dài của một đoạn thẳng giữa hai điểm. [Khoảng cách phi Euclid](https://wikipedia.org/wiki/Non-Euclidean_geometry) được đo dọc theo một đường cong. Nếu dữ liệu của bạn, khi được hình dung, dường như không tồn tại trên một mặt phẳng, bạn có thể cần sử dụng một thuật toán chuyên biệt để xử lý nó.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/flat-nonflat.png\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Infographic bởi Dasani Madipalli</figcaption>\n",
|
|
"\n",
|
|
"> 🎓 ['Distances'](https://web.stanford.edu/class/cs345a/slides/12-clustering.pdf)\n",
|
|
">\n",
|
|
"> Các cụm được xác định bởi ma trận khoảng cách của chúng, ví dụ: khoảng cách giữa các điểm. Khoảng cách này có thể được đo bằng một vài cách. Các cụm Euclid được xác định bởi giá trị trung bình của các điểm và chứa một 'centroid' hoặc điểm trung tâm. Khoảng cách được đo bằng khoảng cách đến centroid đó. Khoảng cách phi Euclid đề cập đến 'clustroids', điểm gần nhất với các điểm khác. Clustroids lần lượt có thể được định nghĩa theo nhiều cách khác nhau.\n",
|
|
">\n",
|
|
"> 🎓 ['Constrained'](https://wikipedia.org/wiki/Constrained_clustering)\n",
|
|
">\n",
|
|
"> [Phân cụm có ràng buộc](https://web.cs.ucdavis.edu/~davidson/Publications/ICDMTutorial.pdf) giới thiệu học 'bán giám sát' vào phương pháp không giám sát này. Các mối quan hệ giữa các điểm được đánh dấu là 'không thể liên kết' hoặc 'phải liên kết' để một số quy tắc được áp dụng cho tập dữ liệu.\n",
|
|
">\n",
|
|
"> Một ví dụ: Nếu một thuật toán được tự do áp dụng trên một loạt dữ liệu không gắn nhãn hoặc gắn nhãn một phần, các cụm mà nó tạo ra có thể có chất lượng kém. Trong ví dụ trên, các cụm có thể nhóm 'những thứ âm nhạc hình tròn', 'những thứ âm nhạc hình vuông', 'những thứ hình tam giác' và 'bánh quy'. Nếu được cung cấp một số ràng buộc hoặc quy tắc để tuân theo (\"mục phải được làm bằng nhựa\", \"mục cần có khả năng tạo ra âm nhạc\"), điều này có thể giúp 'ràng buộc' thuật toán để đưa ra các lựa chọn tốt hơn.\n",
|
|
">\n",
|
|
"> 🎓 'Density'\n",
|
|
">\n",
|
|
"> Dữ liệu 'nhiễu' được coi là 'dày đặc'. Khoảng cách giữa các điểm trong mỗi cụm của nó có thể, khi được kiểm tra, dày đặc hơn hoặc ít dày đặc hơn, hoặc 'đông đúc', và do đó dữ liệu này cần được phân tích bằng phương pháp phân cụm phù hợp. [Bài viết này](https://www.kdnuggets.com/2020/02/understanding-density-based-clustering.html) minh họa sự khác biệt giữa việc sử dụng phân cụm K-Means và các thuật toán HDBSCAN để khám phá một tập dữ liệu nhiễu với mật độ cụm không đồng đều.\n",
|
|
"\n",
|
|
"Nâng cao hiểu biết của bạn về các kỹ thuật phân cụm trong [module học này](https://docs.microsoft.com/learn/modules/train-evaluate-cluster-models?WT.mc_id=academic-77952-leestott)\n",
|
|
"\n",
|
|
"### **Thuật toán phân cụm**\n",
|
|
"\n",
|
|
"Có hơn 100 thuật toán phân cụm, và việc sử dụng chúng phụ thuộc vào bản chất của dữ liệu. Hãy thảo luận một số thuật toán chính:\n",
|
|
"\n",
|
|
"- **Phân cụm phân cấp**. Nếu một đối tượng được phân loại dựa trên sự gần gũi của nó với một đối tượng gần đó, thay vì với một đối tượng xa hơn, các cụm được hình thành dựa trên khoảng cách của các thành viên với các đối tượng khác. Phân cụm phân cấp được đặc trưng bởi việc liên tục kết hợp hai cụm.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/hierarchical.png\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Infographic bởi Dasani Madipalli</figcaption>\n",
|
|
"\n",
|
|
"- **Phân cụm centroid**. Thuật toán phổ biến này yêu cầu chọn 'k', hoặc số lượng cụm cần tạo, sau đó thuật toán xác định điểm trung tâm của một cụm và thu thập dữ liệu xung quanh điểm đó. [Phân cụm K-means](https://wikipedia.org/wiki/K-means_clustering) là một phiên bản phổ biến của phân cụm centroid, chia một tập dữ liệu thành K nhóm được xác định trước. Trung tâm được xác định bởi giá trị trung bình gần nhất, do đó có tên gọi này. Khoảng cách bình phương từ cụm được giảm thiểu.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/centroid.png\"\n",
|
|
" width=\"600\"/>\n",
|
|
" <figcaption>Infographic bởi Dasani Madipalli</figcaption>\n",
|
|
"\n",
|
|
"- **Phân cụm dựa trên phân phối**. Dựa trên mô hình thống kê, phân cụm dựa trên phân phối tập trung vào việc xác định xác suất rằng một điểm dữ liệu thuộc về một cụm và gán nó tương ứng. Các phương pháp hỗn hợp Gaussian thuộc loại này.\n",
|
|
"\n",
|
|
"- **Phân cụm dựa trên mật độ**. Các điểm dữ liệu được gán vào các cụm dựa trên mật độ của chúng, hoặc sự nhóm lại xung quanh nhau. Các điểm dữ liệu xa nhóm được coi là nhiễu hoặc ngoại lệ. DBSCAN, Mean-shift và OPTICS thuộc loại phân cụm này.\n",
|
|
"\n",
|
|
"- **Phân cụm dựa trên lưới**. Đối với các tập dữ liệu đa chiều, một lưới được tạo ra và dữ liệu được chia giữa các ô của lưới, từ đó tạo ra các cụm.\n",
|
|
"\n",
|
|
"Cách tốt nhất để học về phân cụm là tự mình thử nghiệm, và đó là điều bạn sẽ làm trong bài tập này.\n",
|
|
"\n",
|
|
"Chúng ta sẽ cần một số gói để hoàn thành module này. Bạn có thể cài đặt chúng bằng lệnh: `install.packages(c('tidyverse', 'tidymodels', 'DataExplorer', 'summarytools', 'plotly', 'paletteer', 'corrplot', 'patchwork'))`\n",
|
|
"\n",
|
|
"Ngoài ra, đoạn mã dưới đây sẽ kiểm tra xem bạn đã có các gói cần thiết để hoàn thành module này chưa và cài đặt chúng nếu thiếu.\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"suppressWarnings(if(!require(\"pacman\")) install.packages(\"pacman\"))\r\n",
|
|
"\r\n",
|
|
"pacman::p_load('tidyverse', 'tidymodels', 'DataExplorer', 'summarytools', 'plotly', 'paletteer', 'corrplot', 'patchwork')\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"## Bài tập - phân cụm dữ liệu của bạn\n",
|
|
"\n",
|
|
"Phân cụm là một kỹ thuật được hỗ trợ rất nhiều bởi việc trực quan hóa đúng cách, vì vậy hãy bắt đầu bằng cách trực quan hóa dữ liệu âm nhạc của chúng ta. Bài tập này sẽ giúp chúng ta quyết định phương pháp phân cụm nào sẽ được sử dụng hiệu quả nhất cho bản chất của dữ liệu này.\n",
|
|
"\n",
|
|
"Hãy bắt đầu ngay bằng cách nhập dữ liệu.\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Load the core tidyverse and make it available in your current R session\r\n",
|
|
"library(tidyverse)\r\n",
|
|
"\r\n",
|
|
"# Import the data into a tibble\r\n",
|
|
"df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/5-Clustering/data/nigerian-songs.csv\")\r\n",
|
|
"\r\n",
|
|
"# View the first 5 rows of the data set\r\n",
|
|
"df %>% \r\n",
|
|
" slice_head(n = 5)\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Đôi khi, chúng ta có thể muốn biết thêm một chút thông tin về dữ liệu của mình. Chúng ta có thể xem `dữ liệu` và `cấu trúc của nó` bằng cách sử dụng hàm [*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html):\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Glimpse into the data set\r\n",
|
|
"df %>% \r\n",
|
|
" glimpse()\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Làm tốt lắm!💪\n",
|
|
"\n",
|
|
"Chúng ta có thể thấy rằng `glimpse()` sẽ cung cấp cho bạn tổng số hàng (quan sát) và cột (biến), sau đó là một vài giá trị đầu tiên của mỗi biến được hiển thị theo hàng sau tên biến. Ngoài ra, *kiểu dữ liệu* của biến được hiển thị ngay sau tên biến trong dấu `< >`.\n",
|
|
"\n",
|
|
"`DataExplorer::introduce()` có thể tóm tắt thông tin này một cách gọn gàng:\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Describe basic information for our data\r\n",
|
|
"df %>% \r\n",
|
|
" introduce()\r\n",
|
|
"\r\n",
|
|
"# A visual display of the same\r\n",
|
|
"df %>% \r\n",
|
|
" plot_intro()\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Tuyệt vời! Chúng ta vừa biết rằng dữ liệu của mình không có giá trị bị thiếu.\n",
|
|
"\n",
|
|
"Nhân tiện, chúng ta có thể khám phá các thống kê xu hướng trung tâm phổ biến (ví dụ như [mean](https://en.wikipedia.org/wiki/Arithmetic_mean) và [median](https://en.wikipedia.org/wiki/Median)) và các thước đo độ phân tán (ví dụ như [standard deviation](https://en.wikipedia.org/wiki/Standard_deviation)) bằng cách sử dụng `summarytools::descr()`\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Describe common statistics\r\n",
|
|
"df %>% \r\n",
|
|
" descr(stats = \"common\")\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Hãy xem các giá trị tổng quát của dữ liệu. Lưu ý rằng độ phổ biến có thể là `0`, điều này cho thấy các bài hát không có xếp hạng. Chúng ta sẽ loại bỏ chúng ngay sau đây.\n",
|
|
"\n",
|
|
"> 🤔 Nếu chúng ta đang làm việc với phân cụm, một phương pháp không giám sát không yêu cầu dữ liệu được gắn nhãn, tại sao lại hiển thị dữ liệu này với nhãn? Trong giai đoạn khám phá dữ liệu, chúng rất hữu ích, nhưng chúng không cần thiết để các thuật toán phân cụm hoạt động.\n",
|
|
"\n",
|
|
"### 1. Khám phá các thể loại phổ biến\n",
|
|
"\n",
|
|
"Hãy cùng tìm hiểu các thể loại phổ biến nhất 🎶 bằng cách đếm số lần chúng xuất hiện.\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Popular genres\r\n",
|
|
"top_genres <- df %>% \r\n",
|
|
" count(artist_top_genre, sort = TRUE) %>% \r\n",
|
|
"# Encode to categorical and reorder the according to count\r\n",
|
|
" mutate(artist_top_genre = factor(artist_top_genre) %>% fct_inorder())\r\n",
|
|
"\r\n",
|
|
"# Print the top genres\r\n",
|
|
"top_genres\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Điều đó thật tốt! Người ta thường nói một bức tranh đáng giá ngàn dòng của một khung dữ liệu (thực ra chẳng ai nói vậy cả 😅). Nhưng bạn hiểu ý rồi đúng không?\n",
|
|
"\n",
|
|
"Một cách để trực quan hóa dữ liệu phân loại (biến ký tự hoặc biến nhân tố) là sử dụng biểu đồ cột. Hãy tạo một biểu đồ cột cho 10 thể loại hàng đầu:\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Change the default gray theme\r\n",
|
|
"theme_set(theme_light())\r\n",
|
|
"\r\n",
|
|
"# Visualize popular genres\r\n",
|
|
"top_genres %>%\r\n",
|
|
" slice(1:10) %>% \r\n",
|
|
" ggplot(mapping = aes(x = artist_top_genre, y = n,\r\n",
|
|
" fill = artist_top_genre)) +\r\n",
|
|
" geom_col(alpha = 0.8) +\r\n",
|
|
" paletteer::scale_fill_paletteer_d(\"rcartocolor::Vivid\") +\r\n",
|
|
" ggtitle(\"Top genres\") +\r\n",
|
|
" theme(plot.title = element_text(hjust = 0.5),\r\n",
|
|
" # Rotates the X markers (so we can read them)\r\n",
|
|
" axis.text.x = element_text(angle = 90))\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Bây giờ dễ dàng hơn nhiều để nhận ra rằng chúng ta có các thể loại `thiếu` 🧐!\n",
|
|
"\n",
|
|
"> Một hình ảnh trực quan tốt sẽ cho bạn thấy những điều mà bạn không ngờ tới, hoặc gợi lên những câu hỏi mới về dữ liệu - Hadley Wickham và Garrett Grolemund, [R For Data Science](https://r4ds.had.co.nz/introduction.html)\n",
|
|
"\n",
|
|
"Lưu ý, khi thể loại hàng đầu được mô tả là `Thiếu`, điều đó có nghĩa là Spotify đã không phân loại nó, vì vậy hãy loại bỏ nó đi.\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Visualize popular genres\r\n",
|
|
"top_genres %>%\r\n",
|
|
" filter(artist_top_genre != \"Missing\") %>% \r\n",
|
|
" slice(1:10) %>% \r\n",
|
|
" ggplot(mapping = aes(x = artist_top_genre, y = n,\r\n",
|
|
" fill = artist_top_genre)) +\r\n",
|
|
" geom_col(alpha = 0.8) +\r\n",
|
|
" paletteer::scale_fill_paletteer_d(\"rcartocolor::Vivid\") +\r\n",
|
|
" ggtitle(\"Top genres\") +\r\n",
|
|
" theme(plot.title = element_text(hjust = 0.5),\r\n",
|
|
" # Rotates the X markers (so we can read them)\r\n",
|
|
" axis.text.x = element_text(angle = 90))\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Từ việc khám phá dữ liệu ban đầu, chúng ta nhận thấy rằng ba thể loại hàng đầu chiếm ưu thế trong tập dữ liệu này. Hãy tập trung vào `afro dancehall`, `afropop`, và `nigerian pop`, đồng thời lọc tập dữ liệu để loại bỏ bất kỳ mục nào có giá trị phổ biến bằng 0 (nghĩa là không được phân loại với mức độ phổ biến trong tập dữ liệu và có thể được coi là nhiễu đối với mục đích của chúng ta):\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"nigerian_songs <- df %>% \r\n",
|
|
" # Concentrate on top 3 genres\r\n",
|
|
" filter(artist_top_genre %in% c(\"afro dancehall\", \"afropop\",\"nigerian pop\")) %>% \r\n",
|
|
" # Remove unclassified observations\r\n",
|
|
" filter(popularity != 0)\r\n",
|
|
"\r\n",
|
|
"\r\n",
|
|
"\r\n",
|
|
"# Visualize popular genres\r\n",
|
|
"nigerian_songs %>%\r\n",
|
|
" count(artist_top_genre) %>%\r\n",
|
|
" ggplot(mapping = aes(x = artist_top_genre, y = n,\r\n",
|
|
" fill = artist_top_genre)) +\r\n",
|
|
" geom_col(alpha = 0.8) +\r\n",
|
|
" paletteer::scale_fill_paletteer_d(\"ggsci::category10_d3\") +\r\n",
|
|
" ggtitle(\"Top genres\") +\r\n",
|
|
" theme(plot.title = element_text(hjust = 0.5))\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Hãy xem liệu có bất kỳ mối quan hệ tuyến tính rõ ràng nào giữa các biến số trong tập dữ liệu của chúng ta hay không. Mối quan hệ này được định lượng một cách toán học bằng [thống kê tương quan](https://en.wikipedia.org/wiki/Correlation).\n",
|
|
"\n",
|
|
"Thống kê tương quan là một giá trị nằm trong khoảng từ -1 đến 1, biểu thị mức độ mạnh của mối quan hệ. Các giá trị lớn hơn 0 cho thấy mối tương quan *dương* (giá trị cao của một biến thường đi kèm với giá trị cao của biến kia), trong khi các giá trị nhỏ hơn 0 cho thấy mối tương quan *âm* (giá trị cao của một biến thường đi kèm với giá trị thấp của biến kia).\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Narrow down to numeric variables and fid correlation\r\n",
|
|
"corr_mat <- nigerian_songs %>% \r\n",
|
|
" select(where(is.numeric)) %>% \r\n",
|
|
" cor()\r\n",
|
|
"\r\n",
|
|
"# Visualize correlation matrix\r\n",
|
|
"corrplot(corr_mat, order = 'AOE', col = c('white', 'black'), bg = 'gold2') \r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Dữ liệu không có sự tương quan mạnh ngoại trừ giữa `energy` và `loudness`, điều này khá hợp lý vì nhạc lớn thường rất sôi động. `Popularity` có sự liên hệ với `release date`, điều này cũng hợp lý vì các bài hát mới hơn có thể phổ biến hơn. Độ dài và năng lượng dường như cũng có sự tương quan.\n",
|
|
"\n",
|
|
"Sẽ rất thú vị khi xem một thuật toán phân cụm có thể làm gì với dữ liệu này!\n",
|
|
"\n",
|
|
"> 🎓 Lưu ý rằng sự tương quan không đồng nghĩa với nguyên nhân! Chúng ta có bằng chứng về sự tương quan nhưng không có bằng chứng về nguyên nhân. Một [trang web thú vị](https://tylervigen.com/spurious-correlations) có một số hình ảnh minh họa nhấn mạnh điểm này.\n",
|
|
"\n",
|
|
"### 2. Khám phá phân bố dữ liệu\n",
|
|
"\n",
|
|
"Hãy đặt ra một số câu hỏi tinh tế hơn. Liệu các thể loại có khác biệt đáng kể trong cách chúng được cảm nhận về khả năng nhảy múa, dựa trên mức độ phổ biến của chúng? Hãy kiểm tra phân bố dữ liệu của ba thể loại hàng đầu về mức độ phổ biến và khả năng nhảy múa dọc theo trục x và y bằng cách sử dụng [biểu đồ mật độ](https://www.khanacademy.org/math/ap-statistics/density-curves-normal-distribution-ap/density-curves/v/density-curves).\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# Perform 2D kernel density estimation\r\n",
|
|
"density_estimate_2d <- nigerian_songs %>% \r\n",
|
|
" ggplot(mapping = aes(x = popularity, y = danceability, color = artist_top_genre)) +\r\n",
|
|
" geom_density_2d(bins = 5, size = 1) +\r\n",
|
|
" paletteer::scale_color_paletteer_d(\"RSkittleBrewer::wildberry\") +\r\n",
|
|
" xlim(-20, 80) +\r\n",
|
|
" ylim(0, 1.2)\r\n",
|
|
"\r\n",
|
|
"# Density plot based on the popularity\r\n",
|
|
"density_estimate_pop <- nigerian_songs %>% \r\n",
|
|
" ggplot(mapping = aes(x = popularity, fill = artist_top_genre, color = artist_top_genre)) +\r\n",
|
|
" geom_density(size = 1, alpha = 0.5) +\r\n",
|
|
" paletteer::scale_fill_paletteer_d(\"RSkittleBrewer::wildberry\") +\r\n",
|
|
" paletteer::scale_color_paletteer_d(\"RSkittleBrewer::wildberry\") +\r\n",
|
|
" theme(legend.position = \"none\")\r\n",
|
|
"\r\n",
|
|
"# Density plot based on the danceability\r\n",
|
|
"density_estimate_dance <- nigerian_songs %>% \r\n",
|
|
" ggplot(mapping = aes(x = danceability, fill = artist_top_genre, color = artist_top_genre)) +\r\n",
|
|
" geom_density(size = 1, alpha = 0.5) +\r\n",
|
|
" paletteer::scale_fill_paletteer_d(\"RSkittleBrewer::wildberry\") +\r\n",
|
|
" paletteer::scale_color_paletteer_d(\"RSkittleBrewer::wildberry\")\r\n",
|
|
"\r\n",
|
|
"\r\n",
|
|
"# Patch everything together\r\n",
|
|
"library(patchwork)\r\n",
|
|
"density_estimate_2d / (density_estimate_pop + density_estimate_dance)\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Chúng ta thấy rằng có các vòng tròn đồng tâm xếp thẳng hàng, bất kể thể loại. Liệu có thể rằng sở thích của người Nigeria hội tụ ở một mức độ nhảy múa nhất định cho thể loại này?\n",
|
|
"\n",
|
|
"Nhìn chung, ba thể loại này tương đồng về mức độ phổ biến và khả năng nhảy múa. Việc xác định các cụm trong dữ liệu không hoàn toàn đồng nhất này sẽ là một thách thức. Hãy xem liệu biểu đồ phân tán có thể hỗ trợ điều này không.\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"source": [
|
|
"# A scatter plot of popularity and danceability\r\n",
|
|
"scatter_plot <- nigerian_songs %>% \r\n",
|
|
" ggplot(mapping = aes(x = popularity, y = danceability, color = artist_top_genre, shape = artist_top_genre)) +\r\n",
|
|
" geom_point(size = 2, alpha = 0.8) +\r\n",
|
|
" paletteer::scale_color_paletteer_d(\"futurevisions::mars\")\r\n",
|
|
"\r\n",
|
|
"# Add a touch of interactivity\r\n",
|
|
"ggplotly(scatter_plot)\r\n"
|
|
],
|
|
"outputs": [],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"source": [
|
|
"Một biểu đồ phân tán của cùng các trục cho thấy một mô hình hội tụ tương tự.\n",
|
|
"\n",
|
|
"Nhìn chung, đối với việc phân cụm, bạn có thể sử dụng biểu đồ phân tán để hiển thị các cụm dữ liệu, vì vậy việc thành thạo loại hình trực quan hóa này rất hữu ích. Trong bài học tiếp theo, chúng ta sẽ sử dụng dữ liệu đã được lọc này và áp dụng phương pháp phân cụm k-means để khám phá các nhóm trong dữ liệu này, những nhóm có xu hướng chồng lấn theo những cách thú vị.\n",
|
|
"\n",
|
|
"## **🚀 Thử thách**\n",
|
|
"\n",
|
|
"Để chuẩn bị cho bài học tiếp theo, hãy tạo một biểu đồ về các thuật toán phân cụm khác nhau mà bạn có thể khám phá và sử dụng trong môi trường sản xuất. Những loại vấn đề nào mà phân cụm đang cố gắng giải quyết?\n",
|
|
"\n",
|
|
"## [**Câu hỏi kiểm tra sau bài học**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/28/)\n",
|
|
"\n",
|
|
"## **Ôn tập & Tự học**\n",
|
|
"\n",
|
|
"Trước khi bạn áp dụng các thuật toán phân cụm, như chúng ta đã học, việc hiểu rõ bản chất của tập dữ liệu là một ý tưởng tốt. Đọc thêm về chủ đề này [tại đây](https://www.kdnuggets.com/2019/10/right-clustering-algorithm.html)\n",
|
|
"\n",
|
|
"Nâng cao hiểu biết của bạn về các kỹ thuật phân cụm:\n",
|
|
"\n",
|
|
"- [Huấn luyện và Đánh giá Mô hình Phân cụm bằng Tidymodels và các công cụ liên quan](https://rpubs.com/eR_ic/clustering)\n",
|
|
"\n",
|
|
"- Bradley Boehmke & Brandon Greenwell, [*Hands-On Machine Learning with R*](https://bradleyboehmke.github.io/HOML/)*.*\n",
|
|
"\n",
|
|
"## **Bài tập**\n",
|
|
"\n",
|
|
"[Nghiên cứu các cách trực quan hóa khác cho phân cụm](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/assignment.md)\n",
|
|
"\n",
|
|
"## CẢM ƠN ĐẾN:\n",
|
|
"\n",
|
|
"[Jen Looper](https://www.twitter.com/jenlooper) vì đã tạo phiên bản Python gốc của mô-đun này ♥️\n",
|
|
"\n",
|
|
"[`Dasani Madipalli`](https://twitter.com/dasani_decoded) vì đã tạo ra những hình minh họa tuyệt vời giúp các khái niệm học máy trở nên dễ hiểu và dễ tiếp cận hơn.\n",
|
|
"\n",
|
|
"Chúc bạn học vui,\n",
|
|
"\n",
|
|
"[Eric](https://twitter.com/ericntay), Đại sứ Sinh viên Microsoft Learn Vàng.\n"
|
|
],
|
|
"metadata": {}
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**Tuyên bố miễn trừ trách nhiệm**: \nTài liệu này đã được dịch bằng dịch vụ dịch thuật AI [Co-op Translator](https://github.com/Azure/co-op-translator). Mặc dù chúng tôi cố gắng đảm bảo độ chính xác, xin lưu ý rằng các bản dịch tự động có thể chứa lỗi hoặc không chính xác. Tài liệu gốc bằng ngôn ngữ bản địa nên được coi là nguồn tham khảo chính thức. Đối với các thông tin quan trọng, chúng tôi khuyến nghị sử dụng dịch vụ dịch thuật chuyên nghiệp từ con người. Chúng tôi không chịu trách nhiệm cho bất kỳ sự hiểu lầm hoặc diễn giải sai nào phát sinh từ việc sử dụng bản dịch này.\n"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"anaconda-cloud": "",
|
|
"kernelspec": {
|
|
"display_name": "R",
|
|
"language": "R",
|
|
"name": "ir"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": "r",
|
|
"file_extension": ".r",
|
|
"mimetype": "text/x-r-source",
|
|
"name": "R",
|
|
"pygments_lexer": "r",
|
|
"version": "3.4.1"
|
|
},
|
|
"coopTranslator": {
|
|
"original_hash": "99c36449cad3708a435f6798cfa39972",
|
|
"translation_date": "2025-09-06T14:19:17+00:00",
|
|
"source_file": "5-Clustering/1-Visualize/solution/R/lesson_14-R.ipynb",
|
|
"language_code": "vi"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 1
|
|
} |