顾 静

顾 静

1594604092

Python機器學習:機器學習簡介

大四最後一學期因為修了盧信銘老師的統計學習初論(Statistical Learning),開始接觸機器學習(Machine Learning)也開始對這方面產生興趣。由於這堂課作業都是用python寫,吃了不少苦頭。

因此這一系列的文章將會記錄我這一學期來學習機器學習的內容,包含了觀念和如何使用python撰寫機器學習模型。希望可以用淺顯易懂的文字幫助到大家。

誰是此系列文章的目標讀者?

  1. 已經能嫻熟使用 Python 基本程式設計的使用者
  2. 想學習 Python 機器學習模型的使用者

誰可能不是此系列文章的目標讀者?

這是關於機器學習應用的文章,它可能不適合這些人閱讀:

  1. 從未接觸過 Python 的初學者
  2. 已經嫻熟機器學習應用&深度學習領域實作的高階使用者

機器學習在被大家廣泛知道之前,另外大家常在用的一個叫專家法則,另一個叫統計學習(Statistical Learning)。那其實機器學習跟統計學習中間還是有重疊的地方,只是統計學習更注重在模型的解釋力,反而機器學習比較沒有那麼在意解釋力,只要做出來的模型跟預測出來的結果是好的就可以。

所以到底什麼是機器學習(Machine Learning)?

機器學習是透過程式讓電腦能夠從資料中學習的學科

Machine learning is the science of programming computers so they can learn from data.

傳統上我們在讓電腦程式處理問題都是寫很多的if-else,請電腦碰到這個狀況幫我做什麼處理,碰到另一個狀況幫我做什麼處理。但是隨著任務越來越複雜,不是每件事都可以寫成if條件式,所以我們讓電腦只看過往發生的歷史資料&結果和預期結果對比得到一個pattern,再用這個pattern對未知的data做判讀。

機器學習和人工智慧(AI)&深度學習(Deep Learning)的關係又是什麼呢?

簡而言之,機器學習(Machine Learning)是實踐人工智慧(AI)的一種手段,而深度學習(Deep Learning)是機器學習的其中一種方法

Image for post

#python #machine-learning

What is GEEK

Buddha Community

Python機器學習:機器學習簡介
顾 静

顾 静

1594604092

Python機器學習:機器學習簡介

大四最後一學期因為修了盧信銘老師的統計學習初論(Statistical Learning),開始接觸機器學習(Machine Learning)也開始對這方面產生興趣。由於這堂課作業都是用python寫,吃了不少苦頭。

因此這一系列的文章將會記錄我這一學期來學習機器學習的內容,包含了觀念和如何使用python撰寫機器學習模型。希望可以用淺顯易懂的文字幫助到大家。

誰是此系列文章的目標讀者?

  1. 已經能嫻熟使用 Python 基本程式設計的使用者
  2. 想學習 Python 機器學習模型的使用者

誰可能不是此系列文章的目標讀者?

這是關於機器學習應用的文章,它可能不適合這些人閱讀:

  1. 從未接觸過 Python 的初學者
  2. 已經嫻熟機器學習應用&深度學習領域實作的高階使用者

機器學習在被大家廣泛知道之前,另外大家常在用的一個叫專家法則,另一個叫統計學習(Statistical Learning)。那其實機器學習跟統計學習中間還是有重疊的地方,只是統計學習更注重在模型的解釋力,反而機器學習比較沒有那麼在意解釋力,只要做出來的模型跟預測出來的結果是好的就可以。

所以到底什麼是機器學習(Machine Learning)?

機器學習是透過程式讓電腦能夠從資料中學習的學科

Machine learning is the science of programming computers so they can learn from data.

傳統上我們在讓電腦程式處理問題都是寫很多的if-else,請電腦碰到這個狀況幫我做什麼處理,碰到另一個狀況幫我做什麼處理。但是隨著任務越來越複雜,不是每件事都可以寫成if條件式,所以我們讓電腦只看過往發生的歷史資料&結果和預期結果對比得到一個pattern,再用這個pattern對未知的data做判讀。

機器學習和人工智慧(AI)&深度學習(Deep Learning)的關係又是什麼呢?

簡而言之,機器學習(Machine Learning)是實踐人工智慧(AI)的一種手段,而深度學習(Deep Learning)是機器學習的其中一種方法

Image for post

#python #machine-learning

顾 静

顾 静

1594637220

Python機器學習:如何處理加入類別變數的回歸模型

上一篇文章提到如何在模型中加入高次項或是新的變數,那假如我想在模型再加入類別變數要如何處理?目前向量 X 的值(場均得分與場均籃板數)都是數值,所以運算起來並沒有太大的困難,但是在原始資料裡除了數值以外還有一些名目資料,如球員的位置或球員姓名等。

import pandas as pd
nba_data = pd.read_csv('/Users/changyucheng/Desktop/Medium/nba_players.csv')

nba_data.info()

Image for post

從上圖中可以看到在我們nba的資料裡,名目資料包含了球員姓名、出生年月日與位置。如果我在之前訓練出來的模型照著球員的位置去分類,會不會在預測年薪上得到不同的結果呢?

畢竟雖然有些球員他的場均得分不高,但他可以透過其他數字(ex:籃板球數、助攻數等)來提高他的薪資:像是籃球的內線球員,他的得分可能不會像後衛那麼耀眼,但是他的籃板數或阻攻數可能很高,對球隊獲勝也是至關重要。如此看來,在訓練薪資模型時把球員的位置考慮進去是必要的。

籃球員的位置(Position)

大家可能平時不太關注籃球,對籃球的內容不太熟,因此我們從原始資料看一下籃球員的位置(Position)有哪些。一般在探索原始資料的數值時,會畫直方圖或是散步圖看分布的情況如何,但是類別變數要怎麼探索呢?

我們可以使用unique()函數觀察類別函數個別的值有哪些,也可以用value_counts()得知原始資料中的類別變數分佈如何。

Image for post

Image for post

從上圖中觀察到原始資料的位置(pos)有分成 G、F、C、G-F、F-G、F-C、C-F,也就是常聽到的後衛、前鋒跟中鋒。但是除了這三個位置代號,還有一堆G-F、F-G有的沒的,類似這種代號的就是所謂的搖擺人(Swingmen、Tweener)。在現實生活中,大家應該聽過小皇帝詹姆斯(Lebron James)吧,他就是號稱可以從控球後衛打到大前鋒的球員,又能控球,得分能力&搶籃板能力也很突出。

由於含有多個位置的球員分析起來有點繁複,因此我們將位置簡化,大致分成三類(G、F、C)即可,Swingmen或Tweener改以第一位置登錄。

先準備了一個Dictionary,接著讓原來的資料從 Key 使用mapping 函數對應到 Value。如此以來,unique()的結果就只會有3個值(即是我們想要的G、F、C)。同時,我們也在原本的DataFrame新增了一個變數叫 pos-recategorized,正是我們重新分類的新的球員位置。

pos_recategorized = {
    'G': 'G',
    'F': 'F',
    'C': 'C',
    'G-F': 'G',
    'F-C': 'F',
    'C-F': 'C',
    'F-G': 'F'
}
nba_data['pos_recategorized'] = nba_data['pos'].map(pos_recategorized)
print(nba_data['pos_recategorized'].unique())
print(nba_data['pos_recategorized'].value_counts())

Image for post

從上圖中發現,G 跟 F 的數量差不多,C相較之下少一點。折這情況很正常,畢竟一支球隊5個人,2個後衛,2個前鋒,只有1個中鋒,加上中鋒需要的身高要求高,在場上主要又做苦工,因此許多原本打中鋒的球員現在都跑去打前鋒了(NBA時代的變化Q_Q)。

重新分類完了之後,我們將後衛(G)、前鋒(F)、中鋒©分別用不同顏色在散步圖標記:

import matplotlib.pyplot as plt
import seaborn as sns

sns.scatterplot(x = 'ppg', y = 'salary', hue = 'pos_recategorized', data = nba_data)
plt.show()

這裏介紹一個不錯的套件:seaborn。我們一般在用matplotlib.pyplot 作圖時,資料都需要做成陣列。假如我現在要畫3個類型的點,那我就要準備3種類型的陣列,然後分3次畫。使用seaborn套件可以解決這個問題,加速視覺化,在畫圖時方便很多。

Image for post

從上圖中,看起來後衛(G)與前鋒(F)的薪資分佈位置相似,但中鋒©比較自成一格,得分即使再高薪資似乎有天花板存在,這也是為什麼現在大家都不願意打中鋒的原因之一。

#python #機器學習 #machine-learning

顾 静

顾 静

1594673220

Python機器學習:機器學習模型的計算複雜性

**計算複雜性(Computational complexity)**是電腦科學研究解決問題所需的資源,諸如時間(要通過多少步演算才能解決問題)和空間(在解決問題時需要多少記憶體),在演算法中常見到的大 O 符號就是表示演算所需時間的表達式。

計算複雜性的問題為什麼會在使用Normal equations的時候出現呢?

在正規方程(normal equations)中必須要透過計算(𝑋的Transpose𝑋) 的反矩陣來求解𝑤

Image for post

之前在算反矩陣的時候是透過呼叫np.linalg.inv()來完成,但其實反矩陣背後有複雜的計算存在

為何計算 (𝑋的Transpose*𝑋) 的反矩陣是在變數個數 𝑛 增多時才有計算複雜性的議題?𝑚 呢?

觀測值量很多(m很大)其實跟計算複雜性是沒有關係,因為𝑋 的外觀為 𝑚×𝑛,𝑋的Transpose 的外觀為 𝑛×𝑚,(𝑋的Transpose*𝑋)的外觀為 𝑛×𝑛。

因此只有在n變大的時候才有計算複雜性的議題!

但是為什麼計算 𝑛 很大的 𝑛×𝑛 反矩陣會產生計算複雜性議題呢?

這就要回到在2006年Numpy套件被發明出來之前,即使沒有Numpy,但線性代數、矩陣相乘還是要用,如果使用Vanilla Python(不用任何套件的Python)要計算𝐴 的反矩陣 𝐴(-1)了話:

Image for post

import copy

A = [
    [4, 7],
    [2, 6]
]
det_A = A[0][0] * A[1][1]- A[0][1] * A[1][0]
neg_A = copy.deepcopy(A)
for i in range(len(neg_A)):
    for j in range(len(neg_A[0])):
        neg_A[i][j] = -A[i][j]
neg_A[0][0] = A[1][1]
neg_A[1][1] = A[0][0]
inv_A = [
    [0, 0],
    [0, 0]
]
for i in range(len(neg_A)):
    for j in range(len(neg_A[0])):
        inv_A[i][j] = neg_A[i][j] / det_A
        
print(inv_A)

Image for post

使用Vanilla Python算出的反矩陣

import numpy as np

np.linalg.inv(A)

Image for post

使用Numpy套件算出的反矩陣答案和上例一樣

在 Vanilla Python 計算一個 2×2 矩陣 𝐴 的反矩陣其實已經有點辛苦了…,更何況計算 3×3 的反矩陣要計算 9 個 2×2 矩陣的行列式(determinant):

Image for post

以此類推 ,4×4 的反矩陣我們要計算 16 個 3×3 矩陣的行列式,𝑛×𝑛 的反矩陣就要計算 𝑛平方 個 (𝑛−1)×(𝑛−1) 矩陣的行列式。Numpy套件的底層還是用 C 語言與 Python 實作,使用封裝好的函數並不代表計算複雜性的問題不存在。

因此當面對的特徵矩陣n很大時,正規方程的計算複雜性問題就會浮現,這時讀者可能會好奇什麼時候𝑛會很大呢?

#python #machine-learning #機器學習

顾 静

顾 静

1594684020

Python機器學習:資料標準化與進階梯度遞減的實用技巧

在先前的文章中已經教了比正規方程更好用的梯度遞減。但是,在什麼樣的情況下,原本的梯度遞減公式還是會不適用呢?

給定Kaggle資料集艾姆斯房價資料為例,若以其中的 GrLivArea 作為特徵矩陣來預測目標向量 Saleprice。

使用 Scikit-Learn 的 Linear Regression 預測器找出 𝑤:

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression

csv_url = "https://kaggle-getting-started.s3-ap-northeast-1.amazonaws.com/house-prices/train.csv"
housing = pd.read_csv(csv_url)
X = housing["GrLivArea"].values.reshape(-1, 1)
y = housing["SalePrice"].values
X_train, X_validation, y_train, y_validation = train_test_split(X, y, test_size=0.33, random_state=42)
lr = LinearRegression()
lr.fit(X_train, y_train)
w = lr.coef_.copy()
w = np.insert(w, 0, lr.intercept_).reshape(-1, 1)
print(w)

Image for post

使用 Gradient Descent 找出 𝑤:

def get_mse(X, y, w):
    m = y.size
    y_hat = X.dot(w)
    y_reshaped = y.reshape(-1, 1)
    err = y_hat - y_reshaped
    se = err**2
    sse = se.sum()
    mse = sse / m
    return mse

def get_grad(X, y, w):
    m = y.size
    y_hat = X.dot(w)
    y_reshaped = y.reshape(-1, 1)
    err = y_hat - y_reshaped
    grad = (X.T.dot(err))*2/m
    return grad
def gradient_descent(X, y, epochs, learning_rate):
    n = X.shape[1]
    w = np.random.rand(n, 1)
    j_history = []
    w_0_history, w_1_history = [w[0, 0]], [w[1, 0]]
    n_prints = 20
    interval = epochs // n_prints
    for i in range(epochs):
        mse = get_mse(X, y, w)
        j_history.append(mse)
        grad = get_grad(X, y, w)
        w -= learning_rate*grad
        if i % interval == 0:
            w_0_history.append(w[0, 0])
            w_1_history.append(w[1, 0])
            print("{} iterations: w_0 = {}; w_1 = {}".format(i, w[0, 0], w[1, 0]))
    return w, w_0_history, w_1_history, j_history
from sklearn.preprocessing import PolynomialFeatures

poly = PolynomialFeatures(1)
X_poly = poly.fit_transform(X)
X_train, X_validation, y_train, y_validation = train_test_split(X_poly, y, test_size=0.33, random_state=42)
n_epochs = 300000
learning_rate = 1e-7
w, w_0_history, w_1_history, j_history = gradient_descent(X_train, y_train, n_epochs, learning_rate)

Image for post

Image for post

我們發現透過梯度遞減演算法找的w,w0的值(194)與正確解答(30774)還差了十萬八千里。我們試著作圖了解一下原因:

import matplotlib.pyplot as plt

def get_gd_plots(j_history, w_0_history, w_1_history, best_w_0, best_w_1):
    fig, axes = plt.subplots(1, 2, figsize=(12, 3))
    axes[0].plot(range(len(j_history)), j_history)
    axes[0].set_xlabel("Number of iterations")
    axes[0].set_ylabel("MSE")
    axes[0].set_title("MSE trend")
    axes[1].scatter(w_0_history, w_1_history, marker="+")
    axes[1].scatter(best_w_0, best_w_1, marker="x", s=200, color="red")
    axes[1].scatter(w_0_history[-1], w_1_history[-1], marker="x", s=200, color="green")
    axes[1].set_xlabel("$w_0$")
    axes[1].set_ylabel("$w_1$")
    axes[1].set_title("How does $w_0$ and $w_1$ converge")
    #axes[1].set_ylim(0, 15)
    plt.show()
    
get_gd_plots(j_history, w_0_history, w_1_history, 30774, 98.5)

Image for post

由於在一開始迭代時,MSE就已經是最小了,所以w0才會每次只動一點點,造成w0無法抵達最佳解的值。

#python #machine-learning #機器學習

顾 静

顾 静

1594648020

Python機器學習:機器學習中誤差的來源與正規化

還記得之前在評估模型的好壞時,MSE是怎麼算的嗎?是要用真實情況(test)的結果去和預測比對,但是我們一直以來都是用validation data,畢竟真正的testing data要等事情已經發生完了,才能事後檢查模型的好壞。

Image for post

除了MSE,大家還記得機器學習的最終任務嗎?

機器學習的任務:於可及範圍的 H中挑選一個與 f最相似的 h

但是 h 與 f 終究是不同的函數,而我們關心的是 𝑦̂ 與 y 間的差異,差異小的h稱為**泛化(Generalization)**的能力好

h的誤差可能源於 Training error 與 Test error:

Training error 常被稱為 error或 bias

Test error 亦可被稱為 Generalization error, 被簡稱為 variance

如果太過度注重 training data,擴增回歸模型的可及範圍H常伴隨 error 降低,但variance提高。因此機器學習的另一非常重要的任務就是要找平衡。我們試著在回歸模型中分別加入高次項(從1-10次方),分別看Training error 與 Test data 的大小:

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

nba_data = pd.read_csv('/Users/changyucheng/Desktop/Medium/nba_players.csv')
X = nba_data['ppg'].values.reshape(-1, 1)

degrees = range(1, 11)
training_errors = []
test_errors = []
for deg in degrees:
    poly = PolynomialFeatures(degree = deg)
    X_poly = poly.fit_transform(X)
    y = nba_data['salary'].values
    X_train, X_validation, y_train, y_validation = train_test_split(X_poly, y, test_size = 0.33, random_state = 42)
    lr = LinearRegression()
    lr.fit(X_train, y_train)
    y_pred = lr.predict(X_train)
    training_err = mean_squared_error(y_train, y_pred)
    training_errors.append(training_err)
    y_pred = lr.predict(X_validation)
    test_err = mean_squared_error(y_validation, y_pred)
    test_errors.append(test_err)

Image for post

回歸模型 fit 完10次了之後,Training error這個list裡會有10筆資料,是X_train丟到模型h裡,預測出來的值(y_pred)和y_train的差距。可以看到隨著次方越來越高,Training error是越來越小的。

接著看Test error:在前幾次分別加入二次項、三次項,error是有往下降一點,但是隨著加入的次方提高,越到後面error開始飆高。這說明如果模型太複雜,即使 training data 丟到模型裡表現很完美,但是一旦丟testing data,模型的預測結果會非常不準。

#python #機器學習 #machine-learning