Python+機器學習的學習日記(2020.4.22-2020.4.26)

2020.4.22

首先來總結 李宏毅2020機器學習 Logistic Regression部分

(小部分內容摘抄自:
the github page is: https://Sakura-gh.github.io/ML-notes)

視頻加思考總共兩邊纔算有所理解。

上一次結束時,提出了問題,有沒有可能找到一個不那麼麻煩的方法找到w和b。

使用最大似然估計的思想,將各個樣本出現的概率相乘然後求得最大值即可。將這個式子化簡之後,就到得了一個新的loss function:
在這裏插入圖片描述
這個式子的意義在直觀上也很好理解,就是當訓練樣本的標記值爲1時,括號內前一項起作用,當訓練樣本的標記值爲0時,則是後一項起作用。作用在ln之內的,其實就是sigmoid函數,也就是表示這件事情出現的概率,概率越小則數值越大,也就意味着要輔助的代價就越大,反之則相反。

這個式子其實就是交叉熵,表示的是兩個分佈有多接近。

再使用梯度下降法就可以進行數據更新,然後找到最合適的w和b了。有趣的是,對這裏的loss function求導,得到的結果和線性迴歸中的導數是一樣的,說明二者有相同的參數更新方式。
在這裏插入圖片描述
這裏是二者的比較:
在這裏插入圖片描述
再來思考一個問題,爲什麼對數機率迴歸要使用交叉熵來作爲loss function而不像線性迴歸一樣使用方差的和來作爲loss function。可以先假設使用方差和的情況,這種情況下對loss function求導,得到的結果如下:
在這裏插入圖片描述
這個式子明顯是有問題的,如果第n個點的目標target是1,則,此時如果function的output 爲1的話,說明現在離target很接近了,於是得到的微分會變成0,這件事情是很合理的;但是當function的output爲 0的時候,說明離target還很遙遠,但是由於在上中求出來的update表達式中有一個f(x),因此這個時候也會導致得到的微分變成0。

也就是說,這種情況下有着極大的誤差,應該使用極大的代價來彌補,所以在梯度下降中,這一步應該邁得很大,但是若果是上式,這種情況則無法下降。所以我們要使用交叉熵而不是方差和。

上一次學習的分類方法叫Generative,就是需要求出mu和sigma的那個方法。這次學習的方法叫Discriminative,不需要求出mu和sigma便可求出w和b。二者有什麼區別呢?

這裏首先要提到的概念叫‘腦補’,意思是你看到一件事,你也許就很依靠自己的想象來補齊這件事的前因後果,正常人其實應該都有體會。二者的區別其實就在於此,Discriminative其實就是完全按照現有數據就行學習,來找到最佳的w和b,而Generative則是要根據現有數據,通過學習腦補出來一個數據的分佈,然後再得到mu和sigma,再求出w和b。這一塊根據二者的推導過程,很容易明白。

所以,對於數據量較大的樣本總體來說,就可以使用Discriminative的方法,因爲數據量已經足夠大,很能反映樣本的真實分佈了,不需要再去腦補什麼。而對於樣本總量較小的樣本總體來說,腦補就顯得很關鍵,因爲樣本總體不能很好地反映樣本的分佈情況,Generative的方法效果會更好。

所以,Generative model和discriminative model的差別就在於,Generative的model它有做了某些假設,假設你的data來自於某個概率模型;而Discriminative的model是完全不作任何假設的。

多分類問題直接參見 https://Sakura-gh.github.io/ML-notes

老師還提到,對數機率迴歸其實使用侷限性的,李宏毅老師也指出了一個Feature Transformation的方法,具體也參見 https://Sakura-gh.github.io/ML-notes,但是在吳恩達老師講解的機器學習中,可以使用更爲複雜的決策邊界來稍稍克服這一個問題。

然後將很多對數機率迴歸連載一起,就是構成了神經網絡(從對數機率迴歸推導過來的過程還是不是很理解)

後面就是深度學習!

2020.4.23
昨天的Python沒寫,今天一起寫了

學習了《Python編程 從入門到實踐》 第七章

第七章的內容是用戶輸入和while循環
input函數的使用方法如下,注意input函數返回的是字符串

name=input('tell me your name:')
#可使用int(),str()來轉換數據類型

while循環基本內容和其他的語言類似,break爲退出循環,continue爲重新執行循環。
while處理列表

names=['zhao','qian','sun','li','zhou']
while names:
	...
#當列表非空則判斷爲True,可以一個一個取出,直到爲空
while 'qian' in names
	...
#上面這個也可以循環,因爲他的判斷爲True
學習了《Python編程 從入門到實踐》 第八章

這一章的內容是函數

def hello()
	...
def Hello(name)
	...
def Hello(name,age)
	...
#這些都是定義函數和向其傳遞參數的方法

傳遞參數時又分爲按位置傳遞和關鍵字傳遞:

def hello(name,age)
	...
hello(name='su',age='25')#關鍵字傳遞
hello('su','25')#位置傳遞

設定默認值:

def hello(name='su',age='26')
	...

設定返回值

def hello(name)
	...
	return sth
message=hello('su')
#返回的值可以使字符串、數,也可以是列表、字典

讓參數變爲可選參數

def hello(name,age,sex='')
	...#後面加上對最後一個參數的if判斷即可
	#python中默認空字符串爲False

傳遞任意數量的實參:

def hello(*toppings)
	...
#*toppings 其實就是創建名爲toppings的空元祖
#也可以用**toppings創建一個空字典

後面還學習了導入模塊

import time
import time as t   #這是給time模塊重新命名

掌握這兩種足以。

2020.4.24

學習了《Python編程 從入門到實踐》 第九章

類。

個人覺得,類的功能和第三方庫的功能是很像的,存儲在別的文件中也是使用import調用,下面是練習用的一段程序:

class Restaurant():
    def __init__(self,r_name,r_type):
        self.r_name=r_name
        self.r_type=r_type
        self.r_num=0
    def describer(self):
        print('name: '+self.r_name)
        print('type: '+self.r_type)
        print('people: '+str(self.r_num))
    def openr(self):
        print('the restuarant is opening')
    def set_num(self,n):
        self.r_num=n
    def add_num(self,n):
        
    
        if self.r_num+n >= 100:
            more=self.r_num+n-100
            print('more than 100 people,'+str(more)+' people should get out')
        else:
            self.r_num=self.r_num+n

    
class Ice(Restaurant):
    def __init__(self,r_name,r_type):
        super().__init__(r_name,r_type)
        self.flavor='a'
    def inf(self):
        print('name: '+self.r_name)
        print('type: '+self.r_type)
        print('people: '+str(self.r_num))
        print('ice flavor: '+self.flavor)        
r= Ice('okk','chuancai')       
r.set_num(44)
r.add_num(60)
r.inf()

執行的結果是:

more than 100 people,4 people should get out
name: okk
type: chuancai
people: 44
ice flavor: a

對其中的程序進行說明,首先是使用class來定義一個類,其中的第一個函數必須是初始化函數,在這裏使用前後雙下劃線的命名方式來定義這個初始化函數,是一種約定俗成的方式,初始化函數在創建一個類時會自動運行。形參self必不可少,切必須在第一位,self由系統自動傳遞參數,他是一個指向實例本身的引用。剩下的函數就和定義普通函數一樣,但是要加入self。

下一段是一個繼承類,也就是一個子類。定義時括號內要寫入父類的名稱。初始化時要加入super()函數,定義方法見代碼。super()的用途就是繼承父類。創建子類時,子類必須在父類的後面。

這一部分對於我來說是新內容,所以後面還會再挑時間去深究、熟練。

2020.4.26

學習了《Python編程 從入門到實踐》 第十章

這一章的主要內容是用python處理文件和異常。
首先是打開文件和讀取文件:

with open('pi.txt') as file_obj:
	c=file_obj.read()
	print(c)
#引號內可以使相對路徑也可以是絕對路徑
#使用關鍵字with,python可以在你不需要文件時將它自動關閉,省心一些
#.read()是將文件讀取爲一個長字符串

以行的形式讀取文件:

with open('pi.txt') as file_obj:
	for line in file_obj:
		print(line)
或者
with open('pi.txt') as file_obj:
	c=file_obj.readlines()
for line in c:
	print(line.strip())
#第一個方法是直接for循環遍歷文件,這裏的for遍歷是按行遍歷的
#第二種方法是將文件按行存儲在一個列表中

接下來使寫入文件:

with open('pi.txt','w') as file_obj:
	file_obj.write('ni hao')
#程序是向pi.txt中寫入ni hao
#‘w’是寫標誌,除此之外還有:‘r’讀,‘a’附加,‘r+’讀寫
#注意,修改已有文件不能用‘w’	要用‘a’

接下來是異常處理部分:

#通常使用try&except
a=4
b=0
try:
	f=a/b
except:
	print('you cant divide by zero!')
else:
	print(f)
#這樣出現錯誤時,就會顯示你自己設定的提示了

此外還學習了一個函數split(),他可以把文本按空格分割成元素,然後儲存到列表中。

如果在處理異常時,想要得到‘失敗時一聲不吭’的效果,那麼這樣做:

a=4
b=0
try:
	f=a/b
except:
	#print('you cant divide by zero!')
	pass
else:
	print(f)

接下來是存儲數據的部分:

import json
num=[2,3,4]
filename='nums.json'
with open(filename,'w') as f_obj:
	json.dump(num,f_obj)
#創建一個叫nums的文件,然後把num寫入

import json

filename='nums.json'
with open(filename) as f_obj:
	nums=json.load(f_obj)
#這樣就把num.json中的文件讀取到nums中了
至此爲止,《python編程:從入門到實踐》總共學習了一半了,剩下的還有十章,基本都是三個小項目。
李宏毅老師的機器學習網課止於反向傳播那一節,剩餘內容還有很多。
明天開始全力準備考研複試,一個月之後會回來繼續Python與機器學習的學習!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章