標籤:

機器學習是一種認識世界的方式(2)

機器學習是一種認識世界的方式(2)

來自專欄 轉行AI小專欄

上一篇,我說道知道學校和專業畢業後的平均薪酬,怎麼估計某學校某專業的平均薪酬。

霍華德:機器學習是一種認識世界的方式?

zhuanlan.zhihu.com圖標

今天,我又遇到一個不一樣的問題,我能找到一些學校某些專業的數據,但有些數據怎麼也找不到,數據不完全,怎麼估計確實數據呢?如圖1所示。因此,這個問題就變成了:已知某些學校專業的薪酬,如何未知薪酬呢?

圖1 虛構數據 對的 我專門編數據來黑材料和生物的

感覺這方程都沒法聯立啊,這怎麼做呢?魔鬼就藏在數據中。首先,看學校,清華北大上交同一專業的收入是不是有差別呢?這是學校帶來的差異。再看專業,同一學校,不同專業是不是有所不同,這是專業帶來的差異。如果我們能對學校和專業的差異建模,那麼似乎我們就有辦法猜出缺失的數據。

那怎麼估計出學校和專業的差異呢?

思路1: 矩陣分解成專業矩陣和學校矩陣

用奇異值分解(SVD)把我們的矩陣A分解成U->學校矩陣, V->專業矩陣,還有 Sigma 奇異值矩陣。學校矩陣的每一行代表一個學校的特點,這個學校的特點都被概括在向量里了;同理,專業矩陣的一列是一個專業的向量。奇異值矩陣可以簡單的理解成特徵的重要性。選取最大的K個奇異值對應的特徵向量組成的矩陣,然後再乘起來。這個時候,那些缺失值都變成了其他的分數,這個分數就是預估值。

當然,做這些之前,首先要補齊矩陣,殘缺的矩陣是無法分解的。一般的方法呢,就是用平均值填入到缺失值里。

先開啟上帝視角,我們假設完整的矩陣是這樣的:

[[15000, 12000, 10000, 8000], [14000, 11000, 9000, 7000], [13000, 10000, 8000, 6000]])

然後我們把15000和9000扣掉,設成NaN。好,直接上代碼:

matrix_miss = np.array([[np.nan, 12000, 10000, 8000], [14000, 11000, np.nan, 7000], [13000, 10000, 8000, 6000]])#calculate the avg valueavg = np.nanmean(matrix_miss)#repalce the nan with avgwhere_is_nan = np.isnan(matrix_miss)matrix_miss[where_is_nan] = 9900#perform svd u, sigma, v = np.linalg.svd(matrix_miss, full_matrices=False)sigma_m = np.diag(sigma)matrix_f = np.dot(np.dot(u,sigma_m),v)#get top k sigma_r = np.diag(sigma[:2])u_r = u[:,0:2]v_r = v[:2,:]matrix_r = np.dot(np.dot(u_r,sigma_r),v_r)

15000估計出的結果是9898.5,9000估計的結果是9571.95。結果呢不大好,估計得值都特別接近平均值。而且SVD分解是個O(n^3)的複雜度,對於大矩陣算的超級慢。

9898.5 11957.9 10053.6 7997.4514009.2 11257.8 9571.95 7015.612991.2 9754.12 8312.92 5985.12

思路2: 用神經網路來學習

既然在SVD分解里我們可以得到專業向量和學校向量,為何我們不知道用隨機梯度下降法來學習專業向量和學校向量呢?這樣最後學校向量乘以專業向量,不就得到我們想要的估計值了嗎?

我們的目標是通過學習已有的數據,來估計學校向量和專業向量。我們用均方誤差來做損失函數:

loss = (r(u,m) -p(u)q(m))^{2}

直接上代碼:

matrix_miss = np.array([[np.nan, 12000, 10000, 8000], [14000, 11000, np.nan, 7000], [13000, 10000, 8000, 6000]])global_avg = np.nanmean(matrix_miss)where_is_nan = np.isnan(matrix_miss)matrix_miss[where_is_nan] = 0#init x with random variableu = (np.random.random([3,3])+1)*np.sqrt(global_avg/3)m = (np.random.random([4,3])+1)*np.sqrt(global_avg/3)#make x varibleu_var = Variable(torch.FloatTensor(u),requires_grad=True)m_var = Variable(torch.FloatTensor(m),requires_grad=True)matrix_m = torch.FloatTensor(matrix_miss)optimizer = torch.optim.SGD([u_var,m_var], lr=0.0001)for train_step in range(500): loss = 0 for i in range(u_var.size()[0]): #print (x_var[i,:]) for j in range(m_var.size()[0]): if matrix_miss[i,j] != 0.0: value = matrix_m[i,j] loss += (value - torch.dot(u_var[i],m_var[j]))**2 loss_avg = loss/10 if train_step % 100 == 0: print (loss.data.numpy()[0]) optimizer.zero_grad() # 清空上一步的殘餘更新參數值 loss_avg.backward() # 誤差反向傳播, 計算參數更新值 optimizer.step() print (np.dot(u_var.data.numpy(),m_var.data.numpy().T))

然後我們訓練了五百輪,得到了下面的結果。

[14995.14 12000.852 9999.965 7998.7524][14000.228 10998.647 8821.045 7001.6777][12999.779 10000.463 8000.0454 5999.648 ]

結果,棒棒噠。15000估計值是14995,9000估計的是8821!完美~

之所以寫這個例子,是因為在機器學習中有大量這樣的問題,如推薦系統。在推薦系統里,對於用戶數據可以整理成一個用戶-物品矩陣。這個矩陣中含有用戶對物品的評分,但也有很多物品用戶沒有打過評分,就是缺失值。而推薦系統的終極目標就是對用戶,預測未評分物品的分值,並按照分數從高到低推薦給用戶。而起計算過程就如我兩個寫到的兩個思路。


推薦閱讀:

【翻譯】Brian2高級指導_狀態更新
機器學習基石筆記2:感知器學習演算法(PLA)
梯度下降法及其Python實現
人工智慧是怎樣的一門學科?
圖解線性代數:vector length and dot product

TAG:機器學習 |