用邏輯回歸對用戶分類 (理論+實戰)
- 2019 年 10 月 6 日
- 筆記
如果你在運營一個2C的平台,那麼你肯定關心用戶流失的問題。騰訊有個產品叫信鴿Pro,它能夠通過對用戶往期行為的挖掘,預測用戶潛在的流失(付費)行為,進而實現精準營銷。據說,騰訊自己的手游就是用這個系統做用戶分析的。
信鴿Pro獲取大量用戶數據,提取用戶特徵,然後通過演算法建模,評估出用戶可能的行為。演算法建模中最基礎的一步就是對用戶進行分類。這裡就介紹一種常用的分類演算法 - 邏輯回歸。
模型
用戶數據比較複雜,這裡用平面上的點舉例。假設平面上有一些點,如圖所示:
整個平面上只有兩種圖形,一種是三角形,另一種是圓形。可以把它們想像為兩種不同的用戶,比如活躍用戶/非活躍用戶。 問題:如果隨意在這個平面新增加一個點, 比如點P(5,19),那怎知把它歸到哪一組更合適?可以想像為對新用戶的預測。
思路
我們發現,三角形大都位於左上方,而圓形大都位於右下方。我們可以用尺子在圖上畫一條直線,該直線儘可能的將三角形和圓形分到兩邊。然後觀察新點位於哪一側。若與三角形在同一側,則它應該屬於三角形;若位於圓形一側,則應屬於圓形。在本例中,坐標P應該屬於三角形更合適。
這個問題似乎很簡單。但是,如果三維空間存在類似的問題,答案就沒有那麼顯而易見了。那4維空間呢? 1024維空間呢?
不過別擔心!藉助電腦演算法,N維空間分類的問題已經很容易解決,邏輯回歸就是常用的一種。
邏輯回歸
邏輯回歸的核心思想就是通過現有數據,對分類邊界線建立回歸公式,以此進行分類。
在介紹演算法之前,需要先介紹一個函數: Sigmoid函數。
Sigmoid函數
Sigmoid函數的表達式為:
在坐標系中的圖形為:
x>0時,x越大y越接近於1;x<0時,x越小,y越接近於0。如果把坐標拉長,曲線中間就會很「陡」。直觀上x的「輕微」變化,都會導致y接近於0或1。
Sigmoid函數的作用是將任意實數轉換成0~1的數,而0和1剛好可以用做分類,比如,用1表示三角形,用0表示圓形。小於0.5的可以劃分為0類,大於0.5的劃分為1類。(註:Sigmoid是單調增長函數,因而多個數字通過Sigmoid轉換後相對位置不變,這是選擇該函數的重要原因。)
分析步驟
簡化模型
為便於分析,把模型中的坐標簡化一些。下面的六個坐標點和一條分割線:
其中紅色三角形坐標分別是(1,2)、(1.5,7)和(2,6)。綠色圓點坐標分別是(1,0)、(2,3)和(2.5,6)。分割線的函數為y=4x-3. 它的形式還可以轉換成:3-4x+y=0 。
我們設表達式f(x,y) = 3-4x+y
把六個點的坐標代到這個方程式里,有
<表1>
(註:標識1表示三角形;標識0表示圓形) f(x,y)>0的點在分割線上方,是三角形;f(x,y)<0的點在分割線下方,是圓形.
如果有個三角形的坐標是(2,4.5),那這個點的f(x,y)值等於-0.5,這個點就被分割線錯誤劃分了。
現在的問題是,我們只有一些坐標以及這些坐標的分類資訊,如何找到一條最優的分割線,使得儘可能少的點被錯誤劃分?
損失函數
損失函數 (Loss Function) 的作用是判斷直線錯誤劃分數據的程度。一種方法是計算被錯誤劃分的點的個數,錯誤點越少,直線越好。但,這種方法很難優化。另一種方法是計算點到直線的距離。
如果是一個平面來劃分三維空間的點,那距離公式為
一般的,n維空間上一個點到超平面的距離為
w是超平面的參數向量,
x是超平面的自變數,
b是截距
超平面函數:
表示x向量的第i個元素(特性);後面會用到
,表示空間中的第i個點。
為了方便計算,一般在x中增加一個元素1,w中增加一個元素w0=b
於是超平面函數變為:
距離公式變為:
超平面上方的點f(x)>0, 下方的點f(x)<0,因此點到超平面的距離(分正負):
d是一個負無窮到正無窮的數。
通過sigmoid函數,將d變成一個0~1的值,設h = sigmoid(d)。若d為正且越大,h越接近於1,也就越應該屬於三角形(分類1);若d為負,且絕對值越大,h越接近於0,該點也就越應該屬於圓形(分類0)。因此,h越接近於分類標識,劃分的準確性越高。
設第j個點的分類表示為
,那麼下面的公式就表示點j被錯誤劃分的概率。
我們把損失函數設定為所有點被錯誤劃分的平均概率
平方是為了保證概率為正,前面的1/2是為了求導數後消除參數。
那麼,問題轉化成:找到w的一個值,使得損失函數的值最小。
用梯度下降法求w
所謂梯度,就是函數在某個點增長最快的方向,有時稱為斜度。如果函數是一個曲線,某個點的梯度就是該點的斜率,或導數。
如果是曲面,梯度是在兩個方向上求偏導。
梯度下降法的核心思想是:欲求函數的最小值,先從某一點出發,沿著函數的梯度的反方向探尋,直到找到最小值。設每次探尋Delta(w),步長為alpha,則梯度下降的演算法的公式為:
求導
用梯度下降法需要先對損失函數求導,我們的損失函數被分成三部分:
——— (1)
——— (2)
———- (3)
可以通過複合函數求導法對損失函數求偏導:
梯度公式重點關注的是導數的符號,所以這裡可以簡化一下。函數(2)是單調遞增函數,所以導數是正數,不影響整體導數的符號,可以去除。 公式(3)的分母是正數,也不影響導數的符號,也可以去掉。最後得:
代入梯度下降演算法公式得:
1/m為正數,也可用去掉。
程式碼
loadData()函數返回坐標值和分類標識。第一個返回值取前三列 x0,x1,x2;第二個返回值取第四列,即label
from numpy import * def loadData(): data = [[1, 1, 2, 1], [1, 2, 6, 1], [1, 1.5, 7, 1], [1, 1, 0, 0], [1, 2, 3, 0], [1, 2.5, 6, 0]] ds = [e[0:3] for e in data] label = [e[-1] for e in data] return ds, label
Sigmoid函數
def sigmoid(x): return 1.0/(1+exp(-x))
梯度下降演算法 input ds: 坐標數據; label: 標籤 return w: 係數向量, nx1的矩陣
def reduce(ds, label): #轉換成矩陣 dmat = mat(ds) lmat = mat(label).T #mxn的矩陣的行數和列數 m,n = shape(dmat) #步長 alpha = 0.1 #循環次數 loops = 200 #初始化w為[1,1,1],即分割線為 1+x+y=0 w = ones((n,1)) for i in range(loops): h = sigmoid(dmat*w) err = (h - lmat) w = w - alpha * dmat.T* err return w.A[:,0]
測試
def test(): ds,l = loadData() print reduce(ds,l)
運行結果
>>> import lr >>> lr.test() [ 3.1007773 -5.54393712 1.60563033]
也就是說w=(3.1, -5.5, 1.6), 即w0=3.1, w1=-5.5, w2 = 1.6
分割線的表達式為:w0+w1x+w2y=0, 代入w後得 3.1-5.5x+1.6y=0, 即y=3.44x-1.9 。 見下圖,該直線正確地將圖形劃分開。
執行過程
w的初始值為(1,1,1),也就是0號線。 每次循環都會調整分割線的位置,執行到第200次的時候,分割線已經能夠很好對坐標分組了。 <分割線調整圖> 線編號n表示第n次調整(循環)之後的位置
應用
把上面的x,y轉換成用戶特徵,比如登錄時間,登錄頻率等等。把三角形和圓形轉換成付費用戶和免費用戶,就得到了付費用戶預測模型;把三角形和圓形轉換成流失用戶和有效用戶,就得到了流失用戶預測模型。 當然,這只是個理論模型,實際應用要比這複雜的多的多。
相關文章