非監督式學習

非監督式學習（英文：unsupervised learning）係機械學習上一種學習範式，特徵係個設計者唔會明確噉話俾個程式知乜嘢先係「正確答案」：一個用非監督式學習嘅機械學習程式淨係會接收輸入，並且嘗試由收到嘅輸入當中搵出一啲規律。
聚類分析嘅圖解；每一點代表一個個案，每個個案喺用 X 軸同 Y 軸分別代表嗰兩個變數上都各有其數值，由幅圖睇得出，啲個案明顯可以按呢兩個變數分三大類。
非監督式學習一個常見用途係攞嚟做聚類分析。舉例說明，家吓有個生態學家想研究吓一個區域入面嗰啲樹傾向聚集喺啲乜嘢位置，佢可以坐直昇機或者用人造衛星影啲相返嚟，再記錄嗮嗰個區域入面每樖樹生喺邊個位（呢個過程會嘥唔少時間），會得出一個數據庫，記錄嗮每樖樹喺 X 軸同 Y 軸嗰度嘅坐標。跟手佢就可能會想睇吓啲樹會唔會傾向聚集喺個區域入面嘅某啲位置（呢啲資訊可能有助佢保育一啲靠樹生存嘅動物）。如果有某一柞嘅樹彼此之間距離近，又同佢哋以外嘅樹距離遠，噉就可以話佢係「聚埋一羣」，而聚類分析就正係用嚟分析一柞個案入面會唔會有幾羣個體係「彼此之間距離近，同羣以外嘅個體距離遠」嘅。
喺呢次研究入面，個生態學家唔會事先知道啲樹要點分羣，所以用唔到監督式學習，但係佢可以運用非監督式學習嚟整一個神經網絡幫佢手做呢個聚類分析。一個簡單嘅可能做法係好似以下噉：將浸輸入層設做樖樹嘅坐標，等啲隱藏層用每一樖樹嘅數據逐個逐個計吓，而浸輸出層就有例如 5 粒人工神經細胞，喺每樖樹嘅運算之後都會有一粒輸出層神經細胞嘅啟動程度係大過其他嘅－所以個生態學家就可以按「喺將嗰樖樹嘅數據入咗落去個神經網絡度之後，邊粒輸出層神經細胞嘅啟動程度最大」為準則將啲樹分做聚類，而且佢仲有得按照分類結果分得好唔好，嚟計吓使唔使改變吓個神經網絡嗰啲參數－個神經網絡喺度進行學習。除咗噉，電腦科學界仲有第啲更加精良嘅演算法嚟做非監督式學習。
例子碼
想像一個做聚類分析，用四個變數將啲個案分做三類嘅神經網絡：個神經網絡有四個輸入同三個輸出；每個個案喺嗰四個變數上都會各有一個數值，而當用呢個四個數值做個神經網絡嘅輸入嗰陣，會令個神經網絡嗰三粒輸出細胞都各有一定程度嘅啟動（每粒細胞都有一個向量代表呢個啟動）－跟住視乎嗰個個案引致邊粒輸出細胞有最勁嘅啟動，就可以將個個案歸做三個類嘅其中一個，同埋更新啲權重嘅數值。以下係個神經網絡嘅 Python 源碼：
# 指明要用邊柞指令。
import numpy as np
import pandas as pd

# 由網站嗰度讀取數據集，將柞數據集擺喺 ds 嗰度。ds 會係一個表，列嗮每個個案同埋佢喺變數上嘅數值出嚟。
url = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
names = ['sepal length', 'sepal width', 'petal length', 'petal width', 'class']
ds = pd.read_csv(url, names=names)
ds.head()

# 整柞 list，並且將所有數字 normalize，每個 list 包含咗所有個案喺一個變數上嘅數值，個數據集有四個用嚟將個案分類嘅變數，所以有四個 list。
list_sl=[]
list_sw=[]
list_pl=[]
list_pw=[]
for sl in ds['sepal length']:
    sl = (sl-min(ds['sepal length'])) / (max(ds['sepal length'])-min(ds['sepal length']))
    list_sl.append(sl)
for sw in ds['sepal width']:
    sw = (sw-min(ds['sepal width'])) / (max(ds['sepal width'])-min(ds['sepal width']))
    list_sw.append(sw)    
for pl in ds['petal length']:
    pl = (pl-min(ds['petal length'])) / (max(ds['petal length'])-min(ds['petal length']))
    list_pl.append(pl)
for pw in ds['petal width']:
    pw = (pw-min(ds['petal width'])) / (max(ds['petal width'])-min(ds['petal width']))
    list_pw.append(pw) 

# X 係一個 array，當中每個組成元素係一個個案喺四個變數上嘅數值（normalize 咗）。
X = np.array(list(zip(list_sl,list_sw, list_pl, list_pw)) )

# 呢個子程式會俾出隨機產生嘅數字，用嚟初始化嗰陣產生柞權重值。
def get_weights():
    y = np.random.random() * (2.0 / np.sqrt(M))
    return 0.5 - (1 / np.sqrt(M)) + y

# 產生權重，並且將柞數值放入去 W 嗰度。
for i in range(nc): # 三粒輸出層細胞，所以 W 有三個元件。
    W.append(list()) 
    for j in range(N): # 每粒輸出細胞又有四個子元件做權重，即係話每當個網絡讀到一個個案喺四個變數上嘅數值嗰時，三粒輸出層細胞都會分別有若干程度嘅啟動。
        W[i].append(get_weights() * 0.5)

# 一個子程式；呢個子程式會計出兩個點（向量）之間嘅距離。呢個子程式會俾個距離做輸出。
def distance(w, x):
    r = 0
    for i in range(len(w)):
        r = r + (w[i] - x[i])*(w[i] - x[i])
    
    r = np.sqrt(r)
    return r

# 又一個子程式；呢個子程式會搵出 x 入面邊個向量同 W 呢個 array 當中嘅向量最接近。
def Findclosest(W, x):
    wm = W[0]
    r = distance(wm, x)
    i = 0
    i_n = i
    for w in W:
        if distance(w, x) < r:
            r = distance(w, x)
            wm = w
            i_n = i
        i = i + 1
    
    return (wm, i_n)

# 將個權重向量 show 出嚟睇。
print(W)

while la >= 0: # 重複係噉做以下嘅作業，做到 la 變成 0 以下為止。
    for k in range(10):
        for x in X: # For X 入面每個元件 x，搵出 W 入面邊個最近 x，跟住...
            wm = Findclosest(W, x)[0]
            for i in range(len(wm)): # 再調較柞權重
                wm[i] = wm[i] + la * (x[i] - wm[i]) 

    la = la - dla
    
    Data = list() # 整個叫「data」嘅新 list 出嚟。

DS = list() # 整個叫「DS」嘅新 list 出嚟。呢個 list 每個元件係一個個案由個神經網絡分嘅類同埋佢（根據個數據集）個實際類。
i = 0
for x in X: # For X 入面每個元件，做以下嘅指令。
    i_n = Findclosest(W, x)[1]
    Data[i_n].append(x)
    DS.append([i_n, dfList[i]])
    i = i + 1

print (DS) # Show 個 DS 出嚟睇。結果係，個神經網絡做嘅分類同數據集嘅分類好一致。