機(jī)器學(xué)習(xí)常用損失函數(shù)以及各種排序算法浅妆,python實(shí)現(xiàn)

1. 機(jī)器學(xué)習(xí)常用損失函數(shù)

評(píng)價(jià)模型預(yù)測(cè)值和真實(shí)值的函數(shù)為損失函數(shù)(loss function)。它是一個(gè)非負(fù)實(shí)值函數(shù)壳嚎,損失函數(shù)越小,模型的性能就越好末早。


損失函數(shù)

模型最終需要優(yōu)化函數(shù)的是代價(jià)函數(shù)(cost function)或者說目標(biāo)函數(shù)烟馅,需要在損失函數(shù)的基礎(chǔ)上做一些調(diào)整,例如正則化然磷。


代價(jià)函數(shù)

下面主要列出幾種常見的損失函數(shù)郑趁。

1.1. log對(duì)數(shù)損失函數(shù)(邏輯回歸損失,交叉熵?fù)p失)

有些人可能覺得邏輯回歸的損失函數(shù)就是平方損失姿搜,其實(shí)并不是寡润。平方損失函數(shù)可以通過線性回歸在假設(shè)樣本是高斯分布的條件下推導(dǎo)得到,而邏輯回歸得到的并不是平方損失舅柜。在邏輯回歸的推導(dǎo)中梭纹,它假設(shè)樣本服從伯努利分布(0-1分布),然后求得滿足該分布的似然函數(shù)致份,接著取對(duì)數(shù)求極值等等变抽。而邏輯回歸并沒有求似然函數(shù)的極值,而是把極大化當(dāng)做是一種思想氮块,進(jìn)而推導(dǎo)出它的經(jīng)驗(yàn)風(fēng)險(xiǎn)函數(shù)為:最小化負(fù)的似然函數(shù)(即max F(y, f(x)) —> min -F(y, f(x)))绍载。從損失函數(shù)的視角來看,它就成了log損失函數(shù)了滔蝉。
log損失函數(shù)的標(biāo)準(zhǔn)形式:


剛剛說到击儡,取對(duì)數(shù)是為了方便計(jì)算極大似然估計(jì),因?yàn)樵贛LE中蝠引,直接求導(dǎo)比較困難阳谍,所以通常都是先取對(duì)數(shù)再求導(dǎo)找極值點(diǎn)。損失函數(shù)L(Y, P(Y|X))表達(dá)的是樣本X在分類Y的情況下螃概,使概率P(Y|X)達(dá)到最大值(換言之边坤,就是利用已知的樣本分布,找到最有可能(即最大概率)導(dǎo)致這種分布的參數(shù)值谅年;或者說什么樣的參數(shù)才能使我們觀測(cè)到目前這組數(shù)據(jù)的概率最大)茧痒。因?yàn)閘og函數(shù)是單調(diào)遞增的,所以logP(Y|X)也會(huì)達(dá)到最大值融蹂,因此在前面加上負(fù)號(hào)之后旺订,最大化P(Y|X)就等價(jià)于最小化L了弄企。
邏輯回歸的P(Y=y|x)表達(dá)式如下(為了將類別標(biāo)簽y統(tǒng)一為1和0,下面將表達(dá)式分開表示)


將它帶入到上式区拳,通過推導(dǎo)可以得到logistic的損失函數(shù)表達(dá)式拘领,如下:



邏輯回歸最后得到的目標(biāo)式子如下:



上面是針對(duì)二分類而言的。這里需要解釋一下:之所以有人認(rèn)為邏輯回歸是平方損失樱调,是因?yàn)樵谑褂锰荻认陆祦砬笞顑?yōu)解的時(shí)候约素,它的迭代式子與平方損失求導(dǎo)后的式子非常相似,從而給人一種直觀上的錯(cuò)覺笆凌。

1.2. 平方損失函數(shù)(最小二乘法, Ordinary Least Squares )

最小二乘法是線性回歸的一種圣猎,OLS將問題轉(zhuǎn)化成了一個(gè)凸優(yōu)化問題。在線性回歸中乞而,它假設(shè)樣本和噪聲都服從高斯分布(為什么假設(shè)成高斯分布呢送悔?其實(shí)這里隱藏了一個(gè)小知識(shí)點(diǎn),就是中心極限定理爪模,可以參考【central limit theorem】)欠啤,最后通過極大似然估計(jì)(MLE)可以推導(dǎo)出最小二乘式子。最小二乘的基本原則是:最優(yōu)擬合直線應(yīng)該是使各點(diǎn)到回歸直線的距離和最小的直線屋灌,即平方和最小洁段。換言之,OLS是基于距離的共郭,而這個(gè)距離就是我們用的最多的歐幾里得距離眉撵。為什么它會(huì)選擇使用歐式距離作為誤差度量呢(即Mean squared error, MSE)落塑,主要有以下幾個(gè)原因:

簡(jiǎn)單纽疟,計(jì)算方便;
歐氏距離是一種很好的相似性度量標(biāo)準(zhǔn)憾赁;
在不同的表示域變換后特征性質(zhì)不變污朽。
平方損失(Square loss)的標(biāo)準(zhǔn)形式如下:



當(dāng)樣本個(gè)數(shù)為n時(shí),此時(shí)的損失函數(shù)變?yōu)椋?/p>


Y-f(X)表示的是殘差龙考,整個(gè)式子表示的是殘差的平方和蟆肆,而我們的目的就是最小化這個(gè)目標(biāo)函數(shù)值(注:該式子未加入正則項(xiàng)),也就是最小化殘差的平方和(residual sum of squares晦款,RSS)炎功。

而在實(shí)際應(yīng)用中,通常會(huì)使用均方差(MSE)作為一項(xiàng)衡量指標(biāo)缓溅,公式如下:



上面提到了線性回歸蛇损,這里額外補(bǔ)充一句,我們通常說的線性有兩種情況,一種是因變量y是自變量x的線性函數(shù)淤齐,一種是因變量y是參數(shù)α的線性函數(shù)股囊。在機(jī)器學(xué)習(xí)中,通常指的都是后一種情況更啄。

1.3.指數(shù)損失函數(shù)(Adaboost)

學(xué)過Adaboost算法的人都知道稚疹,它是前向分步加法算法的特例,是一個(gè)加和模型祭务,損失函數(shù)就是指數(shù)函數(shù)内狗。在Adaboost中,經(jīng)過m此迭代之后义锥,可以得到fm(x):



Adaboost每次迭代時(shí)的目的是為了找到最小化下列式子時(shí)的參數(shù)α 和G:



而指數(shù)損失函數(shù)(exp-loss)的標(biāo)準(zhǔn)形式如下

可以看出柳沙,Adaboost的目標(biāo)式子就是指數(shù)損失,在給定n個(gè)樣本的情況下缨该,Adaboost的損失函數(shù)為:


1.4.Hinge損失函數(shù)(SVM)

在機(jī)器學(xué)習(xí)算法中偎行,hinge損失函數(shù)和SVM是息息相關(guān)的川背。在線性支持向量機(jī)中贰拿,最優(yōu)化問題可以等價(jià)于下列式子:



下面來對(duì)式子做個(gè)變形,令:



于是熄云,原式就變成了:

如若取λ=1/2C膨更,式子就可以表示成:



可以看出,該式子與下式非常相似:

前半部分中的l就是hinge損失函數(shù)缴允,而后面相當(dāng)于L2正則項(xiàng)荚守。
Hinge 損失函數(shù)的標(biāo)準(zhǔn)形式

可以看出,當(dāng)|y|>=1時(shí)练般,L(y)=0矗漾。

1.5. 其它損失函數(shù)

除了以上這幾種損失函數(shù),常用的還有:

0-1損失函數(shù)



絕對(duì)值損失函數(shù)



Python
先記錄一下python中數(shù)據(jù)結(jié)構(gòu)字典的排序方法薄料。
字典以鍵或值排序:

>>> dict1={"Beijing":2, "Shanghai":3, "Guangzhou":1}  
>>> sorted(dict1.items(), key=lambda A:A[0])   
#在python2.7中第一個(gè)參數(shù)需要改為dict1.iteritems()
[('Beijing', 2), ('Guangzhou', 1), ('Shanghai', 3)]  
>>> sorted(dict1.items(), key=lambda A:A[1])  
[('Guangzhou', 1), ('Beijing', 2), ('Shanghai', 3)] 

如果要以從大到小進(jìn)行排序敞贡,只需要加上reverse=True參數(shù)即可。
>>> sorted(dict1.items(), key=lambda A:A[0], reverse=True)  
[('Shanghai', 3), ('Guangzhou', 1), ('Beijing', 2)]  
>>> sorted(dict1.items(), key=lambda A:A[1], reverse=True)  
[('Shanghai', 3), ('Beijing', 2), ('Guangzhou', 1)]  

注意:sorted()的第一個(gè)參數(shù)為iterable摄职。因?yàn)樽值浔旧聿⒉皇莍terable的誊役,需要利用items()函數(shù)將字典轉(zhuǎn)換為可迭代的。

冒泡排序

#89,45,68,90,29,34,17
#倒序排列
list1 = [89,45,68,90,29,34,17]
for i in range(len(list1)):
    for j in range(len(list1)-1-i):
        if list1[j + 1] < list1[j]:
            list1[j],list1[j + 1] = list1[j + 1],list1[j]

#正序排列
def bubble_sort(lists):
    # 冒泡排序
    count = len(lists)
    for i in range(0, count):
        for j in range(i + 1, count):
            if lists[i] > lists[j]:
                lists[i], lists[j] = lists[j], lists[i]
    return lists

插入排序

描述:
插入排序的基本操作就是將一個(gè)數(shù)據(jù)插入到已經(jīng)排好序的有序數(shù)據(jù)中谷市,從而得到一個(gè)新的蛔垢、個(gè)數(shù)加一的有序數(shù)據(jù),算法適用于少量數(shù)據(jù)的排序迫悠,時(shí)間復(fù)雜度為O(n^2)鹏漆。是穩(wěn)定的排序方法。
插入算法把要排序的數(shù)組分成兩部分:第一部分包含了這個(gè)數(shù)組的所有元素,但將最后一個(gè)元素除外(讓數(shù)組多一個(gè)空間才有插入的位置)甫男,而第二部分就只包含這一個(gè)元素(即待插入元素)且改。在第一部分排序完成后,再將這個(gè)最后元素插入到已排好序的第一部分中板驳。

list1 = [89,45,68,90,29,34,17]
for i in range(1, len(list1)):
    key = list1[i]
    j = i - 1
    while j >= 0:
        if list1[j] > key:
            list1[j + 1] = list1[j]
            list1[j] = key
        j = j - 1
print (list1)
    

#算法課本P104頁例子
#key的左邊都是排好的又跛,插入排序就是把key插入到左邊排好的序列中去
#因?yàn)樽筮呉呀?jīng)排好了,所以如果比最后一個(gè)元素大就只需要和最后一個(gè)元素比就行
#否則key向前移動(dòng)若治,直到比較完前面所有的值
#一個(gè)key插入完以后慨蓝,key自增,直到右邊沒有元素為止
def Insert_sort(list1):
    count = len(list1)
    for i in range(1,count): #假設(shè)第一個(gè)數(shù)是排序好的
        key = list1[i] #取出當(dāng)前未排序的數(shù)
        j = i - 1 #從后往前端幼,先取未排序數(shù)的前一個(gè)數(shù)(已經(jīng)排序好的數(shù))
        while j >= 0 and list1[j] > key:#若當(dāng)前未排序的數(shù)比排序好的數(shù)還小礼烈,并沒有到數(shù)組的開頭。
            list1[j+1] = list1[j] #排序好的數(shù)往后挪一個(gè)位置
            j = j - 1 #去排序好的數(shù)的前一個(gè)數(shù)進(jìn)行比較
        list1[j+1] = key #插入當(dāng)前要排序的數(shù)
    return list1

希爾排序

希爾排序(Shell Sort)是插入排序的一種婆跑。
也稱縮小增量排序此熬,是直接插入排序算法的一種更高效的改進(jìn)版本。希爾排序是非穩(wěn)定排序算法滑进。該方法因DL.Shell于1959年提出而得名犀忱。 同時(shí)該算法是沖破O(n^2)的第一批算法之一。
希爾排序是把記錄按下標(biāo)的一定增量分組扶关,對(duì)每組使用直接插入排序算法排序阴汇;推薦的增量是 length/2,雖然他不一定是最好的。
隨著增量逐漸減少节槐,每組包含的關(guān)鍵詞越來越多搀庶,當(dāng)增量減至1時(shí),整個(gè)文件恰被分成一組铜异,算法便終止哥倔。

list1 = [89,45,68,90,29,34,17]
count = len(list1)
step = 2
group = count // step
while group > 0:
    for i in range(0, group):
        j = i + group
        while j < count:
            k = j - group
            key = list1[j]
            while k >= 0:
                if list1[k] > key:
                    list1[k + group] = list1[k]
                    list1[k] = key
                k -= group
            j += group
    group =  group // step
print (list1)




#python2中/代表整除,python3中//代表整除揍庄,/代表小數(shù)除
#list1 = [89,45,68,90,29,34,17]
def shell_sort(lists):
    # 希爾排序
    count = len(lists)
    step = 2
    group = count // step
    while group > 0:
        for i in range(0, group):
            j = i + group
            while j < count:
                k = j - group
                key = lists[j]
                while k >= 0:
                    if lists[k] > key:
                        lists[k + group] = lists[k]
                        lists[k] = key
                    k -= group
                j += group
        group =  group // step
    return lists

選擇排序

描述:
基本思想:第1次比較咆蒿,在待排序記錄r1 ~ r[n]中選出最小的記錄,將它與r1交換币绩;第2次比較蜡秽,在待排序記錄r2 ~ r[n]中選出最小的記錄,將它與r2交換缆镣;以此類推芽突,第i次在待排序記錄r[i] ~ r[n]中選出最小的記錄,將它與r[i]交換董瞻,使有序序列不斷增長(zhǎng)直到全部排序完畢寞蚌,對(duì)初始排列不敏感田巴,無論怎樣都要比較n-1次。

list1 = [89,45,68,90,29,34,17]
count = len(list1)
for i in range(count):
    min = i
    for j in range(i + 1, count):
        if list1[min] > list1[j]:
            min == j
    list1[min],list1[j] = list1[j],list1[min]
print (list1)   

def select_sort(lists):
    # 選擇排序
    count = len(lists)
    for i in range(0, count):
        min = i
        for j in range(i + 1, count):
            if lists[min] > lists[j]:
                min = j
        lists[min], lists[i] = lists[i], lists[min]
    return lists 

堆排序

一個(gè)完全二叉樹大根堆需要滿足:



i 為下標(biāo)挟秤,n為元素個(gè)數(shù)壹哺,i是從1開始的,0位置需要使用占位符

流程:

1.首先構(gòu)造堆
2.取出這個(gè)大根堆的堆頂節(jié)點(diǎn)(最大值)艘刚,與堆的最下最右的元素進(jìn)行交換管宵,然后把剩下的元素再構(gòu)造一個(gè)大根堆
3.重復(fù)第二步,直到這個(gè)大根堆的長(zhǎng)度為1攀甚,此時(shí)完成排序箩朴。

#占位符比較麻煩,直接使用python中的鏈表結(jié)構(gòu)
from collections import deque

def swap_param(L, i, j):
    L[i], L[j] = L[j], L[i]
    return L

def heap_adjust(L, start, end):
    temp = L[start]

    i = start
    j = 2 * i

    while j <= end:
        if (j < end) and (L[j] < L[j + 1]):
            j += 1
        if temp < L[j]:
            L[i] = L[j]
            i = j
            j = 2 * i
        else:
            break
    L[i] = temp

def heap_sort(L):
    L_length = len(L) - 1

    first_sort_count = L_length // 2
    for i in range(first_sort_count):
        heap_adjust(L, first_sort_count - i, L_length)

    for i in range(L_length - 1):
        L = swap_param(L, 1, L_length - i)
        heap_adjust(L, 1, L_length - i - 1)

    return [L[i] for i in range(1, len(L))]

def main():
    L = deque([50, 16, 30, 10, 60,  90,  2, 80, 70])
    L.appendleft(0)
    print (heap_sort(L))

if __name__ == '__main__':
    main()

描述:
堆排序(Heapsort)是指利用堆積樹(堆)這種數(shù)據(jù)結(jié)構(gòu)所設(shè)計(jì)的一種排序算法秋度,它是選擇排序的一種炸庞。可以利用數(shù)組的特點(diǎn)快速定位指定索引的元素荚斯。堆分為大根堆和小根堆埠居,是完全二叉樹。大根堆的要求是每個(gè)節(jié)點(diǎn)的值都不大于其父節(jié)點(diǎn)的值事期,即A[PARENT[i]] >= A[i]滥壕。在數(shù)組的非降序排序中,需要使用的就是大根堆刑赶,因?yàn)楦鶕?jù)大根堆的要求可知捏浊,最大的值一定在堆頂懂衩。

遞歸構(gòu)造堆撞叨,偽代碼:
MAX-HEAPIFY(A, i)
1 l ← LEFT(i)
2 r ← RIGHT(i)
3 if l ≤ heap-size[A] and A[l] > A[i]
4 then largest ← l
5 else largest ← i
6 if r ≤ heap-size[A] and A[r] > A[largest]
7 then largest ← r
8 if largest ≠ i
9 then exchange A[i] <-> A[largest]
10 MAX-HEAPIFY(A, largest)

快速排序

一趟快速排序的算法是:

1)設(shè)置兩個(gè)變量i、j浊洞,排序開始的時(shí)候:i=0牵敷,j=N-1;

2)以第一個(gè)數(shù)組元素作為關(guān)鍵數(shù)據(jù)法希,賦值給key枷餐,即key=A[0];

3)從j開始向前搜索苫亦,即由后開始向前搜索(j--)毛肋,找到第一個(gè)小于key的值A(chǔ)[j],將A[j]和A[i]互換屋剑;

4)從i開始向后搜索润匙,即由前開始向后搜索(i++),找到第一個(gè)大于key的A[i]唉匾,將A[i]和A[j]互換孕讳;

5)重復(fù)第3匠楚、4步,直到i=j厂财; (3,4步中芋簿,沒找到符合條件的值,即3中A[j]不小于key,4中A[i]不大于key的時(shí)候改變j璃饱、i的值与斤,使得j=j-1,i=i+1荚恶,直至找到為止幽告。找到符合條件的值,進(jìn)行交換的時(shí)候i裆甩, j指針位置不變冗锁。另外,i==j這一過程一定正好是i+或j-完成的時(shí)候嗤栓,此時(shí)令循環(huán)結(jié)束)冻河。

算法導(dǎo)論中的版本

def quick_sort(array, l, r):  
    if l < r:  
        q = partition(array, l, r)  
        quick_sort(array, l, q - 1)  
        quick_sort(array, q + 1, r)  

def partition(array, l, r):  
    x = array[r]  
    i = l - 1  
    for j in range(l, r):  
        if array[j] <= x:  
            i += 1  
            array[i], array[j] = array[j], array[i]  
    array[i + 1], array[r] = array[r], array[i+1]  
    return i + 1
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市茉帅,隨后出現(xiàn)的幾起案子叨叙,更是在濱河造成了極大的恐慌,老刑警劉巖堪澎,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件擂错,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡樱蛤,警方通過查閱死者的電腦和手機(jī)钮呀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昨凡,“玉大人爽醋,你說我怎么就攤上這事”慵梗” “怎么了蚂四?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)哪痰。 經(jīng)常有香客問我遂赠,道長(zhǎng),這世上最難降的妖魔是什么晌杰? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任跷睦,我火速辦了婚禮,結(jié)果婚禮上乎莉,老公的妹妹穿的比我還像新娘送讲。我一直安慰自己奸笤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布哼鬓。 她就那樣靜靜地躺著监右,像睡著了一般。 火紅的嫁衣襯著肌膚如雪异希。 梳的紋絲不亂的頭發(fā)上健盒,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音称簿,去河邊找鬼扣癣。 笑死,一個(gè)胖子當(dāng)著我的面吹牛憨降,可吹牛的內(nèi)容都是我干的父虑。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼授药,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼士嚎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起悔叽,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤莱衩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后娇澎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笨蚁,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年趟庄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了括细。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡岔激,死狀恐怖勒极,靈堂內(nèi)的尸體忽然破棺而出是掰,到底是詐尸還是另有隱情虑鼎,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布键痛,位于F島的核電站炫彩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏絮短。R本人自食惡果不足惜江兢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望丁频。 院中可真熱鬧杉允,春花似錦邑贴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至改基,卻和暖如春繁疤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背秕狰。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工稠腊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鸣哀。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓架忌,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親我衬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鳖昌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容