chore(i18n): sync translations with latest source changes (chunk 6/6, 78 changes)

pull/918/head
localizeflow[bot] 6 months ago
parent a8b0709227
commit 927973b152

@ -0,0 +1,637 @@
{
"nbformat": 4,
"nbformat_minor": 0,
"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"
},
"colab": {
"name": "lesson_14.ipynb",
"provenance": [],
"collapsed_sections": [],
"toc_visible": true
},
"coopTranslator": {
"original_hash": "ad65fb4aad0a156b42216e4929f490fc",
"translation_date": "2025-09-03T20:19:29+00:00",
"source_file": "5-Clustering/2-K-Means/solution/R/lesson_15-R.ipynb",
"language_code": "tw"
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "GULATlQXLXyR"
},
"source": [
"## 使用 R 和 Tidy 數據原則探索 K-Means 分群\n",
"\n",
"### [**課前測驗**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/29/)\n",
"\n",
"在本課程中,您將學習如何使用 Tidymodels 套件以及 R 生態系統中的其他套件(我們稱它們為朋友 🧑‍🤝‍🧑),以及您之前導入的尼日利亞音樂數據集來創建分群。我們將介紹 K-Means 分群的基本概念。請記住,正如您在之前的課程中所學,處理分群的方法有很多,您使用的方法取決於您的數據。我們將嘗試 K-Means因為它是最常見的分群技術。讓我們開始吧\n",
"\n",
"您將學習的術語:\n",
"\n",
"- Silhouette 評分\n",
"\n",
"- Elbow 方法\n",
"\n",
"- Inertia慣性\n",
"\n",
"- Variance方差\n",
"\n",
"### **簡介**\n",
"\n",
"[K-Means 分群](https://wikipedia.org/wiki/K-means_clustering) 是一種源自信號處理領域的方法。它用於根據特徵的相似性將數據分成 `k 個分群`。\n",
"\n",
"這些分群可以用 [Voronoi 圖](https://wikipedia.org/wiki/Voronoi_diagram) 來可視化,其中包括一個點(或“種子”)及其對應的區域。\n",
"\n",
"<p >\n",
" <img src=\"../../images/voronoi.png\"\n",
" width=\"500\"/>\n",
" <figcaption>Jen Looper 的信息圖</figcaption>\n",
"\n",
"K-Means 分群的步驟如下:\n",
"\n",
"1. 數據科學家首先指定要創建的分群數量。\n",
"\n",
"2. 接下來,算法隨機選擇數據集中的 K 個觀測值作為分群的初始中心(即質心)。\n",
"\n",
"3. 然後,將其餘的觀測值分配到距離最近的質心。\n",
"\n",
"4. 接下來,計算每個分群的新均值,並將質心移動到均值位置。\n",
"\n",
"5. 現在質心已重新計算,每個觀測值再次被檢查是否可能更接近其他分群。使用更新的分群均值重新分配所有對象。分群分配和質心更新步驟會反覆進行,直到分群分配不再改變(即達到收斂)。通常,當每次新迭代導致質心的移動微乎其微且分群變得穩定時,算法就會終止。\n",
"\n",
"<div>\n",
"\n",
"> 請注意,由於初始 k 個觀測值的隨機化,我們每次應用該程序時可能會得到略有不同的結果。因此,大多數算法會使用多次 *隨機啟動*,並選擇具有最低 WCSS 的迭代。因此,強烈建議始終使用多個 *nstart* 值運行 K-Means以避免 *不理想的局部最優解*。\n",
"\n",
"</div>\n",
"\n",
"以下短動畫使用 Allison Horst 的 [插圖](https://github.com/allisonhorst/stats-illustrations) 解釋了分群過程:\n",
"\n",
"<p >\n",
" <img src=\"../../images/kmeans.gif\"\n",
" width=\"550\"/>\n",
" <figcaption>@allison_horst 的插圖</figcaption>\n",
"\n",
"分群中出現的一個基本問題是:如何知道應將數據分成多少個分群?使用 K-Means 的一個缺點是您需要確定 `k`,即 `質心` 的數量。幸運的是,`elbow 方法` 有助於估算 `k` 的良好起始值。您稍後將嘗試使用它。\n",
"\n",
"### \n",
"\n",
"**前置條件**\n",
"\n",
"我們將從 [上一課](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/solution/R/lesson_14-R.ipynb) 的結尾開始,在那裡我們分析了數據集,進行了大量可視化,並篩選了感興趣的觀測值。一定要查看!\n",
"\n",
"我們需要一些套件來完成這個模組。您可以通過以下方式安裝它們:`install.packages(c('tidyverse', 'tidymodels', 'cluster', 'summarytools', 'plotly', 'paletteer', 'factoextra', 'patchwork'))`\n",
"\n",
"或者,以下腳本會檢查您是否擁有完成此模組所需的套件,並在缺少某些套件時為您安裝它們。\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "ah_tBi58LXyi"
},
"source": [
"suppressWarnings(if(!require(\"pacman\")) install.packages(\"pacman\"))\n",
"\n",
"pacman::p_load('tidyverse', 'tidymodels', 'cluster', 'summarytools', 'plotly', 'paletteer', 'factoextra', 'patchwork')\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "7e--UCUTLXym"
},
"source": [
"讓我們快速開始吧!\n",
"\n",
"## 1. 與數據共舞:縮小範圍至三大最受歡迎的音樂類型\n",
"\n",
"這是我們在上一課中所做內容的回顧。讓我們來切分和分析一些數據吧!\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "Ycamx7GGLXyn"
},
"source": [
"# Load the core tidyverse and make it available in your current R session\n",
"library(tidyverse)\n",
"\n",
"# Import the data into a tibble\n",
"df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/5-Clustering/data/nigerian-songs.csv\", show_col_types = FALSE)\n",
"\n",
"# Narrow down to top 3 popular genres\n",
"nigerian_songs <- df %>% \n",
" # Concentrate on top 3 genres\n",
" filter(artist_top_genre %in% c(\"afro dancehall\", \"afropop\",\"nigerian pop\")) %>% \n",
" # Remove unclassified observations\n",
" filter(popularity != 0)\n",
"\n",
"\n",
"\n",
"# Visualize popular genres using bar plots\n",
"theme_set(theme_light())\n",
"nigerian_songs %>%\n",
" count(artist_top_genre) %>%\n",
" ggplot(mapping = aes(x = artist_top_genre, y = n,\n",
" fill = artist_top_genre)) +\n",
" geom_col(alpha = 0.8) +\n",
" paletteer::scale_fill_paletteer_d(\"ggsci::category10_d3\") +\n",
" ggtitle(\"Top genres\") +\n",
" theme(plot.title = element_text(hjust = 0.5))\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "b5h5zmkPLXyp"
},
"source": [
"🤩 太棒了!\n",
"\n",
"## 2. 更多數據探索\n",
"\n",
"這些數據有多乾淨?讓我們使用盒形圖檢查是否有異常值。我們將專注於異常值較少的數值型欄位(雖然你也可以清理掉異常值)。盒形圖可以顯示數據的範圍,並幫助選擇要使用的欄位。請注意,盒形圖不顯示方差,而方差是良好可聚類數據的重要元素。請參閱[這篇討論](https://stats.stackexchange.com/questions/91536/deduce-variance-from-boxplot)以了解更多。\n",
"\n",
"[盒形圖](https://en.wikipedia.org/wiki/Box_plot)用於以圖形方式描述`數值型`數據的分佈,因此讓我們從*選擇*所有數值型欄位以及流行音樂類型開始。\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "HhNreJKLLXyq"
},
"source": [
"# Select top genre column and all other numeric columns\n",
"df_numeric <- nigerian_songs %>% \n",
" select(artist_top_genre, where(is.numeric)) \n",
"\n",
"# Display the data\n",
"df_numeric %>% \n",
" slice_head(n = 5)\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "uYXrwJRaLXyq"
},
"source": [
"看看選擇輔助工具 `where` 是如何讓這件事變得簡單的 💁?可以在[這裡](https://tidyselect.r-lib.org/)探索其他類似的函數。\n",
"\n",
"由於我們將為每個數值特徵製作箱型圖,並且希望避免使用迴圈,因此我們需要將數據重新格式化為*更長的*格式,這樣就可以利用 `facets`——每個子圖都顯示數據的一個子集。\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "gd5bR3f8LXys"
},
"source": [
"# Pivot data from wide to long\n",
"df_numeric_long <- df_numeric %>% \n",
" pivot_longer(!artist_top_genre, names_to = \"feature_names\", values_to = \"values\") \n",
"\n",
"# Print out data\n",
"df_numeric_long %>% \n",
" slice_head(n = 15)\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "-7tE1swnLXyv"
},
"source": [
"更長了!現在是時候使用一些 `ggplots` 了!那麼我們會使用哪種 `geom` 呢?\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "r88bIsyuLXyy"
},
"source": [
"# Make a box plot\n",
"df_numeric_long %>% \n",
" ggplot(mapping = aes(x = feature_names, y = values, fill = feature_names)) +\n",
" geom_boxplot() +\n",
" facet_wrap(~ feature_names, ncol = 4, scales = \"free\") +\n",
" theme(legend.position = \"none\")\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "EYVyKIUELXyz"
},
"source": [
"現在我們可以看到這些數據有些雜亂:透過觀察每一列的盒狀圖,可以看到有異常值。你可以逐一檢查數據集並移除這些異常值,但這樣會使數據變得非常有限。\n",
"\n",
"目前,我們來選擇要用於聚類練習的列。讓我們挑選範圍相似的數值型列。我們可以將 `artist_top_genre` 編碼為數值型,但現在先將其排除。\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "-wkpINyZLXy0"
},
"source": [
"# Select variables with similar ranges\n",
"df_numeric_select <- df_numeric %>% \n",
" select(popularity, danceability, acousticness, loudness, energy) \n",
"\n",
"# Normalize data\n",
"# df_numeric_select <- scale(df_numeric_select)\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "D7dLzgpqLXy1"
},
"source": [
"## 3. 在 R 中計算 k-means 分群\n",
"\n",
"我們可以使用 R 中內建的 `kmeans` 函數來計算 k-means請參閱 `help(\"kmeans()\")`。`kmeans()` 函數的主要參數是一個包含所有數值型欄位的資料框。\n",
"\n",
"使用 k-means 分群的第一步是指定最終解決方案中要生成的群數k。我們知道從資料集中分出了 3 種歌曲類型,因此我們嘗試設置為 3\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "uC4EQ5w7LXy5"
},
"source": [
"set.seed(2056)\n",
"# Kmeans clustering for 3 clusters\n",
"kclust <- kmeans(\n",
" df_numeric_select,\n",
" # Specify the number of clusters\n",
" centers = 3,\n",
" # How many random initial configurations\n",
" nstart = 25\n",
")\n",
"\n",
"# Display clustering object\n",
"kclust\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "hzfhscWrLXy-"
},
"source": [
"kmeans 物件包含了許多資訊,這些資訊在 `help(\"kmeans()\")` 中有詳細說明。目前,我們先專注於幾個重點。我們可以看到資料已被分成三個群組,大小分別為 65、110 和 111。輸出中還包含了三個群組在五個變數上的群中心平均值。\n",
"\n",
"聚類向量是每個觀測值的群組分配。我們可以使用 `augment` 函數將群組分配加入到原始資料集中。\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "0XwwpFGQLXy_"
},
"source": [
"# Add predicted cluster assignment to data set\n",
"augment(kclust, df_numeric_select) %>% \n",
" relocate(.cluster) %>% \n",
" slice_head(n = 10)\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "NXIVXXACLXzA"
},
"source": [
"太好了,我們剛剛將數據集分成了三個群組。那麼,我們的分群效果如何呢 🤷?讓我們來看看 `Silhouette score`。\n",
"\n",
"### **Silhouette score**\n",
"\n",
"[Silhouette 分析](https://en.wikipedia.org/wiki/Silhouette_(clustering)) 可以用來研究結果群組之間的分離距離。這個分數範圍從 -1 到 1如果分數接近 1表示群組密集且與其他群組分離良好。接近 0 的值則表示群組重疊,樣本非常接近鄰近群組的決策邊界。[來源](https://dzone.com/articles/kmeans-silhouette-score-explained-with-python-exam)。\n",
"\n",
"平均 Silhouette 方法計算不同 *k* 值下觀測值的平均 Silhouette 分數。高的平均 Silhouette 分數表示分群效果良好。\n",
"\n",
"使用 cluster 套件中的 `silhouette` 函數來計算平均 Silhouette 寬度。\n",
"\n",
"> Silhouette 可以使用任何 [距離](https://en.wikipedia.org/wiki/Distance \"Distance\") 度量來計算,例如 [歐幾里得距離](https://en.wikipedia.org/wiki/Euclidean_distance \"Euclidean distance\") 或 [曼哈頓距離](https://en.wikipedia.org/wiki/Manhattan_distance \"Manhattan distance\"),這些我們在[上一課](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/solution/R/lesson_14-R.ipynb)中已經討論過。\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "Jn0McL28LXzB"
},
"source": [
"# Load cluster package\n",
"library(cluster)\n",
"\n",
"# Compute average silhouette score\n",
"ss <- silhouette(kclust$cluster,\n",
" # Compute euclidean distance\n",
" dist = dist(df_numeric_select))\n",
"mean(ss[, 3])\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "QyQRn97nLXzC"
},
"source": [
"我們的分數是 **.549**,正好位於中間位置。這表明我們的數據並不特別適合這種類型的聚類。讓我們看看是否可以通過視覺化來確認這個猜測。[factoextra 套件](https://rpkgs.datanovia.com/factoextra/index.html) 提供了函數 (`fviz_cluster()`) 用於視覺化聚類。\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "7a6Km1_FLXzD"
},
"source": [
"library(factoextra)\n",
"\n",
"# Visualize clustering results\n",
"fviz_cluster(kclust, df_numeric_select)\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "IBwCWt-0LXzD"
},
"source": [
"群集之間的重疊表明,我們的數據並不特別適合這種類型的群集,但我們還是繼續進行。\n",
"\n",
"## 4. 確定最佳群集數量\n",
"\n",
"在 K-Means 群集分析中,經常出現的一個基本問題是——在沒有已知類別標籤的情況下,如何知道應將數據分成多少個群集?\n",
"\n",
"我們可以嘗試的一種方法是使用數據樣本來`創建一系列群集模型`,並逐步增加群集的數量(例如從 1 到 10然後評估群集指標例如 **Silhouette 分數**。\n",
"\n",
"讓我們通過計算不同 *k* 值的群集算法來確定最佳群集數量,並評估 **群集內平方和**WCSS。群集內平方和WCSS總量衡量群集的緊密性我們希望它越小越好較低的值意味著數據點更接近。\n",
"\n",
"讓我們探索不同的 `k` 選擇(從 1 到 10對此群集的影響。\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "hSeIiylDLXzE"
},
"source": [
"# Create a series of clustering models\n",
"kclusts <- tibble(k = 1:10) %>% \n",
" # Perform kmeans clustering for 1,2,3 ... ,10 clusters\n",
" mutate(model = map(k, ~ kmeans(df_numeric_select, centers = .x, nstart = 25)),\n",
" # Farm out clustering metrics eg WCSS\n",
" glanced = map(model, ~ glance(.x))) %>% \n",
" unnest(cols = glanced)\n",
" \n",
"\n",
"# View clustering rsulsts\n",
"kclusts\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "m7rS2U1eLXzE"
},
"source": [
"現在我們已經獲得每個聚類算法在中心 *k* 下的總集群內平方和 (tot.withinss),接下來我們使用[肘部法](https://en.wikipedia.org/wiki/Elbow_method_(clustering))來尋找最佳的聚類數量。此方法包括將WCSS作為聚類數量的函數進行繪圖並選擇[曲線的肘部](https://en.wikipedia.org/wiki/Elbow_of_the_curve \"曲線的肘部\")作為要使用的聚類數量。\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "o_DjHGItLXzF"
},
"source": [
"set.seed(2056)\n",
"# Use elbow method to determine optimum number of clusters\n",
"kclusts %>% \n",
" ggplot(mapping = aes(x = k, y = tot.withinss)) +\n",
" geom_line(size = 1.2, alpha = 0.8, color = \"#FF7F0EFF\") +\n",
" geom_point(size = 2, color = \"#FF7F0EFF\")\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "pLYyt5XSLXzG"
},
"source": [
"該圖顯示當群集數量從一個增加到兩個時WCSS因此*緊密度*)大幅減少,從兩個增加到三個群集時也有明顯的減少。之後,減少的幅度變得不那麼明顯,導致圖表在大約三個群集處出現一個「肘部」💪。這是一個很好的指標,表明數據點可以合理地分為兩到三個明顯分離的群集。\n",
"\n",
"現在我們可以繼續提取 `k = 3` 的群集模型:\n",
"\n",
"> `pull()`:用於提取單一列\n",
">\n",
"> `pluck()`:用於索引像列表這樣的數據結構\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "JP_JPKBILXzG"
},
"source": [
"# Extract k = 3 clustering\n",
"final_kmeans <- kclusts %>% \n",
" filter(k == 3) %>% \n",
" pull(model) %>% \n",
" pluck(1)\n",
"\n",
"\n",
"final_kmeans\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "l_PDTu8tLXzI"
},
"source": [
"太好了!讓我們來看看獲得的群集。想用 `plotly` 增加一些互動性嗎?\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "dNcleFe-LXzJ"
},
"source": [
"# Add predicted cluster assignment to data set\n",
"results <- augment(final_kmeans, df_numeric_select) %>% \n",
" bind_cols(df_numeric %>% select(artist_top_genre)) \n",
"\n",
"# Plot cluster assignments\n",
"clust_plt <- results %>% \n",
" ggplot(mapping = aes(x = popularity, y = danceability, color = .cluster, shape = artist_top_genre)) +\n",
" geom_point(size = 2, alpha = 0.8) +\n",
" paletteer::scale_color_paletteer_d(\"ggthemes::Tableau_10\")\n",
"\n",
"ggplotly(clust_plt)\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "6JUM_51VLXzK"
},
"source": [
"或許我們原本預期,每個群集(以不同顏色表示)都會有明顯不同的類型(以不同形狀表示)。\n",
"\n",
"讓我們來看看模型的準確性。\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "HdIMUGq7LXzL"
},
"source": [
"# Assign genres to predefined integers\n",
"label_count <- results %>% \n",
" group_by(artist_top_genre) %>% \n",
" mutate(id = cur_group_id()) %>% \n",
" ungroup() %>% \n",
" summarise(correct_labels = sum(.cluster == id))\n",
"\n",
"\n",
"# Print results \n",
"cat(\"Result:\", label_count$correct_labels, \"out of\", nrow(results), \"samples were correctly labeled.\")\n",
"\n",
"cat(\"\\nAccuracy score:\", label_count$correct_labels/nrow(results))\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "C50wvaAOLXzM"
},
"source": [
"這個模型的準確性還不錯,但並不完美。可能是因為這些數據並不適合用於 K-Means 聚類。這些數據過於不平衡,相關性太低,而且各列數值之間的變異性太大,導致難以形成良好的聚類。事實上,形成的聚類可能會受到我們之前定義的三個類型分類的嚴重影響或偏斜。\n",
"\n",
"儘管如此,這仍然是一個很好的學習過程!\n",
"\n",
"在 Scikit-learn 的文檔中,你可以看到像這樣的模型,聚類並不明顯,存在一個「變異性」問題:\n",
"\n",
"<p >\n",
" <img src=\"../../images/problems.png\"\n",
" width=\"500\"/>\n",
" <figcaption>來自 Scikit-learn 的資訊圖表</figcaption>\n",
"\n",
"\n",
"\n",
"## **變異性**\n",
"\n",
"變異性被定義為「與平均值的平方差的平均值」[來源](https://www.mathsisfun.com/data/standard-deviation.html)。在這個聚類問題的背景下,它指的是數據集中數值偏離平均值的程度過大。\n",
"\n",
"✅ 這是一個很好的時機來思考所有可能解決這個問題的方法。稍微調整數據?使用不同的列?使用不同的算法?提示:嘗試[縮放數據](https://www.mygreatlearning.com/blog/learning-data-science-with-k-means-clustering/)以進行標準化,並測試其他列。\n",
"\n",
"> 試試這個「[變異性計算器](https://www.calculatorsoup.com/calculators/statistics/variance-calculator.php)」來更深入理解這個概念。\n",
"\n",
"------------------------------------------------------------------------\n",
"\n",
"## **🚀挑戰**\n",
"\n",
"花一些時間在這個筆記本上,調整參數。通過進一步清理數據(例如移除異常值),你能提高模型的準確性嗎?你可以使用權重來給某些數據樣本更多的權重。還有什麼方法可以用來創建更好的聚類?\n",
"\n",
"提示:嘗試縮放數據。在筆記本中有註解的代碼,添加了標準縮放,使數據列在範圍上更接近。你會發現,雖然輪廓分數下降了,但肘部圖中的「折點」變得更加平滑。這是因為未縮放的數據允許變異性較小的數據承擔更多的權重。可以在[這裡](https://stats.stackexchange.com/questions/21222/are-mean-normalization-and-feature-scaling-needed-for-k-means-clustering/21226#21226)閱讀更多關於這個問題的內容。\n",
"\n",
"## [**課後測驗**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/30/)\n",
"\n",
"## **回顧與自學**\n",
"\n",
"- 看看一個 K-Means 模擬器[例如這個](https://user.ceng.metu.edu.tr/~akifakkus/courses/ceng574/k-means/)。你可以使用這個工具來可視化樣本數據點並確定其中心點。你可以編輯數據的隨機性、聚類數量和中心點數量。這是否幫助你更好地理解數據如何被分組?\n",
"\n",
"- 另外,看看[這份來自 Stanford 的 K-Means 資料](https://stanford.edu/~cpiech/cs221/handouts/kmeans.html)。\n",
"\n",
"想嘗試將你新學到的聚類技能應用到適合 K-Means 聚類的數據集上嗎?請參考:\n",
"\n",
"- [訓練和評估聚類模型](https://rpubs.com/eR_ic/clustering),使用 Tidymodels 和相關工具\n",
"\n",
"- [K-means 聚類分析](https://uc-r.github.io/kmeans_clustering)UC 商業分析 R 編程指南\n",
"\n",
"- [基於整潔數據原則的 K-means 聚類](https://www.tidymodels.org/learn/statistics/k-means/)\n",
"\n",
"## **作業**\n",
"\n",
"[嘗試不同的聚類方法](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/2-K-Means/assignment.md)\n",
"\n",
"## 特別感謝:\n",
"\n",
"[Jen Looper](https://www.twitter.com/jenlooper) 創建了這個模組的原始 Python 版本 ♥️\n",
"\n",
"[`Allison Horst`](https://twitter.com/allison_horst/) 創作了這些令人驚嘆的插圖,使 R 更加親切和有趣。可以在她的[畫廊](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM)中找到更多插圖。\n",
"\n",
"祝學習愉快,\n",
"\n",
"[Eric](https://twitter.com/ericntay)Gold Microsoft Learn 學生大使。\n",
"\n",
"<p >\n",
" <img src=\"../../images/r_learners_sm.jpeg\"\n",
" width=\"500\"/>\n",
" <figcaption>由 @allison_horst 創作的藝術作品</figcaption>\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**免責聲明** \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始語言的文件應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。\n"
]
}
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,33 @@
# 機器學習中的分群模型
分群是一種機器學習任務,旨在尋找彼此相似的物件並將它們分組成稱為「群集」的群體。分群與機器學習中的其他方法不同之處在於,它是自動進行的,事實上,可以說它是監督式學習的反面。
## 區域主題:針對尼日利亞觀眾音樂品味的分群模型 🎧
尼日利亞的多元化觀眾擁有多樣化的音樂品味。使用從 Spotify 擷取的數據(靈感來自[這篇文章](https://towardsdatascience.com/country-wise-visual-analysis-of-music-taste-using-spotify-api-seaborn-in-python-77f5b749b421)),讓我們來看看一些在尼日利亞流行的音樂。這個數據集包含了各種歌曲的「舞蹈性」分數、「聲學性」、音量、「語音性」、流行度和能量等數據。探索這些數據中的模式將會非常有趣!
![唱盤](../../../translated_images/zh-TW/turntable.f2b86b13c53302dc.webp)
> 照片由 <a href="https://unsplash.com/@marcelalaskoski?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Marcela Laskoski</a> 提供,來自 <a href="https://unsplash.com/s/photos/nigerian-music?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
在這系列課程中,您將學習使用分群技術分析數據的新方法。當您的數據集缺乏標籤時,分群特別有用。如果數據集有標籤,那麼您在之前課程中學到的分類技術可能會更有用。但在需要對未標記數據進行分組的情況下,分群是一種發現模式的好方法。
> 有一些有用的低代碼工具可以幫助您學習如何使用分群模型。試試 [Azure ML](https://docs.microsoft.com/learn/modules/create-clustering-model-azure-machine-learning-designer/?WT.mc_id=academic-77952-leestott) 來完成這項任務。
## 課程
1. [分群簡介](1-Visualize/README.md)
2. [K-Means 分群](2-K-Means/README.md)
## 致謝
這些課程由 [Jen Looper](https://www.twitter.com/jenlooper) 精心撰寫,並由 [Rishit Dagli](https://rishit_dagli) 和 [Muhammad Sakib Khan Inan](https://twitter.com/Sakibinan) 提供了有益的審核。
[Nigerian Songs](https://www.kaggle.com/sootersaalu/nigerian-songs-spotify) 數據集來自 Kaggle並從 Spotify 擷取。
有助於創建這些課程的有用 K-Means 示例包括這個[鳶尾花探索](https://www.kaggle.com/bburns/iris-exploration-pca-k-means-and-gmm-clustering)、這個[入門筆記本](https://www.kaggle.com/prashant111/k-means-clustering-with-python),以及這個[假設的 NGO 示例](https://www.kaggle.com/ankandash/pca-k-means-clustering-hierarchical-clustering)。
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,168 @@
# 自然語言處理簡介
本課程涵蓋了*自然語言處理*NLP這一*計算語言學*子領域的簡史及重要概念。
## [課前測驗](https://ff-quizzes.netlify.app/en/ml/)
## 簡介
NLP自然語言處理是機器學習應用最廣泛的領域之一並且已被用於生產軟體中。
✅ 你能想到每天使用的哪些軟體可能內嵌了 NLP 嗎?例如你經常使用的文字處理程式或手機應用程式?
你將學習以下內容:
- **語言的概念**:語言是如何發展的,以及主要的研究領域。
- **定義與概念**:你還將學習計算機如何處理文本的定義與概念,包括解析、語法以及名詞和動詞的識別。本課程中有一些編碼任務,並介紹了一些重要概念,這些概念將在後續課程中進一步學習如何編碼實現。
## 計算語言學
計算語言學是一個研究領域經過數十年的發展研究計算機如何與語言互動甚至理解、翻譯和交流語言。自然語言處理NLP是一個相關領域專注於計算機如何處理“自然”或人類語言。
### 範例 - 手機語音輸入
如果你曾經使用手機語音輸入代替打字,或者向虛擬助理提問,那麼你的語音已被轉換為文本形式,然後被處理或*解析*成你所說的語言。檢測到的關鍵詞隨後被處理成手機或助理可以理解並執行的格式。
![理解](../../../../6-NLP/1-Introduction-to-NLP/images/comprehension.png)
> 真正的語言理解非常困難!圖片來源:[Jen Looper](https://twitter.com/jenlooper)
### 這項技術是如何實現的?
這是因為有人編寫了一個計算機程式來實現這一功能。幾十年前,一些科幻作家預測人們將主要通過語音與計算機交流,而計算機將始終準確理解人們的意思。不幸的是,這個問題比許多人想像的要困難得多。儘管今天對這個問題的理解已經大大加深,但在實現“完美”的自然語言處理方面仍然面臨重大挑戰,尤其是在理解句子含義時。當涉及到理解幽默或檢測句子中的諷刺情緒時,這是一個特別困難的問題。
此時,你可能會回想起學校課堂上老師講解句子語法部分的情景。在某些國家,學生會專門學習語法和語言學,而在許多國家,這些主題則作為語言學習的一部分:例如在小學學習母語(學習閱讀和寫作),以及在中學學習第二語言。如果你無法熟練區分名詞、動詞或副詞、形容詞,不用擔心!
如果你對於區分*一般現在時*和*現在進行時*感到困難,你並不孤單。這對許多人來說都是一個挑戰,即使是母語使用者。好消息是,計算機非常擅長應用形式化規則,你將學習如何編寫程式來像人類一樣*解析*句子。更大的挑戰是理解句子的*含義*和*情感*,這將在後續課程中進一步探討。
## 先修知識
本課程的主要先修條件是能夠閱讀並理解本課程的語言。課程中沒有數學問題或方程需要解決。雖然原作者以英文撰寫了本課程,但它也被翻譯成其他語言,因此你可能正在閱讀翻譯版本。課程中有一些例子使用了多種語言(用於比較不同語言的語法規則)。這些例子*未被翻譯*,但解釋性文本已被翻譯,因此應該能夠理解其含義。
在編碼任務中,你將使用 Python並且範例使用的是 Python 3.8。
在本節中,你將需要並使用以下工具:
- **Python 3 基礎**:理解 Python 3 程式語言,本課程使用輸入、迴圈、文件讀取和陣列。
- **Visual Studio Code + 擴展**:我們將使用 Visual Studio Code 及其 Python 擴展。你也可以選擇使用其他 Python IDE。
- **TextBlob**[TextBlob](https://github.com/sloria/TextBlob) 是一個簡化的 Python 文本處理庫。按照 TextBlob 網站上的說明將其安裝到你的系統中(同時安裝語料庫,如下所示):
```bash
pip install -U textblob
python -m textblob.download_corpora
```
> 💡 提示:你可以直接在 VS Code 環境中運行 Python。查看 [文檔](https://code.visualstudio.com/docs/languages/python?WT.mc_id=academic-77952-leestott) 以獲取更多資訊。
## 與機器對話
讓計算機理解人類語言的歷史可以追溯到數十年前,最早考慮自然語言處理的科學家之一是*艾倫·圖靈*。
### “圖靈測試”
當圖靈在 1950 年代研究*人工智慧*時,他考慮了一種對話測試,該測試讓人類和計算機進行對話(通過打字通信),如果對話中的人類無法確定自己是在與另一個人類還是計算機交流,那麼是否可以說計算機在“思考”?
### 靈感來源 - “模仿遊戲”
這個想法來自一種叫做*模仿遊戲*的派對遊戲。在遊戲中,一名提問者獨自待在一個房間裡,試圖判斷另一個房間中的兩個人分別是男性還是女性。提問者可以發送紙條,並試圖設計問題,通過書面回答來揭示神秘人的性別。當然,另一個房間中的玩家會試圖誤導提問者,通過回答問題來混淆提問者,同時表現得像是在誠實回答。
### 開發 Eliza
1960 年代,麻省理工學院的科學家*約瑟夫·魏森鮑姆*開發了[*Eliza*](https://wikipedia.org/wiki/ELIZA)一個模擬心理治療師的計算機程式。Eliza 會向人類提問,並給人一種理解其回答的假象。然而,雖然 Eliza 能夠解析句子並識別某些語法結構和關鍵詞以生成合理的回答,但它並不能真正*理解*句子。如果 Eliza 收到一個格式為“**我很**<u>難過</u>”的句子,它可能會重新排列並替換句子中的詞語,形成回應“你**有多長時間**<u>難過</u>”。
這給人一種 Eliza 理解了陳述並提出了後續問題的印象,但實際上,它只是改變了時態並添加了一些詞語。如果 Eliza 無法識別關鍵詞以生成回應,它會給出一個隨機的回應,這可能適用於許多不同的陳述。例如,如果用戶輸入“**你是**一輛<u>自行車</u>”,它可能會回應“我**有多長時間**是一輛<u>自行車</u>?”,而不是給出更合理的回答。
[![與 Eliza 對話](https://img.youtube.com/vi/RMK9AphfLco/0.jpg)](https://youtu.be/RMK9AphfLco "與 Eliza 對話")
> 🎥 點擊上方圖片觀看原始 ELIZA 程式的相關影片
> 注意:如果你有 ACM 帳戶,可以閱讀 1966 年發表的 [Eliza 原始描述](https://cacm.acm.org/magazines/1966/1/13317-elizaa-computer-program-for-the-study-of-natural-language-communication-between-man-and-machine/abstract)。或者,參考 [維基百科](https://wikipedia.org/wiki/ELIZA) 了解 Eliza。
## 練習 - 編寫一個基礎對話機器人
一個對話機器人(如 Eliza是一個能夠引導用戶輸入並看似理解並智能回應的程式。與 Eliza 不同,我們的機器人不會有多條規則來模仿智能對話。相反,我們的機器人只有一個功能,即通過隨機回應來保持對話進行,這些回應幾乎適用於任何簡單對話。
### 計劃
構建對話機器人的步驟:
1. 打印指導用戶如何與機器人互動的說明。
2. 啟動一個迴圈:
1. 接受用戶輸入。
2. 如果用戶要求退出,則退出。
3. 處理用戶輸入並確定回應(在本例中,回應是從可能的通用回應列表中隨機選擇)。
4. 打印回應。
3. 返回步驟 2。
### 構建機器人
接下來,我們將創建機器人。首先定義一些短語。
1. 使用以下隨機回應在 Python 中自行創建此機器人:
```python
random_responses = ["That is quite interesting, please tell me more.",
"I see. Do go on.",
"Why do you say that?",
"Funny weather we've been having, isn't it?",
"Let's change the subject.",
"Did you catch the game last night?"]
```
以下是一些示例輸出(用戶輸入以 `>` 開頭):
```output
Hello, I am Marvin, the simple robot.
You can end this conversation at any time by typing 'bye'
After typing each answer, press 'enter'
How are you today?
> I am good thanks
That is quite interesting, please tell me more.
> today I went for a walk
Did you catch the game last night?
> I did, but my team lost
Funny weather we've been having, isn't it?
> yes but I hope next week is better
Let's change the subject.
> ok, lets talk about music
Why do you say that?
> because I like music!
Why do you say that?
> bye
It was nice talking to you, goodbye!
```
任務的一個可能解決方案在[這裡](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/1-Introduction-to-NLP/solution/bot.py)
✅ 停下來思考
1. 你認為這些隨機回應能“欺騙”某人以為機器人真的理解他們嗎?
2. 機器人需要哪些功能才能更有效?
3. 如果機器人真的能“理解”句子的含義,它是否需要“記住”對話中前幾句的含義?
---
## 🚀挑戰
選擇上述“停下來思考”中的一個元素,嘗試用程式碼實現它,或者用偽代碼在紙上寫出解決方案。
在下一課中,你將學習其他解析自然語言和機器學習的方法。
## [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
## 回顧與自學
參考以下資源進行進一步閱讀。
### 參考資料
1. Schubert, Lenhart, "Computational Linguistics", *The Stanford Encyclopedia of Philosophy* (Spring 2020 Edition), Edward N. Zalta (ed.), URL = <https://plato.stanford.edu/archives/spr2020/entries/computational-linguistics/>.
2. Princeton University "About WordNet." [WordNet](https://wordnet.princeton.edu/). Princeton University. 2010.
## 作業
[尋找一個機器人](assignment.md)
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,16 @@
# 搜尋機器人
## 指示
機器人無處不在。你的任務是:找到一個並採用它!你可以在網站、銀行應用程式以及電話上找到它們,例如當你撥打金融服務公司的電話以獲取建議或帳戶資訊時。分析這個機器人,看看你是否能讓它混淆。如果你能讓機器人混淆,為什麼會發生這種情況?寫一篇簡短的文章描述你的經驗。
## 評分標準
| 評分標準 | 卓越 | 合格 | 需要改進 |
| -------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------------- | --------------------- |
| | 撰寫了一整頁的文章,解釋了推測的機器人架構並概述了與它的互動經驗 | 文章不完整或研究不充分 | 未提交文章 |
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,219 @@
# 常見的自然語言處理任務與技術
對於大多數*自然語言處理*任務需將待處理的文本分解、檢查並將結果存儲或與規則和數據集交叉參照。這些任務使程式設計師能夠推導出文本中的_含義_、_意圖_或僅僅是_詞語頻率_。
## [課前測驗](https://ff-quizzes.netlify.app/en/ml/)
讓我們來探索處理文本時常用的技術。結合機器學習,這些技術可以幫助您高效地分析大量文本。然而,在將機器學習應用於這些任務之前,讓我們先了解自然語言處理專家所遇到的問題。
## 自然語言處理的常見任務
分析文本有多種方法。您可以執行一些任務,通過這些任務來理解文本並得出結論。通常,這些任務是按順序進行的。
### 分詞 (Tokenization)
大多數自然語言處理算法的第一步可能是將文本分解為詞元或單詞。雖然這聽起來很簡單,但考慮到標點符號以及不同語言的單詞和句子分隔符,這可能會變得很棘手。您可能需要使用多種方法來確定分界點。
![分詞](../../../../6-NLP/2-Tasks/images/tokenization.png)
> 從**傲慢與偏見**中分詞的示例。資訊圖由 [Jen Looper](https://twitter.com/jenlooper) 提供
### 嵌入 (Embeddings)
[詞嵌入](https://wikipedia.org/wiki/Word_embedding)是一種將文本數據轉換為數字形式的方法。嵌入的方式使得具有相似含義或經常一起使用的詞語聚集在一起。
![詞嵌入](../../../../6-NLP/2-Tasks/images/embedding.png)
> "我對您的神經表示最高的尊重,它們是我的老朋友。" - **傲慢與偏見**中的句子詞嵌入示例。資訊圖由 [Jen Looper](https://twitter.com/jenlooper) 提供
✅ 試試[這個有趣的工具](https://projector.tensorflow.org/)來實驗詞嵌入。點擊一個詞可以顯示相似詞的聚集,例如:'toy' 與 'disney'、'lego'、'playstation' 和 'console' 聚集在一起。
### 解析與詞性標註 (Parsing & Part-of-speech Tagging)
每個被分詞的詞都可以被標註為詞性,例如名詞、動詞或形容詞。句子 `the quick red fox jumped over the lazy brown dog` 可能被詞性標註為 fox = 名詞jumped = 動詞。
![解析](../../../../6-NLP/2-Tasks/images/parse.png)
> 從**傲慢與偏見**中解析句子的示例。資訊圖由 [Jen Looper](https://twitter.com/jenlooper) 提供
解析是識別句子中哪些詞語彼此相關,例如 `the quick red fox jumped` 是形容詞-名詞-動詞序列,與 `lazy brown dog` 序列分開。
### 詞語與短語頻率
分析大量文本時,一個有用的步驟是建立一個字典,記錄每個感興趣的詞語或短語及其出現頻率。句子 `the quick red fox jumped over the lazy brown dog` 中,詞語 `the` 的頻率為 2。
讓我們看一段示例文本計算詞語頻率。拉迪亞德·吉卜林的詩《The Winners》包含以下詩句
```output
What the moral? Who rides may read.
When the night is thick and the tracks are blind
A friend at a pinch is a friend, indeed,
But a fool to wait for the laggard behind.
Down to Gehenna or up to the Throne,
He travels the fastest who travels alone.
```
由於短語頻率可以根據需要設置為大小寫敏感或不敏感,短語 `a friend` 的頻率為 2`the` 的頻率為 6`travels` 的頻率為 2。
### N-grams
文本可以分解為固定長度的詞語序列例如單個詞unigram、兩個詞bigram、三個詞trigram或任意數量的詞n-gram
例如,句子 `the quick red fox jumped over the lazy brown dog` 的 n-gram 值為 2生成以下 n-grams
1. the quick
2. quick red
3. red fox
4. fox jumped
5. jumped over
6. over the
7. the lazy
8. lazy brown
9. brown dog
可以將其視為句子上的滑動框。以下是 n-gram 值為 3 的示例,每個句子中的 n-gram 用粗體表示:
1. <u>**the quick red**</u> fox jumped over the lazy brown dog
2. the **<u>quick red fox</u>** jumped over the lazy brown dog
3. the quick **<u>red fox jumped</u>** over the lazy brown dog
4. the quick red **<u>fox jumped over</u>** the lazy brown dog
5. the quick red fox **<u>jumped over the</u>** lazy brown dog
6. the quick red fox jumped **<u>over the lazy</u>** brown dog
7. the quick red fox jumped over <u>**the lazy brown**</u> dog
8. the quick red fox jumped over the **<u>lazy brown dog</u>**
![n-grams 滑動窗口](../../../../6-NLP/2-Tasks/images/n-grams.gif)
> N-gram 值為 3 的示例。資訊圖由 [Jen Looper](https://twitter.com/jenlooper) 提供
### 名詞短語提取 (Noun phrase Extraction)
在大多數句子中,存在一個名詞作為主語或賓語。在英文中,通常可以通過前面有 'a'、'an' 或 'the' 來識別。通過提取名詞短語來識別句子的主語或賓語,是自然語言處理中試圖理解句子含義時的一項常見任務。
✅ 在句子 "I cannot fix on the hour, or the spot, or the look or the words, which laid the foundation. It is too long ago. I was in the middle before I knew that I had begun." 中,您能識別出名詞短語嗎?
在句子 `the quick red fox jumped over the lazy brown dog` 中,有兩個名詞短語:**quick red fox** 和 **lazy brown dog**
### 情感分析 (Sentiment analysis)
可以分析句子或文本的情感,即其*正面*或*負面*程度。情感通過*極性*和*客觀性/主觀性*來衡量。極性範圍從 -1.0 到 1.0(負面到正面),客觀性範圍從 0.0 到 1.0(最客觀到最主觀)。
✅ 稍後您將學習使用機器學習來確定情感的不同方法,但其中一種方法是由人工專家將詞語和短語分類為正面或負面,並將該模型應用於文本以計算極性分數。您能看到這種方法在某些情況下有效,而在其他情況下效果不佳嗎?
### 詞形變化 (Inflection)
詞形變化使您能夠獲得詞語的單數或複數形式。
### 詞形還原 (Lemmatization)
*詞形還原*是指將詞語還原為其根詞或詞幹,例如 *flew*、*flies*、*flying* 的詞形還原為動詞 *fly*
此外,還有一些對自然語言處理研究者非常有用的數據庫,例如:
### WordNet
[WordNet](https://wordnet.princeton.edu/) 是一個包含詞語、同義詞、反義詞以及其他詳細信息的數據庫,涵蓋多種語言。它在構建翻譯、拼寫檢查器或任何類型的語言工具時非常有用。
## 自然語言處理庫
幸運的是,您不需要自己構建所有這些技術,因為有一些出色的 Python 庫使非自然語言處理或機器學習專家的開發者更容易使用。接下來的課程中會包含更多這些庫的示例,但在這裡您將學習一些有用的示例,幫助您完成下一個任務。
### 練習 - 使用 `TextBlob`
讓我們使用一個名為 TextBlob 的庫,因為它包含了處理這些任務的有用 API。TextBlob "基於 [NLTK](https://nltk.org) 和 [pattern](https://github.com/clips/pattern) 的強大基礎,並與它們良好兼容。" 它的 API 中嵌入了大量機器學習功能。
> 注意TextBlob 的[快速入門指南](https://textblob.readthedocs.io/en/dev/quickstart.html#quickstart)對於有經驗的 Python 開發者來說非常推薦。
在嘗試識別*名詞短語*時TextBlob 提供了多種提取器選項來找到名詞短語。
1. 看看 `ConllExtractor`
```python
from textblob import TextBlob
from textblob.np_extractors import ConllExtractor
# import and create a Conll extractor to use later
extractor = ConllExtractor()
# later when you need a noun phrase extractor:
user_input = input("> ")
user_input_blob = TextBlob(user_input, np_extractor=extractor) # note non-default extractor specified
np = user_input_blob.noun_phrases
```
> 這裡發生了什麼?[ConllExtractor](https://textblob.readthedocs.io/en/dev/api_reference.html?highlight=Conll#textblob.en.np_extractors.ConllExtractor) 是 "一個使用基於 ConLL-2000 訓練語料庫的塊解析進行名詞短語提取的工具。" ConLL-2000 指的是 2000 年的計算自然語言學習會議。每年會議都會舉辦一個研討會來解決自然語言處理中的棘手問題,而在 2000 年的主題是名詞短語解析。一個模型基於《華爾街日報》進行訓練,使用 "15-18 節作為訓練數據211727 個詞元20 節作為測試數據47377 個詞元)"。您可以查看使用的程序[這裡](https://www.clips.uantwerpen.be/conll2000/chunking/)以及[結果](https://ifarm.nl/erikt/research/np-chunking.html)。
### 挑戰 - 使用自然語言處理改進您的機器人
在上一課中,您構建了一個非常簡單的問答機器人。現在,您將通過分析輸入的情感並打印出匹配情感的回應,使 Marvin 更具同理心。您還需要識別一個 `noun_phrase` 並詢問相關話題。
構建更好的對話機器人的步驟:
1. 打印指示,告知用戶如何與機器人互動
2. 開始循環
1. 接受用戶輸入
2. 如果用戶要求退出,則退出
3. 處理用戶輸入並確定適當的情感回應
4. 如果在情感中檢測到名詞短語,將其變為複數並詢問該話題的更多輸入
5. 打印回應
3. 返回步驟 2
以下是使用 TextBlob 確定情感的代碼片段。注意,只有四種*情感回應梯度*(如果您願意,可以設置更多):
```python
if user_input_blob.polarity <= -0.5:
response = "Oh dear, that sounds bad. "
elif user_input_blob.polarity <= 0:
response = "Hmm, that's not great. "
elif user_input_blob.polarity <= 0.5:
response = "Well, that sounds positive. "
elif user_input_blob.polarity <= 1:
response = "Wow, that sounds great. "
```
以下是一些示例輸出以供參考(用戶輸入以 > 開頭的行):
```output
Hello, I am Marvin, the friendly robot.
You can end this conversation at any time by typing 'bye'
After typing each answer, press 'enter'
How are you today?
> I am ok
Well, that sounds positive. Can you tell me more?
> I went for a walk and saw a lovely cat
Well, that sounds positive. Can you tell me more about lovely cats?
> cats are the best. But I also have a cool dog
Wow, that sounds great. Can you tell me more about cool dogs?
> I have an old hounddog but he is sick
Hmm, that's not great. Can you tell me more about old hounddogs?
> bye
It was nice talking to you, goodbye!
```
任務的一個可能解決方案在[這裡](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/2-Tasks/solution/bot.py)
✅ 知識檢查
1. 您認為同理心回應能否“欺騙”某人,使其認為機器人真的理解他們?
2. 識別名詞短語是否使機器人更“可信”?
3. 為什麼從句子中提取“名詞短語”是一件有用的事情?
---
實現上述知識檢查中的機器人並測試它。它能欺騙您的朋友嗎?您能使您的機器人更“可信”嗎?
## 🚀挑戰
嘗試實現上述知識檢查中的任務並測試機器人。它能欺騙您的朋友嗎?您能使您的機器人更“可信”嗎?
## [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
## 回顧與自學
在接下來的幾節課中,您將學習更多關於情感分析的內容。研究這項有趣技術的文章,例如 [KDNuggets](https://www.kdnuggets.com/tag/nlp) 上的文章。
## 作業
[讓機器人回應](assignment.md)
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,16 @@
# 讓機器人回應
## 說明
在過去的幾節課中你已經編寫了一個基本的聊天機器人。這個機器人會隨機回答直到你說「bye」為止。你能否讓它的回答不再那麼隨機並在你說特定詞語例如「why」或「how」時觸發特定回答思考一下機器學習如何讓這類工作變得更自動化並擴展你的機器人。你可以使用 NLTK 或 TextBlob 庫來簡化你的任務。
## 評分標準
| 評分標準 | 卓越 | 合格 | 需要改進 |
| -------- | --------------------------------------------- | ------------------------------------------------ | ----------------------- |
| | 提供了一個新的 bot.py 文件並且有完整的註解 | 提供了一個新的 bot 文件,但包含錯誤 | 未提供文件 |
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對於因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,191 @@
# 翻譯與情感分析使用機器學習
在之前的課程中,你學會了如何使用 `TextBlob` 建立一個基本的聊天機器人。`TextBlob` 是一個內嵌機器學習技術的函式庫用於執行基本的自然語言處理NLP任務例如名詞片語提取。計算語言學中的另一個重要挑戰是準確地將句子從一種語言翻譯成另一種語言。
## [課前測驗](https://ff-quizzes.netlify.app/en/ml/)
翻譯是一個非常困難的問題,因為世界上有數千種語言,每種語言的語法規則可能截然不同。一種方法是將一種語言(例如英語)的正式語法規則轉換為一種不依賴語言的結構,然後再將其轉換回另一種語言。這種方法的步驟如下:
1. **識別**:將輸入語言中的單詞標記為名詞、動詞等。
2. **創建翻譯**:按照目標語言的格式,直接翻譯每個單詞。
### 範例句子:從英語到愛爾蘭語
在「英語」中,句子 _I feel happy_ 包含三個單詞,順序為:
- **主詞**I
- **動詞**feel
- **形容詞**happy
然而,在「愛爾蘭語」中,這句話的語法結構非常不同——像「快樂」或「悲傷」這樣的情感是以「在你身上」的形式表達的。
英語短語 `I feel happy` 翻譯成愛爾蘭語是 `Tá athas orm`。*字面*翻譯是 `Happy is upon me`
一位愛爾蘭語使用者翻譯成英語時會說 `I feel happy`,而不是 `Happy is upon me`,因為他們理解句子的含義,即使單詞和句子結構不同。
愛爾蘭語句子的正式順序是:
- **動詞**Tá 或 is
- **形容詞**athas或 happy
- **主詞**orm或 upon me
## 翻譯
一個簡單的翻譯程式可能只翻譯單詞,忽略句子結構。
✅ 如果你曾經在成年後學習第二(或第三、更多)語言,你可能會先用母語思考,然後在腦海中逐字翻譯成第二語言,最後說出翻譯結果。這與簡單的翻譯程式的工作方式類似。要達到流利程度,重要的是超越這個階段!
簡單的翻譯會導致糟糕(有時甚至是搞笑)的誤譯:`I feel happy` 字面翻譯成愛爾蘭語是 `Mise bhraitheann athas`。這字面意思是 `me feel happy`,但這不是一個有效的愛爾蘭語句子。即使英語和愛爾蘭語是兩個相鄰島嶼上的語言,它們的語法結構仍然非常不同。
> 你可以觀看一些關於愛爾蘭語言傳統的影片,例如 [這個](https://www.youtube.com/watch?v=mRIaLSdRMMs)
### 機器學習方法
到目前為止,你已經學習了基於正式規則的自然語言處理方法。另一種方法是忽略單詞的含義,而是*使用機器學習來檢測模式*。如果你擁有大量的文本(*語料庫*)或雙語文本(*語料*),這種方法在翻譯中可能會奏效。
例如,考慮《傲慢與偏見》這本書,這是 Jane Austen 在 1813 年寫的一本著名英語小說。如果你參考這本書的英語版本和其*法語*的人類翻譯版本,你可以發現一些短語在兩種語言中是*習語化*的翻譯。你將在稍後進行這樣的練習。
例如,當英語短語 `I have no money` 被字面翻譯成法語時,可能會變成 `Je n'ai pas de monnaie`。「Monnaie」是一個棘手的法語「假同源詞」因為「money」和「monnaie」並不是同義詞。一個更好的翻譯是 `Je n'ai pas d'argent`因為它更好地傳達了「我沒有錢」的意思而不是「零錢」這是「monnaie」的意思
![monnaie](../../../../6-NLP/3-Translation-Sentiment/images/monnaie.png)
> 圖片由 [Jen Looper](https://twitter.com/jenlooper) 提供
如果一個機器學習模型擁有足夠多的人類翻譯文本來建立模型,它可以通過識別先前由雙語專家翻譯的文本中的常見模式來提高翻譯的準確性。
### 練習 - 翻譯
你可以使用 `TextBlob` 翻譯句子。試試 **《傲慢與偏見》** 的著名開場白:
```python
from textblob import TextBlob
blob = TextBlob(
"It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife!"
)
print(blob.translate(to="fr"))
```
`TextBlob` 的翻譯效果相當不錯「C'est une vérité universellement reconnue, qu'un homme célibataire en possession d'une bonne fortune doit avoir besoin d'une femme!」。
事實上,可以說 `TextBlob` 的翻譯比 1932 年由 V. Leconte 和 Ch. Pressoir 翻譯的法語版本更為精確:
「C'est une vérité universelle qu'un célibataire pourvu d'une belle fortune doit avoir envie de se marier, et, si peu que l'on sache de son sentiment à cet egard, lorsqu'il arrive dans une nouvelle résidence, cette idée est si bien fixée dans l'esprit de ses voisins qu'ils le considèrent sur-le-champ comme la propriété légitime de l'une ou l'autre de leurs filles。」
在這種情況下,基於機器學習的翻譯比人類翻譯更好,因為後者為了「清晰」而不必要地加入了原作者未提及的內容。
> 這裡發生了什麼?為什麼 `TextBlob` 的翻譯如此出色?事實上,它背後使用的是 Google 翻譯,一種能夠解析數百萬短語並預測最佳翻譯的高級人工智慧。這裡沒有任何手動操作,並且使用 `blob.translate` 時需要網路連線。
✅ 試試更多句子。哪種翻譯更好,機器學習還是人類翻譯?在哪些情況下?
## 情感分析
機器學習在情感分析方面也表現得非常出色。一種非機器學習的方法是識別「正面」和「負面」的單詞和短語。然後,給定一段新文本,計算正面、負面和中性單詞的總值,以確定整體情感。
這種方法很容易被欺騙,正如你可能在 Marvin 任務中看到的那樣——句子 `Great, that was a wonderful waste of time, I'm glad we are lost on this dark road` 是一個帶有諷刺意味的負面情感句子但簡單的演算法會將「great」、「wonderful」、「glad」識別為正面而將「waste」、「lost」和「dark」識別為負面。這些矛盾的單詞會影響整體情感的判斷。
✅ 停下來想一想作為人類說話者我們是如何表達諷刺的。語調的變化起著重要作用。試著用不同的語氣說「Well, that film was awesome」看看你的聲音如何傳達不同的含義。
### 機器學習方法
機器學習的方法是手動收集正面和負面的文本——例如推文、電影評論,或者任何包含評分*和*書面意見的內容。然後,將 NLP 技術應用於這些意見和評分從而發現模式例如正面的電影評論中「Oscar worthy」這個短語出現的頻率比負面評論高而正面的餐廳評論中「gourmet」出現的頻率比「disgusting」高
> ⚖️ **範例**:如果你在一位政治家的辦公室工作,並且有一項新法律正在辯論,選民可能會寫信到辦公室表達支持或反對這項新法律。假設你的任務是閱讀這些信件並將它們分為兩類:*支持*和*反對*。如果信件數量很多,你可能會因為無法全部閱讀而感到不知所措。如果有一個機器人能幫你閱讀所有信件,理解它們並告訴你每封信應該歸入哪一類,那該多好!
>
> 一種實現方法是使用機器學習。你可以用部分*反對*信件和部分*支持*信件來訓練模型。模型會傾向於將某些短語和單詞與反對方或支持方聯繫起來,*但它不會理解任何內容*,只會識別某些單詞和模式更可能出現在反對或支持的信件中。你可以用一些未用於訓練的信件進行測試,看看模型的結論是否與你的結論一致。然後,一旦你對模型的準確性感到滿意,就可以處理未來的信件,而無需逐一閱讀。
✅ 這個過程是否與你在之前的課程中使用的過程類似?
## 練習 - 情感句子
情感以 *極性*polarity來衡量範圍是 -1 到 1-1 表示最負面1 表示最正面。情感還以 0 到 1 的分數衡量客觀性0和主觀性1
再看看 Jane Austen 的《傲慢與偏見》。該文本可在 [Project Gutenberg](https://www.gutenberg.org/files/1342/1342-h/1342-h.htm) 上獲得。以下範例展示了一個簡短的程式,該程式分析了書中第一句和最後一句的情感,並顯示其情感極性和主觀性/客觀性分數。
你應該使用上述的 `TextBlob` 函式庫來確定 `sentiment`(你不需要自己編寫情感計算器)來完成以下任務。
```python
from textblob import TextBlob
quote1 = """It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife."""
quote2 = """Darcy, as well as Elizabeth, really loved them; and they were both ever sensible of the warmest gratitude towards the persons who, by bringing her into Derbyshire, had been the means of uniting them."""
sentiment1 = TextBlob(quote1).sentiment
sentiment2 = TextBlob(quote2).sentiment
print(quote1 + " has a sentiment of " + str(sentiment1))
print(quote2 + " has a sentiment of " + str(sentiment2))
```
你會看到以下輸出:
```output
It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want # of a wife. has a sentiment of Sentiment(polarity=0.20952380952380953, subjectivity=0.27142857142857146)
Darcy, as well as Elizabeth, really loved them; and they were
both ever sensible of the warmest gratitude towards the persons
who, by bringing her into Derbyshire, had been the means of
uniting them. has a sentiment of Sentiment(polarity=0.7, subjectivity=0.8)
```
## 挑戰 - 檢查情感極性
你的任務是使用情感極性來判斷《傲慢與偏見》中是否有更多絕對正面的句子,而不是絕對負面的句子。對於此任務,你可以假設極性分數為 1 或 -1 的句子分別是絕對正面或絕對負面。
**步驟:**
1. 從 [Project Gutenberg](https://www.gutenberg.org/files/1342/1342-h/1342-h.htm) 下載《傲慢與偏見》的副本作為 .txt 文件。刪除文件開頭和結尾的元數據,只保留原始文本。
2. 在 Python 中打開該文件並將內容提取為字串。
3. 使用該書的字串創建一個 TextBlob。
4. 在迴圈中分析書中的每個句子:
1. 如果極性為 1 或 -1將該句子存儲在正面或負面的訊息陣列或列表中。
5. 最後,分別列出所有正面句子和負面句子,並顯示每類句子的數量。
這裡是一個範例[解決方案](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/3-Translation-Sentiment/solution/notebook.ipynb)。
✅ 知識檢查
1. 情感是基於句子中使用的單詞,但程式碼是否*理解*這些單詞?
2. 你認為情感極性準確嗎?換句話說,你是否*同意*這些分數?
1. 特別是,你是否同意以下句子的絕對**正面**極性?
* “What an excellent father you have, girls!” said she, when the door was shut.
* “Your examination of Mr. Darcy is over, I presume,” said Miss Bingley; “and pray what is the result?” “I am perfectly convinced by it that Mr. Darcy has no defect.
* How wonderfully these sort of things occur!
* I have the greatest dislike in the world to that sort of thing.
* Charlotte is an excellent manager, I dare say.
* “This is delightful indeed!
* I am so happy!
* Your idea of the ponies is delightful.
2. 以下三個句子被評為絕對正面情感,但仔細閱讀後,它們並不是正面句子。為什麼情感分析認為它們是正面句子?
* Happy shall I be, when his stay at Netherfield is over!” “I wish I could say anything to comfort you,” replied Elizabeth; “but it is wholly out of my power.
* If I could but see you as happy!
* Our distress, my dear Lizzy, is very great.
3. 你是否同意以下句子的絕對**負面**極性?
- Everybody is disgusted with his pride.
- “I should like to know how he behaves among strangers.” “You shall hear then—but prepare yourself for something very dreadful.
- The pause was to Elizabeths feelings dreadful.
- It would be dreadful!
✅ 任何 Jane Austen 的愛好者都會明白,她經常在書中批判英國攝政時期社會中更荒謬的方面。《傲慢與偏見》的主角 Elizabeth Bennett 是一位敏銳的社會觀察者(就像作者本人一樣),她的語言經常充滿微妙的含義。甚至故事中的愛情對象 Mr. Darcy 也注意到 Elizabeth 的俏皮和戲謔的語言使用:「我與你相識的時間足夠長,知道你偶爾會表達一些實際上並非你真實想法的觀點,並從中獲得極大的樂趣。」
---
## 🚀挑戰
你能讓 Marvin 更加出色,通過從用戶輸入中提取其他特徵嗎?
## [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
## 回顧與自學
有許多方法可以從文本中提取情感。想想可能使用這項技術的商業應用。再想想它可能出錯的情況。深入了解一些能夠分析情感的高級企業級系統,例如 [Azure Text Analysis](https://docs.microsoft.com/azure/cognitive-services/Text-Analytics/how-tos/text-analytics-how-to-sentiment-analysis?tabs=version-3-1?WT.mc_id=academic-77952-leestott)。測試上面的一些《傲慢與偏見》的句子,看看它是否能檢測出細微差別。
## 作業
[詩意的自由](assignment.md)
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,16 @@
# 詩意的許可
## 說明
在[這個筆記本](https://www.kaggle.com/jenlooper/emily-dickinson-word-frequency)中你可以找到超過500首艾蜜莉·狄更生的詩這些詩之前已使用Azure文本分析進行情感分析。使用這個數據集根據課程中描述的技術進行分析。一首詩的建議情感是否與更高級的Azure服務的判斷一致為什麼或為什麼不一致根據你的觀點有什麼讓你感到驚訝嗎
## 評分標準
| 標準 | 卓越表現 | 足夠表現 | 需要改進 |
| -------- | -------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------ |
| | 提供了一個包含作者樣本輸出之完整分析的筆記本 | 筆記本不完整或未進行分析 | 未提供筆記本 |
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,6 @@
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,6 @@
這是一個臨時佔位符
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,100 @@
{
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": 3
},
"orig_nbformat": 4,
"coopTranslator": {
"original_hash": "27de2abc0235ebd22080fc8f1107454d",
"translation_date": "2025-09-03T20:58:11+00:00",
"source_file": "6-NLP/3-Translation-Sentiment/solution/notebook.ipynb",
"language_code": "tw"
}
},
"nbformat": 4,
"nbformat_minor": 2,
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from textblob import TextBlob\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# You should download the book text, clean it, and import it here\n",
"with open(\"pride.txt\", encoding=\"utf8\") as f:\n",
" file_contents = f.read()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"book_pride = TextBlob(file_contents)\n",
"positive_sentiment_sentences = []\n",
"negative_sentiment_sentences = []"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for sentence in book_pride.sentences:\n",
" if sentence.sentiment.polarity == 1:\n",
" positive_sentiment_sentences.append(sentence)\n",
" if sentence.sentiment.polarity == -1:\n",
" negative_sentiment_sentences.append(sentence)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"The \" + str(len(positive_sentiment_sentences)) + \" most positive sentences:\")\n",
"for sentence in positive_sentiment_sentences:\n",
" print(\"+ \" + str(sentence.replace(\"\\n\", \"\").replace(\" \", \" \")))\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"The \" + str(len(negative_sentiment_sentences)) + \" most negative sentences:\")\n",
"for sentence in negative_sentiment_sentences:\n",
" print(\"- \" + str(sentence.replace(\"\\n\", \"\").replace(\" \", \" \")))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**免責聲明** \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解釋不承擔責任。\n"
]
}
]
}

@ -0,0 +1,408 @@
# 使用酒店評論進行情感分析 - 數據處理
在本節中,您將使用前幾課中的技術對一個大型數據集進行一些探索性數據分析。當您對各列的實用性有了良好的理解後,您將學習:
- 如何刪除不必要的列
- 如何基於現有列計算一些新數據
- 如何保存處理後的數據集以用於最終挑戰
## [課前測驗](https://ff-quizzes.netlify.app/en/ml/)
### 簡介
到目前為止,您已經學習了文本數據與數值數據的不同之處。如果文本是由人類書寫或口述的,則可以通過分析來發現模式、頻率、情感和含義。本課將帶您進入一個真實的數據集,並面臨一個真實的挑戰:**[歐洲515K酒店評論數據](https://www.kaggle.com/jiashenliu/515k-hotel-reviews-data-in-europe)**,該數據集包含[CC0: 公共領域許可證](https://creativecommons.org/publicdomain/zero/1.0/)。數據來自Booking.com的公共來源由Jiashen Liu創建。
### 準備工作
您需要:
* 能夠使用Python 3運行.ipynb筆記本
* pandas
* NLTK[您需要在本地安裝](https://www.nltk.org/install.html)
* 可從Kaggle下載的數據集[歐洲515K酒店評論數據](https://www.kaggle.com/jiashenliu/515k-hotel-reviews-data-in-europe)。解壓後約230 MB。將其下載到與這些NLP課程相關的根目錄`/data`文件夾中。
## 探索性數據分析
本挑戰假設您正在使用情感分析和客人評論分數構建一個酒店推薦機器人。您將使用的數據集包括6個城市中1493家不同酒店的評論。
使用Python、酒店評論數據集和NLTK的情感分析您可以找出
* 評論中最常用的詞語和短語是什麼?
* 描述酒店的官方*標籤*是否與評論分數相關(例如,某酒店的*家庭帶小孩*評論是否比*單人旅客*更負面,這可能表明該酒店更適合*單人旅客*
* NLTK的情感分數是否與酒店評論者的數字分數“吻合”
#### 數據集
讓我們探索您已下載並本地保存的數據集。可以在VS Code或Excel等編輯器中打開該文件。
數據集的標題如下:
*Hotel_Address, Additional_Number_of_Scoring, Review_Date, Average_Score, Hotel_Name, Reviewer_Nationality, Negative_Review, Review_Total_Negative_Word_Counts, Total_Number_of_Reviews, Positive_Review, Review_Total_Positive_Word_Counts, Total_Number_of_Reviews_Reviewer_Has_Given, Reviewer_Score, Tags, days_since_review, lat, lng*
以下是按類別分組的方式,可能更容易檢查:
##### 酒店相關列
* `Hotel_Name`, `Hotel_Address`, `lat`(緯度), `lng`(經度)
* 使用*lat*和*lng*您可以使用Python繪製一張地圖顯示酒店位置可能根據正面和負面評論進行顏色編碼
* Hotel_Address對我們來說似乎沒有明顯的用途我們可能會用國家名稱替代以便更容易排序和搜索
**酒店元評論列**
* `Average_Score`
* 根據數據集創建者的說法,此列是*酒店的平均分數,基於過去一年內的最新評論計算*。這似乎是一種不尋常的計算方式,但由於數據是抓取的,我們暫時接受這一點。
✅ 根據此數據中的其他列,您能想到另一種計算平均分數的方法嗎?
* `Total_Number_of_Reviews`
* 該酒店收到的評論總數——目前尚不清楚(需要編寫一些代碼)這是否指數據集中的評論。
* `Additional_Number_of_Scoring`
* 這表示評論者給出了分數,但未撰寫正面或負面評論。
**評論相關列**
- `Reviewer_Score`
- 這是一個數值最多有1位小數範圍在2.5到10之間
- 未解釋為什麼最低分數是2.5
- `Negative_Review`
- 如果評論者未撰寫任何內容,此字段將顯示“**No Negative**”
- 請注意,評論者可能會在負面評論列中撰寫正面評論(例如,“這家酒店沒有任何不好的地方”)
- `Review_Total_Negative_Word_Counts`
- 負面詞彙數量越多,分數越低(不考慮情感分析)
- `Positive_Review`
- 如果評論者未撰寫任何內容,此字段將顯示“**No Positive**”
- 請注意,評論者可能會在正面評論列中撰寫負面評論(例如,“這家酒店完全沒有任何好的地方”)
- `Review_Total_Positive_Word_Counts`
- 正面詞彙數量越多,分數越高(不考慮情感分析)
- `Review_Date``days_since_review`
- 可以對評論應用新鮮度或陳舊度的衡量(例如,由於酒店管理變更、翻修完成或新增設施等原因,較舊的評論可能不如較新的評論準確)
- `Tags`
- 這些是評論者可能選擇用來描述他們身份的簡短描述(例如,單人或家庭)、房間類型、停留時間以及評論提交方式。
- 不幸的是,使用這些標籤存在問題,請參閱下面討論其實用性的部分。
**評論者相關列**
- `Total_Number_of_Reviews_Reviewer_Has_Given`
- 這可能是推薦模型中的一個因素例如如果您能確定撰寫數百條評論的高產評論者更可能給出負面而非正面評論。然而任何特定評論的評論者並未用唯一代碼標識因此無法將其與一組評論聯繫起來。有30位評論者撰寫了100條或更多評論但很難看出這如何幫助推薦模型。
- `Reviewer_Nationality`
- 有些人可能認為某些國籍的人更可能給出正面或負面評論,這是基於國家傾向的假設。在模型中構建這樣的經驗之談需要謹慎。這些是國家(有時是種族)刻板印象,每位評論者都是基於自身經歷撰寫評論的個體。評論可能受到多種因素的影響,例如他們之前的酒店住宿經歷、旅行距離以及個人性格。認為評論分數是由國籍決定的很難站得住腳。
##### 示例
| 平均分數 | 總評論數 | 評論者分數 | 負面評論 | 正面評論 | 標籤 |
| -------- | -------- | -------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | ----------------------------------------------------------------------------------------- |
| 7.8 | 1945 | 2.5 | 這目前不是一家酒店,而是一個建築工地。我在長途旅行後休息並在房間工作時,從早到晚都被不可接受的施工噪音折磨。人們整天在隔壁房間用鑿岩機工作。我要求更換房間,但沒有安靜的房間可用。更糟糕的是,我被多收了費。我在晚上退房,因為我需要趕早班飛機,並收到了一張合適的賬單。一天後,酒店在未經我同意的情況下再次收取了超出預訂價格的費用。這是一個可怕的地方。不要折磨自己,千萬別預訂這裡。 | 沒有任何好的地方 | 商務旅行夫妻標準雙人房停留2晚 |
如您所見這位客人在這家酒店的住宿並不愉快。該酒店的平均分數為7.8擁有1945條評論但這位評論者給出了2.5分並寫了115個字描述他們的負面經歷。如果他們在Positive_Review列中什麼都沒寫您可能會推測沒有任何正面的地方但他們還是寫了7個字的警告。如果我們僅僅計算字數而不是字詞的含義或情感我們可能會對評論者的意圖產生偏差。奇怪的是他們的2.5分令人困惑因為如果這家酒店的住宿如此糟糕為什麼還要給任何分數仔細研究數據集您會發現最低可能分數是2.5而不是0。最高可能分數是10。
##### 標籤
如上所述,乍一看,使用`Tags`來分類數據似乎很有意義。不幸的是,這些標籤並未標準化,這意味著在某家酒店中,選項可能是*單人房*、*雙床房*和*雙人房*,但在另一家酒店中,則是*豪華單人房*、*經典大床房*和*行政特大床房*。這些可能是相同的房型,但變化如此之多,以至於選擇變得困難:
1. 嘗試將所有術語更改為單一標準,這非常困難,因為在每種情況下不清楚轉換路徑(例如,*經典單人房*映射到*單人房*,但*帶庭院花園或城市景觀的高級大床房*則更難映射)
2. 我們可以採用NLP方法測量某些術語如*單人*、*商務旅客*或*帶小孩的家庭*)在每家酒店中的出現頻率,並將其納入推薦模型中。
標籤通常但不總是是一個包含5到6個逗號分隔值的單一字段對應於*旅行類型*、*客人類型*、*房間類型*、*停留天數*以及*提交評論的設備類型*。然而,由於某些評論者未填寫每個字段(可能留空一個),值並不總是按相同順序排列。
例如,考慮*群體類型*。在`Tags`列中此字段有1025種唯一可能性不幸的是其中只有部分提到群體有些是房間類型等。如果您僅篩選提到家庭的標籤結果包含許多*家庭房*類型的結果。如果您包括*with*這個詞,即計算*帶有*的家庭值結果會更好在515,000條結果中有超過80,000條包含“帶小孩的家庭”或“帶大孩的家庭”這樣的短語。
這意味著標籤列對我們來說並非完全無用,但需要一些工作才能使其變得有用。
##### 酒店平均分數
數據集中有一些奇怪或不一致的地方,我無法完全理解,但在此列出以便您在構建模型時注意。如果您能弄清楚,請在討論區告訴我們!
數據集包含以下與平均分數和評論數相關的列:
1. Hotel_Name
2. Additional_Number_of_Scoring
3. Average_Score
4. Total_Number_of_Reviews
5. Reviewer_Score
數據集中評論數最多的酒店是*Britannia International Hotel Canary Wharf*擁有515,000條評論中的4789條。但如果我們查看該酒店的`Total_Number_of_Reviews`值則為9086。您可能會推測有更多未包含評論的分數因此我們可能需要加上`Additional_Number_of_Scoring`列的值。該值為2682將其加到4789得到7471仍然比`Total_Number_of_Reviews`少1615。
如果您查看`Average_Score`列您可能會推測它是數據集中評論的平均值但Kaggle的描述是“*酒店的平均分數,基於過去一年內的最新評論計算*”。這似乎並不那麼有用但我們可以根據數據集中的評論分數計算我們自己的平均值。以同一家酒店為例給出的平均酒店分數是7.1但數據集中計算的平均評論者分數是6.8。這很接近,但不是相同的值,我們只能猜測`Additional_Number_of_Scoring`評論中的分數將平均值提高到7.1。不幸的是,由於無法測試或證明這一假設,難以使用或信任`Average_Score`、`Additional_Number_of_Scoring`和`Total_Number_of_Reviews`,因為它們基於或引用了我們沒有的數據。
更複雜的是評論數第二多的酒店的計算平均分數是8.12,而數據集中的`Average_Score`是8.1。這是否正確是一個巧合,還是第一家酒店存在不一致?
考慮到這些酒店可能是異常值,也許大多數值是匹配的(但某些值由於某些原因不匹配),我們將在接下來編寫一個簡短的程序來探索數據集中的值,並確定這些值的正確用法(或不使用)。
> 🚨 注意事項
>
> 在處理這個數據集時您將撰寫程式碼來從文本中計算某些內容而無需親自閱讀或分析文本。這正是自然語言處理NLP的核心——在不需要人類介入的情況下解讀意義或情感。然而有可能您會讀到一些負面評論。我建議您不要這麼做因為您並不需要這樣做。有些評論可能很無聊或者是與酒店無關的負面評論例如「天氣不好」這是酒店甚至任何人都無法控制的事情。但有些評論的確存在陰暗面。有時候負面評論可能帶有種族歧視、性別歧視或年齡歧視的內容。這很不幸但在從公共網站抓取的數據集中是可以預期的。一些評論者可能會留下讓您感到反感、不適或不安的評論。最好讓程式碼來衡量情感而不是親自閱讀這些評論並讓自己感到不快。話雖如此撰寫這類評論的人是少數但他們的確存在。
## 練習 - 資料探索
### 載入資料
視覺化檢視資料已經足夠,現在你需要撰寫一些程式碼來獲取答案!本節使用 pandas 函式庫。你的第一個任務是確保你能載入並讀取 CSV 資料。pandas 函式庫提供快速的 CSV 載入器,結果會像之前的課程一樣存放在 dataframe 中。我們要載入的 CSV 檔案有超過五十萬行,但只有 17 個欄位。pandas 提供了許多強大的方法來與 dataframe 互動,包括能對每一行進行操作的能力。
從這裡開始,課程中會有程式碼片段以及一些程式碼的解釋,並討論結果的意義。請使用附帶的 _notebook.ipynb_ 來撰寫你的程式碼。
讓我們從載入你將使用的資料檔案開始:
```python
# Load the hotel reviews from CSV
import pandas as pd
import time
# importing time so the start and end time can be used to calculate file loading time
print("Loading data file now, this could take a while depending on file size")
start = time.time()
# df is 'DataFrame' - make sure you downloaded the file to the data folder
df = pd.read_csv('../../data/Hotel_Reviews.csv')
end = time.time()
print("Loading took " + str(round(end - start, 2)) + " seconds")
```
現在資料已載入,我們可以對其進行一些操作。請將這段程式碼放在程式的頂部,以便進行下一部分。
## 探索資料
在這個案例中,資料已經是*乾淨的*,這意味著它已準備好使用,並且不包含可能會讓只接受英文字符的演算法出錯的其他語言字符。
✅ 你可能需要處理一些需要初步格式化的資料,才能應用 NLP 技術,但這次不需要。如果需要,你會如何處理非英文字符?
花點時間確保資料載入後,你可以使用程式碼來探索它。很容易想要專注於 `Negative_Review``Positive_Review` 欄位。這些欄位充滿了自然文本,供你的 NLP 演算法處理。但等等!在進行 NLP 和情感分析之前,你應該遵循以下程式碼,確認資料集中提供的值是否與你使用 pandas 計算的值相符。
## Dataframe 操作
本課程的第一個任務是撰寫一些程式碼來檢查以下斷言是否正確(不更改資料框)。
> 像許多程式設計任務一樣,完成這些任務的方法有很多,但好的建議是以最簡單、最容易的方式完成,尤其是當你未來回顧這段程式碼時更容易理解。對於 dataframe有一個全面的 API通常可以有效地完成你想要的操作。
將以下問題視為程式設計任務,嘗試在不查看解答的情況下回答它們。
1. 輸出你剛載入的資料框的*形狀*(形狀是行數和列數)
2. 計算評論者國籍的頻率:
1. `Reviewer_Nationality` 欄位中有多少個不同的值?它們是什麼?
2. 資料集中最常見的評論者國籍是什麼(輸出國家和評論數量)?
3. 接下來最常見的前 10 個國籍及其頻率分布是什麼?
3. 對於前 10 個最常見的評論者國籍,每個國籍最常被評論的酒店是什麼?
4. 資料集中每家酒店有多少評論(酒店的評論頻率分布)?
5. 雖然資料集中每家酒店都有一個 `Average_Score` 欄位,但你也可以計算平均分數(計算資料集中每家酒店所有評論者分數的平均值)。新增一個名為 `Calc_Average_Score` 的新欄位到你的 dataframe該欄位包含計算出的平均分數。
6. 是否有酒店的 `Average_Score``Calc_Average_Score`(四捨五入到小數點後一位)相同?
1. 嘗試撰寫一個 Python 函數,該函數接受一個 Series作為參數並比較這些值當值不相等時輸出一條訊息。然後使用 `.apply()` 方法處理每一行。
7. 計算並輸出 `Negative_Review` 欄位值為 "No Negative" 的行數
8. 計算並輸出 `Positive_Review` 欄位值為 "No Positive" 的行數
9. 計算並輸出 `Positive_Review` 欄位值為 "No Positive" **且** `Negative_Review` 欄位值為 "No Negative" 的行數
### 程式碼解答
1. 輸出你剛載入的資料框的*形狀*(形狀是行數和列數)
```python
print("The shape of the data (rows, cols) is " + str(df.shape))
> The shape of the data (rows, cols) is (515738, 17)
```
2. 計算評論者國籍的頻率:
1. `Reviewer_Nationality` 欄位中有多少個不同的值?它們是什麼?
2. 資料集中最常見的評論者國籍是什麼(輸出國家和評論數量)?
```python
# value_counts() creates a Series object that has index and values in this case, the country and the frequency they occur in reviewer nationality
nationality_freq = df["Reviewer_Nationality"].value_counts()
print("There are " + str(nationality_freq.size) + " different nationalities")
# print first and last rows of the Series. Change to nationality_freq.to_string() to print all of the data
print(nationality_freq)
There are 227 different nationalities
United Kingdom 245246
United States of America 35437
Australia 21686
Ireland 14827
United Arab Emirates 10235
...
Comoros 1
Palau 1
Northern Mariana Islands 1
Cape Verde 1
Guinea 1
Name: Reviewer_Nationality, Length: 227, dtype: int64
```
3. 接下來最常見的前 10 個國籍及其頻率分布是什麼?
```python
print("The highest frequency reviewer nationality is " + str(nationality_freq.index[0]).strip() + " with " + str(nationality_freq[0]) + " reviews.")
# Notice there is a leading space on the values, strip() removes that for printing
# What is the top 10 most common nationalities and their frequencies?
print("The next 10 highest frequency reviewer nationalities are:")
print(nationality_freq[1:11].to_string())
The highest frequency reviewer nationality is United Kingdom with 245246 reviews.
The next 10 highest frequency reviewer nationalities are:
United States of America 35437
Australia 21686
Ireland 14827
United Arab Emirates 10235
Saudi Arabia 8951
Netherlands 8772
Switzerland 8678
Germany 7941
Canada 7894
France 7296
```
3. 對於前 10 個最常見的評論者國籍,每個國籍最常被評論的酒店是什麼?
```python
# What was the most frequently reviewed hotel for the top 10 nationalities
# Normally with pandas you will avoid an explicit loop, but wanted to show creating a new dataframe using criteria (don't do this with large amounts of data because it could be very slow)
for nat in nationality_freq[:10].index:
# First, extract all the rows that match the criteria into a new dataframe
nat_df = df[df["Reviewer_Nationality"] == nat]
# Now get the hotel freq
freq = nat_df["Hotel_Name"].value_counts()
print("The most reviewed hotel for " + str(nat).strip() + " was " + str(freq.index[0]) + " with " + str(freq[0]) + " reviews.")
The most reviewed hotel for United Kingdom was Britannia International Hotel Canary Wharf with 3833 reviews.
The most reviewed hotel for United States of America was Hotel Esther a with 423 reviews.
The most reviewed hotel for Australia was Park Plaza Westminster Bridge London with 167 reviews.
The most reviewed hotel for Ireland was Copthorne Tara Hotel London Kensington with 239 reviews.
The most reviewed hotel for United Arab Emirates was Millennium Hotel London Knightsbridge with 129 reviews.
The most reviewed hotel for Saudi Arabia was The Cumberland A Guoman Hotel with 142 reviews.
The most reviewed hotel for Netherlands was Jaz Amsterdam with 97 reviews.
The most reviewed hotel for Switzerland was Hotel Da Vinci with 97 reviews.
The most reviewed hotel for Germany was Hotel Da Vinci with 86 reviews.
The most reviewed hotel for Canada was St James Court A Taj Hotel London with 61 reviews.
```
4. 資料集中每家酒店有多少評論(酒店的評論頻率分布)?
```python
# First create a new dataframe based on the old one, removing the uneeded columns
hotel_freq_df = df.drop(["Hotel_Address", "Additional_Number_of_Scoring", "Review_Date", "Average_Score", "Reviewer_Nationality", "Negative_Review", "Review_Total_Negative_Word_Counts", "Positive_Review", "Review_Total_Positive_Word_Counts", "Total_Number_of_Reviews_Reviewer_Has_Given", "Reviewer_Score", "Tags", "days_since_review", "lat", "lng"], axis = 1)
# Group the rows by Hotel_Name, count them and put the result in a new column Total_Reviews_Found
hotel_freq_df['Total_Reviews_Found'] = hotel_freq_df.groupby('Hotel_Name').transform('count')
# Get rid of all the duplicated rows
hotel_freq_df = hotel_freq_df.drop_duplicates(subset = ["Hotel_Name"])
display(hotel_freq_df)
```
| Hotel_Name | Total_Number_of_Reviews | Total_Reviews_Found |
| :----------------------------------------: | :---------------------: | :-----------------: |
| Britannia International Hotel Canary Wharf | 9086 | 4789 |
| Park Plaza Westminster Bridge London | 12158 | 4169 |
| Copthorne Tara Hotel London Kensington | 7105 | 3578 |
| ... | ... | ... |
| Mercure Paris Porte d Orleans | 110 | 10 |
| Hotel Wagner | 135 | 10 |
| Hotel Gallitzinberg | 173 | 8 |
你可能會注意到*資料集中計算的*結果與 `Total_Number_of_Reviews` 的值不匹配。尚不清楚資料集中該值是否代表酒店的總評論數,但並非所有評論都被抓取,或者是其他計算方式。由於這種不明確性,`Total_Number_of_Reviews` 不會在模型中使用。
5. 雖然資料集中每家酒店都有一個 `Average_Score` 欄位,但你也可以計算平均分數(計算資料集中每家酒店所有評論者分數的平均值)。新增一個名為 `Calc_Average_Score` 的新欄位到你的 dataframe該欄位包含計算出的平均分數。輸出欄位 `Hotel_Name`、`Average_Score` 和 `Calc_Average_Score`
```python
# define a function that takes a row and performs some calculation with it
def get_difference_review_avg(row):
return row["Average_Score"] - row["Calc_Average_Score"]
# 'mean' is mathematical word for 'average'
df['Calc_Average_Score'] = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)
# Add a new column with the difference between the two average scores
df["Average_Score_Difference"] = df.apply(get_difference_review_avg, axis = 1)
# Create a df without all the duplicates of Hotel_Name (so only 1 row per hotel)
review_scores_df = df.drop_duplicates(subset = ["Hotel_Name"])
# Sort the dataframe to find the lowest and highest average score difference
review_scores_df = review_scores_df.sort_values(by=["Average_Score_Difference"])
display(review_scores_df[["Average_Score_Difference", "Average_Score", "Calc_Average_Score", "Hotel_Name"]])
```
你可能也會好奇 `Average_Score` 的值以及為什麼它有時與計算出的平均分數不同。由於我們無法知道為什麼有些值匹配,但其他值有差異,在這種情況下,最安全的做法是使用我們擁有的評論分數自行計算平均分數。儘管如此,差異通常非常小,以下是資料集中平均分數與計算出的平均分數差異最大的酒店:
| Average_Score_Difference | Average_Score | Calc_Average_Score | Hotel_Name |
| :----------------------: | :-----------: | :----------------: | ------------------------------------------: |
| -0.8 | 7.7 | 8.5 | Best Western Hotel Astoria |
| -0.7 | 8.8 | 9.5 | Hotel Stendhal Place Vend me Paris MGallery |
| -0.7 | 7.5 | 8.2 | Mercure Paris Porte d Orleans |
| -0.7 | 7.9 | 8.6 | Renaissance Paris Vendome Hotel |
| -0.5 | 7.0 | 7.5 | Hotel Royal Elys es |
| ... | ... | ... | ... |
| 0.7 | 7.5 | 6.8 | Mercure Paris Op ra Faubourg Montmartre |
| 0.8 | 7.1 | 6.3 | Holiday Inn Paris Montparnasse Pasteur |
| 0.9 | 6.8 | 5.9 | Villa Eugenie |
| 0.9 | 8.6 | 7.7 | MARQUIS Faubourg St Honor Relais Ch teaux |
| 1.3 | 7.2 | 5.9 | Kube Hotel Ice Bar |
只有 1 家酒店的分數差異超過 1這意味著我們可能可以忽略差異並使用計算出的平均分數。
6. 計算並輸出 `Negative_Review` 欄位值為 "No Negative" 的行數
7. 計算並輸出 `Positive_Review` 欄位值為 "No Positive" 的行數
8. 計算並輸出 `Positive_Review` 欄位值為 "No Positive" **且** `Negative_Review` 欄位值為 "No Negative" 的行數
```python
# with lambdas:
start = time.time()
no_negative_reviews = df.apply(lambda x: True if x['Negative_Review'] == "No Negative" else False , axis=1)
print("Number of No Negative reviews: " + str(len(no_negative_reviews[no_negative_reviews == True].index)))
no_positive_reviews = df.apply(lambda x: True if x['Positive_Review'] == "No Positive" else False , axis=1)
print("Number of No Positive reviews: " + str(len(no_positive_reviews[no_positive_reviews == True].index)))
both_no_reviews = df.apply(lambda x: True if x['Negative_Review'] == "No Negative" and x['Positive_Review'] == "No Positive" else False , axis=1)
print("Number of both No Negative and No Positive reviews: " + str(len(both_no_reviews[both_no_reviews == True].index)))
end = time.time()
print("Lambdas took " + str(round(end - start, 2)) + " seconds")
Number of No Negative reviews: 127890
Number of No Positive reviews: 35946
Number of both No Negative and No Positive reviews: 127
Lambdas took 9.64 seconds
```
## 另一種方法
另一種方法是不用 Lambdas並使用 sum 來計算行數:
```python
# without lambdas (using a mixture of notations to show you can use both)
start = time.time()
no_negative_reviews = sum(df.Negative_Review == "No Negative")
print("Number of No Negative reviews: " + str(no_negative_reviews))
no_positive_reviews = sum(df["Positive_Review"] == "No Positive")
print("Number of No Positive reviews: " + str(no_positive_reviews))
both_no_reviews = sum((df.Negative_Review == "No Negative") & (df.Positive_Review == "No Positive"))
print("Number of both No Negative and No Positive reviews: " + str(both_no_reviews))
end = time.time()
print("Sum took " + str(round(end - start, 2)) + " seconds")
Number of No Negative reviews: 127890
Number of No Positive reviews: 35946
Number of both No Negative and No Positive reviews: 127
Sum took 0.19 seconds
```
你可能注意到有 127 行的 `Negative_Review``Positive_Review` 欄位分別為 "No Negative" 和 "No Positive"。這意味著評論者給酒店一個數字分數但拒絕撰寫正面或負面的評論。幸運的是這是一個很小的行數127 行中的 515738 行,或 0.02%),因此它可能不會在任何特定方向上影響我們的模型或結果,但你可能不會預期到評論資料集中會有沒有評論的行,因此值得探索資料以發現這樣的行。
現在你已經探索了資料集,在下一課中你將篩選資料並進行一些情感分析。
---
## 🚀挑戰
本課程展示了,如同我們在之前的課程中看到的,了解你的資料及其特性在進行操作之前是多麼重要。特別是基於文本的資料,需要仔細檢查。深入挖掘各種以文本為主的資料集,看看你是否能發現可能引入偏差或情感偏斜的地方。
## [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
## 回顧與自學
參加 [這個 NLP 學習路徑](https://docs.microsoft.com/learn/paths/explore-natural-language-processing/?WT.mc_id=academic-77952-leestott),探索在構建語音和文本模型時可以嘗試的工具。
## 作業
[NLTK](assignment.md)
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,10 @@
# NLTK
## 說明
NLTK 是一個廣為人知的圖書館,用於計算語言學和自然語言處理。趁此機會閱讀『[NLTK 書籍](https://www.nltk.org/book/)』並嘗試其中的練習。在這個不計分的作業中,您將更深入地了解這個圖書館。
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用本翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,6 @@
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,6 @@
這是一個臨時佔位符
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,174 @@
{
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": 3
},
"orig_nbformat": 4,
"coopTranslator": {
"original_hash": "2d05e7db439376aa824f4b387f8324ca",
"translation_date": "2025-09-03T20:57:53+00:00",
"source_file": "6-NLP/4-Hotel-Reviews-1/solution/notebook.ipynb",
"language_code": "tw"
}
},
"nbformat": 4,
"nbformat_minor": 2,
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# EDA\n",
"import pandas as pd\n",
"import time"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def get_difference_review_avg(row):\n",
" return row[\"Average_Score\"] - row[\"Calc_Average_Score\"]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Load the hotel reviews from CSV\n",
"print(\"Loading data file now, this could take a while depending on file size\")\n",
"start = time.time()\n",
"df = pd.read_csv('../../data/Hotel_Reviews.csv')\n",
"end = time.time()\n",
"print(\"Loading took \" + str(round(end - start, 2)) + \" seconds\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# What shape is the data (rows, columns)?\n",
"print(\"The shape of the data (rows, cols) is \" + str(df.shape))\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# value_counts() creates a Series object that has index and values\n",
"# in this case, the country and the frequency they occur in reviewer nationality\n",
"nationality_freq = df[\"Reviewer_Nationality\"].value_counts()\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# What reviewer nationality is the most common in the dataset?\n",
"print(\"The highest frequency reviewer nationality is \" + str(nationality_freq.index[0]).strip() + \" with \" + str(nationality_freq[0]) + \" reviews.\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# What is the top 10 most common nationalities and their frequencies?\n",
"print(\"The top 10 highest frequency reviewer nationalities are:\")\n",
"print(nationality_freq[0:10].to_string())\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# How many unique nationalities are there?\n",
"print(\"There are \" + str(nationality_freq.index.size) + \" unique nationalities in the dataset\")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# What was the most frequently reviewed hotel for the top 10 nationalities - print the hotel and number of reviews\n",
"for nat in nationality_freq[:10].index:\n",
" # First, extract all the rows that match the criteria into a new dataframe\n",
" nat_df = df[df[\"Reviewer_Nationality\"] == nat] \n",
" # Now get the hotel freq\n",
" freq = nat_df[\"Hotel_Name\"].value_counts()\n",
" print(\"The most reviewed hotel for \" + str(nat).strip() + \" was \" + str(freq.index[0]) + \" with \" + str(freq[0]) + \" reviews.\") \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# How many reviews are there per hotel (frequency count of hotel) and do the results match the value in `Total_Number_of_Reviews`?\n",
"# First create a new dataframe based on the old one, removing the uneeded columns\n",
"hotel_freq_df = df.drop([\"Hotel_Address\", \"Additional_Number_of_Scoring\", \"Review_Date\", \"Average_Score\", \"Reviewer_Nationality\", \"Negative_Review\", \"Review_Total_Negative_Word_Counts\", \"Positive_Review\", \"Review_Total_Positive_Word_Counts\", \"Total_Number_of_Reviews_Reviewer_Has_Given\", \"Reviewer_Score\", \"Tags\", \"days_since_review\", \"lat\", \"lng\"], axis = 1)\n",
"# Group the rows by Hotel_Name, count them and put the result in a new column Total_Reviews_Found\n",
"hotel_freq_df['Total_Reviews_Found'] = hotel_freq_df.groupby('Hotel_Name').transform('count')\n",
"# Get rid of all the duplicated rows\n",
"hotel_freq_df = hotel_freq_df.drop_duplicates(subset = [\"Hotel_Name\"])\n",
"print()\n",
"print(hotel_freq_df.to_string())\n",
"print(str(hotel_freq_df.shape))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# While there is an `Average_Score` for each hotel according to the dataset, \n",
"# you can also calculate an average score (getting the average of all reviewer scores in the dataset for each hotel)\n",
"# Add a new column to your dataframe with the column header `Calc_Average_Score` that contains that calculated average. \n",
"df['Calc_Average_Score'] = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)\n",
"# Add a new column with the difference between the two average scores\n",
"df[\"Average_Score_Difference\"] = df.apply(get_difference_review_avg, axis = 1)\n",
"# Create a df without all the duplicates of Hotel_Name (so only 1 row per hotel)\n",
"review_scores_df = df.drop_duplicates(subset = [\"Hotel_Name\"])\n",
"# Sort the dataframe to find the lowest and highest average score difference\n",
"review_scores_df = review_scores_df.sort_values(by=[\"Average_Score_Difference\"])\n",
"print(review_scores_df[[\"Average_Score_Difference\", \"Average_Score\", \"Calc_Average_Score\", \"Hotel_Name\"]])\n",
"# Do any hotels have the same (rounded to 1 decimal place) `Average_Score` and `Calc_Average_Score`?\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**免責聲明** \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤釋不承擔責任。\n"
]
}
]
}

@ -0,0 +1,375 @@
# 使用酒店評論進行情感分析
現在您已經詳細探索了數據集,是時候篩選欄位並對數據集使用 NLP 技術,以獲得關於酒店的新見解。
## [課前測驗](https://ff-quizzes.netlify.app/en/ml/)
### 篩選與情感分析操作
正如您可能已經注意到的,數據集中存在一些問題。一些欄位充滿了無用的信息,其他欄位似乎不正確。即使它們是正確的,也不清楚它們是如何計算的,並且無法通過自己的計算獨立驗證答案。
## 練習:進一步處理數據
稍微清理一下數據。添加一些稍後會有用的欄位,修改其他欄位中的值,並完全刪除某些欄位。
1. 初步欄位處理
1. 刪除 `lat``lng`
2. 將 `Hotel_Address` 的值替換為以下值(如果地址包含城市和國家的名稱,則將其更改為僅顯示城市和國家)。
以下是數據集中唯一的城市和國家:
阿姆斯特丹,荷蘭
巴塞隆納,西班牙
倫敦,英國
米蘭,義大利
巴黎,法國
維也納,奧地利
```python
def replace_address(row):
if "Netherlands" in row["Hotel_Address"]:
return "Amsterdam, Netherlands"
elif "Barcelona" in row["Hotel_Address"]:
return "Barcelona, Spain"
elif "United Kingdom" in row["Hotel_Address"]:
return "London, United Kingdom"
elif "Milan" in row["Hotel_Address"]:
return "Milan, Italy"
elif "France" in row["Hotel_Address"]:
return "Paris, France"
elif "Vienna" in row["Hotel_Address"]:
return "Vienna, Austria"
# Replace all the addresses with a shortened, more useful form
df["Hotel_Address"] = df.apply(replace_address, axis = 1)
# The sum of the value_counts() should add up to the total number of reviews
print(df["Hotel_Address"].value_counts())
```
現在您可以查詢國家級數據:
```python
display(df.groupby("Hotel_Address").agg({"Hotel_Name": "nunique"}))
```
| Hotel_Address | Hotel_Name |
| :--------------------- | :--------: |
| Amsterdam, Netherlands | 105 |
| Barcelona, Spain | 211 |
| London, United Kingdom | 400 |
| Milan, Italy | 162 |
| Paris, France | 458 |
| Vienna, Austria | 158 |
2. 處理酒店元評論欄位
1. 刪除 `Additional_Number_of_Scoring`
2. 用實際在數據集中該酒店的評論總數替換 `Total_Number_of_Reviews`
3. 用我們自己計算的分數替換 `Average_Score`
```python
# Drop `Additional_Number_of_Scoring`
df.drop(["Additional_Number_of_Scoring"], axis = 1, inplace=True)
# Replace `Total_Number_of_Reviews` and `Average_Score` with our own calculated values
df.Total_Number_of_Reviews = df.groupby('Hotel_Name').transform('count')
df.Average_Score = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)
```
3. 處理評論欄位
1. 刪除 `Review_Total_Negative_Word_Counts`、`Review_Total_Positive_Word_Counts`、`Review_Date` 和 `days_since_review`
2. 保留 `Reviewer_Score`、`Negative_Review` 和 `Positive_Review` 不變
3. 暫時保留 `Tags`
- 我們會在下一部分對標籤進行一些額外的篩選操作,然後再刪除標籤
4. 處理評論者欄位
1. 刪除 `Total_Number_of_Reviews_Reviewer_Has_Given`
2. 保留 `Reviewer_Nationality`
### 標籤欄位
`Tag` 欄位是一個問題,因為它是一個以文本形式存儲在欄位中的列表。不幸的是,該欄位中的子部分順序和數量並不總是相同。由於數據集中有 515,000 行和 1427 家酒店,每個評論者可以選擇的選項略有不同,因此人類很難識別出需要關注的正確短語。這正是 NLP 的用武之地。您可以掃描文本,找到最常見的短語並對其進行計數。
不幸的是,我們對單詞不感興趣,而是對多詞短語(例如 *商務旅行*感興趣。在如此大量的數據6762646 個單詞)上運行多詞頻率分佈算法可能需要花費大量時間,但如果不查看數據,這似乎是必要的開銷。這時,探索性數據分析就派上用場了,因為您已經看過一些標籤樣本,例如 `[' 商務旅行 ', ' 獨自旅行者 ', ' 單人房 ', ' 住了 5 晚 ', ' 從移動設備提交 ']`,您可以開始思考是否有可能大幅減少需要處理的數據量。幸運的是,這是可能的——但首先您需要遵循一些步驟來確定感興趣的標籤。
### 篩選標籤
請記住,數據集的目標是添加情感和欄位,幫助您選擇最佳酒店(無論是為自己還是為委託您製作酒店推薦機器人的客戶)。您需要問自己這些標籤在最終數據集中是否有用。以下是一種解釋(如果您出於其他原因需要數據集,不同的標籤可能會保留/刪除):
1. 旅行類型是相關的,應保留
2. 客戶群類型很重要,應保留
3. 客人入住的房間、套房或工作室類型無關緊要(所有酒店基本上都有相同的房間)
4. 提交評論的設備無關緊要
5. 評論者入住的晚數*可能*相關,如果您認為更長的入住時間意味著他們更喜歡酒店,但這有點牽強,可能無關緊要
總結來說,**保留兩種類型的標籤,刪除其他標籤**。
首先在標籤格式更好之前您不想對標籤進行計數這意味著需要刪除方括號和引號。您可以通過多種方式完成此操作但您需要最快的方法因為處理大量數據可能需要很長時間。幸運的是pandas 提供了一種簡單的方法來完成這些步驟。
```Python
# Remove opening and closing brackets
df.Tags = df.Tags.str.strip("[']")
# remove all quotes too
df.Tags = df.Tags.str.replace(" ', '", ",", regex = False)
```
每個標籤變成類似於:`商務旅行, 獨自旅行者, 單人房, 住了 5 晚, 從移動設備提交`。
接下來,我們發現了一個問題。一些評論(或行)有 5 個欄位,一些有 3 個,一些有 6 個。這是數據集創建方式的結果,很難修復。您希望獲得每個短語的頻率計數,但它們在每條評論中的順序不同,因此計數可能會出錯,酒店可能無法獲得應得的標籤。
相反,您將利用這種不同的順序,因為每個標籤是多詞的,但也用逗號分隔!最簡單的方法是創建 6 個臨時欄位,將每個標籤插入到對應於其順序的欄位中。然後,您可以將這 6 個欄位合併為一個大欄位,並對結果欄位運行 `value_counts()` 方法。打印出來後,您會看到有 2428 個唯一標籤。以下是其中的一小部分樣本:
| 標籤 | 計數 |
| --------------------------------- | ------ |
| 休閒旅行 | 417778 |
| 從移動設備提交 | 307640 |
| 情侶 | 252294 |
| 住了 1 晚 | 193645 |
| 住了 2 晚 | 133937 |
| 獨自旅行者 | 108545 |
| 住了 3 晚 | 95821 |
| 商務旅行 | 82939 |
| 團體 | 65392 |
| 帶小孩的家庭 | 61015 |
| 住了 4 晚 | 47817 |
| 雙人房 | 35207 |
| 標準雙人房 | 32248 |
| 高級雙人房 | 31393 |
| 帶大孩的家庭 | 26349 |
| 豪華雙人房 | 24823 |
| 雙人或雙床房 | 22393 |
| 住了 5 晚 | 20845 |
| 標準雙人或雙床房 | 17483 |
| 經典雙人房 | 16989 |
| 高級雙人或雙床房 | 13570 |
| 2 間房 | 12393 |
一些常見的標籤如 `從移動設備提交` 對我們沒有用,因此在計算短語出現次數之前刪除它們可能是一個明智的選擇,但這是一個非常快速的操作,您可以將它們保留在內並忽略它們。
### 刪除入住時長標籤
刪除這些標籤是第一步,它稍微減少了需要考慮的標籤總數。請注意,您並未從數據集中刪除它們,只是選擇不將它們作為評論數據集中要計數/保留的值。
| 入住時長 | 計數 |
| -------------- | ------ |
| 住了 1 晚 | 193645 |
| 住了 2 晚 | 133937 |
| 住了 3 晚 | 95821 |
| 住了 4 晚 | 47817 |
| 住了 5 晚 | 20845 |
| 住了 6 晚 | 9776 |
| 住了 7 晚 | 7399 |
| 住了 8 晚 | 2502 |
| 住了 9 晚 | 1293 |
| ... | ... |
有各種各樣的房間、套房、工作室、公寓等。它們的含義大致相同,對您來說並不重要,因此從考慮中刪除它們。
| 房間類型 | 計數 |
| ---------------------------- | ------ |
| 雙人房 | 35207 |
| 標準雙人房 | 32248 |
| 高級雙人房 | 31393 |
| 豪華雙人房 | 24823 |
| 雙人或雙床房 | 22393 |
| 標準雙人或雙床房 | 17483 |
| 經典雙人房 | 16989 |
| 高級雙人或雙床房 | 13570 |
最後,這是令人愉快的(因為幾乎不需要處理),您將剩下以下**有用的**標籤:
| 標籤 | 計數 |
| --------------------------------------------- | ------ |
| 休閒旅行 | 417778 |
| 情侶 | 252294 |
| 獨自旅行者 | 108545 |
| 商務旅行 | 82939 |
| 團體(與朋友旅行者合併) | 67535 |
| 帶小孩的家庭 | 61015 |
| 帶大孩的家庭 | 26349 |
| 帶寵物 | 1405 |
您可以認為 `與朋友旅行者``團體` 基本相同,將兩者合併是合理的,如上所示。識別正確標籤的代碼位於 [Tags notebook](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/5-Hotel-Reviews-2/solution/1-notebook.ipynb)。
最後一步是為每個這些標籤創建新欄位。然後,對於每條評論行,如果 `Tag` 欄位與新欄位之一匹配,則添加 1否則添加 0。最終結果將是計算有多少評論者選擇這家酒店總體上作為商務旅行、休閒旅行或帶寵物入住的選擇這在推薦酒店時是有用的信息。
```python
# Process the Tags into new columns
# The file Hotel_Reviews_Tags.py, identifies the most important tags
# Leisure trip, Couple, Solo traveler, Business trip, Group combined with Travelers with friends,
# Family with young children, Family with older children, With a pet
df["Leisure_trip"] = df.Tags.apply(lambda tag: 1 if "Leisure trip" in tag else 0)
df["Couple"] = df.Tags.apply(lambda tag: 1 if "Couple" in tag else 0)
df["Solo_traveler"] = df.Tags.apply(lambda tag: 1 if "Solo traveler" in tag else 0)
df["Business_trip"] = df.Tags.apply(lambda tag: 1 if "Business trip" in tag else 0)
df["Group"] = df.Tags.apply(lambda tag: 1 if "Group" in tag or "Travelers with friends" in tag else 0)
df["Family_with_young_children"] = df.Tags.apply(lambda tag: 1 if "Family with young children" in tag else 0)
df["Family_with_older_children"] = df.Tags.apply(lambda tag: 1 if "Family with older children" in tag else 0)
df["With_a_pet"] = df.Tags.apply(lambda tag: 1 if "With a pet" in tag else 0)
```
### 保存文件
最後,將當前數據集保存為新名稱。
```python
df.drop(["Review_Total_Negative_Word_Counts", "Review_Total_Positive_Word_Counts", "days_since_review", "Total_Number_of_Reviews_Reviewer_Has_Given"], axis = 1, inplace=True)
# Saving new data file with calculated columns
print("Saving results to Hotel_Reviews_Filtered.csv")
df.to_csv(r'../data/Hotel_Reviews_Filtered.csv', index = False)
```
## 情感分析操作
在最後一部分中,您將對評論欄位應用情感分析,並將結果保存到數據集中。
## 練習:加載並保存篩選後的數據
請注意,現在您加載的是上一部分保存的篩選後數據集,而**不是**原始數據集。
```python
import time
import pandas as pd
import nltk as nltk
from nltk.corpus import stopwords
from nltk.sentiment.vader import SentimentIntensityAnalyzer
nltk.download('vader_lexicon')
# Load the filtered hotel reviews from CSV
df = pd.read_csv('../../data/Hotel_Reviews_Filtered.csv')
# You code will be added here
# Finally remember to save the hotel reviews with new NLP data added
print("Saving results to Hotel_Reviews_NLP.csv")
df.to_csv(r'../data/Hotel_Reviews_NLP.csv', index = False)
```
### 刪除停用詞
如果您對負面和正面評論欄位運行情感分析,可能需要很長時間。在一台性能強大的測試筆記本電腦上進行測試時,根據使用的情感分析庫不同,耗時約 12-14 分鐘。這是一段(相對)較長的時間,因此值得研究是否可以加快速度。
刪除停用詞(即不改變句子情感的常見英文字詞)是第一步。通過刪除它們,情感分析應該會運行得更快,但不會降低準確性(因為停用詞不影響情感,但會減慢分析速度)。
最長的負面評論有 395 個單詞,但刪除停用詞後,只有 195 個單詞。
刪除停用詞也是一個快速操作,在測試設備上,從 2 個評論欄位的 515,000 行中刪除停用詞耗時 3.3 秒。具體時間可能因您的設備 CPU 速度、RAM、是否有 SSD 等因素略有不同。操作相對較短,這意味著如果它能改善情感分析時間,那麼值得執行。
```python
from nltk.corpus import stopwords
# Load the hotel reviews from CSV
df = pd.read_csv("../../data/Hotel_Reviews_Filtered.csv")
# Remove stop words - can be slow for a lot of text!
# Ryan Han (ryanxjhan on Kaggle) has a great post measuring performance of different stop words removal approaches
# https://www.kaggle.com/ryanxjhan/fast-stop-words-removal # using the approach that Ryan recommends
start = time.time()
cache = set(stopwords.words("english"))
def remove_stopwords(review):
text = " ".join([word for word in review.split() if word not in cache])
return text
# Remove the stop words from both columns
df.Negative_Review = df.Negative_Review.apply(remove_stopwords)
df.Positive_Review = df.Positive_Review.apply(remove_stopwords)
```
### 執行情感分析
現在,您應該計算負面和正面評論欄位的情感分析,並將結果存儲在 2 個新欄位中。情感測試將與評論者對同一評論的評分進行比較。例如,如果情感分析認為負面評論的情感為 1極度正面情感正面評論的情感也為 1但評論者給酒店的評分是最低分那麼要麼評論文本與評分不匹配要麼情感分析器無法正確識別情感。您應該預期某些情感分數完全錯誤這通常是可以解釋的例如評論可能極具諷刺意味“當然我**喜歡**住在一個沒有暖氣的房間裡”,情感分析器可能認為這是正面情感,但人類閱讀時會知道這是諷刺。
NLTK 提供了不同的情感分析器供學習使用,您可以替換它們,看看情感分析的準確性是否有所不同。這裡使用的是 VADER 情感分析。
> Hutto, C.J. & Gilbert, E.E. (2014). VADER: A Parsimonious Rule-based Model for Sentiment Analysis of Social Media Text. Eighth International Conference on Weblogs and Social Media (ICWSM-14). Ann Arbor, MI, June 2014.
```python
from nltk.sentiment.vader import SentimentIntensityAnalyzer
# Create the vader sentiment analyser (there are others in NLTK you can try too)
vader_sentiment = SentimentIntensityAnalyzer()
# Hutto, C.J. & Gilbert, E.E. (2014). VADER: A Parsimonious Rule-based Model for Sentiment Analysis of Social Media Text. Eighth International Conference on Weblogs and Social Media (ICWSM-14). Ann Arbor, MI, June 2014.
# There are 3 possibilities of input for a review:
# It could be "No Negative", in which case, return 0
# It could be "No Positive", in which case, return 0
# It could be a review, in which case calculate the sentiment
def calc_sentiment(review):
if review == "No Negative" or review == "No Positive":
return 0
return vader_sentiment.polarity_scores(review)["compound"]
```
在您的程式中,當您準備計算情感時,可以將其應用到每條評論,如下所示:
```python
# Add a negative sentiment and positive sentiment column
print("Calculating sentiment columns for both positive and negative reviews")
start = time.time()
df["Negative_Sentiment"] = df.Negative_Review.apply(calc_sentiment)
df["Positive_Sentiment"] = df.Positive_Review.apply(calc_sentiment)
end = time.time()
print("Calculating sentiment took " + str(round(end - start, 2)) + " seconds")
```
在我的電腦上這大約需要 120 秒,但每台電腦的時間可能會有所不同。如果您想列印結果並檢查情感是否與評論相符:
```python
df = df.sort_values(by=["Negative_Sentiment"], ascending=True)
print(df[["Negative_Review", "Negative_Sentiment"]])
df = df.sort_values(by=["Positive_Sentiment"], ascending=True)
print(df[["Positive_Review", "Positive_Sentiment"]])
```
在挑戰中使用該檔案之前,最後要做的事情就是保存它!您還應該考慮重新排列所有新欄位,使其更易於操作(對人類來說,這是一個外觀上的改變)。
```python
# Reorder the columns (This is cosmetic, but to make it easier to explore the data later)
df = df.reindex(["Hotel_Name", "Hotel_Address", "Total_Number_of_Reviews", "Average_Score", "Reviewer_Score", "Negative_Sentiment", "Positive_Sentiment", "Reviewer_Nationality", "Leisure_trip", "Couple", "Solo_traveler", "Business_trip", "Group", "Family_with_young_children", "Family_with_older_children", "With_a_pet", "Negative_Review", "Positive_Review"], axis=1)
print("Saving results to Hotel_Reviews_NLP.csv")
df.to_csv(r"../data/Hotel_Reviews_NLP.csv", index = False)
```
您應該執行[分析筆記本](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/5-Hotel-Reviews-2/solution/3-notebook.ipynb)的完整程式碼(在您執行[篩選筆記本](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/5-Hotel-Reviews-2/solution/1-notebook.ipynb)以生成 Hotel_Reviews_Filtered.csv 檔案之後)。
回顧一下,步驟如下:
1. 原始數據集檔案 **Hotel_Reviews.csv** 在上一課中使用[探索筆記本](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/4-Hotel-Reviews-1/solution/notebook.ipynb)進行了探索。
2. **Hotel_Reviews.csv** 通過[篩選筆記本](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/5-Hotel-Reviews-2/solution/1-notebook.ipynb)進行篩選,生成 **Hotel_Reviews_Filtered.csv**
3. **Hotel_Reviews_Filtered.csv** 通過[情感分析筆記本](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/5-Hotel-Reviews-2/solution/3-notebook.ipynb)進行處理,生成 **Hotel_Reviews_NLP.csv**
4. 在下面的 NLP 挑戰中使用 **Hotel_Reviews_NLP.csv**
### 結論
當您開始時,您擁有一個包含欄位和數據的數據集,但並非所有數據都可以被驗證或使用。您已經探索了數據,篩選出不需要的部分,將標籤轉換為有用的內容,計算了自己的平均值,添加了一些情感欄位,並希望學到了一些關於處理自然文本的有趣知識。
## [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
## 挑戰
現在您已經對數據集進行了情感分析,看看您是否可以使用本課程中學到的策略(例如聚類)來找出情感模式。
## 回顧與自學
參加[這個 Learn 模組](https://docs.microsoft.com/en-us/learn/modules/classify-user-feedback-with-the-text-analytics-api/?WT.mc_id=academic-77952-leestott),學習更多內容,並使用不同的工具來探索文本中的情感。
## 作業
[嘗試一個不同的數據集](assignment.md)
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對於因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,16 @@
# 嘗試不同的數據集
## 說明
現在您已經學習了如何使用 NLTK 為文本分配情感,嘗試使用不同的數據集。您可能需要對其進行一些數據處理,因此請創建一個筆記本並記錄您的思考過程。您發現了什麼?
## 評分標準
| 標準 | 卓越 | 合格 | 需要改進 |
| -------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------- | --------------------- |
| | 提供完整的筆記本和數據集,並且有詳細的單元格記錄如何分配情感的過程 | 筆記本缺乏良好的解釋 | 筆記本存在缺陷 |
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,172 @@
{
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.0"
},
"orig_nbformat": 4,
"kernelspec": {
"name": "python3",
"display_name": "Python 3.7.0 64-bit ('3.7')"
},
"interpreter": {
"hash": "70b38d7a306a849643e446cd70466270a13445e5987dfa1344ef2b127438fa4d"
},
"coopTranslator": {
"original_hash": "033cb89c85500224b3c63fd04f49b4aa",
"translation_date": "2025-09-03T20:58:32+00:00",
"source_file": "6-NLP/5-Hotel-Reviews-2/solution/1-notebook.ipynb",
"language_code": "tw"
}
},
"nbformat": 4,
"nbformat_minor": 2,
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import time\n",
"import ast"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def replace_address(row):\n",
" if \"Netherlands\" in row[\"Hotel_Address\"]:\n",
" return \"Amsterdam, Netherlands\"\n",
" elif \"Barcelona\" in row[\"Hotel_Address\"]:\n",
" return \"Barcelona, Spain\"\n",
" elif \"United Kingdom\" in row[\"Hotel_Address\"]:\n",
" return \"London, United Kingdom\"\n",
" elif \"Milan\" in row[\"Hotel_Address\"]: \n",
" return \"Milan, Italy\"\n",
" elif \"France\" in row[\"Hotel_Address\"]:\n",
" return \"Paris, France\"\n",
" elif \"Vienna\" in row[\"Hotel_Address\"]:\n",
" return \"Vienna, Austria\" \n",
" else:\n",
" return row.Hotel_Address\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# Load the hotel reviews from CSV\n",
"start = time.time()\n",
"df = pd.read_csv('../../data/Hotel_Reviews.csv')\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# dropping columns we will not use:\n",
"df.drop([\"lat\", \"lng\"], axis = 1, inplace=True)\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Replace all the addresses with a shortened, more useful form\n",
"df[\"Hotel_Address\"] = df.apply(replace_address, axis = 1)\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Drop `Additional_Number_of_Scoring`\n",
"df.drop([\"Additional_Number_of_Scoring\"], axis = 1, inplace=True)\n",
"# Replace `Total_Number_of_Reviews` and `Average_Score` with our own calculated values\n",
"df.Total_Number_of_Reviews = df.groupby('Hotel_Name').transform('count')\n",
"df.Average_Score = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Process the Tags into new columns\n",
"# The file Hotel_Reviews_Tags.py, identifies the most important tags\n",
"# Leisure trip, Couple, Solo traveler, Business trip, Group combined with Travelers with friends, \n",
"# Family with young children, Family with older children, With a pet\n",
"df[\"Leisure_trip\"] = df.Tags.apply(lambda tag: 1 if \"Leisure trip\" in tag else 0)\n",
"df[\"Couple\"] = df.Tags.apply(lambda tag: 1 if \"Couple\" in tag else 0)\n",
"df[\"Solo_traveler\"] = df.Tags.apply(lambda tag: 1 if \"Solo traveler\" in tag else 0)\n",
"df[\"Business_trip\"] = df.Tags.apply(lambda tag: 1 if \"Business trip\" in tag else 0)\n",
"df[\"Group\"] = df.Tags.apply(lambda tag: 1 if \"Group\" in tag or \"Travelers with friends\" in tag else 0)\n",
"df[\"Family_with_young_children\"] = df.Tags.apply(lambda tag: 1 if \"Family with young children\" in tag else 0)\n",
"df[\"Family_with_older_children\"] = df.Tags.apply(lambda tag: 1 if \"Family with older children\" in tag else 0)\n",
"df[\"With_a_pet\"] = df.Tags.apply(lambda tag: 1 if \"With a pet\" in tag else 0)\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# No longer need any of these columns\n",
"df.drop([\"Review_Date\", \"Review_Total_Negative_Word_Counts\", \"Review_Total_Positive_Word_Counts\", \"days_since_review\", \"Total_Number_of_Reviews_Reviewer_Has_Given\"], axis = 1, inplace=True)\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Saving results to Hotel_Reviews_Filtered.csv\n",
"Filtering took 23.74 seconds\n"
]
}
],
"source": [
"# Saving new data file with calculated columns\n",
"print(\"Saving results to Hotel_Reviews_Filtered.csv\")\n",
"df.to_csv(r'../../data/Hotel_Reviews_Filtered.csv', index = False)\n",
"end = time.time()\n",
"print(\"Filtering took \" + str(round(end - start, 2)) + \" seconds\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**免責聲明** \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解讀概不負責。\n"
]
}
]
}

@ -0,0 +1,137 @@
{
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.0"
},
"orig_nbformat": 4,
"kernelspec": {
"name": "python3",
"display_name": "Python 3.7.0 64-bit ('3.7')"
},
"interpreter": {
"hash": "70b38d7a306a849643e446cd70466270a13445e5987dfa1344ef2b127438fa4d"
},
"coopTranslator": {
"original_hash": "341efc86325ec2a214f682f57a189dfd",
"translation_date": "2025-09-03T20:58:48+00:00",
"source_file": "6-NLP/5-Hotel-Reviews-2/solution/2-notebook.ipynb",
"language_code": "tw"
}
},
"nbformat": 4,
"nbformat_minor": 2,
"cells": [
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# Load the hotel reviews from CSV (you can )\n",
"import pandas as pd \n",
"\n",
"df = pd.read_csv('../../data/Hotel_Reviews_Filtered.csv')\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# We want to find the most useful tags to keep\n",
"# Remove opening and closing brackets\n",
"df.Tags = df.Tags.str.strip(\"[']\")\n",
"# remove all quotes too\n",
"df.Tags = df.Tags.str.replace(\" ', '\", \",\", regex = False)\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# removing this to take advantage of the 'already a phrase' fact of the dataset \n",
"# Now split the strings into a list\n",
"tag_list_df = df.Tags.str.split(',', expand = True)\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Remove leading and trailing spaces\n",
"df[\"Tag_1\"] = tag_list_df[0].str.strip()\n",
"df[\"Tag_2\"] = tag_list_df[1].str.strip()\n",
"df[\"Tag_3\"] = tag_list_df[2].str.strip()\n",
"df[\"Tag_4\"] = tag_list_df[3].str.strip()\n",
"df[\"Tag_5\"] = tag_list_df[4].str.strip()\n",
"df[\"Tag_6\"] = tag_list_df[5].str.strip()\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# Merge the 6 columns into one with melt\n",
"df_tags = df.melt(value_vars=[\"Tag_1\", \"Tag_2\", \"Tag_3\", \"Tag_4\", \"Tag_5\", \"Tag_6\"])\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"The shape of the tags with no filtering: (2514684, 2)\n",
" index count\n",
"0 Leisure trip 338423\n",
"1 Couple 205305\n",
"2 Solo traveler 89779\n",
"3 Business trip 68176\n",
"4 Group 51593\n",
"5 Family with young children 49318\n",
"6 Family with older children 21509\n",
"7 Travelers with friends 1610\n",
"8 With a pet 1078\n"
]
}
],
"source": [
"# Get the value counts\n",
"tag_vc = df_tags.value.value_counts()\n",
"# print(tag_vc)\n",
"print(\"The shape of the tags with no filtering:\", str(df_tags.shape))\n",
"# Drop rooms, suites, and length of stay, mobile device and anything with less count than a 1000\n",
"df_tags = df_tags[~df_tags.value.str.contains(\"Standard|room|Stayed|device|Beds|Suite|Studio|King|Superior|Double\", na=False, case=False)]\n",
"tag_vc = df_tags.value.value_counts().reset_index(name=\"count\").query(\"count > 1000\")\n",
"# Print the top 10 (there should only be 9 and we'll use these in the filtering section)\n",
"print(tag_vc[:10])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**免責聲明** \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。\n"
]
}
]
}

@ -0,0 +1,260 @@
{
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.0"
},
"orig_nbformat": 4,
"kernelspec": {
"name": "python3",
"display_name": "Python 3.7.0 64-bit ('3.7')"
},
"interpreter": {
"hash": "70b38d7a306a849643e446cd70466270a13445e5987dfa1344ef2b127438fa4d"
},
"coopTranslator": {
"original_hash": "705bf02633759f689abc37b19749a16d",
"translation_date": "2025-09-03T20:59:04+00:00",
"source_file": "6-NLP/5-Hotel-Reviews-2/solution/3-notebook.ipynb",
"language_code": "tw"
}
},
"nbformat": 4,
"nbformat_minor": 2,
"cells": [
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stderr",
"text": [
"[nltk_data] Downloading package vader_lexicon to\n[nltk_data] /Users/jenlooper/nltk_data...\n"
]
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
"True"
]
},
"metadata": {},
"execution_count": 9
}
],
"source": [
"import time\n",
"import pandas as pd\n",
"import nltk as nltk\n",
"from nltk.corpus import stopwords\n",
"from nltk.sentiment.vader import SentimentIntensityAnalyzer\n",
"nltk.download('vader_lexicon')\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"vader_sentiment = SentimentIntensityAnalyzer()\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"# There are 3 possibilities of input for a review:\n",
"# It could be \"No Negative\", in which case, return 0\n",
"# It could be \"No Positive\", in which case, return 0\n",
"# It could be a review, in which case calculate the sentiment\n",
"def calc_sentiment(review): \n",
" if review == \"No Negative\" or review == \"No Positive\":\n",
" return 0\n",
" return vader_sentiment.polarity_scores(review)[\"compound\"] \n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"# Load the hotel reviews from CSV\n",
"df = pd.read_csv(\"../../data/Hotel_Reviews_Filtered.csv\")\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"# Remove stop words - can be slow for a lot of text!\n",
"# Ryan Han (ryanxjhan on Kaggle) has a great post measuring performance of different stop words removal approaches\n",
"# https://www.kaggle.com/ryanxjhan/fast-stop-words-removal # using the approach that Ryan recommends\n",
"start = time.time()\n",
"cache = set(stopwords.words(\"english\"))\n",
"def remove_stopwords(review):\n",
" text = \" \".join([word for word in review.split() if word not in cache])\n",
" return text\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"# Remove the stop words from both columns\n",
"df.Negative_Review = df.Negative_Review.apply(remove_stopwords) \n",
"df.Positive_Review = df.Positive_Review.apply(remove_stopwords)\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Removing stop words took 5.77 seconds\n"
]
}
],
"source": [
"end = time.time()\n",
"print(\"Removing stop words took \" + str(round(end - start, 2)) + \" seconds\")\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Calculating sentiment columns for both positive and negative reviews\n",
"Calculating sentiment took 201.07 seconds\n"
]
}
],
"source": [
"# Add a negative sentiment and positive sentiment column\n",
"print(\"Calculating sentiment columns for both positive and negative reviews\")\n",
"start = time.time()\n",
"df[\"Negative_Sentiment\"] = df.Negative_Review.apply(calc_sentiment)\n",
"df[\"Positive_Sentiment\"] = df.Positive_Review.apply(calc_sentiment)\n",
"end = time.time()\n",
"print(\"Calculating sentiment took \" + str(round(end - start, 2)) + \" seconds\")\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
" Negative_Review Negative_Sentiment\n",
"186584 So bad experience memories I hotel The first n... -0.9920\n",
"129503 First charged twice room booked booking second... -0.9896\n",
"307286 The staff Had bad experience even booking Janu... -0.9889\n",
"452092 No WLAN room Incredibly rude restaurant staff ... -0.9884\n",
"201293 We usually traveling Paris 2 3 times year busi... -0.9873\n",
"... ... ...\n",
"26899 I would say however one night expensive even d... 0.9933\n",
"138365 Wifi terribly slow I speed test network upload... 0.9938\n",
"79215 I find anything hotel first I walked past hote... 0.9938\n",
"278506 The property great location There bakery next ... 0.9945\n",
"339189 Guys I like hotel I wish return next year Howe... 0.9948\n",
"\n",
"[515738 rows x 2 columns]\n",
" Positive_Review Positive_Sentiment\n",
"137893 Bathroom Shower We going stay twice hotel 2 ni... -0.9820\n",
"5839 I completely disappointed mad since reception ... -0.9780\n",
"64158 get everything extra internet parking breakfas... -0.9751\n",
"124178 I didnt like anythig Room small Asked upgrade ... -0.9721\n",
"489137 Very rude manager abusive staff reception Dirt... -0.9703\n",
"... ... ...\n",
"331570 Everything This recently renovated hotel class... 0.9984\n",
"322920 From moment stepped doors Guesthouse Hotel sta... 0.9985\n",
"293710 This place surprise expected good actually gre... 0.9985\n",
"417442 We celebrated wedding night Langham I commend ... 0.9985\n",
"132492 We arrived super cute boutique hotel area expl... 0.9987\n",
"\n",
"[515738 rows x 2 columns]\n"
]
}
],
"source": [
"df = df.sort_values(by=[\"Negative_Sentiment\"], ascending=True)\n",
"print(df[[\"Negative_Review\", \"Negative_Sentiment\"]])\n",
"df = df.sort_values(by=[\"Positive_Sentiment\"], ascending=True)\n",
"print(df[[\"Positive_Review\", \"Positive_Sentiment\"]])\n"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"# Reorder the columns (This is cosmetic, but to make it easier to explore the data later)\n",
"df = df.reindex([\"Hotel_Name\", \"Hotel_Address\", \"Total_Number_of_Reviews\", \"Average_Score\", \"Reviewer_Score\", \"Negative_Sentiment\", \"Positive_Sentiment\", \"Reviewer_Nationality\", \"Leisure_trip\", \"Couple\", \"Solo_traveler\", \"Business_trip\", \"Group\", \"Family_with_young_children\", \"Family_with_older_children\", \"With_a_pet\", \"Negative_Review\", \"Positive_Review\"], axis=1)\n"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Saving results to Hotel_Reviews_NLP.csv\n"
]
}
],
"source": [
"print(\"Saving results to Hotel_Reviews_NLP.csv\")\n",
"df.to_csv(r\"../../data/Hotel_Reviews_NLP.csv\", index = False)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**免責聲明** \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。\n"
]
}
]
}

@ -0,0 +1,6 @@
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,6 @@
這是一個臨時佔位符
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始語言的文件應被視為權威來源。對於重要資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,29 @@
# 開始學習自然語言處理
自然語言處理NLP是指電腦程式能夠理解人類語言口語和書面語的能力這些語言被稱為自然語言。NLP 是人工智慧AI的一個組成部分。自然語言處理已有超過 50 年的歷史,其根源可追溯至語言學領域。整個領域的目標是幫助機器理解和處理人類語言,進而用於執行拼寫檢查或機器翻譯等任務。它在許多領域中有著多種現實應用,包括醫學研究、搜尋引擎和商業情報。
## 區域主題:歐洲語言與文學以及歐洲的浪漫酒店 ❤️
在本課程的這一部分中您將接觸到機器學習最廣泛的應用之一自然語言處理NLP。這一人工智慧的分支源自計算語言學通過語音或文本交流搭建了人類與機器之間的橋樑。
在這些課程中,我們將通過構建小型對話機器人來學習 NLP 的基礎知識,了解機器學習如何幫助使這些對話變得越來越「智能」。您將穿越時光,與珍·奧斯汀 1813 年出版的經典小說《傲慢與偏見》中的伊麗莎白·班內特和達西先生進行對話。接著,您將進一步學習如何通過分析歐洲酒店評論來了解情感分析。
![傲慢與偏見書籍與茶](../../../translated_images/zh-TW/p&p.279f1c49ecd88941.webp)
> 圖片由 <a href="https://unsplash.com/@elaineh?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Elaine Howlin</a> 提供,來自 <a href="https://unsplash.com/s/photos/pride-and-prejudice?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
## 課程
1. [自然語言處理簡介](1-Introduction-to-NLP/README.md)
2. [常見的 NLP 任務與技術](2-Tasks/README.md)
3. [使用機器學習進行翻譯與情感分析](3-Translation-Sentiment/README.md)
4. [準備您的數據](4-Hotel-Reviews-1/README.md)
5. [使用 NLTK 進行情感分析](5-Hotel-Reviews-2/README.md)
## 鳴謝
這些自然語言處理課程由 [Stephen Howell](https://twitter.com/Howell_MSFT) 用 ☕ 編寫完成
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,6 @@
下載酒店評論數據到此資料夾。
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,190 @@
# 時間序列預測簡介
![時間序列摘要手繪圖](../../../../sketchnotes/ml-timeseries.png)
> 手繪圖由 [Tomomi Imura](https://www.twitter.com/girlie_mac) 提供
在本課程及接下來的課程中,您將學習一些關於時間序列預測的知識。這是一個有趣且有價值的機器學習科學家技能之一,但相較於其他主題,它可能較少被人熟知。時間序列預測就像一個“水晶球”:根據某個變數(例如價格)的過去表現,您可以預測其未來的潛在價值。
[![時間序列預測簡介](https://img.youtube.com/vi/cBojo1hsHiI/0.jpg)](https://youtu.be/cBojo1hsHiI "時間序列預測簡介")
> 🎥 點擊上方圖片觀看關於時間序列預測的影片
## [課前測驗](https://ff-quizzes.netlify.app/en/ml/)
這是一個有用且有趣的領域,對於商業具有實際價值,因為它直接應用於定價、庫存和供應鏈問題。雖然深度學習技術已開始被用來獲得更多洞察以更好地預測未來表現,但時間序列預測仍然是一個主要由經典機器學習技術所驅動的領域。
> 賓州州立大學的時間序列課程可在[此處](https://online.stat.psu.edu/stat510/lesson/1)找到
## 簡介
假設您管理一組智能停車計時器,這些計時器提供有關它們使用頻率及使用時長的數據。
> 如果您能根據計時器的過去表現,根據供需法則預測其未來價值,會怎麼樣?
準確地預測何時採取行動以達成目標是一個挑戰,而這可以通過時間序列預測來解決。雖然在繁忙時段收取更高的停車費可能不會讓人們感到高興,但這確實是一種有效的方式來增加收入以清潔街道!
讓我們探索一些時間序列算法的類型,並開始使用筆記本清理和準備一些數據。您將分析的數據來自 GEFCom2014 預測競賽。它包含了 2012 年至 2014 年三年期間的每小時電力負載和溫度值。根據電力負載和溫度的歷史模式,您可以預測未來的電力負載值。
在這個例子中,您將學習如何僅使用歷史負載數據來預測下一個時間步驟的值。然而,在開始之前,了解背後的原理是很有幫助的。
## 一些定義
當遇到“時間序列”這個術語時,您需要了解它在不同上下文中的使用。
🎓 **時間序列**
在數學中,“時間序列是一系列按時間順序索引(或列出或繪製)的數據點。最常見的是,時間序列是在連續且等間隔的時間點上採集的序列。” 時間序列的一個例子是 [道瓊斯工業平均指數](https://wikipedia.org/wiki/Time_series) 的每日收盤價。時間序列圖和統計建模的使用在信號處理、天氣預測、地震預測以及其他事件發生且數據點可以隨時間繪製的領域中經常遇到。
🎓 **時間序列分析**
時間序列分析是對上述時間序列數據的分析。時間序列數據可以採取不同的形式,包括“中斷時間序列”,它檢測時間序列在中斷事件前後的演變模式。所需的分析類型取決於數據的性質。時間序列數據本身可以是數字或字符的序列。
進行分析時,使用了多種方法,包括頻域和時域、線性和非線性等。[了解更多](https://www.itl.nist.gov/div898/handbook/pmc/section4/pmc4.htm) 關於分析此類數據的方法。
🎓 **時間序列預測**
時間序列預測是使用模型根據過去收集的數據所顯示的模式來預測未來值。雖然可以使用回歸模型來探索時間序列數據,並將時間索引作為圖上的 x 變數,但此類數據最好使用特殊類型的模型進行分析。
時間序列數據是一組有序的觀測值,不同於可以通過線性回歸分析的數據。最常見的模型是 ARIMA這是“自回歸整合移動平均”的縮寫。
[ARIMA 模型](https://online.stat.psu.edu/stat510/lesson/1/1.1) “將序列的當前值與過去的值和過去的預測誤差相關聯。” 它們最適合分析時間域數據,即按時間順序排列的數據。
> ARIMA 模型有多種類型,您可以在[此處](https://people.duke.edu/~rnau/411arim.htm)了解更多,並在下一課中進一步探討。
在下一課中,您將使用 [單變量時間序列](https://itl.nist.gov/div898/handbook/pmc/section4/pmc44.htm) 建立 ARIMA 模型,該模型專注於一個隨時間變化的變數。此類數據的一個例子是[這個數據集](https://itl.nist.gov/div898/handbook/pmc/section4/pmc4411.htm),記錄了 Mauna Loa 天文台的每月 CO2 濃度:
| CO2 | YearMonth | Year | Month |
| :-----: | :-------: | :---: | :---: |
| 330.62 | 1975.04 | 1975 | 1 |
| 331.40 | 1975.13 | 1975 | 2 |
| 331.87 | 1975.21 | 1975 | 3 |
| 333.18 | 1975.29 | 1975 | 4 |
| 333.92 | 1975.38 | 1975 | 5 |
| 333.43 | 1975.46 | 1975 | 6 |
| 331.85 | 1975.54 | 1975 | 7 |
| 330.01 | 1975.63 | 1975 | 8 |
| 328.51 | 1975.71 | 1975 | 9 |
| 328.41 | 1975.79 | 1975 | 10 |
| 329.25 | 1975.88 | 1975 | 11 |
| 330.97 | 1975.96 | 1975 | 12 |
✅ 識別此數據集中隨時間變化的變數
## 時間序列數據的特徵需考慮
當查看時間序列數據時,您可能會注意到它具有[某些特徵](https://online.stat.psu.edu/stat510/lesson/1/1.1),需要考慮並減少這些特徵以更好地理解其模式。如果您將時間序列數據視為可能提供“信號”的數據,這些特徵可以被視為“噪音”。您通常需要使用一些統計技術來減少這些“噪音”。
以下是一些您需要了解的概念,以便能夠處理時間序列:
🎓 **趨勢**
趨勢是指隨時間可測量的增長或減少。[了解更多](https://machinelearningmastery.com/time-series-trends-in-python)。在時間序列的背景下,這是關於如何使用以及(如果需要)移除時間序列中的趨勢。
🎓 **[季節性](https://machinelearningmastery.com/time-series-seasonality-with-python/)**
季節性是指周期性的波動,例如假日銷售高峰可能影響銷售數據。[了解更多](https://itl.nist.gov/div898/handbook/pmc/section4/pmc443.htm) 不同類型的圖表如何顯示數據中的季節性。
🎓 **異常值**
異常值是遠離標準數據變異範圍的數據點。
🎓 **長期週期**
獨立於季節性,數據可能顯示長期週期,例如持續超過一年的經濟衰退。
🎓 **恆定變異**
隨時間推移,一些數據顯示恆定的波動,例如每日和夜間的能源使用量。
🎓 **突變**
數據可能顯示突變,這可能需要進一步分析。例如,由於 COVID 的突然爆發導致企業關閉,數據發生了變化。
✅ 這裡有一個[示例時間序列圖](https://www.kaggle.com/kashnitsky/topic-9-part-1-time-series-analysis-in-python),顯示了幾年內每日遊戲內貨幣消費。您能在此數據中識別出上述特徵嗎?
![遊戲內貨幣消費](../../../../7-TimeSeries/1-Introduction/images/currency.png)
## 練習 - 開始使用電力使用數據
讓我們開始創建一個時間序列模型,根據過去的使用情況來預測未來的電力使用。
> 本例中的數據來自 GEFCom2014 預測競賽。它包含了 2012 年至 2014 年三年期間的每小時電力負載和溫度值。
>
> Tao Hong, Pierre Pinson, Shu Fan, Hamidreza Zareipour, Alberto Troccoli 和 Rob J. Hyndman, "Probabilistic energy forecasting: Global Energy Forecasting Competition 2014 and beyond", International Journal of Forecasting, vol.32, no.3, pp 896-913, July-September, 2016.
1. 在本課程的 `working` 資料夾中,打開 _notebook.ipynb_ 文件。首先添加幫助您加載和可視化數據的庫:
```python
import os
import matplotlib.pyplot as plt
from common.utils import load_data
%matplotlib inline
```
注意,您正在使用包含的 `common` 資料夾中的文件,這些文件設置了您的環境並處理數據的下載。
2. 接下來,通過調用 `load_data()``head()` 查看數據作為數據框:
```python
data_dir = './data'
energy = load_data(data_dir)[['load']]
energy.head()
```
您可以看到有兩列分別表示日期和負載:
| | load |
| :-----------------: | :----: |
| 2012-01-01 00:00:00 | 2698.0 |
| 2012-01-01 01:00:00 | 2558.0 |
| 2012-01-01 02:00:00 | 2444.0 |
| 2012-01-01 03:00:00 | 2402.0 |
| 2012-01-01 04:00:00 | 2403.0 |
3. 現在,通過調用 `plot()` 繪製數據:
```python
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
```
![能源圖](../../../../7-TimeSeries/1-Introduction/images/energy-plot.png)
4. 現在,通過提供 `[from date]: [to date]` 格式的輸入,繪製 2014 年 7 月的第一周:
```python
energy['2014-07-01':'2014-07-07'].plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
```
![七月](../../../../7-TimeSeries/1-Introduction/images/july-2014.png)
一個漂亮的圖表!看看這些圖表,看看您是否能確定上述列出的特徵。通過可視化數據,我們可以推測什麼?
在下一課中,您將創建一個 ARIMA 模型來進行一些預測。
---
## 🚀挑戰
列出您能想到的所有可能受益於時間序列預測的行業和研究領域。您能想到這些技術在藝術、計量經濟學、生態學、零售業、工業、金融等領域的應用嗎?還有其他地方嗎?
## [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
## 回顧與自學
雖然我們在此不會涵蓋,但有時會使用神經網絡來增強經典的時間序列預測方法。[在這篇文章中](https://medium.com/microsoftazure/neural-networks-for-forecasting-financial-and-economic-time-series-6aca370ff412)了解更多相關內容。
## 作業
[可視化更多時間序列](assignment.md)
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,16 @@
# 視覺化更多時間序列
## 說明
您已開始學習時間序列預測,並了解需要這種特殊建模的數據類型。您已經視覺化了一些與能源相關的數據。現在,請尋找其他適合時間序列預測的數據。找到三個例子(可以嘗試 [Kaggle](https://kaggle.com) 和 [Azure Open Datasets](https://azure.microsoft.com/en-us/services/open-datasets/catalog/?WT.mc_id=academic-77952-leestott)),並建立一個筆記本來視覺化它們。在筆記本中註明它們的任何特殊特徵(季節性、突然變化或其他趨勢)。
## 評分標準
| 評分標準 | 卓越 | 合格 | 需要改進 |
| -------- | ------------------------------------------------ | ------------------------------------------------ | -------------------------------------------------------------------------------- |
| | 在筆記本中繪製並解釋了三個數據集 | 在筆記本中繪製並解釋了兩個數據集 | 在筆記本中繪製或解釋的數據集較少,或所呈現的數據不足 |
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵信息,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,6 @@
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,6 @@
這是一個臨時佔位符
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

File diff suppressed because one or more lines are too long

@ -0,0 +1,63 @@
{
"cells": [
{
"source": [
"# 數據設置\n",
"\n",
"在此筆記本中,我們將展示如何:\n",
"\n",
"設置此模組的時間序列數據 \n",
"可視化數據 \n",
"此範例中的數據取自GEFCom2014預測競賽。它包含2012年至2014年之間3年的每小時電力負載和溫度值。\n",
"\n",
"1Tao Hong, Pierre Pinson, Shu Fan, Hamidreza Zareipour, Alberto Troccoli 和 Rob J. Hyndman\"Probabilistic energy forecasting: Global Energy Forecasting Competition 2014 and beyond\"《國際預測期刊》第32卷第3期頁896-9132016年7月至9月。\n"
],
"cell_type": "markdown",
"metadata": {}
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**免責聲明** \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解釋不承擔責任。\n"
]
}
],
"metadata": {
"kernel_info": {
"name": "python3"
},
"kernelspec": {
"name": "python37364bit8d3b438fb5fc4430a93ac2cb74d693a7",
"display_name": "Python 3.7.0 64-bit ('3.7')"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.0"
},
"nteract": {
"version": "nteract-front-end@1.0.0"
},
"metadata": {
"interpreter": {
"hash": "70b38d7a306a849643e446cd70466270a13445e5987dfa1344ef2b127438fa4d"
}
},
"coopTranslator": {
"original_hash": "5e2bbe594906dce3aaaa736d6dac6683",
"translation_date": "2025-09-03T19:57:20+00:00",
"source_file": "7-TimeSeries/1-Introduction/working/notebook.ipynb",
"language_code": "tw"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

@ -0,0 +1,398 @@
# 使用 ARIMA 進行時間序列預測
在上一課中,你學習了一些關於時間序列預測的知識,並載入了一個展示電力負載隨時間波動的數據集。
[![ARIMA 簡介](https://img.youtube.com/vi/IUSk-YDau10/0.jpg)](https://youtu.be/IUSk-YDau10 "Introduction to ARIMA")
> 🎥 點擊上方圖片觀看影片ARIMA 模型的簡要介紹。範例使用 R 語言,但概念具有普遍性。
## [課前測驗](https://ff-quizzes.netlify.app/en/ml/)
## 簡介
在本課中,你將學習如何使用 [ARIMA: *A*uto*R*egressive *I*ntegrated *M*oving *A*verage](https://wikipedia.org/wiki/Autoregressive_integrated_moving_average) 建立模型。ARIMA 模型特別適合用於處理顯示 [非平穩性](https://wikipedia.org/wiki/Stationary_process) 的數據。
## 基本概念
在使用 ARIMA 之前,你需要了解以下一些概念:
- 🎓 **平穩性**。從統計學的角度來看,平穩性指的是數據的分佈在時間移動時不會改變。非平穩數據則會因趨勢而波動,這些趨勢必須經過轉換才能進行分析。例如,季節性可能會引入數據波動,這可以通過“季節性差分”過程來消除。
- 🎓 **[差分](https://wikipedia.org/wiki/Autoregressive_integrated_moving_average#Differencing)**。差分是指通過移除非平穩數據中的非恆定趨勢,將其轉換為平穩數據的過程。“差分可以消除時間序列中的水平變化,從而消除趨勢和季節性,並穩定時間序列的均值。” [Shixiong 等人的論文](https://arxiv.org/abs/1904.07632)
## ARIMA 在時間序列中的應用
讓我們拆解 ARIMA 的各個部分,以更好地理解它如何幫助我們對時間序列建模並進行預測。
- **AR - 自回歸 (AutoRegressive)**。顧名思義,自回歸模型會“回顧”過去的數據值,並對其進行分析以作出假設。這些過去的數據值被稱為“滯後值”。例如,顯示每月鉛筆銷售數據的數據集。每個月的銷售總額被認為是數據集中的“演變變量”。該模型的構建方式是“將感興趣的演變變量回歸到其自身的滯後值(即先前的值)上。” [維基百科](https://wikipedia.org/wiki/Autoregressive_integrated_moving_average)
- **I - 積分 (Integrated)**。與類似的 'ARMA' 模型不同ARIMA 中的 'I' 指的是其 *[積分](https://wikipedia.org/wiki/Order_of_integration)* 特性。當應用差分步驟以消除非平穩性時,數據即被“積分”。
- **MA - 移動平均 (Moving Average)**。該模型的 [移動平均](https://wikipedia.org/wiki/Moving-average_model) 部分指的是通過觀察當前和過去的滯後值來確定輸出變量。
總結ARIMA 用於使模型盡可能貼合時間序列數據的特殊形式。
## 練習 - 構建 ARIMA 模型
打開本課中的 [_/working_](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/2-ARIMA/working) 資料夾,找到 [_notebook.ipynb_](https://github.com/microsoft/ML-For-Beginners/blob/main/7-TimeSeries/2-ARIMA/working/notebook.ipynb) 文件。
1. 運行 notebook 以載入 `statsmodels` Python 庫;這是 ARIMA 模型所需的。
1. 載入必要的庫。
1. 現在,載入更多用於繪製數據的庫:
```python
import os
import warnings
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import datetime as dt
import math
from pandas.plotting import autocorrelation_plot
from statsmodels.tsa.statespace.sarimax import SARIMAX
from sklearn.preprocessing import MinMaxScaler
from common.utils import load_data, mape
from IPython.display import Image
%matplotlib inline
pd.options.display.float_format = '{:,.2f}'.format
np.set_printoptions(precision=2)
warnings.filterwarnings("ignore") # specify to ignore warning messages
```
1. 將 `/data/energy.csv` 文件中的數據載入 Pandas dataframe並查看數據
```python
energy = load_data('./data')[['load']]
energy.head(10)
```
1. 繪製 2012 年 1 月至 2014 年 12 月的所有能源數據。這些數據應該沒有什麼意外,因為我們在上一課中已經看到過:
```python
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
```
現在,讓我們構建一個模型!
### 創建訓練和測試數據集
現在數據已載入,你可以將其分為訓練集和測試集。你將在訓練集上訓練模型。與往常一樣,模型訓練完成後,你將使用測試集評估其準確性。你需要確保測試集涵蓋的時間段晚於訓練集,以確保模型不會從未來的時間段中獲取信息。
1. 將 2014 年 9 月 1 日至 10 月 31 日的兩個月期間分配給訓練集。測試集將包括 2014 年 11 月 1 日至 12 月 31 日的兩個月期間:
```python
train_start_dt = '2014-11-01 00:00:00'
test_start_dt = '2014-12-30 00:00:00'
```
由於這些數據反映了每日的能源消耗,因此存在明顯的季節性模式,但消耗量與最近幾天的消耗量最為相似。
1. 可視化差異:
```python
energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)][['load']].rename(columns={'load':'train'}) \
.join(energy[test_start_dt:][['load']].rename(columns={'load':'test'}), how='outer') \
.plot(y=['train', 'test'], figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
```
![訓練和測試數據](../../../../7-TimeSeries/2-ARIMA/images/train-test.png)
因此,使用一個相對較小的時間窗口來訓練數據應該是足夠的。
> 注意:由於我們用於擬合 ARIMA 模型的函數在擬合過程中使用了樣本內驗證,因此我們將省略驗證數據。
### 為訓練準備數據
現在,你需要通過對數據進行過濾和縮放來準備訓練數據。過濾數據集以僅包含所需的時間段和列,並縮放數據以確保數據投影在 0 到 1 的區間內。
1. 過濾原始數據集以僅包含上述每個集合的時間段並僅包括所需的“load”列和日期
```python
train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']]
test = energy.copy()[energy.index >= test_start_dt][['load']]
print('Training data shape: ', train.shape)
print('Test data shape: ', test.shape)
```
你可以查看數據的形狀:
```output
Training data shape: (1416, 1)
Test data shape: (48, 1)
```
1. 將數據縮放到 (0, 1) 範圍內。
```python
scaler = MinMaxScaler()
train['load'] = scaler.fit_transform(train)
train.head(10)
```
1. 可視化原始數據與縮放後的數據:
```python
energy[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']].rename(columns={'load':'original load'}).plot.hist(bins=100, fontsize=12)
train.rename(columns={'load':'scaled load'}).plot.hist(bins=100, fontsize=12)
plt.show()
```
![原始數據](../../../../7-TimeSeries/2-ARIMA/images/original.png)
> 原始數據
![縮放後數據](../../../../7-TimeSeries/2-ARIMA/images/scaled.png)
> 縮放後數據
1. 現在你已校準縮放後的數據,可以縮放測試數據:
```python
test['load'] = scaler.transform(test)
test.head()
```
### 實現 ARIMA
現在是時候實現 ARIMA 了!你將使用之前安裝的 `statsmodels` 庫。
接下來需要遵循幾個步驟:
1. 通過調用 `SARIMAX()` 並傳入模型參數p、d 和 q 參數,以及 P、D 和 Q 參數)來定義模型。
2. 通過調用 `fit()` 函數為訓練數據準備模型。
3. 通過調用 `forecast()` 函數並指定要預測的步數(即“預測範圍”)來進行預測。
> 🎓 這些參數是什麼意思?在 ARIMA 模型中,有 3 個參數用於幫助建模時間序列的主要方面:季節性、趨勢和噪聲。這些參數是:
`p`:與模型的自回歸部分相關的參數,該部分包含*過去*的值。
`d`:與模型的積分部分相關的參數,該部分影響應用於時間序列的*差分*次數(🎓 還記得差分嗎 👆?)。
`q`:與模型的移動平均部分相關的參數。
> 注意:如果你的數據具有季節性特徵(例如本例),我們使用季節性 ARIMA 模型SARIMA。在這種情況下你需要使用另一組參數`P`、`D` 和 `Q`,它們與 `p`、`d` 和 `q` 的關聯相同,但對應於模型的季節性部分。
1. 首先設置你偏好的預測範圍值。我們試試 3 小時:
```python
# Specify the number of steps to forecast ahead
HORIZON = 3
print('Forecasting horizon:', HORIZON, 'hours')
```
為 ARIMA 模型選擇最佳參數值可能具有挑戰性,因為這在某種程度上是主觀且耗時的。你可以考慮使用 [`pyramid` 庫](https://alkaline-ml.com/pmdarima/0.9.0/modules/generated/pyramid.arima.auto_arima.html) 的 `auto_arima()` 函數。
1. 現在嘗試一些手動選擇以找到一個合適的模型。
```python
order = (4, 1, 0)
seasonal_order = (1, 1, 0, 24)
model = SARIMAX(endog=train, order=order, seasonal_order=seasonal_order)
results = model.fit()
print(results.summary())
```
一個結果表格將被打印出來。
你已經構建了第一個模型!現在我們需要找到一種方法來評估它。
### 評估你的模型
為了評估你的模型,你可以執行所謂的 `逐步前進` 驗證。在實踐中,每當有新數據可用時,時間序列模型都會重新訓練。這使得模型能夠在每個時間步驟中進行最佳預測。
使用此技術從時間序列的開頭開始,對訓練數據集進行模型訓練。然後對下一個時間步驟進行預測。將預測值與已知值進行評估。然後將訓練集擴展以包括已知值,並重複該過程。
> 注意:為了提高訓練效率,你應該保持訓練集窗口固定,這樣每次向訓練集添加新觀測值時,你需要從集合的開頭移除一個觀測值。
此過程提供了模型在實踐中表現的更穩健估計。然而,這需要付出創建大量模型的計算成本。如果數據量小或模型簡單,這是可以接受的,但在規模較大時可能會成為問題。
逐步前進驗證是時間序列模型評估的黃金標準,並建議在你的項目中使用。
1. 首先,為每個 HORIZON 步驟創建一個測試數據點。
```python
test_shifted = test.copy()
for t in range(1, HORIZON+1):
test_shifted['load+'+str(t)] = test_shifted['load'].shift(-t, freq='H')
test_shifted = test_shifted.dropna(how='any')
test_shifted.head(5)
```
| | | load | load+1 | load+2 |
| ---------- | -------- | ---- | ------ | ------ |
| 2014-12-30 | 00:00:00 | 0.33 | 0.29 | 0.27 |
| 2014-12-30 | 01:00:00 | 0.29 | 0.27 | 0.27 |
| 2014-12-30 | 02:00:00 | 0.27 | 0.27 | 0.30 |
| 2014-12-30 | 03:00:00 | 0.27 | 0.30 | 0.41 |
| 2014-12-30 | 04:00:00 | 0.30 | 0.41 | 0.57 |
數據根據其預測範圍點水平移動。
1. 使用此滑動窗口方法對測試數據進行預測,循環次數為測試數據長度:
```python
%%time
training_window = 720 # dedicate 30 days (720 hours) for training
train_ts = train['load']
test_ts = test_shifted
history = [x for x in train_ts]
history = history[(-training_window):]
predictions = list()
order = (2, 1, 0)
seasonal_order = (1, 1, 0, 24)
for t in range(test_ts.shape[0]):
model = SARIMAX(endog=history, order=order, seasonal_order=seasonal_order)
model_fit = model.fit()
yhat = model_fit.forecast(steps = HORIZON)
predictions.append(yhat)
obs = list(test_ts.iloc[t])
# move the training window
history.append(obs[0])
history.pop(0)
print(test_ts.index[t])
print(t+1, ': predicted =', yhat, 'expected =', obs)
```
你可以觀察到訓練過程:
```output
2014-12-30 00:00:00
1 : predicted = [0.32 0.29 0.28] expected = [0.32945389435989236, 0.2900626678603402, 0.2739480752014323]
2014-12-30 01:00:00
2 : predicted = [0.3 0.29 0.3 ] expected = [0.2900626678603402, 0.2739480752014323, 0.26812891674127126]
2014-12-30 02:00:00
3 : predicted = [0.27 0.28 0.32] expected = [0.2739480752014323, 0.26812891674127126, 0.3025962399283795]
```
1. 將預測值與實際負載進行比較:
```python
eval_df = pd.DataFrame(predictions, columns=['t+'+str(t) for t in range(1, HORIZON+1)])
eval_df['timestamp'] = test.index[0:len(test.index)-HORIZON+1]
eval_df = pd.melt(eval_df, id_vars='timestamp', value_name='prediction', var_name='h')
eval_df['actual'] = np.array(np.transpose(test_ts)).ravel()
eval_df[['prediction', 'actual']] = scaler.inverse_transform(eval_df[['prediction', 'actual']])
eval_df.head()
```
輸出
| | | timestamp | h | prediction | actual |
| --- | ---------- | --------- | --- | ---------- | -------- |
| 0 | 2014-12-30 | 00:00:00 | t+1 | 3,008.74 | 3,023.00 |
| 1 | 2014-12-30 | 01:00:00 | t+1 | 2,955.53 | 2,935.00 |
| 2 | 2014-12-30 | 02:00:00 | t+1 | 2,900.17 | 2,899.00 |
| 3 | 2014-12-30 | 03:00:00 | t+1 | 2,917.69 | 2,886.00 |
| 4 | 2014-12-30 | 04:00:00 | t+1 | 2,946.99 | 2,963.00 |
觀察每小時數據的預測值與實際負載的比較。這有多準確?
### 檢查模型準確性
通過測試所有預測的平均絕對百分比誤差 (MAPE) 來檢查模型的準確性。
> **🧮 展示數學公式**
>
> ![MAPE](../../../../7-TimeSeries/2-ARIMA/images/mape.png)
>
> [MAPE](https://www.linkedin.com/pulse/what-mape-mad-msd-time-series-allameh-statistics/) 用於顯示預測準確度,公式如上所示。實際值與預測值之間的差異除以實際值。
>
> 「此計算中的絕對值會對每個預測點進行加總,然後除以擬合點的數量 n。」 [wikipedia](https://wikipedia.org/wiki/Mean_absolute_percentage_error)
1. 在程式碼中表達方程式:
```python
if(HORIZON > 1):
eval_df['APE'] = (eval_df['prediction'] - eval_df['actual']).abs() / eval_df['actual']
print(eval_df.groupby('h')['APE'].mean())
```
1. 計算單步驟的 MAPE
```python
print('One step forecast MAPE: ', (mape(eval_df[eval_df['h'] == 't+1']['prediction'], eval_df[eval_df['h'] == 't+1']['actual']))*100, '%')
```
單步預測 MAPE0.5570581332313952 %
1. 輸出多步預測的 MAPE
```python
print('Multi-step forecast MAPE: ', mape(eval_df['prediction'], eval_df['actual'])*100, '%')
```
```output
Multi-step forecast MAPE: 1.1460048657704118 %
```
一個較低的數值是最好的:請考慮,如果一個預測的 MAPE 為 10則表示偏差為 10%。
1. 但一如往常,視覺化這種準確性測量會更容易理解,所以讓我們繪製圖表:
```python
if(HORIZON == 1):
## Plotting single step forecast
eval_df.plot(x='timestamp', y=['actual', 'prediction'], style=['r', 'b'], figsize=(15, 8))
else:
## Plotting multi step forecast
plot_df = eval_df[(eval_df.h=='t+1')][['timestamp', 'actual']]
for t in range(1, HORIZON+1):
plot_df['t+'+str(t)] = eval_df[(eval_df.h=='t+'+str(t))]['prediction'].values
fig = plt.figure(figsize=(15, 8))
ax = plt.plot(plot_df['timestamp'], plot_df['actual'], color='red', linewidth=4.0)
ax = fig.add_subplot(111)
for t in range(1, HORIZON+1):
x = plot_df['timestamp'][(t-1):]
y = plot_df['t+'+str(t)][0:len(x)]
ax.plot(x, y, color='blue', linewidth=4*math.pow(.9,t), alpha=math.pow(0.8,t))
ax.legend(loc='best')
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
```
![時間序列模型](../../../../7-TimeSeries/2-ARIMA/images/accuracy.png)
🏆 一個非常棒的圖表,顯示了一個準確性良好的模型。做得好!
---
## 🚀挑戰
深入研究測試時間序列模型準確性的方法。本課程中我們提到了 MAPE但還有其他方法可以使用嗎研究它們並加以註解。一份有幫助的文件可以在[這裡](https://otexts.com/fpp2/accuracy.html)找到。
## [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
## 回顧與自學
本課程僅觸及了使用 ARIMA 進行時間序列預測的基礎知識。花些時間深入了解[這個資源庫](https://microsoft.github.io/forecasting/)及其各種模型類型,學習其他構建時間序列模型的方法。
## 作業
[一個新的 ARIMA 模型](assignment.md)
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,16 @@
# 一個新的 ARIMA 模型
## 說明
現在您已經建立了一個 ARIMA 模型,請使用新的數據建立另一個模型(可以嘗試使用[杜克大學的這些數據集](http://www2.stat.duke.edu/~mw/ts_data_sets.html))。在筆記本中註解您的工作,視覺化數據和您的模型,並使用 MAPE 測試其準確性。
## 評分標準
| 評分標準 | 優秀 | 合格 | 需要改進 |
| -------- | ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------- |
| | 提供了一個筆記本,其中包含建立、測試並解釋的新 ARIMA 模型,並附有視覺化和準確性說明。 | 提供的筆記本未註解或包含錯誤 | 提供了一個不完整的筆記本 |
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,6 @@
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,6 @@
這是一個臨時佔位符
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要信息,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

File diff suppressed because one or more lines are too long

@ -0,0 +1,59 @@
{
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": 3
},
"orig_nbformat": 2,
"coopTranslator": {
"original_hash": "523ec472196307b3c4235337353c9ceb",
"translation_date": "2025-09-03T19:55:51+00:00",
"source_file": "7-TimeSeries/2-ARIMA/working/notebook.ipynb",
"language_code": "tw"
}
},
"nbformat": 4,
"nbformat_minor": 2,
"cells": [
{
"source": [
"# 使用 ARIMA 進行時間序列預測\n",
"\n",
"在本筆記中,我們將展示如何:\n",
"- 準備時間序列數據以訓練 ARIMA 時間序列預測模型\n",
"- 實現一個簡單的 ARIMA 模型,用於預測時間序列中未來的 HORIZON 步(從時間 *t+1* 到 *t+HORIZON*\n",
"- 評估模型\n",
"\n",
"此範例中的數據來自 GEFCom2014 預測競賽。它包含 2012 年至 2014 年間 3 年的每小時電力負載和溫度值。任務是預測未來的電力負載值。在此範例中,我們展示如何僅使用歷史負載數據來預測下一個時間步。 \n",
"\n",
"陶宏、Pierre Pinson、Shu Fan、Hamidreza Zareipour、Alberto Troccoli 和 Rob J. Hyndman\"Probabilistic energy forecasting: Global Energy Forecasting Competition 2014 and beyond\",《國際預測期刊》,第 32 卷,第 3 期,頁 896-9132016 年 7 月至 9 月。\n"
],
"cell_type": "markdown",
"metadata": {}
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pip install statsmodels"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**免責聲明** \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤釋不承擔責任。\n"
]
}
]
}

@ -0,0 +1,384 @@
# 使用支持向量回歸進行時間序列預測
在上一課中,你學習了如何使用 ARIMA 模型進行時間序列預測。現在我們將探討支持向量回歸模型Support Vector Regressor這是一種用於預測連續數據的回歸模型。
## [課前測驗](https://ff-quizzes.netlify.app/en/ml/)
## 簡介
在本課中,你將學習如何使用[**SVM****支持向量機**](https://en.wikipedia.org/wiki/Support-vector_machine)進行回歸,也就是**SVR支持向量回歸**。
### SVR 在時間序列中的應用 [^1]
在理解 SVR 在時間序列預測中的重要性之前,以下是一些你需要了解的重要概念:
- **回歸:** 一種監督式學習技術,用於根據給定的輸入集預測連續值。其核心思想是找到特徵空間中包含最多數據點的曲線(或直線)。[點擊這裡](https://en.wikipedia.org/wiki/Regression_analysis)了解更多資訊。
- **支持向量機SVM** 一種監督式機器學習模型,用於分類、回歸和異常檢測。該模型在特徵空間中是一個超平面,分類時作為邊界,回歸時作為最佳擬合線。在 SVM 中,通常使用核函數將數據集轉換到更高維度的空間,以便更容易分離。[點擊這裡](https://en.wikipedia.org/wiki/Support-vector_machine)了解更多關於 SVM 的資訊。
- **支持向量回歸SVR** SVM 的一種,用於找到最佳擬合線(在 SVM 中是超平面),以包含最多的數據點。
### 為什麼選擇 SVR [^1]
在上一課中,你學習了 ARIMA它是一種非常成功的統計線性方法用於預測時間序列數據。然而在許多情況下時間序列數據具有*非線性*特性這些特性無法通過線性模型映射。在這種情況下SVM 在回歸任務中考慮數據非線性的能力使得 SVR 在時間序列預測中非常成功。
## 練習 - 建立 SVR 模型
數據準備的前幾步與上一課的 [ARIMA](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/2-ARIMA) 相同。
打開本課中的 [_/working_](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/3-SVR/working) 資料夾,找到 [_notebook.ipynb_](https://github.com/microsoft/ML-For-Beginners/blob/main/7-TimeSeries/3-SVR/working/notebook.ipynb) 文件。[^2]
1. 執行 notebook 並導入必要的庫:[ ^2]
```python
import sys
sys.path.append('../../')
```
```python
import os
import warnings
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import datetime as dt
import math
from sklearn.svm import SVR
from sklearn.preprocessing import MinMaxScaler
from common.utils import load_data, mape
```
2. 從 `/data/energy.csv` 文件中加載數據到 Pandas dataframe並查看數據[ ^2]
```python
energy = load_data('../../data')[['load']]
```
3. 繪製 2012 年 1 月至 2014 年 12 月的所有能源數據:[ ^2]
```python
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
```
![完整數據](../../../../7-TimeSeries/3-SVR/images/full-data.png)
現在,讓我們建立 SVR 模型。
### 創建訓練和測試數據集
現在數據已加載,你可以將其分為訓練集和測試集。接著,你需要重塑數據以創建基於時間步長的數據集,這是 SVR 所需的。你將在訓練集上訓練模型。模型訓練完成後,你將在訓練集、測試集以及完整數據集上評估其準確性,以查看整體性能。需要確保測試集涵蓋訓練集之後的時間段,以避免模型從未來時間段中獲取信息 [^2](這種情況稱為*過擬合*)。
1. 將 2014 年 9 月 1 日至 10 月 31 日的兩個月分配給訓練集。測試集將包括 2014 年 11 月 1 日至 12 月 31 日的兩個月:[ ^2]
```python
train_start_dt = '2014-11-01 00:00:00'
test_start_dt = '2014-12-30 00:00:00'
```
2. 可視化差異:[ ^2]
```python
energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)][['load']].rename(columns={'load':'train'}) \
.join(energy[test_start_dt:][['load']].rename(columns={'load':'test'}), how='outer') \
.plot(y=['train', 'test'], figsize=(15, 8), fontsize=12)
plt.xlabel('timestamp', fontsize=12)
plt.ylabel('load', fontsize=12)
plt.show()
```
![訓練和測試數據](../../../../7-TimeSeries/3-SVR/images/train-test.png)
### 為訓練準備數據
現在,你需要通過篩選和縮放數據來準備訓練數據。篩選數據集以僅包含所需的時間段和列,並縮放數據以確保其投影在 0 到 1 的區間內。
1. 篩選原始數據集以僅包含上述時間段的數據集,以及僅包含所需的列 'load' 和日期:[ ^2]
```python
train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']]
test = energy.copy()[energy.index >= test_start_dt][['load']]
print('Training data shape: ', train.shape)
print('Test data shape: ', test.shape)
```
```output
Training data shape: (1416, 1)
Test data shape: (48, 1)
```
2. 將訓練數據縮放到範圍 (0, 1)[ ^2]
```python
scaler = MinMaxScaler()
train['load'] = scaler.fit_transform(train)
```
4. 現在,縮放測試數據:[ ^2]
```python
test['load'] = scaler.transform(test)
```
### 創建基於時間步長的數據 [^1]
對於 SVR你需要將輸入數據轉換為 `[batch, timesteps]` 的形式。因此,你需要重塑現有的 `train_data``test_data`,以便新增一個表示時間步長的維度。
```python
# Converting to numpy arrays
train_data = train.values
test_data = test.values
```
在此示例中,我們設置 `timesteps = 5`。因此,模型的輸入是前 4 個時間步長的數據,輸出是第 5 個時間步長的數據。
```python
timesteps=5
```
使用嵌套列表推導將訓練數據轉換為 2D 張量:
```python
train_data_timesteps=np.array([[j for j in train_data[i:i+timesteps]] for i in range(0,len(train_data)-timesteps+1)])[:,:,0]
train_data_timesteps.shape
```
```output
(1412, 5)
```
將測試數據轉換為 2D 張量:
```python
test_data_timesteps=np.array([[j for j in test_data[i:i+timesteps]] for i in range(0,len(test_data)-timesteps+1)])[:,:,0]
test_data_timesteps.shape
```
```output
(44, 5)
```
選擇訓練和測試數據的輸入和輸出:
```python
x_train, y_train = train_data_timesteps[:,:timesteps-1],train_data_timesteps[:,[timesteps-1]]
x_test, y_test = test_data_timesteps[:,:timesteps-1],test_data_timesteps[:,[timesteps-1]]
print(x_train.shape, y_train.shape)
print(x_test.shape, y_test.shape)
```
```output
(1412, 4) (1412, 1)
(44, 4) (44, 1)
```
### 實現 SVR [^1]
現在是時候實現 SVR 了。要了解更多有關此實現的資訊,你可以參考[此文檔](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVR.html)。在我們的實現中,我們遵循以下步驟:
1. 通過調用 `SVR()` 並傳入模型超參數kernel、gamma、c 和 epsilon 來定義模型
2. 通過調用 `fit()` 函數準備訓練數據的模型
3. 通過調用 `predict()` 函數進行預測
現在我們創建一個 SVR 模型。在此,我們使用 [RBF 核函數](https://scikit-learn.org/stable/modules/svm.html#parameters-of-the-rbf-kernel),並將超參數 gamma、C 和 epsilon 分別設置為 0.5、10 和 0.05。
```python
model = SVR(kernel='rbf',gamma=0.5, C=10, epsilon = 0.05)
```
#### 在訓練數據上擬合模型 [^1]
```python
model.fit(x_train, y_train[:,0])
```
```output
SVR(C=10, cache_size=200, coef0=0.0, degree=3, epsilon=0.05, gamma=0.5,
kernel='rbf', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
```
#### 進行模型預測 [^1]
```python
y_train_pred = model.predict(x_train).reshape(-1,1)
y_test_pred = model.predict(x_test).reshape(-1,1)
print(y_train_pred.shape, y_test_pred.shape)
```
```output
(1412, 1) (44, 1)
```
你已經建立了 SVR現在我們需要評估它。
### 評估你的模型 [^1]
為了評估,首先我們需要將數據縮放回原始比例。然後,為了檢查性能,我們將繪製原始和預測的時間序列圖,並打印 MAPE 結果。
將預測和原始輸出縮放回原始比例:
```python
# Scaling the predictions
y_train_pred = scaler.inverse_transform(y_train_pred)
y_test_pred = scaler.inverse_transform(y_test_pred)
print(len(y_train_pred), len(y_test_pred))
```
```python
# Scaling the original values
y_train = scaler.inverse_transform(y_train)
y_test = scaler.inverse_transform(y_test)
print(len(y_train), len(y_test))
```
#### 檢查模型在訓練和測試數據上的性能 [^1]
我們從數據集中提取時間戳,以顯示在圖表的 x 軸上。注意,我們使用前 ```timesteps-1``` 個值作為第一個輸出的輸入,因此輸出的時間戳將從那之後開始。
```python
train_timestamps = energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)].index[timesteps-1:]
test_timestamps = energy[test_start_dt:].index[timesteps-1:]
print(len(train_timestamps), len(test_timestamps))
```
```output
1412 44
```
繪製訓練數據的預測:
```python
plt.figure(figsize=(25,6))
plt.plot(train_timestamps, y_train, color = 'red', linewidth=2.0, alpha = 0.6)
plt.plot(train_timestamps, y_train_pred, color = 'blue', linewidth=0.8)
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.title("Training data prediction")
plt.show()
```
![訓練數據預測](../../../../7-TimeSeries/3-SVR/images/train-data-predict.png)
打印訓練數據的 MAPE
```python
print('MAPE for training data: ', mape(y_train_pred, y_train)*100, '%')
```
```output
MAPE for training data: 1.7195710200875551 %
```
繪製測試數據的預測:
```python
plt.figure(figsize=(10,3))
plt.plot(test_timestamps, y_test, color = 'red', linewidth=2.0, alpha = 0.6)
plt.plot(test_timestamps, y_test_pred, color = 'blue', linewidth=0.8)
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.show()
```
![測試數據預測](../../../../7-TimeSeries/3-SVR/images/test-data-predict.png)
打印測試數據的 MAPE
```python
print('MAPE for testing data: ', mape(y_test_pred, y_test)*100, '%')
```
```output
MAPE for testing data: 1.2623790187854018 %
```
🏆 你在測試數據集上取得了非常好的結果!
### 檢查模型在完整數據集上的性能 [^1]
```python
# Extracting load values as numpy array
data = energy.copy().values
# Scaling
data = scaler.transform(data)
# Transforming to 2D tensor as per model input requirement
data_timesteps=np.array([[j for j in data[i:i+timesteps]] for i in range(0,len(data)-timesteps+1)])[:,:,0]
print("Tensor shape: ", data_timesteps.shape)
# Selecting inputs and outputs from data
X, Y = data_timesteps[:,:timesteps-1],data_timesteps[:,[timesteps-1]]
print("X shape: ", X.shape,"\nY shape: ", Y.shape)
```
```output
Tensor shape: (26300, 5)
X shape: (26300, 4)
Y shape: (26300, 1)
```
```python
# Make model predictions
Y_pred = model.predict(X).reshape(-1,1)
# Inverse scale and reshape
Y_pred = scaler.inverse_transform(Y_pred)
Y = scaler.inverse_transform(Y)
```
```python
plt.figure(figsize=(30,8))
plt.plot(Y, color = 'red', linewidth=2.0, alpha = 0.6)
plt.plot(Y_pred, color = 'blue', linewidth=0.8)
plt.legend(['Actual','Predicted'])
plt.xlabel('Timestamp')
plt.show()
```
![完整數據預測](../../../../7-TimeSeries/3-SVR/images/full-data-predict.png)
```python
print('MAPE: ', mape(Y_pred, Y)*100, '%')
```
```output
MAPE: 2.0572089029888656 %
```
🏆 非常棒的圖表,顯示了一個具有良好準確性的模型。做得好!
---
## 🚀挑戰
- 嘗試在創建模型時調整超參數gamma、C、epsilon並在數據上進行評估以查看哪組超參數在測試數據上表現最佳。要了解更多關於這些超參數的資訊你可以參考[此文檔](https://scikit-learn.org/stable/modules/svm.html#parameters-of-the-rbf-kernel)。
- 嘗試為模型使用不同的核函數,並分析它們在數據集上的性能。一份有用的文檔可以在[這裡](https://scikit-learn.org/stable/modules/svm.html#kernel-functions)找到。
- 嘗試為模型使用不同的 `timesteps` 值,讓模型回顧以進行預測。
## [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
## 回顧與自學
本課旨在介紹 SVR 在時間序列預測中的應用。要了解更多關於 SVR 的資訊,你可以參考[這篇博客](https://www.analyticsvidhya.com/blog/2020/03/support-vector-regression-tutorial-for-machine-learning/)。此[scikit-learn 文檔](https://scikit-learn.org/stable/modules/svm.html)提供了更全面的解釋,包括 SVM 的一般概念、[SVR](https://scikit-learn.org/stable/modules/svm.html#regression),以及其他實現細節,例如可以使用的不同[核函數](https://scikit-learn.org/stable/modules/svm.html#kernel-functions)及其參數。
## 作業
[一個新的 SVR 模型](assignment.md)
## 致謝
[^1]: 本節中的文字、代碼和輸出由 [@AnirbanMukherjeeXD](https://github.com/AnirbanMukherjeeXD) 貢獻
[^2]: 本節中的文字、代碼和輸出取自 [ARIMA](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/2-ARIMA)
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,20 @@
# 一個新的 SVR 模型
## 說明 [^1]
現在您已經建立了一個 SVR 模型,請使用新的數據集建立一個新的模型(可以嘗試使用[這些來自杜克大學的數據集](http://www2.stat.duke.edu/~mw/ts_data_sets.html))。在筆記本中註解您的工作,將數據和模型可視化,並使用適當的圖表和 MAPE 測試其準確性。同時嘗試調整不同的超參數,並嘗試使用不同的時間步長值。
## 評分標準 [^1]
| 評分標準 | 優秀 | 合格 | 需要改進 |
| -------- | ----------------------------------------------------------- | --------------------------------------------------------- | ----------------------------------- |
| | 提供了一個包含 SVR 模型的筆記本,模型已建立、測試並通過可視化進行解釋,且準確性已說明。 | 提供的筆記本未註解或包含錯誤。 | 提供了一個不完整的筆記本。 |
[^1]:本節中的文字基於[ARIMA 的作業](https://github.com/microsoft/ML-For-Beginners/tree/main/7-TimeSeries/2-ARIMA/assignment.md)
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

File diff suppressed because one or more lines are too long

@ -0,0 +1,699 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "fv9OoQsMFk5A"
},
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在本筆記中,我們將展示如何:\n",
"\n",
"- 準備二維時間序列數據以訓練 SVM 回歸模型\n",
"- 使用 RBF 核實現 SVR\n",
"- 通過圖表和 MAPE 評估模型\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 匯入模組\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"sys.path.append('../../')"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"id": "M687KNlQFp0-"
},
"outputs": [],
"source": [
"import os\n",
"import warnings\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import pandas as pd\n",
"import datetime as dt\n",
"import math\n",
"\n",
"from sklearn.svm import SVR\n",
"from sklearn.preprocessing import MinMaxScaler\n",
"from common.utils import load_data, mape"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Cj-kfVdMGjWP"
},
"source": [
"## 準備資料\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "8fywSjC6GsRz"
},
"source": [
"### 加載數據\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 363
},
"id": "aBDkEB11Fumg",
"outputId": "99cf7987-0509-4b73-8cc2-75d7da0d2740"
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>load</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>2012-01-01 00:00:00</th>\n",
" <td>2698.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2012-01-01 01:00:00</th>\n",
" <td>2558.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2012-01-01 02:00:00</th>\n",
" <td>2444.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2012-01-01 03:00:00</th>\n",
" <td>2402.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2012-01-01 04:00:00</th>\n",
" <td>2403.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" load\n",
"2012-01-01 00:00:00 2698.0\n",
"2012-01-01 01:00:00 2558.0\n",
"2012-01-01 02:00:00 2444.0\n",
"2012-01-01 03:00:00 2402.0\n",
"2012-01-01 04:00:00 2403.0"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"energy = load_data('../../data')[['load']]\n",
"energy.head(5)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "O0BWP13rGnh4"
},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 486
},
"id": "hGaNPKu_Gidk",
"outputId": "7f89b326-9057-4f49-efbe-cb100ebdf76d"
},
"outputs": [],
"source": [
"energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)\n",
"plt.xlabel('timestamp', fontsize=12)\n",
"plt.ylabel('load', fontsize=12)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "IPuNor4eGwYY"
},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ysvsNyONGt0Q"
},
"outputs": [],
"source": [
"train_start_dt = '2014-11-01 00:00:00'\n",
"test_start_dt = '2014-12-30 00:00:00'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 548
},
"id": "SsfdLoPyGy9w",
"outputId": "d6d6c25b-b1f4-47e5-91d1-707e043237d7"
},
"outputs": [],
"source": [
"energy[(energy.index < test_start_dt) & (energy.index >= train_start_dt)][['load']].rename(columns={'load':'train'}) \\\n",
" .join(energy[test_start_dt:][['load']].rename(columns={'load':'test'}), how='outer') \\\n",
" .plot(y=['train', 'test'], figsize=(15, 8), fontsize=12)\n",
"plt.xlabel('timestamp', fontsize=12)\n",
"plt.ylabel('load', fontsize=12)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "XbFTqBw6G1Ch"
},
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"現在,您需要通過過濾和縮放數據來準備訓練所需的數據。\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "cYivRdQpHDj3",
"outputId": "a138f746-461c-4fd6-bfa6-0cee094c4aa1"
},
"outputs": [],
"source": [
"train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']]\n",
"test = energy.copy()[energy.index >= test_start_dt][['load']]\n",
"\n",
"print('Training data shape: ', train.shape)\n",
"print('Test data shape: ', test.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"將數據縮放至範圍 (0, 1)。\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 363
},
"id": "3DNntGQnZX8G",
"outputId": "210046bc-7a66-4ccd-d70d-aa4a7309949c"
},
"outputs": [],
"source": [
"scaler = MinMaxScaler()\n",
"train['load'] = scaler.fit_transform(train)\n",
"train.head(5)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 206
},
"id": "26Yht-rzZexe",
"outputId": "20326077-a38a-4e78-cc5b-6fd7af95d301"
},
"outputs": [],
"source": [
"test['load'] = scaler.transform(test)\n",
"test.head(5)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "x0n6jqxOQ41Z"
},
"source": [
"### 使用時間步驟創建數據\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "fdmxTZtOQ8xs"
},
"source": [
"對於我們的 SVR我們將輸入數據轉換為 `[batch, timesteps]` 的形式。因此,我們重新調整現有的 `train_data` 和 `test_data`,使其具有一個新的維度,該維度表示時間步。在我們的例子中,我們取 `timesteps = 5`。因此,模型的輸入是前 4 個時間步的數據,輸出將是第 5 個時間步的數據。\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "Rpju-Sc2HFm0"
},
"outputs": [],
"source": [
"# Converting to numpy arrays\n",
"\n",
"train_data = train.values\n",
"test_data = test.values"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Selecting the timesteps\n",
"\n",
"timesteps=None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "O-JrsrsVJhUQ",
"outputId": "c90dbe71-bacc-4ec4-b452-f82fe5aefaef"
},
"outputs": [],
"source": [
"# Converting data to 2D tensor\n",
"\n",
"train_data_timesteps=None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "exJD8AI7KE4g",
"outputId": "ce90260c-f327-427d-80f2-77307b5a6318"
},
"outputs": [],
"source": [
"# Converting test data to 2D tensor\n",
"\n",
"test_data_timesteps=None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2u0R2sIsLuq5"
},
"outputs": [],
"source": [
"x_train, y_train = None\n",
"x_test, y_test = None\n",
"\n",
"print(x_train.shape, y_train.shape)\n",
"print(x_test.shape, y_test.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "8wIPOtAGLZlh"
},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "EhA403BEPEiD"
},
"outputs": [],
"source": [
"# Create model using RBF kernel\n",
"\n",
"model = None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "GS0UA3csMbqp",
"outputId": "d86b6f05-5742-4c1d-c2db-c40510bd4f0d"
},
"outputs": [],
"source": [
"# Fit model on training data"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Rz_x8S3UrlcF"
},
"source": [
"### 建立模型預測\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "XR0gnt3MnuYS",
"outputId": "157e40ab-9a23-4b66-a885-0d52a24b2364"
},
"outputs": [],
"source": [
"# Making predictions\n",
"\n",
"y_train_pred = None\n",
"y_test_pred = None"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "_2epncg-SGzr"
},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Scaling the predictions\n",
"\n",
"y_train_pred = scaler.inverse_transform(y_train_pred)\n",
"y_test_pred = scaler.inverse_transform(y_test_pred)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "xmm_YLXhq7gV",
"outputId": "18392f64-4029-49ac-c71a-a4e2411152a1"
},
"outputs": [],
"source": [
"# Scaling the original values\n",
"\n",
"y_train = scaler.inverse_transform(y_train)\n",
"y_test = scaler.inverse_transform(y_test)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "u3LBj93coHEi",
"outputId": "d4fd49e8-8c6e-4bb0-8ef9-ca0b26d725b4"
},
"outputs": [],
"source": [
"# Extract the timesteps for x-axis\n",
"\n",
"train_timestamps = None\n",
"test_timestamps = None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(25,6))\n",
"# plot original output\n",
"# plot predicted output\n",
"plt.legend(['Actual','Predicted'])\n",
"plt.xlabel('Timestamp')\n",
"plt.title(\"Training data prediction\")\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "LnhzcnYtXHCm",
"outputId": "f5f0d711-f18b-4788-ad21-d4470ea2c02b"
},
"outputs": [],
"source": [
"print('MAPE for training data: ', mape(y_train_pred, y_train)*100, '%')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 225
},
"id": "53Q02FoqQH4V",
"outputId": "53e2d59b-5075-4765-ad9e-aed56c966583"
},
"outputs": [],
"source": [
"plt.figure(figsize=(10,3))\n",
"# plot original output\n",
"# plot predicted output\n",
"plt.legend(['Actual','Predicted'])\n",
"plt.xlabel('Timestamp')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "clOAUH-SXCJG",
"outputId": "a3aa85ff-126a-4a4a-cd9e-90b9cc465ef5"
},
"outputs": [],
"source": [
"print('MAPE for testing data: ', mape(y_test_pred, y_test)*100, '%')"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "DHlKvVCId5ue"
},
"source": [
"## 全數據集預測\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "cOFJ45vreO0N",
"outputId": "35628e33-ecf9-4966-8036-f7ea86db6f16"
},
"outputs": [],
"source": [
"# Extracting load values as numpy array\n",
"data = None\n",
"\n",
"# Scaling\n",
"data = None\n",
"\n",
"# Transforming to 2D tensor as per model input requirement\n",
"data_timesteps=None\n",
"\n",
"# Selecting inputs and outputs from data\n",
"X, Y = None, None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "ESSAdQgwexIi"
},
"outputs": [],
"source": [
"# Make model predictions\n",
"\n",
"# Inverse scale and reshape\n",
"Y_pred = None\n",
"Y = None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 328
},
"id": "M_qhihN0RVVX",
"outputId": "a89cb23e-1d35-437f-9d63-8b8907e12f80"
},
"outputs": [],
"source": [
"plt.figure(figsize=(30,8))\n",
"# plot original output\n",
"# plot predicted output\n",
"plt.legend(['Actual','Predicted'])\n",
"plt.xlabel('Timestamp')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "AcN7pMYXVGTK",
"outputId": "7e1c2161-47ce-496c-9d86-7ad9ae0df770"
},
"outputs": [],
"source": [
"print('MAPE: ', mape(Y_pred, Y)*100, '%')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**免責聲明** \n本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始語言的文件應被視為權威來源。對於關鍵信息,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤釋不承擔責任。\n"
]
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"collapsed_sections": [],
"name": "Recurrent_Neural_Networks.ipynb",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.1"
},
"coopTranslator": {
"original_hash": "e86ce102239a14c44585623b9b924a74",
"translation_date": "2025-09-03T20:01:36+00:00",
"source_file": "7-TimeSeries/3-SVR/working/notebook.ipynb",
"language_code": "tw"
}
},
"nbformat": 4,
"nbformat_minor": 1
}

@ -0,0 +1,28 @@
# 時間序列預測介紹
什麼是時間序列預測?它是通過分析過去的趨勢來預測未來事件。
## 地區主題:全球電力使用 ✨
在這兩節課中,您將了解時間序列預測,這是一個相對較少被人熟知但在工業和商業應用等領域中極具價值的機器學習領域。雖然神經網絡可以用來提升這些模型的效用,但我們將在經典機器學習的背景下研究它們,因為這些模型可以根據過去的表現來幫助預測未來。
我們的地區重點是全球的電力使用,這是一個有趣的數據集,可以用來學習如何根據過去的負載模式預測未來的電力使用。您可以看到這種預測在商業環境中是多麼有幫助。
![電力網](../../../translated_images/zh-TW/electric-grid.0c21d5214db09ffa.webp)
照片由 [Peddi Sai hrithik](https://unsplash.com/@shutter_log?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 拍攝,展示了拉賈斯坦邦道路上的電力塔,來自 [Unsplash](https://unsplash.com/s/photos/electric-india?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)
## 課程
1. [時間序列預測介紹](1-Introduction/README.md)
2. [構建 ARIMA 時間序列模型](2-ARIMA/README.md)
3. [構建支持向量回歸器進行時間序列預測](3-SVR/README.md)
## 致謝
"時間序列預測介紹" 由 [Francesca Lazzeri](https://twitter.com/frlazzeri) 和 [Jen Looper](https://twitter.com/jenlooper) ⚡️ 撰寫。這些筆記本最初出現在 [Azure "Deep Learning For Time Series" repo](https://github.com/Azure/DeepLearningForTimeSeriesForecasting),由 Francesca Lazzeri 原創撰寫。SVR 課程由 [Anirban Mukherjee](https://github.com/AnirbanMukherjeeXD) 撰寫。
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,247 @@
# 強化學習與 Q-Learning 簡介
![機器學習中強化學習的摘要示意圖](../../../../sketchnotes/ml-reinforcement.png)
> 示意圖由 [Tomomi Imura](https://www.twitter.com/girlie_mac) 提供
強化學習涉及三個重要概念代理agent、一些狀態states以及每個狀態的一組行動actions。通過在指定狀態下執行某個行動代理會獲得一個獎勵。想像一下電腦遊戲《超級瑪利歐》。你是瑪利歐處於遊戲關卡中站在懸崖邊上。你的上方有一枚金幣。你作為瑪利歐處於遊戲關卡中的特定位置……這就是你的狀態。向右移動一步行動會讓你掉下懸崖這會給你一個低的數值分數。然而按下跳躍按鈕可以讓你得分並保持存活。這是一個正面的結果應該給你一個正的數值分數。
通過使用強化學習和模擬器(遊戲),你可以學習如何玩遊戲以最大化獎勵,即保持存活並盡可能多地得分。
[![強化學習簡介](https://img.youtube.com/vi/lDq_en8RNOo/0.jpg)](https://www.youtube.com/watch?v=lDq_en8RNOo)
> 🎥 點擊上方圖片聽 Dmitry 討論強化學習
## [課前測驗](https://ff-quizzes.netlify.app/en/ml/)
## 前置條件與設置
在本課程中,我們將使用 Python 實驗一些代碼。你應該能夠在你的電腦或雲端運行本課程中的 Jupyter Notebook 代碼。
你可以打開[課程筆記本](https://github.com/microsoft/ML-For-Beginners/blob/main/8-Reinforcement/1-QLearning/notebook.ipynb),並按照課程步驟進行。
> **注意:** 如果你從雲端打開此代碼,你還需要獲取 [`rlboard.py`](https://github.com/microsoft/ML-For-Beginners/blob/main/8-Reinforcement/1-QLearning/rlboard.py) 文件,該文件在筆記本代碼中使用。將其添加到與筆記本相同的目錄中。
## 簡介
在本課程中,我們將探索 **[彼得與狼](https://en.wikipedia.org/wiki/Peter_and_the_Wolf)** 的世界,靈感來自俄羅斯作曲家 [Sergei Prokofiev](https://en.wikipedia.org/wiki/Sergei_Prokofiev) 的音樂童話。我們將使用 **強化學習** 讓彼得探索他的環境,收集美味的蘋果並避免遇到狼。
**強化學習**RL是一種學習技術通過多次實驗我們可以學習代理在某個**環境**中的最佳行為。代理在這個環境中應該有某些**目標**,由**獎勵函數**定義。
## 環境
為了簡化,我們將彼得的世界視為一個大小為 `width` x `height` 的方形棋盤,如下所示:
![彼得的環境](../../../../8-Reinforcement/1-QLearning/images/environment.png)
棋盤中的每個格子可以是:
* **地面**,彼得和其他生物可以在上面行走。
* **水域**,顯然不能行走。
* **樹**或**草地**,可以休息的地方。
* **蘋果**,彼得很高興找到的食物。
* **狼**,危險且應該避免。
有一個單獨的 Python 模塊 [`rlboard.py`](https://github.com/microsoft/ML-For-Beginners/blob/main/8-Reinforcement/1-QLearning/rlboard.py),包含與此環境交互的代碼。由於這些代碼對理解概念並不重要,我們將導入該模塊並使用它來創建示例棋盤(代碼塊 1
```python
from rlboard import *
width, height = 8,8
m = Board(width,height)
m.randomize(seed=13)
m.plot()
```
此代碼應該打印出類似於上方圖片的環境。
## 行動與策略
在我們的示例中,彼得的目標是找到蘋果,同時避免狼和其他障礙物。為此,他可以在棋盤上四處走動,直到找到蘋果。
因此,在任何位置,他可以選擇以下行動之一:向上、向下、向左和向右。
我們將這些行動定義為一個字典,並將它們映射到相應的坐標變化。例如,向右移動(`R`)對應於坐標對 `(1,0)`。(代碼塊 2
```python
actions = { "U" : (0,-1), "D" : (0,1), "L" : (-1,0), "R" : (1,0) }
action_idx = { a : i for i,a in enumerate(actions.keys()) }
```
總結一下,此場景的策略和目標如下:
- **策略**:我們的代理(彼得)的策略由所謂的**策略函數**policy定義。策略是一個函數能在任何給定狀態下返回行動。在我們的例子中問題的狀態由棋盤表示包括玩家的當前位置。
- **目標**:強化學習的目標是最終學習一個良好的策略,能有效地解決問題。然而,作為基線,我們先考慮最簡單的策略,稱為**隨機行走**。
## 隨機行走
首先,我們通過實現隨機行走策略來解決問題。在隨機行走中,我們將隨機選擇下一個行動,直到到達蘋果(代碼塊 3
1. 使用以下代碼實現隨機行走:
```python
def random_policy(m):
return random.choice(list(actions))
def walk(m,policy,start_position=None):
n = 0 # number of steps
# set initial position
if start_position:
m.human = start_position
else:
m.random_start()
while True:
if m.at() == Board.Cell.apple:
return n # success!
if m.at() in [Board.Cell.wolf, Board.Cell.water]:
return -1 # eaten by wolf or drowned
while True:
a = actions[policy(m)]
new_pos = m.move_pos(m.human,a)
if m.is_valid(new_pos) and m.at(new_pos)!=Board.Cell.water:
m.move(a) # do the actual move
break
n+=1
walk(m,random_policy)
```
調用 `walk` 應返回相應路徑的長度,該長度可能因每次運行而異。
1. 多次運行行走實驗例如100 次),並打印結果統計數據(代碼塊 4
```python
def print_statistics(policy):
s,w,n = 0,0,0
for _ in range(100):
z = walk(m,policy)
if z<0:
w+=1
else:
s += z
n += 1
print(f"Average path length = {s/n}, eaten by wolf: {w} times")
print_statistics(random_policy)
```
注意,路徑的平均長度約為 30-40 步,這相當多,考慮到到最近蘋果的平均距離約為 5-6 步。
你還可以看到彼得在隨機行走中的移動情況:
![彼得的隨機行走](../../../../8-Reinforcement/1-QLearning/images/random_walk.gif)
## 獎勵函數
為了讓我們的策略更智能,我們需要了解哪些移動比其他移動更“好”。為此,我們需要定義目標。
目標可以通過**獎勵函數**定義,該函數會為每個狀態返回一些分數值。數值越高,獎勵函數越好。(代碼塊 5
```python
move_reward = -0.1
goal_reward = 10
end_reward = -10
def reward(m,pos=None):
pos = pos or m.human
if not m.is_valid(pos):
return end_reward
x = m.at(pos)
if x==Board.Cell.water or x == Board.Cell.wolf:
return end_reward
if x==Board.Cell.apple:
return goal_reward
return move_reward
```
獎勵函數的一個有趣之處在於,大多數情況下,*只有在遊戲結束時才會給出實質性獎勵*。這意味著我們的算法應該以某種方式記住導致正面獎勵的“好”步驟,並增加它們的重要性。同樣,所有導致不良結果的移動應該被抑制。
## Q-Learning
我們將討論的算法稱為 **Q-Learning**。在此算法中,策略由一個函數(或數據結構)定義,稱為 **Q-Table**。它記錄了在給定狀態下每個行動的“好壞程度”。
之所以稱為 Q-Table是因為將其表示為表格或多維數組通常很方便。由於我們的棋盤尺寸為 `width` x `height`,我們可以使用形狀為 `width` x `height` x `len(actions)` 的 numpy 數組來表示 Q-Table代碼塊 6
```python
Q = np.ones((width,height,len(actions)),dtype=np.float)*1.0/len(actions)
```
注意,我們將 Q-Table 的所有值初始化為相等值,在我們的例子中是 0.25。這對應於“隨機行走”策略,因為每個狀態中的所有移動都是同樣好的。我們可以將 Q-Table 傳遞給 `plot` 函數,以便在棋盤上可視化該表:`m.plot(Q)`。
![彼得的環境](../../../../8-Reinforcement/1-QLearning/images/env_init.png)
在每個格子的中心有一個“箭頭”,指示移動的首選方向。由於所有方向都是相等的,因此顯示為一個點。
現在我們需要運行模擬,探索環境,並學習更好的 Q-Table 值分佈,這將使我們更快地找到蘋果的路徑。
## Q-Learning 的核心:貝爾曼方程
一旦我們開始移動,每個行動都會有相應的獎勵,即我們理論上可以根據最高的即時獎勵選擇下一個行動。然而,在大多數狀態下,移動並不會實現我們到達蘋果的目標,因此我們無法立即決定哪個方向更好。
> 記住,重要的不是即時結果,而是最終結果,即我們在模擬結束時獲得的結果。
為了考慮這種延遲獎勵,我們需要使用**[動態規劃](https://en.wikipedia.org/wiki/Dynamic_programming)**的原則,這使我們能以遞歸方式思考問題。
假設我們現在處於狀態 *s*,並希望移動到下一個狀態 *s'*。通過這樣做,我們將獲得由獎勵函數定義的即時獎勵 *r(s,a)*,加上一些未來的獎勵。如果我們假設 Q-Table 正確反映了每個行動的“吸引力”,那麼在狀態 *s'* 我們將選擇對應於最大值 *Q(s',a')* 的行動 *a'*。因此,我們在狀態 *s* 能夠獲得的最佳未來獎勵將定義為 `max`
## 檢查政策
由於 Q-Table 列出了每個狀態下每個行動的「吸引力」,因此使用它來定義我們世界中的高效導航非常簡單。在最簡單的情況下,我們可以選擇對應於最高 Q-Table 值的行動:(程式碼區塊 9
```python
def qpolicy_strict(m):
x,y = m.human
v = probs(Q[x,y])
a = list(actions)[np.argmax(v)]
return a
walk(m,qpolicy_strict)
```
> 如果多次嘗試上述程式碼,您可能會注意到有時它會「卡住」,需要按下筆記本中的 STOP 按鈕來中斷執行。這是因為可能存在某些情況,兩個狀態在最佳 Q-Value 上「指向」彼此,導致代理無限地在這些狀態之間移動。
## 🚀挑戰
> **任務 1** 修改 `walk` 函數以限制路徑的最大長度為一定步數(例如 100並觀察上述程式碼有時會返回此值。
> **任務 2** 修改 `walk` 函數,使其不會回到之前已經到過的地方。這將防止 `walk` 進入循環,但代理仍可能被「困」在無法逃脫的位置。
## 導航
更好的導航政策是我們在訓練期間使用的政策,它結合了利用和探索。在此政策中,我們將以一定的概率選擇每個行動,該概率與 Q-Table 中的值成比例。此策略可能仍會導致代理返回到已探索過的位置,但正如您從以下程式碼中看到的,它會導致到達目標位置的平均路徑非常短(請記住,`print_statistics` 會模擬 100 次):(程式碼區塊 10
```python
def qpolicy(m):
x,y = m.human
v = probs(Q[x,y])
a = random.choices(list(actions),weights=v)[0]
return a
print_statistics(qpolicy)
```
執行此程式碼後,您應該會得到比之前更短的平均路徑長度,範圍約為 3-6。
## 探索學習過程
如我們所提到的,學習過程是在探索和利用已獲得的問題空間結構知識之間取得平衡。我們已經看到學習的結果(幫助代理找到通往目標的短路徑的能力)有所改善,但觀察平均路徑長度在學習過程中的變化也很有趣:
學習過程可以總結如下:
- **平均路徑長度增加**。我們在這裡看到的是,起初平均路徑長度增加。這可能是因為當我們對環境一無所知時,很容易陷入不良狀態,例如水或狼。隨著我們學到更多並開始使用這些知識,我們可以更長時間地探索環境,但仍然不太清楚蘋果的位置。
- **隨著學習的深入,路徑長度減少**。一旦我們學到足夠的知識,代理更容易達成目標,路徑長度開始減少。然而,我們仍然保持探索的開放性,因此經常偏離最佳路徑,探索新的選項,導致路徑比最佳路徑更長。
- **路徑長度突然增加**。我們在圖表上還觀察到某些時候路徑長度突然增加。這表明過程的隨機性,並且我們可能在某些時候通過覆寫新值「破壞」了 Q-Table 的係數。理想情況下,這應該通過降低學習率來最小化(例如,在訓練結束時,我們僅以小值調整 Q-Table 的值)。
總體而言,重要的是要記住,學習過程的成功和質量在很大程度上取決於參數,例如學習率、學習率衰減和折扣因子。這些通常被稱為 **超參數**,以區別於 **參數**,後者是在訓練期間優化的(例如 Q-Table 的係數)。尋找最佳超參數值的過程稱為 **超參數優化**,這是一個值得單獨討論的主題。
## [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
## 作業
[更真實的世界](assignment.md)
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,32 @@
# 一個更真實的世界
在我們的情境中,彼得幾乎可以毫不疲倦或飢餓地四處移動。在一個更真實的世界裡,他需要不時地坐下來休息,還需要進食。我們來讓這個世界更貼近現實,通過實現以下規則:
1. 每次從一個地方移動到另一個地方,彼得會損失一些**能量**並增加一些**疲勞**。
2. 彼得可以通過吃蘋果來獲得更多能量。
3. 彼得可以通過在樹下或草地上休息來消除疲勞(例如,走到有樹或草地的棋盤位置——綠色區域)。
4. 彼得需要找到並擊敗狼。
5. 為了擊敗狼,彼得需要達到一定的能量和疲勞水平,否則他會輸掉戰鬥。
## 指導說明
使用原始的 [notebook.ipynb](notebook.ipynb) 筆記本作為解決方案的起點。
根據遊戲規則修改上述的獎勵函數,運行強化學習算法以學習贏得遊戲的最佳策略,並將隨機漫步的結果與你的算法進行比較,從而分析贏得和輸掉的遊戲數量。
> **Note**: 在你的新世界中,狀態會更加複雜,除了人類的位置,還包括疲勞和能量水平。你可以選擇將狀態表示為一個元組 (Board, energy, fatigue),或者為狀態定義一個類(你也可以考慮從 `Board` 繼承),甚至修改原始的 `Board` 類(位於 [rlboard.py](../../../../8-Reinforcement/1-QLearning/rlboard.py) 中)。
在你的解決方案中,請保留負責隨機漫步策略的代碼,並在最後將你的算法結果與隨機漫步進行比較。
> **Note**: 你可能需要調整超參數以使其正常運行,特別是訓練的迭代次數。由於遊戲的成功(例如擊敗狼)是一個罕見事件,你可以預期訓練時間會更長。
## 評分標準
| 評分標準 | 優秀 | 合格 | 需要改進 |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| | 筆記本展示了新世界規則的定義、Q-Learning 算法以及一些文字說明。Q-Learning 能夠顯著改善與隨機漫步相比的結果。 | 筆記本展示了 Q-Learning 的實現,並且結果相比隨機漫步有所改善,但不顯著;或者筆記本文檔不完整,代碼結構不佳。 | 嘗試重新定義世界規則,但 Q-Learning 算法無法正常運行,或者獎勵函數未完全定義。 |
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解釋不承擔責任。

File diff suppressed because one or more lines are too long

@ -0,0 +1,6 @@
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,6 @@
這是一個臨時佔位符
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,342 @@
# CartPole 滑行
在上一課中我們解決的問題可能看起來像是一個玩具問題,似乎與現實生活場景無關。但事實並非如此,因為許多現實世界的問題也具有類似的情境——包括下棋或圍棋。它們是相似的,因為我們也有一個具有特定規則的棋盤和一個**離散狀態**。
## [課前測驗](https://ff-quizzes.netlify.app/en/ml/)
## 簡介
在本課中,我們將把 Q-Learning 的相同原則應用於具有**連續狀態**的問題,也就是由一個或多個實數表示的狀態。我們將處理以下問題:
> **問題**:如果彼得想要逃離狼的追捕,他需要能夠移動得更快。我們將看看彼得如何學會滑行,特別是通過 Q-Learning 學會保持平衡。
![大逃亡!](../../../../8-Reinforcement/2-Gym/images/escape.png)
> 彼得和他的朋友們發揮創意來逃離狼的追捕!圖片由 [Jen Looper](https://twitter.com/jenlooper) 提供
我們將使用一個簡化的平衡問題,稱為 **CartPole** 問題。在 CartPole 世界中,我們有一個可以左右移動的水平滑塊,目標是讓滑塊上的垂直桿保持平衡。
## 前置知識
在本課中,我們將使用一個名為 **OpenAI Gym** 的庫來模擬不同的**環境**。你可以在本地運行本課的代碼(例如,通過 Visual Studio Code此時模擬將在新窗口中打開。如果在線運行代碼可能需要對代碼進行一些調整具體請參考[這裡](https://towardsdatascience.com/rendering-openai-gym-envs-on-binder-and-google-colab-536f99391cc7)。
## OpenAI Gym
在上一課中,遊戲的規則和狀態由我們自己定義的 `Board` 類提供。在這裡,我們將使用一個特殊的**模擬環境**,它將模擬平衡桿背後的物理原理。最受歡迎的用於訓練強化學習算法的模擬環境之一是 [Gym](https://gym.openai.com/),由 [OpenAI](https://openai.com/) 維護。通過使用這個 Gym我們可以創建從 CartPole 模擬到 Atari 遊戲的不同**環境**。
> **注意**:你可以在 [這裡](https://gym.openai.com/envs/#classic_control) 查看 OpenAI Gym 提供的其他環境。
首先,讓我們安裝 Gym 並導入所需的庫(代碼塊 1
```python
import sys
!{sys.executable} -m pip install gym
import gym
import matplotlib.pyplot as plt
import numpy as np
import random
```
## 練習 - 初始化一個 CartPole 環境
為了處理 CartPole 平衡問題,我們需要初始化相應的環境。每個環境都與以下內容相關聯:
- **觀察空間**:定義我們從環境中接收到的信息結構。對於 CartPole 問題,我們接收到桿的位置、速度以及其他一些值。
- **行動空間**:定義可能的行動。在我們的情況下,行動空間是離散的,包括兩個行動——**左**和**右**。(代碼塊 2
1. 要初始化,輸入以下代碼:
```python
env = gym.make("CartPole-v1")
print(env.action_space)
print(env.observation_space)
print(env.action_space.sample())
```
為了了解環境如何運作,讓我們運行一個 100 步的簡短模擬。在每一步中,我們提供一個行動——在這個模擬中,我們只是隨機從 `action_space` 中選擇一個行動。
1. 運行以下代碼,看看會產生什麼結果。
✅ 請記住,建議在本地 Python 安裝中運行此代碼!(代碼塊 3
```python
env.reset()
for i in range(100):
env.render()
env.step(env.action_space.sample())
env.close()
```
你應該會看到類似於以下圖片的內容:
![未平衡的 CartPole](../../../../8-Reinforcement/2-Gym/images/cartpole-nobalance.gif)
1. 在模擬過程中,我們需要獲取觀察值以決定如何行動。事實上,`step` 函數返回當前的觀察值、一個獎勵函數,以及一個表示是否應繼續模擬的 `done` 標誌:(代碼塊 4
```python
env.reset()
done = False
while not done:
env.render()
obs, rew, done, info = env.step(env.action_space.sample())
print(f"{obs} -> {rew}")
env.close()
```
你最終會在筆記本輸出中看到類似以下的內容:
```text
[ 0.03403272 -0.24301182 0.02669811 0.2895829 ] -> 1.0
[ 0.02917248 -0.04828055 0.03248977 0.00543839] -> 1.0
[ 0.02820687 0.14636075 0.03259854 -0.27681916] -> 1.0
[ 0.03113408 0.34100283 0.02706215 -0.55904489] -> 1.0
[ 0.03795414 0.53573468 0.01588125 -0.84308041] -> 1.0
...
[ 0.17299878 0.15868546 -0.20754175 -0.55975453] -> 1.0
[ 0.17617249 0.35602306 -0.21873684 -0.90998894] -> 1.0
```
在模擬的每一步中返回的觀察向量包含以下值:
- 小車的位置
- 小車的速度
- 桿的角度
- 桿的旋轉速率
1. 獲取這些數字的最小值和最大值:(代碼塊 5
```python
print(env.observation_space.low)
print(env.observation_space.high)
```
你可能還會注意到,在每次模擬步驟中,獎勵值始終為 1。這是因為我們的目標是生存得越久越好也就是說讓桿在最長時間內保持在合理的垂直位置。
✅ 實際上,如果我們能在 100 次連續試驗中獲得平均獎勵 195則認為 CartPole 模擬已經解決。
## 狀態離散化
在 Q-Learning 中,我們需要構建 Q-表,定義在每個狀態下該做什麼。為了做到這一點,我們需要讓狀態是**離散的**,更準確地說,它應該包含有限數量的離散值。因此,我們需要以某種方式**離散化**我們的觀察值,將它們映射到有限的狀態集合。
有幾種方法可以做到這一點:
- **分割成區間**。如果我們知道某個值的範圍,我們可以將該範圍分割成若干**區間**,然後用該值所屬的區間編號替代該值。這可以使用 numpy 的 [`digitize`](https://numpy.org/doc/stable/reference/generated/numpy.digitize.html) 方法來完成。在這種情況下,我們將精確知道狀態的大小,因為它將取決於我們為離散化選擇的區間數量。
✅ 我們可以使用線性插值將值映射到某個有限範圍(例如,從 -20 到 20然後通過四捨五入將數字轉換為整數。這樣我們對狀態大小的控制會稍弱一些特別是如果我們不知道輸入值的確切範圍。例如在我們的情況下4 個值中的 2 個沒有上下界,這可能導致無限多的狀態。
在我們的例子中,我們將採用第二種方法。正如你稍後可能注意到的,儘管某些值沒有明確的上下界,但這些值很少超出某些有限範圍,因此具有極端值的狀態將非常罕見。
1. 以下是將模型的觀察值轉換為 4 個整數值元組的函數:(代碼塊 6
```python
def discretize(x):
return tuple((x/np.array([0.25, 0.25, 0.01, 0.1])).astype(np.int))
```
1. 我們還可以探索另一種使用區間的離散化方法:(代碼塊 7
```python
def create_bins(i,num):
return np.arange(num+1)*(i[1]-i[0])/num+i[0]
print("Sample bins for interval (-5,5) with 10 bins\n",create_bins((-5,5),10))
ints = [(-5,5),(-2,2),(-0.5,0.5),(-2,2)] # intervals of values for each parameter
nbins = [20,20,10,10] # number of bins for each parameter
bins = [create_bins(ints[i],nbins[i]) for i in range(4)]
def discretize_bins(x):
return tuple(np.digitize(x[i],bins[i]) for i in range(4))
```
1. 現在讓我們運行一個簡短的模擬,觀察這些離散化的環境值。隨意嘗試 `discretize``discretize_bins`,看看是否有差異。
`discretize_bins` 返回的是區間編號,從 0 開始。因此,對於接近 0 的輸入變量值它返回的是區間中間的數字10。在 `discretize`我們不關心輸出值的範圍允許它們為負因此狀態值未偏移0 對應於 0。代碼塊 8
```python
env.reset()
done = False
while not done:
#env.render()
obs, rew, done, info = env.step(env.action_space.sample())
#print(discretize_bins(obs))
print(discretize(obs))
env.close()
```
✅ 如果你想查看環境的執行過程,可以取消註釋以 `env.render` 開頭的那一行。否則,你可以在後台執行,這樣速度更快。在我們的 Q-Learning 過程中,我們將使用這種“隱形”執行方式。
## Q-表結構
在上一課中,狀態是一對簡單的數字,範圍從 0 到 8因此用形狀為 8x8x2 的 numpy 張量來表示 Q-表非常方便。如果我們使用區間離散化,狀態向量的大小也是已知的,因此我們可以使用相同的方法,將狀態表示為形狀為 20x20x10x10x2 的數組(其中 2 是行動空間的維度,前幾個維度對應於我們為觀察空間中每個參數選擇的區間數量)。
然而,有時觀察空間的精確維度是未知的。在使用 `discretize` 函數的情況下,我們無法確定狀態是否保持在某些限制範圍內,因為某些原始值是無界的。因此,我們將使用稍微不同的方法,用字典來表示 Q-表。
1. 使用 *(state, action)* 作為字典鍵,值對應於 Q-表的條目值。(代碼塊 9
```python
Q = {}
actions = (0,1)
def qvalues(state):
return [Q.get((state,a),0) for a in actions]
```
在這裡,我們還定義了一個函數 `qvalues()`,它返回對應於給定狀態的所有可能行動的 Q-表值列表。如果 Q-表中沒有該條目,我們將默認返回 0。
## 開始 Q-Learning
現在我們準備教彼得如何保持平衡了!
1. 首先,設置一些超參數:(代碼塊 10
```python
# hyperparameters
alpha = 0.3
gamma = 0.9
epsilon = 0.90
```
其中,`alpha` 是**學習率**,定義了我們在每一步中應該在多大程度上調整 Q-表的當前值。在上一課中,我們從 1 開始,然後在訓練過程中將 `alpha` 降低到較低的值。在本例中,為了簡化,我們將保持其恆定,你可以稍後嘗試調整 `alpha` 的值。
`gamma` 是**折扣因子**,表示我們應該在多大程度上優先考慮未來的獎勵而非當前的獎勵。
`epsilon` 是**探索/利用因子**,決定我們應該偏向於探索還是利用。在我們的算法中,我們將在 `epsilon` 百分比的情況下根據 Q-表值選擇下一個行動,而在剩餘的情況下執行隨機行動。這將允許我們探索以前從未見過的搜索空間區域。
✅ 就平衡而言,選擇隨機行動(探索)就像是一個隨機的錯誤方向的推動,桿子需要學會如何從這些“錯誤”中恢復平衡。
### 改進算法
我們還可以對上一課的算法進行兩項改進:
- **計算平均累積獎勵**,在多次模擬中取平均值。我們將每 5000 次迭代打印一次進度,並將累積獎勵取平均值。這意味著如果我們獲得超過 195 分——我們可以認為問題已經解決,並且質量甚至高於要求。
- **計算最大平均累積結果**`Qmax`,並存儲對應於該結果的 Q-表值。當你運行訓練時,你會注意到有時平均累積結果開始下降,我們希望保留對應於訓練過程中觀察到的最佳模型的 Q-表值。
1. 在每次模擬中收集所有累積獎勵到 `rewards` 向量中,以便進一步繪圖。(代碼塊 11
```python
def probs(v,eps=1e-4):
v = v-v.min()+eps
v = v/v.sum()
return v
Qmax = 0
cum_rewards = []
rewards = []
for epoch in range(100000):
obs = env.reset()
done = False
cum_reward=0
# == do the simulation ==
while not done:
s = discretize(obs)
if random.random()<epsilon:
# exploitation - chose the action according to Q-Table probabilities
v = probs(np.array(qvalues(s)))
a = random.choices(actions,weights=v)[0]
else:
# exploration - randomly chose the action
a = np.random.randint(env.action_space.n)
obs, rew, done, info = env.step(a)
cum_reward+=rew
ns = discretize(obs)
Q[(s,a)] = (1 - alpha) * Q.get((s,a),0) + alpha * (rew + gamma * max(qvalues(ns)))
cum_rewards.append(cum_reward)
rewards.append(cum_reward)
# == Periodically print results and calculate average reward ==
if epoch%5000==0:
print(f"{epoch}: {np.average(cum_rewards)}, alpha={alpha}, epsilon={epsilon}")
if np.average(cum_rewards) > Qmax:
Qmax = np.average(cum_rewards)
Qbest = Q
cum_rewards=[]
```
從這些結果中你可能注意到:
- **接近目標**。我們非常接近實現目標,即在 100 次以上的連續模擬中獲得 195 的累積獎勵,或者我們可能已經實現了目標!即使我們獲得較小的數字,我們仍然無法確定,因為我們是對 5000 次運行取平均值,而正式標準僅要求 100 次運行。
- **獎勵開始下降**。有時獎勵開始下降,這意味著我們可能用更糟糕的值覆蓋了 Q-表中已經學到的值。
這一觀察在我們繪製訓練進度時會更加明顯。
## 繪製訓練進度
在訓練過程中,我們將每次迭代的累積獎勵值收集到 `rewards` 向量中。以下是將其與迭代次數繪製在一起的圖表:
```python
plt.plot(rewards)
```
![原始進度](../../../../8-Reinforcement/2-Gym/images/train_progress_raw.png)
從這個圖表中無法看出任何信息,因為由於隨機訓練過程的特性,訓練會話的長度變化很大。為了讓這個圖表更有意義,我們可以計算一系列實驗的**移動平均值**,比如 100 次。這可以方便地使用 `np.convolve` 完成:(代碼塊 12
```python
def running_average(x,window):
return np.convolve(x,np.ones(window)/window,mode='valid')
plt.plot(running_average(rewards,100))
```
![訓練進度](../../../../8-Reinforcement/2-Gym/images/train_progress_runav.png)
## 調整超參數
為了使學習更加穩定,我們可以在訓練過程中調整一些超參數。特別是:
- **對於學習率**`alpha`,我們可以從接近 1 的值開始,然後逐漸減小該參數。隨著時間的推移,我們會在 Q-表中獲得較好的概率值,因此我們應該稍微調整它們,而不是完全用新值覆蓋。
- **增加 epsilon**。我們可能希望慢慢增加 `epsilon`,以便減少探索,增加利用。這可能意味著從較低的 `epsilon` 值開始,然後逐漸增加到接近 1。
> **任務 1**:嘗試調整超參數的值,看看是否能獲得更高的累積回報。你的回報是否超過 195
> **任務 2**:為了正式解決這個問題,你需要在連續 100 次運行中獲得 195 的平均獎勵。在訓練過程中測量這一點,並確保你已經正式解決了這個問題!
## 查看結果的實際效果
實際觀察訓練後的模型行為會很有趣。我們來運行模擬,並遵循與訓練時相同的動作選擇策略,根據 Q-Table 中的概率分佈進行採樣:(代碼塊 13
```python
obs = env.reset()
done = False
while not done:
s = discretize(obs)
env.render()
v = probs(np.array(qvalues(s)))
a = random.choices(actions,weights=v)[0]
obs,_,done,_ = env.step(a)
env.close()
```
你應該會看到類似這樣的畫面:
![一個保持平衡的平衡車](../../../../8-Reinforcement/2-Gym/images/cartpole-balance.gif)
---
## 🚀挑戰
> **任務 3**:在這裡,我們使用的是 Q-Table 的最終版本,但這可能不是表現最好的版本。記住,我們已經將表現最好的 Q-Table 存儲在 `Qbest` 變數中!嘗試將 `Qbest` 複製到 `Q` 中,並使用表現最好的 Q-Table 來運行相同的例子,看看是否能發現差異。
> **任務 4**:在這裡,我們並不是每一步都選擇最佳動作,而是根據相應的概率分佈進行採樣。是否更有意義每次都選擇 Q-Table 值最高的最佳動作?這可以通過使用 `np.argmax` 函數來找到對應於最高 Q-Table 值的動作編號。實現這種策略,看看是否能改進平衡效果。
## [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
## 作業
[訓練一輛山地車](assignment.md)
## 結論
我們現在已經學會如何通過提供定義遊戲期望狀態的獎勵函數,並讓代理智能地探索搜索空間,來訓練代理以獲得良好的結果。我們已成功將 Q-Learning 演算法應用於離散和連續環境中的情況,但動作是離散的。
同樣重要的是研究動作狀態也是連續的情況,以及觀察空間更加複雜的情況,例如來自 Atari 遊戲畫面的圖像。在這些問題中,我們通常需要使用更強大的機器學習技術,例如神經網絡,來獲得良好的結果。這些更高級的主題將是我們即將推出的更高級 AI 課程的內容。
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,48 @@
# 訓練山地車
[OpenAI Gym](http://gym.openai.com) 的設計使得所有環境都提供相同的 API —— 即相同的方法 `reset`、`step` 和 `render`,以及相同的 **動作空間** 和 **觀察空間** 抽象。因此,應該可以將相同的強化學習算法適配到不同的環境,並且只需進行最少的代碼修改。
## 山地車環境
[山地車環境](https://gym.openai.com/envs/MountainCar-v0/) 包含一輛被困在山谷中的車:
目標是通過每一步執行以下動作之一,成功駛出山谷並捕獲旗幟:
| 值 | 意義 |
|------|------------------|
| 0 | 向左加速 |
| 1 | 不加速 |
| 2 | 向右加速 |
然而,這個問題的主要難點在於,車子的引擎不夠強大,無法一次性爬上山頂。因此,唯一的成功方法是來回駕駛以積累動能。
觀察空間僅包含兩個值:
| 編號 | 觀察項目 | 最小值 | 最大值 |
|------|------------------|--------|--------|
| 0 | 車的位置 | -1.2 | 0.6 |
| 1 | 車的速度 | -0.07 | 0.07 |
山地車的獎勵系統相當棘手:
* 如果代理成功到達山頂的旗幟位置(位置 = 0.5),則獲得 0 的獎勵。
* 如果代理的位置小於 0.5,則獲得 -1 的獎勵。
當車的位置超過 0.5 或劇集長度超過 200 時,劇集終止。
## 指導說明
將我們的強化學習算法適配到山地車問題。從現有的 [notebook.ipynb](notebook.ipynb) 代碼開始,替換新的環境,修改狀態離散化函數,並嘗試以最少的代碼修改使現有算法進行訓練。通過調整超參數來優化結果。
> **注意**: 可能需要調整超參數以使算法收斂。
## 評分標準
| 評分標準 | 優秀表現 | 合格表現 | 需要改進 |
|----------|----------|----------|----------|
| | 成功將 Q-Learning 算法從 CartPole 示例中適配,並進行最少的代碼修改,能夠在 200 步內解決捕獲旗幟的問題。 | 從網絡上採用了新的 Q-Learning 算法,但有良好的文檔記錄;或者採用了現有算法,但未達到預期結果。 | 學生未能成功採用任何算法但在解決方案上有實質性進展實現了狀態離散化、Q-Table 數據結構等)。 |
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

File diff suppressed because one or more lines are too long

@ -0,0 +1,6 @@
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,6 @@
這是一個臨時佔位符
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

File diff suppressed because one or more lines are too long

@ -0,0 +1,58 @@
# 強化學習簡介
強化學習RL被視為與監督學習和非監督學習並列的基本機器學習範式之一。RL 的核心在於決策:做出正確的決策,或者至少從中學習。
想像你有一個模擬環境例如股票市場。如果你施加某項規定會發生什麼它會產生正面還是負面的影響如果發生負面影響你需要接受這種_負面強化_從中學習並改變方向。如果是正面結果你需要基於這種_正面強化_進一步發展。
![彼得與狼](../../../translated_images/zh-TW/peter.779730f9ba3a8a8d.webp)
> 彼得和他的朋友們需要逃離飢餓的狼!圖片由 [Jen Looper](https://twitter.com/jenlooper) 提供
## 區域主題:彼得與狼(俄羅斯)
[彼得與狼](https://en.wikipedia.org/wiki/Peter_and_the_Wolf) 是由俄羅斯作曲家 [Sergei Prokofiev](https://en.wikipedia.org/wiki/Sergei_Prokofiev) 創作的一部音樂童話故事。這是一個關於年輕的先鋒彼得的故事,他勇敢地走出家門,來到森林空地追逐狼。在本節中,我們將訓練機器學習算法來幫助彼得:
- **探索**周圍環境並建立最佳導航地圖
- **學習**如何使用滑板並保持平衡,以便更快地移動。
[![彼得與狼](https://img.youtube.com/vi/Fmi5zHg4QSM/0.jpg)](https://www.youtube.com/watch?v=Fmi5zHg4QSM)
> 🎥 點擊上方圖片收聽 Prokofiev 的《彼得與狼》
## 強化學習
在之前的章節中,你已經看到兩個機器學習問題的例子:
- **監督學習**,我們擁有建議問題解決方案的數據集。[分類](../4-Classification/README.md) 和 [回歸](../2-Regression/README.md) 是監督學習任務。
- **非監督學習**,我們沒有標記的訓練數據。非監督學習的主要例子是 [聚類](../5-Clustering/README.md)。
在本節中,我們將介紹一種不需要標記訓練數據的新型學習問題。有幾種類型的此類問題:
- **[半監督學習](https://wikipedia.org/wiki/Semi-supervised_learning)**,我們擁有大量未標記的數據,可以用來預訓練模型。
- **[強化學習](https://wikipedia.org/wiki/Reinforcement_learning)**,代理通過在某些模擬環境中進行實驗來學習如何行為。
### 示例 - 電腦遊戲
假設你想教電腦玩遊戲,例如象棋或 [超級瑪利歐](https://wikipedia.org/wiki/Super_Mario)。為了讓電腦玩遊戲,我們需要它在每個遊戲狀態下預測應該採取的行動。雖然這看起來像是一個分類問題,但事實並非如此——因為我們沒有包含狀態和相應行動的數據集。雖然我們可能擁有一些數據,例如現有的象棋比賽或玩家玩超級瑪利歐的錄像,但這些數據可能不足以涵蓋足夠多的可能狀態。
與其尋找現有的遊戲數據,**強化學習**RL的核心思想是讓電腦多次玩遊戲並觀察結果。因此要應用強化學習我們需要兩樣東西
- **一個環境**和**一個模擬器**,允許我們多次玩遊戲。這個模擬器會定義所有的遊戲規則以及可能的狀態和行動。
- **一個獎勵函數**,告訴我們在每次行動或遊戲中表現得如何。
其他類型的機器學習與 RL 的主要區別在於RL 通常直到遊戲結束才知道我們是贏還是輸。因此,我們無法判斷某個單獨的行動是否是好的——我們只有在遊戲結束時才會收到獎勵。而我們的目標是設計算法,讓我們能夠在不確定的條件下訓練模型。我們將學習一種名為 **Q-learning** 的 RL 算法。
## 課程
1. [強化學習與 Q-Learning 簡介](1-QLearning/README.md)
2. [使用 gym 模擬環境](2-Gym/README.md)
## 致謝
《強化學習簡介》由 [Dmitry Soshnikov](http://soshnikov.com) 用 ♥️ 編寫
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤釋不承擔責任。

@ -0,0 +1,148 @@
# 後記:機器學習在現實世界中的應用
![機器學習在現實世界中的應用摘要](../../../../sketchnotes/ml-realworld.png)
> 手繪筆記由 [Tomomi Imura](https://www.twitter.com/girlie_mac) 提供
在這門課程中,你學習了許多準備數據進行訓練以及建立機器學習模型的方法。你構建了一系列經典的回歸、聚類、分類、自然語言處理和時間序列模型。恭喜你!現在,你可能會想知道這些學習的意義是什麼……這些模型在現實世界中的應用是什麼?
雖然業界對通常利用深度學習的人工智慧AI充滿興趣但經典的機器學習模型仍然有其價值和應用。事實上你今天可能已經在使用其中一些應用在這節課中你將探索八個不同產業和專業領域如何利用這些模型來提升應用的效能、可靠性、智能性以及對用戶的價值。
## [課前測驗](https://ff-quizzes.netlify.app/en/ml/)
## 💰 金融
金融領域提供了許多機器學習的應用機會。這個領域中的許多問題都適合用機器學習來建模和解決。
### 信用卡詐欺檢測
我們在課程中學習了 [k-means 聚類](../../5-Clustering/2-K-Means/README.md),但它如何用於解決信用卡詐欺相關的問題呢?
k-means 聚類在一種稱為**異常檢測**的信用卡詐欺檢測技術中非常有用。異常值,或者說數據集中的偏差,可以幫助我們判斷信用卡的使用是否正常,或者是否有異常情況發生。根據以下論文所述,你可以使用 k-means 聚類算法對信用卡數據進行分類,並根據每筆交易的異常程度將其分配到不同的群組。接著,你可以評估風險最高的群組,判斷其交易是詐欺還是合法的。
[參考資料](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.680.1195&rep=rep1&type=pdf)
### 財富管理
在財富管理中,個人或公司代表客戶管理投資。他們的工作是長期維持和增長財富,因此選擇表現良好的投資至關重要。
評估某項投資表現的一種方法是通過統計回歸。[線性回歸](../../2-Regression/1-Tools/README.md) 是一種有價值的工具,可以用來理解某基金相對於基準的表現。我們還可以推斷回歸結果是否具有統計顯著性,或者它們對客戶投資的影響程度。你甚至可以進一步擴展分析,使用多元回歸來考慮額外的風險因素。以下論文展示了如何使用回歸來評估特定基金的表現。
[參考資料](http://www.brightwoodventures.com/evaluating-fund-performance-using-regression/)
## 🎓 教育
教育領域也是機器學習應用的一個非常有趣的領域。在這裡可以解決許多有趣的問題,例如檢測考試或作文中的作弊行為,或者管理糾正過程中的偏見(無論是有意還是無意的)。
### 預測學生行為
[Coursera](https://coursera.com),一家線上開放課程提供商,在其技術博客中討論了許多工程決策。在這個案例研究中,他們繪製了一條回歸線,試圖探索低 NPS淨推薦值評分與課程保留率或退課率之間的相關性。
[參考資料](https://medium.com/coursera-engineering/controlled-regression-quantifying-the-impact-of-course-quality-on-learner-retention-31f956bd592a)
### 減少偏見
[Grammarly](https://grammarly.com),一款檢查拼寫和語法錯誤的寫作助手,在其技術博客中發表了一篇有趣的案例研究,討論了他們如何處理機器學習中的性別偏見問題。你可以在我們的[公平性入門課程](../../1-Introduction/3-fairness/README.md)中學到相關知識。
[參考資料](https://www.grammarly.com/blog/engineering/mitigating-gender-bias-in-autocorrect/)
## 👜 零售
零售行業可以從機器學習中獲益良多,從創造更好的客戶旅程到以最佳方式管理庫存。
### 個性化客戶旅程
在 Wayfair一家銷售家具等家居用品的公司幫助客戶找到符合其品味和需求的產品至關重要。在這篇文章中該公司的工程師描述了他們如何使用機器學習和 NLP 來「為客戶提供合適的搜索結果」。值得注意的是,他們的查詢意圖引擎使用了實體提取、分類器訓練、資產和意見提取以及客戶評論的情感標記。這是 NLP 在線上零售中的經典應用案例。
[參考資料](https://www.aboutwayfair.com/tech-innovation/how-we-use-machine-learning-and-natural-language-processing-to-empower-search)
### 庫存管理
像 [StitchFix](https://stitchfix.com) 這樣創新且靈活的公司,一家向消費者寄送服裝的盒裝服務公司,嚴重依賴機器學習進行推薦和庫存管理。他們的造型團隊與商品團隊密切合作:「我們的一位數據科學家嘗試了一種遺傳算法,並將其應用於服裝,預測出一件尚未存在的成功服裝。我們將這一工具提供給商品團隊,現在他們可以將其用作工具。」
[參考資料](https://www.zdnet.com/article/how-stitch-fix-uses-machine-learning-to-master-the-science-of-styling/)
## 🏥 醫療保健
醫療保健領域可以利用機器學習來優化研究任務以及解決物流問題,例如患者再入院管理或疾病傳播的阻止。
### 臨床試驗管理
臨床試驗中的毒性是藥物製造商的一大關注點。多少毒性是可接受的?在這項研究中,分析了各種臨床試驗方法,並開發了一種新的方法來預測臨床試驗結果的可能性。具體來說,他們使用隨機森林生成了一個[分類器](../../4-Classification/README.md),能夠區分不同藥物群組。
[參考資料](https://www.sciencedirect.com/science/article/pii/S2451945616302914)
### 醫院再入院管理
醫院護理成本高昂,尤其是當患者需要再次入院時。這篇論文討論了一家公司如何使用機器學習來預測再入院的可能性,通過[聚類](../../5-Clustering/README.md)算法來實現。這些群組幫助分析師「發現可能具有共同原因的再入院群組」。
[參考資料](https://healthmanagement.org/c/healthmanagement/issuearticle/hospital-readmissions-and-machine-learning)
### 疾病管理
最近的疫情突顯了機器學習在阻止疾病傳播方面的作用。在這篇文章中,你會看到 ARIMA、邏輯曲線、線性回歸和 SARIMA 的應用。「這項工作試圖計算病毒的傳播率,並預測死亡、康復和確診病例,以便我們能更好地準備和應對。」
[參考資料](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7979218/)
## 🌲 生態與綠色科技
自然與生態由許多敏感的系統組成,動物與自然之間的相互作用尤為重要。準確測量這些系統並在發生問題(如森林火災或動物數量下降)時採取適當行動至關重要。
### 森林管理
你在之前的課程中學習了[強化學習](../../8-Reinforcement/README.md)。它在預測自然模式時非常有用。特別是它可以用於追蹤生態問題如森林火災和入侵物種的擴散。在加拿大一組研究人員使用強化學習從衛星圖像中構建了森林火災動態模型。他們使用了一種創新的「空間擴散過程SSP將森林火災視為「景觀中任何單元格的代理」。
[參考資料](https://www.frontiersin.org/articles/10.3389/fict.2018.00006/full)
### 動物運動感測
雖然深度學習在視覺追蹤動物運動方面帶來了革命性變化(你可以在這裡構建自己的[北極熊追蹤器](https://docs.microsoft.com/learn/modules/build-ml-model-with-azure-stream-analytics/?WT.mc_id=academic-77952-leestott)),但經典的機器學習在這項任務中仍有一席之地。
用於追蹤農場動物運動的感測器和物聯網技術利用了這類視覺處理,但更基本的機器學習技術對數據預處理非常有用。例如,在這篇論文中,研究人員使用各種分類器算法監測和分析羊的姿勢。你可能會在第 335 頁認出 ROC 曲線。
[參考資料](https://druckhaus-hofmann.de/gallery/31-wj-feb-2020.pdf)
### ⚡️ 能源管理
在我們的[時間序列預測](../../7-TimeSeries/README.md)課程中,我們提到了基於供需理解的智能停車收費表如何為城鎮創造收入。這篇文章詳細討論了聚類、回歸和時間序列預測如何結合起來,幫助預測愛爾蘭未來的能源使用情況,基於智能計量技術。
[參考資料](https://www-cdn.knime.com/sites/default/files/inline-images/knime_bigdata_energy_timeseries_whitepaper.pdf)
## 💼 保險
保險行業是另一個利用機器學習構建和優化可行財務和精算模型的領域。
### 波動性管理
MetLife一家人壽保險提供商公開了他們如何分析和減少財務模型中的波動性。在這篇文章中你會看到二元和序數分類的可視化以及預測的可視化。
[參考資料](https://investments.metlife.com/content/dam/metlifecom/us/investments/insights/research-topics/macro-strategy/pdf/MetLifeInvestmentManagement_MachineLearnedRanking_070920.pdf)
## 🎨 藝術、文化與文學
在藝術領域,例如新聞業,有許多有趣的問題需要解決。檢測假新聞是一個巨大的挑戰,因為它已被證明會影響人們的觀點,甚至顛覆民主。博物館也可以利用機器學習,從發現文物之間的聯繫到資源規劃。
### 假新聞檢測
在當今的媒體中,檢測假新聞已成為一場貓捉老鼠的遊戲。在這篇文章中,研究人員建議測試並部署最佳模型,該系統結合了我們學過的多種機器學習技術:「該系統基於自然語言處理來提取數據特徵,然後這些特徵用於訓練機器學習分類器,例如 Naive Bayes、支持向量機SVM、隨機森林RF、隨機梯度下降SGD和邏輯回歸LR。」
[參考資料](https://www.irjet.net/archives/V7/i6/IRJET-V7I6688.pdf)
這篇文章展示了如何結合不同的機器學習領域來產生有趣的結果,幫助阻止假新聞的傳播和造成的實際損害;在這個案例中,動機是阻止關於 COVID 治療的謠言引發的暴力事件。
### 博物館機器學習
博物館正處於人工智慧革命的前沿,隨著技術的進步,對藏品進行編目和數字化以及發現文物之間的聯繫變得更加容易。像 [In Codice Ratio](https://www.sciencedirect.com/science/article/abs/pii/S0306457321001035#:~:text=1.,studies%20over%20large%20historical%20sources.) 這樣的項目正在幫助解開無法訪問的藏品(如梵蒂岡檔案館)的奧秘。但博物館的商業方面也受益於機器學習模型。
例如,芝加哥藝術博物館建立了模型來預測觀眾的興趣以及他們何時會參觀展覽。目標是每次用戶參觀博物館時,創造個性化和最佳化的參觀體驗。「在 2017 財年,該模型以 1% 的準確率預測了參觀人數和門票收入,」芝加哥藝術博物館高級副總裁 Andrew Simnick 說道。
[參考資料](https://www.chicagobusiness.com/article/20180518/ISSUE01/180519840/art-institute-of-chicago-uses-data-to-make-exhibit-choices)
## 🏷 行銷
### 客戶分群
最有效的行銷策略是根據不同的群組以不同的方式針對客戶。在這篇文章中,討論了使用聚類算法來支持差異化行銷的應用。差異化行銷幫助公司提高品牌認知度、觸及更多客戶並賺取更多收入。
[參考資料](https://ai.inqline.com/machine-learning-for-marketing-customer-segmentation/)
## 🚀 挑戰
找出另一個受益於本課程中學到的技術的行業,並探索它如何使用機器學習。
## [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
## 複習與自學
Wayfair 的數據科學團隊有幾部有趣的影片,介紹他們如何在公司中運用機器學習。值得[看看](https://www.youtube.com/channel/UCe2PjkQXqOuwkW1gw6Ameuw/videos)
## 作業
[機器學習尋寶遊戲](assignment.md)
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,18 @@
# 機器學習尋寶遊戲
## 說明
在本課程中,你學到了許多使用傳統機器學習解決的真實案例。雖然深度學習、人工智慧的新技術和工具,以及神經網絡的應用加速了這些領域工具的開發,但使用本課程中的技術進行的傳統機器學習仍然具有重要價值。
在這項作業中,假設你正在參加一場黑客松。利用你在課程中學到的知識,提出一個使用傳統機器學習解決本課程中討論的某個領域問題的方案。製作一個演示文稿,討論你將如何實現你的想法。如果你能收集樣本數據並建立一個機器學習模型來支持你的概念,還能獲得額外加分!
## 評分標準
| 評分標準 | 傑出表現 | 基本表現 | 需要改進 |
| -------- | ---------------------------------------------------------------- | --------------------------------------------- | --------------------- |
| | 提交了一份 PowerPoint 演示文稿 - 建立模型可獲得額外加分 | 提交了一份非創新性、基礎的演示文稿 | 作業未完成 |
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始語言的文件應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,174 @@
# 後記:使用負責任 AI 儀表板元件進行機器學習模型調試
## [課前測驗](https://ff-quizzes.netlify.app/en/ml/)
## 簡介
機器學習已深刻影響我們的日常生活。AI 正逐漸融入一些對個人及社會至關重要的系統例如醫療保健、金融、教育和就業。例如系統和模型參與了日常決策任務如醫療診斷或欺詐檢測。因此AI 的進步及其加速採用也伴隨著不斷演變的社會期望和日益增長的監管要求。我們經常看到 AI 系統未能達到期望的領域;它們暴露出新的挑戰;而各國政府也開始對 AI 解決方案進行監管。因此,分析這些模型以提供公平、可靠、包容、透明和負責任的結果對每個人都至關重要。
在本課程中,我們將探討一些實用工具,用於評估模型是否存在負責任 AI 的問題。傳統的機器學習調試技術通常基於定量計算,例如整體準確率或平均錯誤損失。想像一下,如果您用來構建這些模型的數據缺乏某些人口統計信息,例如種族、性別、政治觀點、宗教,或者這些人口統計信息的比例不均衡,會發生什麼情況?如果模型的輸出被解釋為偏向某些人口統計信息,又會如何?這可能導致這些敏感特徵群體的過度或不足表現,從而引發模型的公平性、包容性或可靠性問題。另一個因素是,機器學習模型通常被視為黑盒子,這使得理解和解釋模型的預測驅動因素變得困難。當數據科學家和 AI 開發者缺乏足夠的工具來調試和評估模型的公平性或可信度時,這些都是他們面臨的挑戰。
在本課程中,您將學習如何使用以下方法調試模型:
- **錯誤分析**:識別模型在數據分佈中錯誤率較高的區域。
- **模型概覽**:對不同數據群體進行比較分析,以發現模型性能指標中的差異。
- **數據分析**:調查數據是否存在過度或不足表現,可能導致模型偏向某些數據群體。
- **特徵重要性**:了解哪些特徵在全局或局部層面上驅動模型的預測。
## 前置條件
作為前置條件,請先查看 [開發者的負責任 AI 工具](https://www.microsoft.com/ai/ai-lab-responsible-ai-dashboard)
> ![負責任 AI 工具的動態圖](../../../../9-Real-World/2-Debugging-ML-Models/images/rai-overview.gif)
## 錯誤分析
傳統的模型性能指標用於衡量準確性,通常基於正確與錯誤預測的計算。例如,判斷模型 89% 的時間是準確的,錯誤損失為 0.001,可以被認為是良好的性能。然而,錯誤通常在底層數據集中並非均勻分佈。您可能獲得 89% 的模型準確率,但發現模型在某些數據區域的錯誤率高達 42%。這些特定數據群體的失敗模式可能導致公平性或可靠性問題。因此,了解模型表現良好或不佳的區域至關重要。模型在某些數據區域的高錯誤率可能揭示出重要的數據人口統計信息。
![分析和調試模型錯誤](../../../../9-Real-World/2-Debugging-ML-Models/images/ea-error-distribution.png)
RAI 儀表板上的錯誤分析元件通過樹狀可視化展示模型失敗在各群體中的分佈情況。這有助於識別數據集中錯誤率較高的特徵或區域。通過查看模型大部分錯誤的來源,您可以開始調查根本原因。您還可以創建數據群體進行分析。這些數據群體有助於調試過程,確定為什麼模型在某些群體中表現良好,而在其他群體中出現錯誤。
![錯誤分析](../../../../9-Real-World/2-Debugging-ML-Models/images/ea-error-cohort.png)
樹狀圖上的可視化指標有助於更快定位問題區域。例如,樹節的紅色陰影越深,錯誤率越高。
熱圖是另一種可視化功能,用於通過一個或兩個特徵調查錯誤率,找出整個數據集或群體中模型錯誤的貢獻因素。
![錯誤分析熱圖](../../../../9-Real-World/2-Debugging-ML-Models/images/ea-heatmap.png)
使用錯誤分析時,您可以:
* 深入了解模型失敗如何在數據集和多個輸入及特徵維度中分佈。
* 分解整體性能指標,並自動發現錯誤群體,以指導有針對性的緩解措施。
## 模型概覽
評估機器學習模型的性能需要全面了解其行為。這可以通過查看多個指標(例如錯誤率、準確率、召回率、精確度或 MAE來實現以發現性能指標中的差異。一個性能指標可能看起來很好但另一個指標可能暴露出不準確性。此外比較整個數據集或群體中的指標差異有助於揭示模型表現良好或不佳的地方。這在查看模型對敏感特徵例如患者的種族、性別或年齡與非敏感特徵的表現時尤為重要以揭示模型可能存在的潛在不公平性。例如發現模型在具有敏感特徵的群體中錯誤率更高可能揭示模型存在潛在的不公平性。
RAI 儀表板的模型概覽元件不僅有助於分析數據群體中的性能指標,還使用戶能夠比較模型在不同群體中的行為。
![數據集群體 - RAI 儀表板中的模型概覽](../../../../9-Real-World/2-Debugging-ML-Models/images/model-overview-dataset-cohorts.png)
該元件的基於特徵的分析功能允許用戶縮小特定特徵中的數據子群體,以更細緻地識別異常。例如,儀表板具有內置智能,可以自動生成用戶選擇特徵的群體(例如 *"time_in_hospital < 3"**"time_in_hospital >= 7"*)。這使用戶能夠從更大的數據群體中隔離特定特徵,以查看它是否是模型錯誤結果的關鍵影響因素。
![特徵群體 - RAI 儀表板中的模型概覽](../../../../9-Real-World/2-Debugging-ML-Models/images/model-overview-feature-cohorts.png)
模型概覽元件支持兩類差異指標:
**模型性能差異**:這些指標計算所選性能指標在數據子群體之間的差異(差距)。以下是一些示例:
* 準確率差異
* 錯誤率差異
* 精確度差異
* 召回率差異
* 平均絕對誤差MAE差異
**選擇率差異**:此指標包含子群體之間選擇率(有利預測)的差異。例如,貸款批准率的差異。選擇率指的是每個類別中被分類為 1 的數據點比例(在二元分類中)或預測值的分佈(在回歸中)。
## 數據分析
> 「如果你對數據施加足夠的壓力,它會承認任何事情」——羅納德·科斯
這句話聽起來極端,但事實上數據確實可以被操縱以支持任何結論。有時這種操縱可能是無意的。作為人類,我們都有偏見,並且往往難以有意識地知道何時在數據中引入了偏見。保證 AI 和機器學習的公平性仍然是一個複雜的挑戰。
數據是傳統模型性能指標的一個巨大盲點。您可能擁有高準確率,但這並不總是反映出數據集中可能存在的底層數據偏差。例如,如果某公司高管職位的員工數據集中有 27% 的女性和 73% 的男性,基於此數據訓練的招聘 AI 模型可能會主要針對男性群體進行高級職位的招聘。數據中的這種不平衡使模型的預測偏向於某一性別,揭示了模型存在性別偏見的公平性問題。
RAI 儀表板上的數據分析元件有助於識別數據集中過度和不足表現的區域。它幫助用戶診斷由數據不平衡或缺乏特定數據群體代表性引入的錯誤和公平性問題的根本原因。這使用戶能夠根據預測和實際結果、錯誤群體以及特定特徵來可視化數據集。有時發現一個代表性不足的數據群體也可能揭示模型未能很好地學習,因此錯誤率較高。具有數據偏差的模型不僅是一個公平性問題,還表明模型不具包容性或可靠性。
![RAI 儀表板上的數據分析元件](../../../../9-Real-World/2-Debugging-ML-Models/images/dataanalysis-cover.png)
使用數據分析時,您可以:
* 通過選擇不同的篩選器探索數據集統計,將數據切片為不同的維度(也稱為群體)。
* 了解數據集在不同群體和特徵群體中的分佈。
* 確定與公平性、錯誤分析和因果關係相關的發現(來自其他儀表板元件)是否是數據集分佈的結果。
* 決定在哪些區域收集更多數據,以減少由代表性問題、標籤噪音、特徵噪音、標籤偏差等因素引起的錯誤。
## 模型可解釋性
機器學習模型通常是黑盒子。理解哪些關鍵數據特徵驅動模型的預測可能具有挑戰性。提供模型做出某種預測的透明性至關重要。例如,如果 AI 系統預測某糖尿病患者有可能在 30 天內再次入院,它應該能夠提供支持其預測的數據。提供支持數據指標可以幫助醫生或醫院做出明智的決策。此外,能夠解釋模型為個別患者做出某種預測的原因,有助於符合健康法規的問責要求。當您使用機器學習模型影響人們的生活時,了解和解釋模型行為的驅動因素至關重要。模型可解釋性和可理解性有助於回答以下場景中的問題:
* 模型調試:為什麼我的模型犯了這個錯誤?我如何改進我的模型?
* 人類與 AI 協作:我如何理解並信任模型的決策?
* 法規合規性:我的模型是否符合法律要求?
RAI 儀表板的特徵重要性元件幫助您調試並全面了解模型如何做出預測。它也是機器學習專業人士和決策者解釋和展示影響模型行為的特徵證據的有用工具,以符合法規要求。接下來,用戶可以探索全局和局部解釋,驗證哪些特徵驅動模型的預測。全局解釋列出影響模型整體預測的主要特徵。局部解釋顯示哪些特徵導致模型對個別案例的預測。評估局部解釋的能力在調試或審核特定案例時也很有幫助,以更好地理解和解釋模型為什麼做出準確或不準確的預測。
![RAI 儀表板的特徵重要性元件](../../../../9-Real-World/2-Debugging-ML-Models/images/9-feature-importance.png)
* 全局解釋:例如,哪些特徵影響糖尿病患者再次入院模型的整體行為?
* 局部解釋:例如,為什麼一位超過 60 歲且有過住院史的糖尿病患者被預測為會或不會在 30 天內再次入院?
在調試模型性能的過程中,特徵重要性顯示特徵在不同群體中的影響程度。它有助於揭示異常情況,尤其是在比較特徵對模型錯誤預測的影響程度時。特徵重要性元件可以顯示特徵中的哪些值對模型結果產生了正面或負面影響。例如,如果模型做出了不準確的預測,該元件使您能夠深入分析並確定哪些特徵或特徵值驅動了預測。這種細節不僅有助於調試,還在審核情況下提供透明性和問責性。最後,該元件可以幫助您識別公平性問題。例如,如果某敏感特徵(如種族或性別)在驅動模型預測中具有高度影響力,這可能表明模型存在種族或性別偏見。
![特徵重要性](../../../../9-Real-World/2-Debugging-ML-Models/images/9-features-influence.png)
使用可解釋性時,您可以:
* 通過了解哪些特徵對預測最重要,判斷 AI 系統的預測是否值得信任。
* 通過首先理解模型並確定模型是否使用健康特徵或僅僅是錯誤相關性,來進行模型調試。
* 通過了解模型是否基於敏感特徵或與敏感特徵高度相關的特徵進行預測,揭示潛在的不公平性來源。
* 通過生成局部解釋來展示模型結果,建立用戶對模型決策的信任。
* 完成 AI 系統的法規審核,以驗證模型並監控模型決策對人類的影響。
## 結論
RAI 儀表板的所有元件都是幫助您構建對社會更少傷害、更值得信賴的機器學習模型的實用工具。它有助於防止對人權的威脅;避免歧視或排除某些群體的生活機會;以及減少身體或心理傷害的風險。它還通過生成局部解釋來展示模型結果,幫助建立對模型決策的信任。一些潛在的傷害可以分類為:
- **分配**:例如,某性別或種族被偏向於另一性別或種族。
- **服務質量**:如果您僅針對一個特定場景訓練數據,但現實情況更為複雜,可能導致服務性能不佳。
- **刻板印象**:將某一群體與預先分配的屬性聯繫起來。
- **貶低**:不公平地批評或標籤某事或某人。
- **過度或不足的代表性**。這個概念指的是某些群體在某些職業中未被看到,而任何持續推動這種情況的服務或功能都會造成傷害。
### Azure RAI 儀表板
[Azure RAI 儀表板](https://learn.microsoft.com/en-us/azure/machine-learning/concept-responsible-ai-dashboard?WT.mc_id=aiml-90525-ruyakubu) 基於由領先的學術機構和組織(包括 Microsoft開發的開源工具構建這些工具對於數據科學家和 AI 開發者更好地理解模型行為、發現並減輕 AI 模型中的不良問題至關重要。
- 通過查看 RAI 儀表板的[文檔](https://learn.microsoft.com/en-us/azure/machine-learning/how-to-responsible-ai-dashboard?WT.mc_id=aiml-90525-ruyakubu)來學習如何使用不同的組件。
- 查看一些 RAI 儀表板的[範例筆記本](https://github.com/Azure/RAI-vNext-Preview/tree/main/examples/notebooks),以便在 Azure 機器學習中調試更負責任的 AI 場景。
---
## 🚀 挑戰
為了從一開始就防止統計或數據偏差的引入,我們應該:
- 確保參與系統開發的人員具有多樣化的背景和觀點
- 投資於能夠反映我們社會多樣性的數據集
- 開發更好的方法來檢測和糾正偏差
思考一些現實生活中模型構建和使用中明顯不公平的情境。我們還應該考慮什麼?
## [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
## 回顧與自學
在本課中,您學習了一些將負責任 AI 融入機器學習的實用工具。
觀看以下工作坊以更深入了解這些主題:
- 負責任 AI 儀表板:實踐中實現 RAI 的一站式工具,由 Besmira Nushi 和 Mehrnoosh Sameki 主講
[![負責任 AI 儀表板:實踐中實現 RAI 的一站式工具](https://img.youtube.com/vi/f1oaDNl3djg/0.jpg)](https://www.youtube.com/watch?v=f1oaDNl3djg "負責任 AI 儀表板:實踐中實現 RAI 的一站式工具")
> 🎥 點擊上方圖片觀看影片:負責任 AI 儀表板:實踐中實現 RAI 的一站式工具,由 Besmira Nushi 和 Mehrnoosh Sameki 主講
參考以下材料以進一步了解負責任 AI 以及如何構建更值得信賴的模型:
- Microsoft 的 RAI 儀表板工具,用於調試 ML 模型:[負責任 AI 工具資源](https://aka.ms/rai-dashboard)
- 探索負責任 AI 工具包:[Github](https://github.com/microsoft/responsible-ai-toolbox)
- Microsoft 的 RAI 資源中心:[負責任 AI 資源 Microsoft AI](https://www.microsoft.com/ai/responsible-ai-resources?activetab=pivot1%3aprimaryr4)
- Microsoft 的 FATE 研究小組:[FATEAI 中的公平性、問責性、透明性和倫理 - Microsoft Research](https://www.microsoft.com/research/theme/fate/)
## 作業
[探索 RAI 儀表板](assignment.md)
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解讀概不負責。

@ -0,0 +1,16 @@
# 探索負責任人工智慧 (RAI) 儀表板
## 說明
在本課程中,您學習了關於 RAI 儀表板的內容。這是一套基於「開源」工具的元件,旨在幫助資料科學家進行錯誤分析、資料探索、公平性評估、模型可解釋性、反事實/假設情境評估以及人工智慧系統的因果分析。作為本次作業的一部分,請探索一些 RAI 儀表板的範例[筆記本](https://github.com/Azure/RAI-vNext-Preview/tree/main/examples/notebooks),並在報告或簡報中分享您的發現。
## 評分標準
| 評分標準 | 卓越 | 合格 | 需要改進 |
| -------- | --------- | -------- | ----------------- |
| | 提交了一份報告或簡報,詳細討論了 RAI 儀表板的元件、執行的筆記本以及從中得出的結論 | 提交了一份報告,但未包含結論 | 未提交報告 |
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始語言的文件應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,23 @@
# 後記:經典機器學習的實際應用
在本課程的這一部分,您將了解一些經典機器學習在現實世界中的應用。我們在網路上搜尋了許多白皮書和文章,介紹使用這些策略的應用,並儘量避免涉及神經網絡、深度學習和人工智慧。了解機器學習如何應用於商業系統、生態環境、金融、藝術與文化等領域。
![chess](../../../translated_images/zh-TW/chess.e704a268781bdad8.webp)
> 照片由 <a href="https://unsplash.com/@childeye?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Alexis Fauvet</a> 提供,來源於 <a href="https://unsplash.com/s/photos/artificial-intelligence?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
## 課程
1. [機器學習的實際應用](1-Applications/README.md)
2. [使用負責任的人工智慧儀表板元件進行機器學習模型調試](2-Debugging-ML-Models/README.md)
## 致謝
「機器學習的實際應用」由一個團隊撰寫,包括 [Jen Looper](https://twitter.com/jenlooper) 和 [Ornella Altunyan](https://twitter.com/ornelladotcom)。
「使用負責任的人工智慧儀表板元件進行機器學習模型調試」由 [Ruth Yakubu](https://twitter.com/ruthieyakubu) 撰寫。
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,336 @@
# AGENTS.md
## 專案概述
這是 **機器學習初學者課程**一個為期12週、共26課的完整課程涵蓋使用 Python主要使用 Scikit-learn和 R 的經典機器學習概念。本儲存庫設計為自學資源,包含實作專案、測驗和作業。每節課透過來自世界各地不同文化和地區的真實數據探索機器學習概念。
主要內容:
- **教育內容**26課涵蓋機器學習入門、回歸、分類、聚類、自然語言處理NLP、時間序列和強化學習
- **測驗應用程式**:基於 Vue.js 的測驗應用程式,提供課前和課後評估
- **多語言支持**:透過 GitHub Actions 自動翻譯至40多種語言
- **雙語支持**:課程提供 PythonJupyter notebooks和 RR Markdown 文件)版本
- **專案式學習**:每個主題都包含實作專案和作業
## 儲存庫結構
```
ML-For-Beginners/
├── 1-Introduction/ # ML basics, history, fairness, techniques
├── 2-Regression/ # Regression models with Python/R
├── 3-Web-App/ # Flask web app for ML model deployment
├── 4-Classification/ # Classification algorithms
├── 5-Clustering/ # Clustering techniques
├── 6-NLP/ # Natural Language Processing
├── 7-TimeSeries/ # Time series forecasting
├── 8-Reinforcement/ # Reinforcement learning
├── 9-Real-World/ # Real-world ML applications
├── quiz-app/ # Vue.js quiz application
├── translations/ # Auto-generated translations
└── sketchnotes/ # Visual learning aids
```
每個課程資料夾通常包含:
- `README.md` - 主要課程內容
- `notebook.ipynb` - Python Jupyter notebook
- `solution/` - 解答程式碼Python 和 R 版本)
- `assignment.md` - 練習題
- `images/` - 視覺資源
## 設置指令
### Python 課程
大多數課程使用 Jupyter notebooks。安裝所需的依賴項
```bash
# Install Python 3.8+ if not already installed
python --version
# Install Jupyter
pip install jupyter
# Install common ML libraries
pip install scikit-learn pandas numpy matplotlib seaborn
# For specific lessons, check lesson-specific requirements
# Example: Web App lesson
pip install flask
```
### R 課程
R 課程位於 `solution/R/` 資料夾中,格式為 `.rmd``.ipynb` 文件:
```bash
# Install R and required packages
# In R console:
install.packages(c("tidyverse", "tidymodels", "caret"))
```
### 測驗應用程式
測驗應用程式是一個位於 `quiz-app/` 資料夾中的 Vue.js 應用程式:
```bash
cd quiz-app
npm install
```
### 文件網站
本地運行文件網站:
```bash
# Install Docsify
npm install -g docsify-cli
# Serve from repository root
docsify serve
# Access at http://localhost:3000
```
## 開發工作流程
### 使用課程筆記本
1. 進入課程資料夾(例如,`2-Regression/1-Tools/`
2. 打開 Jupyter notebook
```bash
jupyter notebook notebook.ipynb
```
3. 完成課程內容和練習
4. 如有需要,可查看 `solution/` 資料夾中的解答
### Python 開發
- 課程使用標準的 Python 數據科學庫
- 使用 Jupyter notebooks 進行互動式學習
- 每個課程的 `solution/` 資料夾中提供解答程式碼
### R 開發
- R 課程以 `.rmd` 格式R Markdown提供
- 解答位於 `solution/R/` 子資料夾中
- 使用 RStudio 或帶有 R kernel 的 Jupyter 運行 R notebooks
### 測驗應用程式開發
```bash
cd quiz-app
# Start development server
npm run serve
# Access at http://localhost:8080
# Build for production
npm run build
# Lint and fix files
npm run lint
```
## 測試說明
### 測驗應用程式測試
```bash
cd quiz-app
# Lint code
npm run lint
# Build to verify no errors
npm run build
```
**注意**:這主要是一個教育課程儲存庫,課程內容沒有自動化測試。驗證方式包括:
- 完成課程練習
- 成功運行 notebook 的每個單元格
- 將輸出與解答中的預期結果進行比對
## 程式碼風格指南
### Python 程式碼
- 遵循 PEP 8 風格指南
- 使用清晰、描述性的變數名稱
- 對複雜操作添加註解
- Jupyter notebooks 應包含解釋概念的 markdown 單元格
### JavaScript/Vue.js測驗應用程式
- 遵循 Vue.js 風格指南
- ESLint 配置位於 `quiz-app/package.json`
- 運行 `npm run lint` 檢查並自動修復問題
### 文件
- Markdown 文件應清晰且結構良好
- 在圍欄代碼塊中包含代碼示例
- 使用相對鏈接進行內部引用
- 遵循現有的格式約定
## 構建與部署
### 測驗應用程式部署
測驗應用程式可部署至 Azure 靜態網頁應用程式:
1. **先決條件**
- Azure 帳戶
- GitHub 儲存庫(已分叉)
2. **部署至 Azure**
- 創建 Azure 靜態網頁應用程式資源
- 連接至 GitHub 儲存庫
- 設置應用程式位置:`/quiz-app`
- 設置輸出位置:`dist`
- Azure 自動創建 GitHub Actions 工作流程
3. **GitHub Actions 工作流程**
- 工作流程文件創建於 `.github/workflows/azure-static-web-apps-*.yml`
- 推送至主分支時自動構建和部署
### 文件 PDF
從文件生成 PDF
```bash
npm install
npm run convert
```
## 翻譯工作流程
**重要**:翻譯透過 GitHub Actions 使用 Co-op Translator 自動完成。
- 當更改推送至 `main` 分支時,翻譯會自動生成
- **請勿手動翻譯內容** - 系統會處理
- 工作流程定義於 `.github/workflows/co-op-translator.yml`
- 使用 Azure AI/OpenAI 服務進行翻譯
- 支持40多種語言
## 貢獻指南
### 對內容貢獻者的指導
1. **分叉儲存庫**並創建功能分支
2. **修改課程內容**以添加或更新課程
3. **不要修改翻譯文件** - 它們是自動生成的
4. **測試您的程式碼** - 確保所有 notebook 單元格成功運行
5. **驗證鏈接和圖片**是否正常工作
6. **提交拉取請求**並提供清晰的描述
### 拉取請求指南
- **標題格式**`[章節] 簡要描述更改`
- 示例:`[回歸] 修正第5課中的拼寫錯誤`
- 示例:`[測驗應用程式] 更新依賴項`
- **提交前**
- 確保所有 notebook 單元格無錯誤執行
- 如果修改測驗應用程式,運行 `npm run lint`
- 驗證 Markdown 格式
- 測試任何新的代碼示例
- **拉取請求必須包含**
- 更改描述
- 更改原因
- 如果有 UI 更改,提供截圖
- **行為準則**:遵循 [Microsoft 開源行為準則](CODE_OF_CONDUCT.md)
- **CLA**:您需要簽署貢獻者許可協議
## 課程結構
每節課遵循一致的模式:
1. **課前測驗** - 測試基礎知識
2. **課程內容** - 書面指導和解釋
3. **代碼演示** - notebook 中的實作示例
4. **知識檢查** - 驗證學習進度
5. **挑戰** - 獨立應用概念
6. **作業** - 延伸練習
7. **課後測驗** - 評估學習成果
## 常用指令參考
```bash
# Python/Jupyter
jupyter notebook # Start Jupyter server
jupyter notebook notebook.ipynb # Open specific notebook
pip install -r requirements.txt # Install dependencies (where available)
# Quiz App
cd quiz-app
npm install # Install dependencies
npm run serve # Development server
npm run build # Production build
npm run lint # Lint and fix
# Documentation
docsify serve # Serve documentation locally
npm run convert # Generate PDF
# Git workflow
git checkout -b feature/my-change # Create feature branch
git add . # Stage changes
git commit -m "Description" # Commit changes
git push origin feature/my-change # Push to remote
```
## 其他資源
- **Microsoft Learn 集合**[機器學習初學者模組](https://learn.microsoft.com/en-us/collections/qrqzamz1nn2wx3?WT.mc_id=academic-77952-bethanycheum)
- **測驗應用程式**[線上測驗](https://ff-quizzes.netlify.app/en/ml/)
- **討論板**[GitHub 討論](https://github.com/microsoft/ML-For-Beginners/discussions)
- **視頻講解**[YouTube 播放列表](https://aka.ms/ml-beginners-videos)
## 關鍵技術
- **Python**機器學習課程的主要語言Scikit-learn、Pandas、NumPy、Matplotlib
- **R**:使用 tidyverse、tidymodels、caret 的替代實現
- **Jupyter**Python 課程的互動式筆記本
- **R Markdown**R 課程的文件格式
- **Vue.js 3**:測驗應用程式框架
- **Flask**:機器學習模型部署的網頁應用框架
- **Docsify**:文件網站生成器
- **GitHub Actions**CI/CD 和自動翻譯
## 安全考量
- **代碼中不包含秘密**:切勿提交 API 密鑰或憑證
- **依賴項**:保持 npm 和 pip 套件更新
- **用戶輸入**Flask 網頁應用示例包含基本輸入驗證
- **敏感數據**:示例數據集是公開且非敏感的
## 疑難排解
### Jupyter Notebooks
- **內核問題**如果單元格掛起重啟內核Kernel → Restart
- **導入錯誤**:確保使用 pip 安裝所有所需套件
- **路徑問題**:從包含 notebook 的目錄運行
### 測驗應用程式
- **npm install 失敗**:清除 npm 緩存:`npm cache clean --force`
- **端口衝突**:更改端口:`npm run serve -- --port 8081`
- **構建錯誤**:刪除 `node_modules` 並重新安裝:`rm -rf node_modules && npm install`
### R 課程
- **找不到套件**:使用以下指令安裝:`install.packages("package-name")`
- **RMarkdown 渲染問題**:確保已安裝 rmarkdown 套件
- **內核問題**:可能需要為 Jupyter 安裝 IRkernel
## 專案特定注意事項
- 這主要是一個 **學習課程**,而非生產代碼
- 重點在於透過 **實作練習理解機器學習概念**
- 代碼示例以 **清晰性優先於優化**
- 大多數課程是 **自包含的**,可獨立完成
- **提供解答**,但學習者應先嘗試完成練習
- 儲存庫使用 **Docsify** 生成網頁文件,無需構建步驟
- **手繪筆記**提供概念的視覺摘要
- **多語言支持**使內容全球可訪問
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤釋不承擔責任。

@ -0,0 +1,14 @@
# Microsoft 開源行為準則
此專案已採用 [Microsoft 開源行為準則](https://opensource.microsoft.com/codeofconduct/)。
資源:
- [Microsoft 開源行為準則](https://opensource.microsoft.com/codeofconduct/)
- [Microsoft 行為準則常見問題](https://opensource.microsoft.com/codeofconduct/faq/)
- 如有疑問或擔憂,請聯絡 [opencode@microsoft.com](mailto:opencode@microsoft.com)
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,15 @@
# 貢獻指南
此專案歡迎各種貢獻與建議。大多數的貢獻需要您同意一份貢獻者授權協議 (CLA),以聲明您擁有授權權利,並且確實授予我們使用您貢獻內容的權利。詳細資訊請參訪 https://cla.microsoft.com。
> 重要提示:在翻譯此存儲庫中的內容時,請確保不要使用機器翻譯。我們將透過社群驗證翻譯,因此請僅在您精通的語言中自願進行翻譯。
當您提交拉取請求 (pull request) 時CLA 機器人會自動判斷您是否需要提供 CLA並適當地標記 PR例如標籤、評論。只需按照機器人提供的指示操作即可。您只需在所有使用我們 CLA 的存儲庫中完成一次此步驟。
此專案採用了 [Microsoft 開源行為準則](https://opensource.microsoft.com/codeofconduct/)。
如需更多資訊,請參閱 [行為準則常見問題](https://opensource.microsoft.com/codeofconduct/faq/) 或聯絡 [opencode@microsoft.com](mailto:opencode@microsoft.com) 提出其他問題或意見。
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解釋不承擔責任。

File diff suppressed because it is too large Load Diff

@ -0,0 +1,221 @@
[![GitHub license](https://img.shields.io/github/license/microsoft/ML-For-Beginners.svg)](https://github.com/microsoft/ML-For-Beginners/blob/master/LICENSE)
[![GitHub contributors](https://img.shields.io/github/contributors/microsoft/ML-For-Beginners.svg)](https://GitHub.com/microsoft/ML-For-Beginners/graphs/contributors/)
[![GitHub issues](https://img.shields.io/github/issues/microsoft/ML-For-Beginners.svg)](https://GitHub.com/microsoft/ML-For-Beginners/issues/)
[![GitHub pull-requests](https://img.shields.io/github/issues-pr/microsoft/ML-For-Beginners.svg)](https://GitHub.com/microsoft/ML-For-Beginners/pulls/)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
[![GitHub watchers](https://img.shields.io/github/watchers/microsoft/ML-For-Beginners.svg?style=social&label=Watch)](https://GitHub.com/microsoft/ML-For-Beginners/watchers/)
[![GitHub forks](https://img.shields.io/github/forks/microsoft/ML-For-Beginners.svg?style=social&label=Fork)](https://GitHub.com/microsoft/ML-For-Beginners/network/)
[![GitHub stars](https://img.shields.io/github/stars/microsoft/ML-For-Beginners.svg?style=social&label=Star)](https://GitHub.com/microsoft/ML-For-Beginners/stargazers/)
### 🌐 多語言支援
#### 透過 GitHub Action 支援(自動且持續更新)
<!-- CO-OP TRANSLATOR LANGUAGES TABLE START -->
[阿拉伯語](../ar/README.md) | [孟加拉語](../bn/README.md) | [保加利亞語](../bg/README.md) | [緬甸語](../my/README.md) | [簡體中文](../zh-CN/README.md) | [繁體中文(香港)](../zh-HK/README.md) | [繁體中文(澳門)](../zh-MO/README.md) | [繁體中文(台灣)](./README.md) | [克羅埃西亞語](../hr/README.md) | [捷克語](../cs/README.md) | [丹麥語](../da/README.md) | [荷蘭語](../nl/README.md) | [愛沙尼亞語](../et/README.md) | [芬蘭語](../fi/README.md) | [法語](../fr/README.md) | [德語](../de/README.md) | [希臘語](../el/README.md) | [希伯來語](../he/README.md) | [印地語](../hi/README.md) | [匈牙利語](../hu/README.md) | [印尼語](../id/README.md) | [義大利語](../it/README.md) | [日語](../ja/README.md) | [坎納達語](../kn/README.md) | [韓語](../ko/README.md) | [立陶宛語](../lt/README.md) | [馬來語](../ms/README.md) | [馬拉雅拉姆語](../ml/README.md) | [馬拉地語](../mr/README.md) | [尼泊爾語](../ne/README.md) | [尼日利亞皮欽語](../pcm/README.md) | [挪威語](../no/README.md) | [波斯語(法爾西語)](../fa/README.md) | [波蘭語](../pl/README.md) | [葡萄牙語(巴西)](../pt-BR/README.md) | [葡萄牙語(葡萄牙)](../pt-PT/README.md) | [旁遮普語Gurmukhi](../pa/README.md) | [羅馬尼亞語](../ro/README.md) | [俄語](../ru/README.md) | [塞爾維亞語(西里爾字母)](../sr/README.md) | [斯洛伐克語](../sk/README.md) | [斯洛維尼亞語](../sl/README.md) | [西班牙語](../es/README.md) | [斯瓦希里語](../sw/README.md) | [瑞典語](../sv/README.md) | [他加祿語(菲律賓語)](../tl/README.md) | [泰米爾語](../ta/README.md) | [泰盧固語](../te/README.md) | [泰語](../th/README.md) | [土耳其語](../tr/README.md) | [烏克蘭語](../uk/README.md) | [烏爾都語](../ur/README.md) | [越南語](../vi/README.md)
> **想要本機複製?**
> 此儲存庫包含超過 50 種語言翻譯,這會大幅增加下載大小。若想不包含翻譯檔案可使用 sparse checkout
> ```bash
> git clone --filter=blob:none --sparse https://github.com/microsoft/ML-For-Beginners.git
> cd ML-For-Beginners
> git sparse-checkout set --no-cone '/*' '!translations' '!translated_images'
> ```
> 這能讓你快速獲得完成課程所需的全部內容,下載速度更快。
<!-- CO-OP TRANSLATOR LANGUAGES TABLE END -->
#### 加入我們的社群
[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
我們正持續舉辦 Discord 人工智慧系列學習活動,更多資訊及加入請至 [Learn with AI Series](https://aka.ms/learnwithai/discord),活動時間為 2025 年 9 月 18 日至 30 日。你將獲得使用 GitHub Copilot 於資料科學的技巧與秘訣。
![Learn with AI series](../../translated_images/zh-TW/3.9b58fd8d6c373c20.webp)
# 機器學習初學者課程
> 🌍 跟隨世界文化環遊世界,一起探索機器學習 🌍
微軟的 Cloud Advocates 很高興提供一套為期 12 週、共 26 課的 **機器學習** 課程。在這套課程中,你將學習有時稱作**經典機器學習**的知識,主要使用 Scikit-learn 作為函式庫,並避免深入探討深度學習,那部分內容包含在我們的 [AI 初學者課程](https://aka.ms/ai4beginners) 中。也可以搭配我們的 ['資料科學初學者課程'](https://aka.ms/ds4beginners)一併學習!
跟我們一起環遊世界,應用這些經典技術於世界各地的資料。每堂課包括課前與課後小測驗、步驟說明完成課程、解答、專題練習等。我們採用專案式教學法,讓你透過實做學習,這是讓新技能容易學會的方法。
**✍️ 感謝我們的作者** Jen Looper、Stephen Howell、Francesca Lazzeri、Tomomi Imura、Cassie Breviu、Dmitry Soshnikov、Chris Noring、Anirban Mukherjee、Ornella Altunyan、Ruth Yakubu 和 Amy Boyd
**🎨 也感謝插畫家** Tomomi Imura、Dasani Madipalli 和 Jen Looper
**🙏 特別感謝微軟學生大使們,包括作者、審核者與內容貢獻者**,尤其是 Rishit Dagli、Muhammad Sakib Khan Inan、Rohan Raj、Alexandru Petrescu、Abhishek Jaiswal、Nawrin Tabassum、Ioan Samuila 以及 Snigdha Agarwal
**🤩 額外感謝微軟學生大使 Eric Wanjau、Jasleen Sondhi 和 Vidushi Gupta 為我們的 R 課程增添助力!**
# 開始使用
請跟著以下步驟:
1. **分支此儲存庫**:點擊本頁右上方的 "Fork" 按鈕。
2. **複製此儲存庫**`git clone https://github.com/microsoft/ML-For-Beginners.git`
> [欲獲得本課程的所有額外資源,請參閱我們的 Microsoft Learn 集合](https://learn.microsoft.com/en-us/collections/qrqzamz1nn2wx3?WT.mc_id=academic-77952-bethanycheum)
> 🔧 **需要幫助?** 請查看我們的 [疑難排解指南](TROUBLESHOOTING.md),了解安裝、設定及執行課程常見問題的解決方案。
**[學生](https://aka.ms/student-page)**,使用此課程時,請將整個儲存庫 fork 到你自己的 GitHub 帳號,然後單獨或與團隊完成練習:
- 先進行課前小測驗。
- 閱讀課程內容並完成活動,於每個知識點停下反思。
- 盡量嘗試理解教材自行製作專案,而不是直接執行解答程式碼;不過解答都放在各專案課程的 `/solution` 資料夾中。
- 完成課後小測驗。
- 完成挑戰題。
- 完成作業。
- 完成一組課程後,請到 [討論區](https://github.com/microsoft/ML-For-Beginners/discussions) 並透過填寫適當的 PAT 評量表來「邊學邊說」。PAT 是一種進度評估工具,你填寫後有助於深化學習。你也可以對其他人的 PAT 做回應,共同學習。
> 想深造的話,我們推薦下列 [Microsoft Learn](https://docs.microsoft.com/en-us/users/jenlooper-2911/collections/k7o7tg1gp306q4?WT.mc_id=academic-77952-leestott) 模組與學習路徑。
**老師們**,我們已經 [提供如何使用這套課程的建議](for-teachers.md)。
---
## 影片導覽
部分課程提供短片影片。你可以在各堂課中找到,或前往 [微軟開發者 YouTube 頻道的 ML for Beginners 播放清單](https://aka.ms/ml-beginners-videos),點擊下方圖片觀看。
[![ML for beginners banner](../../translated_images/zh-TW/ml-for-beginners-video-banner.63f694a100034bc6.webp)](https://aka.ms/ml-beginners-videos)
---
## 團隊介紹
[![Promo video](../../images/ml.gif)](https://youtu.be/Tj1XWrDSYJU)
**Gif 動畫製作者** [Mohit Jaisal](https://linkedin.com/in/mohitjaisal)
> 🎥 點擊上方圖片觀看專案與製作者影片介紹!
---
## 教學法
我們在設計這套課程時採用了兩個教學原則:保證是實作為主的 **專案導向**,以及包含 **頻繁的測驗**。同時,課程有統一的 **主題**,讓內容更連貫。
將內容與專題緊密結合,使學習過程更生動,也能加強概念記憶。課前的低壓力測驗能幫助學生設定學習目標,而課後測驗則促進更完整的學習吸收。這套課程設計靈活有趣,整體或部分學習都適合。專案從簡單開始,隨 12 週推進逐漸複雜。課程還包括一篇關於機器學習實際應用的後記,可作為附加學分或討論基礎。
> 請參閱我們的 [行為守則](CODE_OF_CONDUCT.md)、[貢獻指南](CONTRIBUTING.md)、[翻譯指南](TRANSLATIONS.md) 及 [疑難排解](TROUBLESHOOTING.md) 方針。我們歡迎您的建設性回饋!
## 每堂課包括
- 可選擇的手繪筆記
- 可選擇的補充影片
- 影片導覽(部分課程)
- [課前熱身小測驗](https://ff-quizzes.netlify.app/en/ml/)
- 書面課程說明
- 專案課程的逐步指南教你建構專案
- 知識點檢測
- 挑戰題
- 補充閱讀
- 作業
- [課後測驗](https://ff-quizzes.netlify.app/en/ml/)
> **關於語言的說明**:這些課程主要用 Python 撰寫,但很多也提供 R 版本。若欲完成 R 課程,請進入 `/solution` 資料夾查找 R 版本課程。它們以 .rmd 副檔名標示,代表 **R Markdown** 文件,這種格式將 R 或其他語言的「程式碼區塊」與「YAML 標頭」(指導如何格式化輸出如 PDF結合在 Markdown 文件中。此格式是資料科學的理想編寫架構,因為它允許你同時記錄程式碼、執行輸出與心得,透過 Markdown 直觀呈現。此外R Markdown 文件可以輸出為 PDF、HTML 或 Word 等格式。
> **關於測驗的說明**:所有測驗皆包含於 [Quiz App folder](../../quiz-app) 中,共有 52 個測驗,每個測驗包含三個問題。這些測驗會從課程中連結,但也可以在本地執行測驗應用程式;請依照 `quiz-app` 資料夾中的說明進行本地端架設或部署到 Azure。
| Lesson Number | Topic | Lesson Grouping | Learning Objectives | Linked Lesson | Author |
| :-----------: | :------------------------------------------------------------: | :-------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------: |
| 01 | 機器學習導論 | [Introduction](1-Introduction/README.md) | 瞭解機器學習的基本概念 | [Lesson](1-Introduction/1-intro-to-ML/README.md) | Muhammad |
| 02 | 機器學習的歷史 | [Introduction](1-Introduction/README.md) | 瞭解此領域背後的歷史 | [Lesson](1-Introduction/2-history-of-ML/README.md) | Jen and Amy |
| 03 | 公平性與機器學習 | [Introduction](1-Introduction/README.md) | 學生在建構及應用機器學習模型時,應思考的公平性相關重要哲學議題 | [Lesson](1-Introduction/3-fairness/README.md) | Tomomi |
| 04 | 機器學習技術 | [Introduction](1-Introduction/README.md) | 機器學習研究者用以建構機器學習模型的方法有哪些? | [Lesson](1-Introduction/4-techniques-of-ML/README.md) | Chris and Jen |
| 05 | 回歸介紹 | [Regression](2-Regression/README.md) | 開始使用 Python 和 Scikit-learn 進行回歸模型建構 | [Python](2-Regression/1-Tools/README.md) • [R](../../2-Regression/1-Tools/solution/R/lesson_1.html) | Jen • Eric Wanjau |
| 06 | 北美洲南瓜價格 🎃 | [Regression](2-Regression/README.md) | 視覺化與清理資料,為機器學習作準備 | [Python](2-Regression/2-Data/README.md) • [R](../../2-Regression/2-Data/solution/R/lesson_2.html) | Jen • Eric Wanjau |
| 07 | 北美洲南瓜價格 🎃 | [Regression](2-Regression/README.md) | 建構線性及多項式回歸模型 | [Python](2-Regression/3-Linear/README.md) • [R](../../2-Regression/3-Linear/solution/R/lesson_3.html) | Jen and Dmitry • Eric Wanjau |
| 08 | 北美洲南瓜價格 🎃 | [Regression](2-Regression/README.md) | 建立邏輯斯回歸模型 | [Python](2-Regression/4-Logistic/README.md) • [R](../../2-Regression/4-Logistic/solution/R/lesson_4.html) | Jen • Eric Wanjau |
| 09 | 一個網頁應用 🔌 | [Web App](3-Web-App/README.md) | 建立使用已訓練模型的網頁應用 | [Python](3-Web-App/1-Web-App/README.md) | Jen |
| 10 | 分類介紹 | [Classification](4-Classification/README.md) | 洗淨、準備及視覺化資料;分類介紹 | [Python](4-Classification/1-Introduction/README.md) • [R](../../4-Classification/1-Introduction/solution/R/lesson_10.html) | Jen and Cassie • Eric Wanjau |
| 11 | 美味的亞洲與印度料理 🍜 | [Classification](4-Classification/README.md) | 分類器介紹 | [Python](4-Classification/2-Classifiers-1/README.md) • [R](../../4-Classification/2-Classifiers-1/solution/R/lesson_11.html) | Jen and Cassie • Eric Wanjau |
| 12 | 美味的亞洲與印度料理 🍜 | [Classification](4-Classification/README.md) | 更多分類器 | [Python](4-Classification/3-Classifiers-2/README.md) • [R](../../4-Classification/3-Classifiers-2/solution/R/lesson_12.html) | Jen and Cassie • Eric Wanjau |
| 13 | 美味的亞洲與印度料理 🍜 | [Classification](4-Classification/README.md) | 使用模型建立推薦系統網頁應用 | [Python](4-Classification/4-Applied/README.md) | Jen |
| 14 | 叢集介紹 | [Clustering](5-Clustering/README.md) | 清理、準備及視覺化資料;叢集介紹 | [Python](5-Clustering/1-Visualize/README.md) • [R](../../5-Clustering/1-Visualize/solution/R/lesson_14.html) | Jen • Eric Wanjau |
| 15 | 探索奈及利亞音樂品味 🎧 | [Clustering](5-Clustering/README.md) | 探索 K-Means 叢集方法 | [Python](5-Clustering/2-K-Means/README.md) • [R](../../5-Clustering/2-K-Means/solution/R/lesson_15.html) | Jen • Eric Wanjau |
| 16 | 自然語言處理入門 ☕️ | [Natural language processing](6-NLP/README.md) | 透過建立簡單機器人來學習自然語言處理的基礎 | [Python](6-NLP/1-Introduction-to-NLP/README.md) | Stephen |
| 17 | 常見的自然語言處理任務 ☕️ | [Natural language processing](6-NLP/README.md) | 深入了解處理語言結構時常見的自然語言處理任務 | [Python](6-NLP/2-Tasks/README.md) | Stephen |
| 18 | 翻譯與情感分析 ♥️ | [Natural language processing](6-NLP/README.md) | 使用 Jane Austen 進行翻譯與情感分析 | [Python](6-NLP/3-Translation-Sentiment/README.md) | Stephen |
| 19 | 歐洲浪漫飯店 ♥️ | [Natural language processing](6-NLP/README.md) | 使用飯店評論進行情感分析 1 | [Python](6-NLP/4-Hotel-Reviews-1/README.md) | Stephen |
| 20 | 歐洲浪漫飯店 ♥️ | [Natural language processing](6-NLP/README.md) | 使用飯店評論進行情感分析 2 | [Python](6-NLP/5-Hotel-Reviews-2/README.md) | Stephen |
| 21 | 時序預測入門 | [Time series](7-TimeSeries/README.md) | 時序預測介紹 | [Python](7-TimeSeries/1-Introduction/README.md) | Francesca |
| 22 | ⚡️ 世界能源使用 ⚡️ - 使用 ARIMA 進行時序預測 | [Time series](7-TimeSeries/README.md) | 使用 ARIMA 進行時序預測 | [Python](7-TimeSeries/2-ARIMA/README.md) | Francesca |
| 23 | ⚡️ 世界能源使用 ⚡️ - 使用 SVR 進行時序預測 | [Time series](7-TimeSeries/README.md) | 使用支持向量迴歸 (SVR) 進行時序預測 | [Python](7-TimeSeries/3-SVR/README.md) | Anirban |
| 24 | 強化學習介紹 | [Reinforcement learning](8-Reinforcement/README.md) | 以 Q-Learning 介紹強化學習 | [Python](8-Reinforcement/1-QLearning/README.md) | Dmitry |
| 25 | 幫助彼得避免狼!🐺 | [Reinforcement learning](8-Reinforcement/README.md) | 強化學習 Gym | [Python](8-Reinforcement/2-Gym/README.md) | Dmitry |
| 後記 | 現實世界中的機器學習場景與應用 | [ML in the Wild](9-Real-World/README.md) | 傳統機器學習在現實世界中有趣且深刻的應用 | [Lesson](9-Real-World/1-Applications/README.md) | 團隊 |
| 後記 | 使用 RAI 儀表板進行機器學習模型偵錯 | [ML in the Wild](9-Real-World/README.md) | 使用 Responsible AI 儀表板元件進行機器學習模型偵錯 | [Lesson](9-Real-World/2-Debugging-ML-Models/README.md) | Ruth Yakubu |
> [在我們的 Microsoft Learn 集合中找到本課程的所有額外資源](https://learn.microsoft.com/en-us/collections/qrqzamz1nn2wx3?WT.mc_id=academic-77952-bethanycheum)
## 離線存取
您可以使用 [Docsify](https://docsify.js.org/#/) 離線執行本文件。複製此倉庫,在本機安裝 [Docsify](https://docsify.js.org/#/quickstart),然後在此倉庫根目錄輸入 `docsify serve`。網頁將在本機的 3000 連接埠啟動:`localhost:3000`。
## PDF
[此處](https://microsoft.github.io/ML-For-Beginners/pdf/readme.pdf)可找到課程大綱及連結的 PDF 檔案。
## 🎒 其他課程
我們團隊還製作其他課程!歡迎參考:
<!-- CO-OP TRANSLATOR OTHER COURSES START -->
### LangChain
[![LangChain4j for Beginners](https://img.shields.io/badge/LangChain4j%20for%20Beginners-22C55E?style=for-the-badge&&labelColor=E5E7EB&color=0553D6)](https://aka.ms/langchain4j-for-beginners)
[![LangChain.js for Beginners](https://img.shields.io/badge/LangChain.js%20for%20Beginners-22C55E?style=for-the-badge&labelColor=E5E7EB&color=0553D6)](https://aka.ms/langchainjs-for-beginners?WT.mc_id=m365-94501-dwahlin)
---
### Azure / Edge / MCP / Agents
[![AZD for Beginners](https://img.shields.io/badge/AZD%20for%20Beginners-0078D4?style=for-the-badge&labelColor=E5E7EB&color=0078D4)](https://github.com/microsoft/AZD-for-beginners?WT.mc_id=academic-105485-koreyst)
[![Edge AI for Beginners](https://img.shields.io/badge/Edge%20AI%20for%20Beginners-00B8E4?style=for-the-badge&labelColor=E5E7EB&color=00B8E4)](https://github.com/microsoft/edgeai-for-beginners?WT.mc_id=academic-105485-koreyst)
[![MCP for Beginners](https://img.shields.io/badge/MCP%20for%20Beginners-009688?style=for-the-badge&labelColor=E5E7EB&color=009688)](https://github.com/microsoft/mcp-for-beginners?WT.mc_id=academic-105485-koreyst)
[![AI Agents for Beginners](https://img.shields.io/badge/AI%20Agents%20for%20Beginners-00C49A?style=for-the-badge&labelColor=E5E7EB&color=00C49A)](https://github.com/microsoft/ai-agents-for-beginners?WT.mc_id=academic-105485-koreyst)
---
### Generative AI Series
[![入門生成式 AI](https://img.shields.io/badge/Generative%20AI%20for%20Beginners-8B5CF6?style=for-the-badge&labelColor=E5E7EB&color=8B5CF6)](https://github.com/microsoft/generative-ai-for-beginners?WT.mc_id=academic-105485-koreyst)
[![生成式 AI (.NET)](https://img.shields.io/badge/Generative%20AI%20(.NET)-9333EA?style=for-the-badge&labelColor=E5E7EB&color=9333EA)](https://github.com/microsoft/Generative-AI-for-beginners-dotnet?WT.mc_id=academic-105485-koreyst)
[![生成式 AI (Java)](https://img.shields.io/badge/Generative%20AI%20(Java)-C084FC?style=for-the-badge&labelColor=E5E7EB&color=C084FC)](https://github.com/microsoft/generative-ai-for-beginners-java?WT.mc_id=academic-105485-koreyst)
[![生成式 AI (JavaScript)](https://img.shields.io/badge/Generative%20AI%20(JavaScript)-E879F9?style=for-the-badge&labelColor=E5E7EB&color=E879F9)](https://github.com/microsoft/generative-ai-with-javascript?WT.mc_id=academic-105485-koreyst)
---
### 核心學習
[![入門機器學習](https://img.shields.io/badge/ML%20for%20Beginners-22C55E?style=for-the-badge&labelColor=E5E7EB&color=22C55E)](https://aka.ms/ml-beginners?WT.mc_id=academic-105485-koreyst)
[![入門資料科學](https://img.shields.io/badge/Data%20Science%20for%20Beginners-84CC16?style=for-the-badge&labelColor=E5E7EB&color=84CC16)](https://aka.ms/datascience-beginners?WT.mc_id=academic-105485-koreyst)
[![入門人工智慧](https://img.shields.io/badge/AI%20for%20Beginners-A3E635?style=for-the-badge&labelColor=E5E7EB&color=A3E635)](https://aka.ms/ai-beginners?WT.mc_id=academic-105485-koreyst)
[![入門網路安全](https://img.shields.io/badge/Cybersecurity%20for%20Beginners-F97316?style=for-the-badge&labelColor=E5E7EB&color=F97316)](https://github.com/microsoft/Security-101?WT.mc_id=academic-96948-sayoung)
[![入門網頁開發](https://img.shields.io/badge/Web%20Dev%20for%20Beginners-EC4899?style=for-the-badge&labelColor=E5E7EB&color=EC4899)](https://aka.ms/webdev-beginners?WT.mc_id=academic-105485-koreyst)
[![入門物聯網](https://img.shields.io/badge/IoT%20for%20Beginners-14B8A6?style=for-the-badge&labelColor=E5E7EB&color=14B8A6)](https://aka.ms/iot-beginners?WT.mc_id=academic-105485-koreyst)
[![入門擴增實境開發](https://img.shields.io/badge/XR%20Development%20for%20Beginners-38BDF8?style=for-the-badge&labelColor=E5E7EB&color=38BDF8)](https://github.com/microsoft/xr-development-for-beginners?WT.mc_id=academic-105485-koreyst)
---
### Copilot 系列
[![AI 配對編程 Copilot](https://img.shields.io/badge/Copilot%20for%20AI%20Paired%20Programming-FACC15?style=for-the-badge&labelColor=E5E7EB&color=FACC15)](https://aka.ms/GitHubCopilotAI?WT.mc_id=academic-105485-koreyst)
[![C#/.NET Copilot](https://img.shields.io/badge/Copilot%20for%20C%23/.NET-FBBF24?style=for-the-badge&labelColor=E5E7EB&color=FBBF24)](https://github.com/microsoft/mastering-github-copilot-for-dotnet-csharp-developers?WT.mc_id=academic-105485-koreyst)
[![Copilot 冒險](https://img.shields.io/badge/Copilot%20Adventure-FDE68A?style=for-the-badge&labelColor=E5E7EB&color=FDE68A)](https://github.com/microsoft/CopilotAdventures?WT.mc_id=academic-105485-koreyst)
<!-- CO-OP TRANSLATOR OTHER COURSES END -->
## 尋求協助
如果您在構建 AI 應用程式時遇到困難或有任何疑問,歡迎加入學習者和經驗豐富的開發者一起討論 MCP。這是一個支持性的社群歡迎提問並自由分享知識。
[![Microsoft Foundry Discord](https://dcbadge.limes.pink/api/server/nTYy5BXMWG)](https://discord.gg/nTYy5BXMWG)
如果您在開發過程中有產品反饋或錯誤,請造訪:
[![Microsoft Foundry Developer Forum](https://img.shields.io/badge/GitHub-Microsoft_Foundry_Developer_Forum-blue?style=for-the-badge&logo=github&color=000000&logoColor=fff)](https://aka.ms/foundry/forum)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**免責聲明**
本文件係使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應視為權威來源。對於重要資訊,建議採用專業人工翻譯。我們不對因使用本翻譯所導致的任何誤解或誤譯承擔責任。
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

@ -0,0 +1,42 @@
## 安全性
Microsoft 非常重視我們軟體產品和服務的安全性,包括透過我們的 GitHub 組織管理的所有原始碼庫,這些組織包括 [Microsoft](https://github.com/Microsoft)、[Azure](https://github.com/Azure)、[DotNet](https://github.com/dotnet)、[AspNet](https://github.com/aspnet)、[Xamarin](https://github.com/xamarin) 以及 [我們的 GitHub 組織](https://opensource.microsoft.com/)。
如果您認為在任何 Microsoft 擁有的原始碼庫中發現了符合 [Microsoft 對安全性漏洞的定義](https://docs.microsoft.com/previous-versions/tn-archive/cc751383(v=technet.10)?WT.mc_id=academic-77952-leestott) 的安全性漏洞,請按照以下描述向我們報告。
## 報告安全性問題
**請勿透過公開的 GitHub 問題報告安全性漏洞。**
相反,請透過 Microsoft Security Response Center (MSRC) 報告,網址為 [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report)。
如果您希望在不登入的情況下提交報告,請發送電子郵件至 [secure@microsoft.com](mailto:secure@microsoft.com)。如果可能,請使用我們的 PGP 金鑰加密您的訊息;您可以從 [Microsoft Security Response Center PGP Key 頁面](https://www.microsoft.com/en-us/msrc/pgp-key-msrc) 下載。
您應在 24 小時內收到回覆。如果因某些原因未收到回覆,請透過電子郵件跟進,以確保我們收到您的原始訊息。更多資訊可參考 [microsoft.com/msrc](https://www.microsoft.com/msrc)。
請提供以下所需資訊(盡可能完整),以幫助我們更好地了解問題的性質和範圍:
* 問題類型例如緩衝區溢位、SQL 注入、跨站腳本攻擊等)
* 與問題相關的原始檔案的完整路徑
* 受影響原始碼的位置(標籤/分支/提交或直接 URL
* 重現問題所需的任何特殊配置
* 重現問題的逐步指導
* 概念驗證或漏洞利用程式碼(如果可能)
* 問題的影響,包括攻擊者可能如何利用該問題
這些資訊將幫助我們更快速地處理您的報告。
如果您是為漏洞賞金計劃報告,提供更完整的報告可能會獲得更高的賞金獎勵。請造訪我們的 [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) 頁面,了解更多有關我們現行計劃的詳細資訊。
## 偏好語言
我們偏好所有的溝通使用英文。
## 政策
Microsoft 遵循 [協調式漏洞披露](https://www.microsoft.com/en-us/msrc/cvd) 的原則。
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,20 @@
# 支援
## 如何提交問題並獲得幫助
在提交問題之前,請先查看我們的 [故障排除指南](TROUBLESHOOTING.md),以尋找有關安裝、設置和運行課程的常見問題解決方案。
此專案使用 GitHub Issues 來追蹤錯誤和功能請求。在提交新問題之前,請先搜尋現有的問題,以避免重複。對於新問題,請將您的錯誤或功能請求提交為一個新的 Issue。
如果您需要幫助或對使用此專案有疑問,您也可以:
- 查看 [故障排除指南](TROUBLESHOOTING.md)
- 參加我們的 [Discord 討論 #ml-for-beginners 頻道](https://aka.ms/foundry/discord)
- 提交一個 Issue
## Microsoft 支援政策
對於此存儲庫的支援僅限於上述列出的資源。
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤釋不承擔責任。

@ -0,0 +1,601 @@
# 疑難排解指南
本指南旨在幫助您解決使用《機器學習初學者》課程時常見的問題。如果您在此未找到解決方案,請查看我們的 [Discord 討論區](https://aka.ms/foundry/discord) 或 [提交問題](https://github.com/microsoft/ML-For-Beginners/issues)。
## 目錄
- [安裝問題](../..)
- [Jupyter Notebook 問題](../..)
- [Python 套件問題](../..)
- [R 環境問題](../..)
- [測驗應用程式問題](../..)
- [數據和檔案路徑問題](../..)
- [常見錯誤訊息](../..)
- [效能問題](../..)
- [環境與配置](../..)
---
## 安裝問題
### Python 安裝
**問題**: `python: command not found`
**解決方案**:
1. 從 [python.org](https://www.python.org/downloads/) 安裝 Python 3.8 或更高版本
2. 驗證安裝: `python --version``python3 --version`
3. 在 macOS/Linux 上,可能需要使用 `python3` 而非 `python`
**問題**: 多個 Python 版本導致衝突
**解決方案**:
```bash
# Use virtual environments to isolate projects
python -m venv ml-env
# Activate virtual environment
# On Windows:
ml-env\Scripts\activate
# On macOS/Linux:
source ml-env/bin/activate
```
### Jupyter 安裝
**問題**: `jupyter: command not found`
**解決方案**:
```bash
# Install Jupyter
pip install jupyter
# Or with pip3
pip3 install jupyter
# Verify installation
jupyter --version
```
**問題**: Jupyter 無法在瀏覽器中啟動
**解決方案**:
```bash
# Try specifying the browser
jupyter notebook --browser=chrome
# Or copy the URL with token from terminal and paste in browser manually
# Look for: http://localhost:8888/?token=...
```
### R 安裝
**問題**: R 套件無法安裝
**解決方案**:
```r
# Ensure you have the latest R version
# Install packages with dependencies
install.packages(c("tidyverse", "tidymodels", "caret"), dependencies = TRUE)
# If compilation fails, try installing binary versions
install.packages("package-name", type = "binary")
```
**問題**: IRkernel 無法在 Jupyter 中使用
**解決方案**:
```r
# In R console
install.packages('IRkernel')
IRkernel::installspec(user = TRUE)
```
---
## Jupyter Notebook 問題
### 核心問題
**問題**: 核心持續崩潰或重新啟動
**解決方案**:
1. 重啟核心: `Kernel → Restart`
2. 清除輸出並重啟: `Kernel → Restart & Clear Output`
3. 檢查記憶體問題 (請參閱 [效能問題](../..))
4. 嘗試逐個執行單元以識別有問題的程式碼
**問題**: 選擇了錯誤的 Python 核心
**解決方案**:
1. 檢查當前核心: `Kernel → Change Kernel`
2. 選擇正確的 Python 版本
3. 如果核心缺失,請建立它:
```bash
python -m ipykernel install --user --name=ml-env
```
**問題**: 核心無法啟動
**解決方案**:
```bash
# Reinstall ipykernel
pip uninstall ipykernel
pip install ipykernel
# Register the kernel again
python -m ipykernel install --user
```
### Notebook 單元問題
**問題**: 單元正在執行但未顯示輸出
**解決方案**:
1. 檢查單元是否仍在執行 (查看 `[*]` 指示器)
2. 重啟核心並執行所有單元: `Kernel → Restart & Run All`
3. 檢查瀏覽器主控台是否有 JavaScript 錯誤 (按 F12)
**問題**: 無法執行單元 - 點擊「執行」無反應
**解決方案**:
1. 檢查 Jupyter 伺服器是否仍在終端中運行
2. 刷新瀏覽器頁面
3. 關閉並重新打開 Notebook
4. 重啟 Jupyter 伺服器
---
## Python 套件問題
### 匯入錯誤
**問題**: `ModuleNotFoundError: No module named 'sklearn'`
**解決方案**:
```bash
pip install scikit-learn
# Common ML packages for this course
pip install scikit-learn pandas numpy matplotlib seaborn
```
**問題**: `ImportError: cannot import name 'X' from 'sklearn'`
**解決方案**:
```bash
# Update scikit-learn to latest version
pip install --upgrade scikit-learn
# Check version
python -c "import sklearn; print(sklearn.__version__)"
```
### 版本衝突
**問題**: 套件版本不相容錯誤
**解決方案**:
```bash
# Create a new virtual environment
python -m venv fresh-env
source fresh-env/bin/activate # or fresh-env\Scripts\activate on Windows
# Install packages fresh
pip install jupyter scikit-learn pandas numpy matplotlib seaborn
# If specific version needed
pip install scikit-learn==1.3.0
```
**問題**: `pip install` 因權限錯誤而失敗
**解決方案**:
```bash
# Install for current user only
pip install --user package-name
# Or use virtual environment (recommended)
python -m venv venv
source venv/bin/activate
pip install package-name
```
### 數據載入問題
**問題**: 載入 CSV 檔案時出現 `FileNotFoundError`
**解決方案**:
```python
import os
# Check current working directory
print(os.getcwd())
# Use relative paths from notebook location
df = pd.read_csv('../../data/filename.csv')
# Or use absolute paths
df = pd.read_csv('/full/path/to/data/filename.csv')
```
---
## R 環境問題
### 套件安裝
**問題**: 套件安裝因編譯錯誤而失敗
**解決方案**:
```r
# Install binary version (Windows/macOS)
install.packages("package-name", type = "binary")
# Update R to latest version if packages require it
# Check R version
R.version.string
# Install system dependencies (Linux)
# For Ubuntu/Debian, in terminal:
# sudo apt-get install r-base-dev
```
**問題**: `tidyverse` 無法安裝
**解決方案**:
```r
# Install dependencies first
install.packages(c("rlang", "vctrs", "pillar"))
# Then install tidyverse
install.packages("tidyverse")
# Or install components individually
install.packages(c("dplyr", "ggplot2", "tidyr", "readr"))
```
### RMarkdown 問題
**問題**: RMarkdown 無法渲染
**解決方案**:
```r
# Install/update rmarkdown
install.packages("rmarkdown")
# Install pandoc if needed
install.packages("pandoc")
# For PDF output, install tinytex
install.packages("tinytex")
tinytex::install_tinytex()
```
---
## 測驗應用程式問題
### 建置與安裝
**問題**: `npm install` 失敗
**解決方案**:
```bash
# Clear npm cache
npm cache clean --force
# Remove node_modules and package-lock.json
rm -rf node_modules package-lock.json
# Reinstall
npm install
# If still fails, try with legacy peer deps
npm install --legacy-peer-deps
```
**問題**: 8080 埠已被佔用
**解決方案**:
```bash
# Use different port
npm run serve -- --port 8081
# Or find and kill process using port 8080
# On Linux/macOS:
lsof -ti:8080 | xargs kill -9
# On Windows:
netstat -ano | findstr :8080
taskkill /PID <PID> /F
```
### 建置錯誤
**問題**: `npm run build` 失敗
**解決方案**:
```bash
# Check Node.js version (should be 14+)
node --version
# Update Node.js if needed
# Then clean install
rm -rf node_modules package-lock.json
npm install
npm run build
```
**問題**: Linting 錯誤阻止建置
**解決方案**:
```bash
# Fix auto-fixable issues
npm run lint -- --fix
# Or temporarily disable linting in build
# (not recommended for production)
```
---
## 數據和檔案路徑問題
### 路徑問題
**問題**: 執行 Notebook 時找不到數據檔案
**解決方案**:
1. **始終從 Notebook 所在目錄執行**
```bash
cd /path/to/lesson/folder
jupyter notebook
```
2. **檢查程式碼中的相對路徑**
```python
# Correct path from notebook location
df = pd.read_csv('../data/filename.csv')
# Not from your terminal location
```
3. **必要時使用絕對路徑**
```python
import os
base_path = os.path.dirname(os.path.abspath(__file__))
data_path = os.path.join(base_path, 'data', 'filename.csv')
```
### 缺少數據檔案
**問題**: 數據集檔案缺失
**解決方案**:
1. 檢查數據是否應包含在存儲庫中 - 大多數數據集已包含
2. 某些課程可能需要下載數據 - 查看課程 README
3. 確保已拉取最新更改:
```bash
git pull origin main
```
---
## 常見錯誤訊息
### 記憶體錯誤
**錯誤**: `MemoryError` 或核心在處理數據時崩潰
**解決方案**:
```python
# Load data in chunks
for chunk in pd.read_csv('large_file.csv', chunksize=10000):
process(chunk)
# Or read only needed columns
df = pd.read_csv('file.csv', usecols=['col1', 'col2'])
# Free memory when done
del large_dataframe
import gc
gc.collect()
```
### 收斂警告
**警告**: `ConvergenceWarning: Maximum number of iterations reached`
**解決方案**:
```python
from sklearn.linear_model import LogisticRegression
# Increase max iterations
model = LogisticRegression(max_iter=1000)
# Or scale your features first
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
```
### 繪圖問題
**問題**: Jupyter 中未顯示繪圖
**解決方案**:
```python
# Enable inline plotting
%matplotlib inline
# Import pyplot
import matplotlib.pyplot as plt
# Show plot explicitly
plt.plot(data)
plt.show()
```
**問題**: Seaborn 繪圖顯示異常或出現錯誤
**解決方案**:
```python
import warnings
warnings.filterwarnings('ignore', category=UserWarning)
# Update to compatible version
# pip install --upgrade seaborn matplotlib
```
### Unicode/編碼錯誤
**問題**: 讀取檔案時出現 `UnicodeDecodeError`
**解決方案**:
```python
# Specify encoding explicitly
df = pd.read_csv('file.csv', encoding='utf-8')
# Or try different encoding
df = pd.read_csv('file.csv', encoding='latin-1')
# For errors='ignore' to skip problematic characters
df = pd.read_csv('file.csv', encoding='utf-8', errors='ignore')
```
---
## 效能問題
### Notebook 執行速度慢
**問題**: Notebook 執行速度非常慢
**解決方案**:
1. **重啟核心以釋放記憶體**: `Kernel → Restart`
2. **關閉未使用的 Notebook** 以釋放資源
3. **使用較小的數據樣本進行測試**:
```python
# Work with subset during development
df_sample = df.sample(n=1000)
```
4. **分析程式碼效能**以找到瓶頸:
```python
%time operation() # Time single operation
%timeit operation() # Time with multiple runs
```
### 高記憶體使用率
**問題**: 系統記憶體不足
**解決方案**:
```python
# Check memory usage
df.info(memory_usage='deep')
# Optimize data types
df['column'] = df['column'].astype('int32') # Instead of int64
# Drop unnecessary columns
df = df[['col1', 'col2']] # Keep only needed columns
# Process in batches
for batch in np.array_split(df, 10):
process(batch)
```
---
## 環境與配置
### 虛擬環境問題
**問題**: 虛擬環境無法啟動
**解決方案**:
```bash
# Windows
python -m venv venv
venv\Scripts\activate.bat
# macOS/Linux
python3 -m venv venv
source venv/bin/activate
# Check if activated (should show venv name in prompt)
which python # Should point to venv python
```
**問題**: 套件已安裝但在 Notebook 中找不到
**解決方案**:
```bash
# Ensure notebook uses the correct kernel
# Install ipykernel in your venv
pip install ipykernel
python -m ipykernel install --user --name=ml-env --display-name="Python (ml-env)"
# In Jupyter: Kernel → Change Kernel → Python (ml-env)
```
### Git 問題
**問題**: 無法拉取最新更改 - 合併衝突
**解決方案**:
```bash
# Stash your changes
git stash
# Pull latest
git pull origin main
# Reapply your changes
git stash pop
# If conflicts, resolve manually or:
git checkout --theirs path/to/file # Take remote version
git checkout --ours path/to/file # Keep your version
```
### VS Code 整合
**問題**: Jupyter Notebook 無法在 VS Code 中打開
**解決方案**:
1. 在 VS Code 中安裝 Python 擴展
2. 在 VS Code 中安裝 Jupyter 擴展
3. 選擇正確的 Python 解釋器: `Ctrl+Shift+P` → "Python: Select Interpreter"
4. 重啟 VS Code
---
## 其他資源
- **Discord 討論區**: [在 #ml-for-beginners 頻道中提問並分享解決方案](https://aka.ms/foundry/discord)
- **Microsoft Learn**: [機器學習初學者模組](https://learn.microsoft.com/en-us/collections/qrqzamz1nn2wx3?WT.mc_id=academic-77952-bethanycheum)
- **影片教程**: [YouTube 播放列表](https://aka.ms/ml-beginners-videos)
- **問題追蹤器**: [回報錯誤](https://github.com/microsoft/ML-For-Beginners/issues)
---
## 仍有問題?
如果您已嘗試上述解決方案但仍遇到問題:
1. **搜尋現有問題**: [GitHub Issues](https://github.com/microsoft/ML-For-Beginners/issues)
2. **查看 Discord 討論**: [Discord Discussions](https://aka.ms/foundry/discord)
3. **提交新問題**: 包括以下內容:
- 您的操作系統及版本
- Python/R 版本
- 錯誤訊息 (完整回溯)
- 重現問題的步驟
- 您已嘗試的解決方法
我們隨時為您提供幫助! 🚀
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原文文件為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或誤釋不承擔責任。

@ -0,0 +1,48 @@
- 介紹
- [機器學習介紹](../1-Introduction/1-intro-to-ML/README.md)
- [機器學習的歷史](../1-Introduction/2-history-of-ML/README.md)
- [機器學習與公平性](../1-Introduction/3-fairness/README.md)
- [機器學習的技術](../1-Introduction/4-techniques-of-ML/README.md)
- 回歸分析
- [工具介紹](../2-Regression/1-Tools/README.md)
- [資料](../2-Regression/2-Data/README.md)
- [線性回歸](../2-Regression/3-Linear/README.md)
- [邏輯回歸](../2-Regression/4-Logistic/README.md)
- 建立網頁應用程式
- [網頁應用程式](../3-Web-App/1-Web-App/README.md)
- 分類
- [分類介紹](../4-Classification/1-Introduction/README.md)
- [分類器 1](../4-Classification/2-Classifiers-1/README.md)
- [分類器 2](../4-Classification/3-Classifiers-2/README.md)
- [應用機器學習](../4-Classification/4-Applied/README.md)
- 分群
- [資料視覺化](../5-Clustering/1-Visualize/README.md)
- [K-Means 演算法](../5-Clustering/2-K-Means/README.md)
- 自然語言處理 (NLP)
- [自然語言處理介紹](../6-NLP/1-Introduction-to-NLP/README.md)
- [自然語言處理任務](../6-NLP/2-Tasks/README.md)
- [翻譯與情感分析](../6-NLP/3-Translation-Sentiment/README.md)
- [酒店評論 1](../6-NLP/4-Hotel-Reviews-1/README.md)
- [酒店評論 2](../6-NLP/5-Hotel-Reviews-2/README.md)
- 時間序列預測
- [時間序列預測介紹](../7-TimeSeries/1-Introduction/README.md)
- [ARIMA 模型](../7-TimeSeries/2-ARIMA/README.md)
- [SVR 模型](../7-TimeSeries/3-SVR/README.md)
- 強化學習
- [Q-Learning](../8-Reinforcement/1-QLearning/README.md)
- [Gym](../8-Reinforcement/2-Gym/README.md)
- 真實世界中的機器學習
- [應用](../9-Real-World/1-Applications/README.md)
---
**免責聲明**
本文件使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不精確之處。原始文件的母語版本應被視為權威來源。對於重要資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,28 @@
## 給教育工作者
您是否希望在課堂上使用這份課程?請隨意使用!
事實上,您可以直接在 GitHub 上使用它,透過 GitHub Classroom 來進行。
要做到這一點,請先 fork 此 repo。您需要為每個課程創建一個 repo因此需要將每個資料夾提取到一個單獨的 repo 中。這樣,[GitHub Classroom](https://classroom.github.com/classrooms) 就能分別處理每個課程。
這些[完整的指導說明](https://github.blog/2020-03-18-set-up-your-digital-classroom-with-github-classroom/)可以幫助您了解如何設置您的課堂。
## 直接使用此 repo
如果您希望直接使用目前的 repo而不使用 GitHub Classroom也可以這樣做。您需要與您的學生溝通告訴他們一起學習哪一課。
在線上教學形式(例如 Zoom、Teams 或其他平台)中,您可以為測驗設置分組討論室,並指導學生做好學習準備。然後邀請學生參加測驗,並在指定時間以 "issues" 的形式提交答案。如果您希望學生在公開環境中合作完成作業,也可以採取相同的方式。
如果您更喜歡較為私密的形式,可以要求您的學生逐課 fork 此課程到他們自己的 GitHub 私人 repo並授予您訪問權限。然後他們可以私下完成測驗和作業並通過 classroom repo 的 issues 提交給您。
在線課堂有許多不同的運作方式。請告訴我們哪種方式最適合您!
## 請提供您的意見!
我們希望這份課程能夠滿足您和您學生的需求。請提供您的[反饋](https://forms.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR2humCsRZhxNuI79cm6n0hRUQzRVVU9VVlU5UlFLWTRLWlkyQUxORTg5WS4u)。
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,118 @@
# 測驗
這些測驗是 https://aka.ms/ml-beginners 的機器學習課程的課前和課後測驗。
## 專案設置
```
npm install
```
### 編譯並熱重載以進行開發
```
npm run serve
```
### 編譯並壓縮以進行生產環境
```
npm run build
```
### 檢查並修復檔案
```
npm run lint
```
### 自訂配置
請參閱 [配置參考](https://cli.vuejs.org/config/)。
致謝感謝此測驗應用程式的原始版本https://github.com/arpan45/simple-quiz-vue
## 部署到 Azure
以下是幫助您開始的逐步指南:
1. Fork GitHub 儲存庫
確保您的靜態網頁應用程式代碼在您的 GitHub 儲存庫中。Fork 此儲存庫。
2. 建立 Azure 靜態網頁應用程式
- 建立 [Azure 帳戶](http://azure.microsoft.com)
- 前往 [Azure 入口網站](https://portal.azure.com)
- 點擊「建立資源」,然後搜尋「靜態網頁應用程式」。
- 點擊「建立」。
3. 配置靜態網頁應用程式
- 基本設定:
- 訂閱:選擇您的 Azure 訂閱。
- 資源群組:建立新的資源群組或使用現有的資源群組。
- 名稱:為您的靜態網頁應用程式提供一個名稱。
- 區域:選擇最接近您使用者的區域。
- #### 部署詳細資訊:
- 原始碼來源選擇「GitHub」。
- GitHub 帳戶:授權 Azure 訪問您的 GitHub 帳戶。
- 組織:選擇您的 GitHub 組織。
- 儲存庫:選擇包含靜態網頁應用程式的儲存庫。
- 分支:選擇您要部署的分支。
- #### 建置詳細資訊:
- 建置預設:選擇您的應用程式所使用的框架(例如 React、Angular、Vue 等)。
- 應用程式位置:指定包含應用程式代碼的資料夾(例如,如果在根目錄則為 /)。
- API 位置:如果有 API請指定其位置可選
- 輸出位置:指定生成輸出的資料夾(例如 build 或 dist
4. 檢查並建立
檢查您的設置然後點擊「建立」。Azure 將設置必要的資源並在您的儲存庫中建立 GitHub Actions 工作流程。
5. GitHub Actions 工作流程
Azure 會自動在您的儲存庫中建立 GitHub Actions 工作流程檔案(.github/workflows/azure-static-web-apps-<name>.yml。此工作流程將處理建置和部署過程。
6. 監控部署
前往 GitHub 儲存庫中的「Actions」標籤。
您應該看到一個工作流程正在運行。此工作流程將建置並部署您的靜態網頁應用程式到 Azure。
工作流程完成後,您的應用程式將在提供的 Azure URL 上線。
### 範例工作流程檔案
以下是 GitHub Actions 工作流程檔案的範例:
name: Azure Static Web Apps CI/CD
```
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened, closed]
branches:
- main
jobs:
build_and_deploy_job:
runs-on: ubuntu-latest
name: Build and Deploy Job
steps:
- uses: actions/checkout@v2
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
repo_token: ${{ secrets.GITHUB_TOKEN }}
action: "upload"
app_location: "/quiz-app" # App source code path
api_location: ""API source code path optional
output_location: "dist" #Built app content directory - optional
```
### 其他資源
- [Azure 靜態網頁應用程式文件](https://learn.microsoft.com/azure/static-web-apps/getting-started)
- [GitHub Actions 文件](https://docs.github.com/actions/use-cases-and-examples/deploying/deploying-to-azure-static-web-app)
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們努力確保翻譯的準確性,但請注意,自動翻譯可能包含錯誤或不準確之處。原始語言的文件應被視為權威來源。對於重要資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而產生的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,190 @@
Attribution-ShareAlike 4.0 國際版
=======================================================================
創用CCCreative Commons組織以下簡稱「創用CC」不是律師事務所亦不提供法律服務或法律建議。分發創用CC公共授權並不構成律師與客戶或其他關係。創用CC以「現狀」提供其授權及相關資訊對其授權、根據授權條款和條件授權的任何材料或相關資訊不作任何保證。創用CC在法律允許的最大範圍內對因使用其授權而導致的損害不承擔任何責任。
使用創用CC公共授權
創用CC公共授權提供了一套標準的條款和條件創作者及其他權利持有人可用於分享受版權及以下公共授權中指定的某些其他權利約束的原創作品及其他材料。以下考量僅供參考並非詳盡無遺亦不構成我們授權的一部分。
授權者的考量我們的公共授權旨在供那些有權授予公眾使用材料的許可否則受版權及某些其他權利限制的人使用。我們的授權是不可撤銷的。授權者在應用授權之前應仔細閱讀並理解所選授權的條款和條件。授權者還應在應用授權之前確保擁有所有必要的權利以便公眾能按預期重用材料。授權者應清楚標記任何不受授權約束的材料包括其他創用CC授權的材料或根據版權的例外或限制使用的材料。更多授權者考量
wiki.creativecommons.org/Considerations_for_licensors
公眾的考量:通過使用我們的公共授權,授權者授予公眾根據指定的條款和條件使用授權材料的許可。如果因任何原因不需要授權者的許可,例如因適用的版權例外或限制,則該使用不受授權約束。我們的授權僅授予授權者有權授予的版權及某些其他權利下的許可。授權材料的使用可能仍因其他原因受到限制,包括因其他人對材料擁有版權或其他權利。授權者可能提出特殊要求,例如要求標記或描述所有更改。雖然我們的授權不要求這樣做,但建議在合理的情況下尊重這些要求。更多公眾考量:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
創用CC Attribution-ShareAlike 4.0 國際公共授權
通過行使以下定義的授權權利您接受並同意受創用CC Attribution-ShareAlike 4.0 國際公共授權(以下簡稱「公共授權」)的條款和條件約束。在公共授權可被解釋為合同的範圍內,您因接受這些條款和條件而被授予授權權利,授權者因根據這些條款和條件提供授權材料而獲得利益,授予您這些權利。
第 1 節 —— 定義。
a. 改編材料指受版權及類似權利約束的材料,該材料基於授權材料進行衍生或改編,並且授權材料被翻譯、修改、編排、轉化或以其他方式更改,需授權者持有的版權及類似權利的許可。就本公共授權而言,當授權材料是音樂作品、表演或聲音錄製時,改編材料始終指授權材料與動態影像同步呈現的情況。
b. 改編者授權指您根據本公共授權的條款和條件,應用於您對改編材料的版權及類似權利的授權。
c. BY-SA 兼容授權指創用CC批准的授權列於 creativecommons.org/compatiblelicenses並被認為與本公共授權基本等同。
d. 版權及類似權利指版權及/或與版權密切相關的類似權利,包括但不限於表演、廣播、聲音錄製及特殊數據庫權利,不論這些權利如何被標記或分類。就本公共授權而言,第 2 節 (b)(1)-(2) 中指定的權利不屬於版權及類似權利。
e. 有效技術措施指在未獲得適當授權的情況下,根據 1996 年 12 月 20 日通過的 WIPO 版權條約第 11 條及/或類似國際協議的義務,無法被規避的措施。
f. 例外和限制指合理使用、合理交易及/或任何其他適用於您使用授權材料的版權及類似權利的例外或限制。
g. 授權元素指創用CC公共授權名稱中列出的授權屬性。本公共授權的授權元素為 Attribution 和 ShareAlike。
h. 授權材料指授權者應用本公共授權的藝術或文學作品、數據庫或其他材料。
i. 授權權利指根據本公共授權的條款和條件授予您的權利,僅限於適用於您使用授權材料的所有版權及類似權利,且授權者有權授予。
j. 授權者指根據本公共授權授予權利的個人或實體。
k. 分享指以任何需要授權權利許可的方式或過程向公眾提供材料,例如複製、公開展示、公開表演、分發、傳播、通信或進口,以及使公眾能夠在其選擇的時間和地點訪問材料。
l. 特殊數據庫權利指歐洲議會和理事會於 1996 年 3 月 11 日通過的 96/9/EC 指令中規定的數據庫法律保護所產生的版權以外的權利,以及在世界其他地方的基本等同權利。
m. 您指根據本公共授權行使授權權利的個人或實體。「您的」具有相應含義。
第 2 節 —— 範圍。
a. 授權授予。
1. 根據本公共授權的條款和條件,授權者特此授予您全球範圍內免版稅、不可再授權、非排他性、不可撤銷的授權,行使授權材料的授權權利以:
a. 複製並分享授權材料,無論是全部還是部分;以及
b. 創作、複製並分享改編材料。
2. 例外和限制。為避免疑義,當例外和限制適用於您的使用時,本公共授權不適用,您無需遵守其條款和條件。
3. 有效期。本公共授權的有效期在第 6 節 (a) 中規定。
4. 媒體和格式;允許技術修改。授權者授權您在現有或未來創建的所有媒體和格式中行使授權權利,並進行必要的技術修改以實現此目的。授權者放棄及/或同意不主張任何禁止您進行必要技術修改的權利或權威,包括必要技術修改以規避有效技術措施。就本公共授權而言,僅進行第 2 節 (a)(4) 授權的修改永遠不會產生改編材料。
5. 下游接收者。
a. 授權者的提供——授權材料。授權材料的每位接收者自動收到授權者的提供,根據本公共授權的條款和條件行使授權權利。
b. 授權者的額外提供——改編材料。您提供的改編材料的每位接收者自動收到授權者的提供,根據您應用的改編者授權條件行使改編材料的授權權利。
c. 無下游限制。您不得對授權材料提供或施加任何額外或不同的條款和條件,或應用任何有效技術措施,若此舉限制了授權材料接收者行使授權權利。
6. 無認可。本公共授權中的任何內容均不構成或不得解釋為授予您或您的使用授權材料與授權者或其他指定接收者有關聯、受到支持、認可或授予官方地位的許可。
b. 其他權利。
1. 道德權利,例如完整性權利,不在本公共授權範圍內,也不包括宣傳、隱私及/或其他類似人格權;然而,在可能的範圍內,授權者放棄及/或同意不主張授權者持有的此類權利,以有限範圍內允許您行使授權權利,但不超出此範圍。
2. 專利和商標權不在本公共授權範圍內。
3. 在可能的範圍內,授權者放棄任何直接或通過收費機構根據任何自願或可放棄的法定或強制性授權計劃向您收取版稅的權利,以行使授權權利。在所有其他情況下,授權者明確保留收取此類版稅的權利。
第 3 節 —— 授權條件。
您行使授權權利明確受以下條件約束。
a. 歸屬。
1. 如果您分享授權材料(包括修改後的形式),您必須:
a. 保留以下內容(如果授權者隨授權材料提供):
i. 授權材料創作者及任何其他指定接收者的身份,以授權者要求的任何合理方式(包括使用筆名,如果指定);
ii. 版權聲明;
iii. 提及本公共授權的通知;
iv. 提及免責聲明的通知;
v. 在合理可行的範圍內,授權材料的 URI 或超鏈接;
b. 表明您是否修改了授權材料,並保留任何先前修改的指示;以及
c. 表明授權材料是根據本公共授權授權的,並包括本公共授權的文本或 URI 或超鏈接。
2. 您可以根據您分享授權材料的媒介、方式和上下文,以任何合理方式滿足第 3 節 (a)(1) 的條件。例如,提供包含所需信息的資源的 URI 或超鏈接可能是合理的。
3. 如果授權者要求,您必須在合理可行的範圍內移除第 3 節 (a)(1)(A) 要求的任何信息。
b. ShareAlike。
除第 3 節 (a) 的條件外,如果您分享您創作的改編材料,以下條件也適用。
1. 您應用的改編者授權必須是具有相同授權元素的創用CC授權本版本或更高版本或 BY-SA 兼容授權。
2. 您必須包括您應用的改編者授權的文本或 URI 或超鏈接。您可以根據您分享改編材料的媒介、方式和上下文,以任何合理方式滿足此條件。
3. 您不得對改編材料提供或施加任何額外或不同的條款和條件,或應用任何有效技術措施,若此舉限制了根據您應用的改編者授權授予的權利。
第 4 節 —— 特殊數據庫權利。
當授權權利包括適用於您使用授權材料的特殊數據庫權利時:
a. 為避免疑義,第 2 節 (a)(1) 授予您提取、重用、複製及分享數據庫內容全部或實質部分的權利;
b. 如果您將數據庫內容全部或實質部分納入您擁有特殊數據庫權利的數據庫中:
權利,然後您擁有「特殊資料庫權利」的資料庫(但不包括其個別內容)屬於改編素材,
包括為了第 3(b) 節的目的;以及
c. 如果您分享資料庫的全部或大部分內容,您必須遵守第 3(a) 節中的條件。
為避免疑義,本第 4 節是補充而非取代您在本公共授權下的義務,當授權權利包括其他版權及類似權利時。
第 5 節 —— 保證免責聲明及責任限制。
a. 除非授權方另行單獨承諾,在可能的範圍內,授權方以「現狀」及「可用狀態」提供授權素材,並且不對授權素材作出任何形式的陳述或保證,包括明示、默示、法定或其他形式的保證。這包括但不限於所有權保證、適銷性保證、特定用途適用性保證、非侵權保證、隱性或其他缺陷的不存在保證、準確性保證,或錯誤的存在或不存在保證(無論是否已知或可發現)。如果法律不允許完全或部分免除保證,則此免責聲明可能不適用於您。
b. 在可能的範圍內,授權方在任何法律理論(包括但不限於過失)或其他情況下,均不對您因本公共授權或使用授權素材而產生的任何直接、特殊、間接、附帶、後果性、懲罰性、示範性或其他損失、成本、費用或損害負責,即使授權方已被告知可能發生此類損失、成本、費用或損害。如果法律不允許完全或部分限制責任,則此責任限制可能不適用於您。
c. 上述保證免責聲明及責任限制應以最接近絕對免責及放棄所有責任的方式解釋,在可能的範圍內。
第 6 節 —— 期限及終止。
a. 本公共授權適用於授權的版權及類似權利的期限。然而,如果您未遵守本公共授權,則您在本公共授權下的權利將自動終止。
b. 當您使用授權素材的權利根據第 6(a) 節終止時,該權利可恢復:
1. 自違規行為被糾正之日起自動恢復,前提是該行為在您發現違規後的 30 天內被糾正;或
2. 經授權方明確恢復。
為避免疑義,本第 6(b) 節不影響授權方因您違反本公共授權而尋求補救的任何權利。
c. 為避免疑義,授權方也可以在任何時候以其他條款或條件提供授權素材或停止分發授權素材;然而,這不會終止本公共授權。
d. 第 1 節、第 5 節、第 6 節、第 7 節及第 8 節在本公共授權終止後仍然有效。
第 7 節 —— 其他條款及條件。
a. 除非授權方明確同意,授權方不受您傳達的任何額外或不同條款或條件的約束。
b. 關於授權素材的任何安排、理解或協議,若未在本授權中明確說明,則屬於與本公共授權條款及條件無關且獨立的事項。
第 8 節 —— 解釋。
a. 為避免疑義,本公共授權不會且不應被解釋為減少、限制、約束或施加條件於任何在未經本公共授權許可的情況下合法使用授權素材的行為。
b. 在可能的範圍內,如果本公共授權的任何條款被認為不可執行,則該條款應自動調整至最低必要程度以使其可執行。如果該條款無法調整,則應從本公共授權中刪除,而不影響其餘條款及條件的可執行性。
c. 除非授權方明確同意,本公共授權的任何條款或條件均不得被放棄,且任何未遵守的行為均不得被視為授權方的同意。
d. 本公共授權中的任何內容均不構成或不得被解釋為對授權方或您適用的任何司法管轄區或機構的法律程序的特權及豁免的限制或放棄。
=======================================================================
Creative Commons 並非其公共授權的當事方。然而Creative Commons 可以選擇將其公共授權應用於其發布的素材在這些情況下Creative Commons 將被視為「授權方」。Creative Commons 公共授權的文本已根據 CC0 公共領域貢獻被捐獻至公共領域。除非為了有限的目的表明素材是根據 Creative Commons 公共授權共享或根據 Creative Commons 在 creativecommons.org/policies 發布的政策另行允許Creative Commons 不授權使用「Creative Commons」商標或任何其他 Creative Commons 的商標或標誌,除非事先獲得書面同意,包括但不限於任何未經授權修改其公共授權或任何其他安排、理解或協議中涉及授權素材的使用。為避免疑義,本段不構成本公共授權的一部分。
Creative Commons 可通過 creativecommons.org 聯繫。
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。

@ -0,0 +1,12 @@
所有課程的手繪筆記可以在這裡下載。
🖨 如果需要高解析度列印TIFF版本可在 [此倉庫](https://github.com/girliemac/a-picture-is-worth-a-1000-words/tree/main/ml/tiff) 中找到。
🎨 製作人:[Tomomi Imura](https://github.com/girliemac)Twitter: [@girlie_mac](https://twitter.com/girlie_mac)
[![CC BY-SA 4.0](https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg)](https://creativecommons.org/licenses/by-sa/4.0/)
---
**免責聲明**
本文件已使用 AI 翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 進行翻譯。雖然我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋不承擔責任。
Loading…
Cancel
Save