線性回歸 ( Linear Regression )
線性回歸中,只包括一個自變量和一個因變量,且二者的關系可用一條直線近似表示,這種回歸稱為一元線性回歸。
如果回歸分析中包括兩個或兩個以上的自變量,且因變量和自變量之間是線性關系,則稱為多元線性回歸。
在監(jiān)督學習中,學習樣本為 D = { (x(i), y(i));i =1, . . . , m } ,預測的結果y(i)為連續(xù)值變量,需要學習映射 f:X → Y ,并且假定輸入X和輸出Y之間有線性相關關系。
給出一組數據:

其中x是實數域中的二維向量。比如,xi1是第i個房子的居住面積,xi2是這個房子的房間數。
為了執(zhí)行監(jiān)督學習,我們需要決定怎樣在計算機中表示我們的函數/假設。我們可以近似地使用線性函數來表示。

(矩陣形式)
現在,有了訓練數據,我們怎么挑選,或者說得知θ的值呢?一個可信的方法是使得h(x)與y更加接近,至少對于我們訓練的例子來說是這樣的。
于是,我們定義一個損失函數 / 成本函數( loss function / cost function ):
我們把 x 到 y 的映射函數 f 記作 θ 的函數 hθ(x)

損失函數有很多種類型,根據需求進行選擇。
然后進行最小化損失函數,將函數優(yōu)化成凸函數 (往往只會有一個全局最優(yōu)解,不用過多擔心算法收斂到局部最優(yōu)解) 。

梯度下降 ( Gradient Descent algorithm )
最快的速度最小化損失函數,比作如何最快地下山,也就是每一步都應該往坡度最陡的方向往下走,而坡度最陡的方向就是損失函數相應的偏導數。
因此算法迭代的規(guī)則是:

假設現在有n個特征、或者變量xj (j=1…n)

其中α是算法的參數learning rate,α越大每一步下降的幅度越大,速度也會越快,但過大有可能反復震蕩,導致算法不準確。

欠擬合與過擬合(Underfitting and Overfitting)
欠擬合問題:特征值少,模型過于簡單不足與支撐。
過擬合問題:有非常多特征,模型很復雜, 我們的假設函數曲線可以對原始數據擬合得非常好, 但喪失了一般性, 從而導致對新給的待預測樣本,預測效果差。
正則項、正則化
通過正則項控制參數幅度。


正則項有多種方式選擇,常采用的有:
L1正則:|θj|
L2正則:θj2
Logistic 回歸(Logistic Regression)
采用線性回歸解決分類問題時,往往會遇到模型健壯性低,遇到噪聲時,受干擾嚴重。
 
我們可以對舊的線性回歸算法來進行適當的修改來得到我們想要的函數。
引入sigmoid 函數:

對原函數hθ(x)進行改寫得到:

觀察函數圖像發(fā)現:當x大于0時,y的值大于0.5,根據這特性可以將線性回歸得到的預測值壓縮在0~1范圍內。

1.線性判定邊界:
假設線性函數為: ,

當 hθ(x) > 0 時,g(hθ(x)) 的值為大于 0.5;
當 hθ(x) < 0 時,g(hθ(x)) 的值為小于 0.5;
2.非線性判定邊界:
假設函數為:
當θ0=0,θ1=0,θ2=0,θ3=1,θ4=1,得到函數g(x12+x22-1),邊界為一個圓,圓內點的值小于0

定義損失函數:

該函數為非凸函數,有局部最小值,應選擇其他函數。

定義損失函數為:

該函數的圖像如下:

我們可以發(fā)現該函數在:
y=1的正樣本中,hθ(x)趨向于0.99~9 ,此時我們希望得到的代價越小,而當得到的預測值是0.00~1時,我們希望它的代價越大;
y=0的負樣本中,hθ(x)趨向于0.00~1 ,此時我們希望得到的代價越小,而當得到的預測值是0.99~9時,我們希望它的代價越大;
損失函數可以改寫成:

加入正則項:

二分類與多分類
one vs one

one vs rest
方法一:

1.先對三角形與叉叉進行分類,得到分類器C1,以及概率值Pc1(x) 和 1-Pc1(x)
2.然后對三角形與正方形進行分類,得到分類器C2,以及概率值Pc2(x) 和 1-Pc2(x)
3.最后對正方形與叉叉進行分類,得到分類器C3,以及概率值Pc3(x) 和 1-Pc3(x)
得到通過3個分類器,6個概率值,概率值最大的判斷為相應的類型!
方法二:

1.先對三角形進行分類,判斷是否為三角形,得到分類器C1,以及概率值Pc1(x)
2.然后對正方形進行分類,判斷是否為正方形,得到分類器C2,以及概率值Pc2(x)
3.最后對叉叉叉進行分類,判斷是否為叉叉叉,得到分類器C3,以及概率值Pc3(x)
得到3個分類器,3個概率值,概率值最大的判斷為相應的類型!
應用一:( Linear Regression )
1、導入相應的包,設置畫圖格式:
1 2 3 4 5 6 7 8 | import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_context( 'notebook' )
sns.set_style( 'white' )
plt.figure(figsize = ( 8 , 6 ))
|
2、數據準備: ??下載地址
1 2 3 4 | df = pd.read_csv(r '..\..\input\data1.txt' ,header = None ,names = [ 'x' , 'y' ])
xdata = np.c_[np.ones(df.shape[ 0 ]),df[ 'x' ]] # 轉換成numpy 形式
ydata = np.c_[df[ 'y' ]]
|
3、畫出數據的散點圖:
1 2 3 4 5 | plt.scatter(xdata[:, 1 ],ydata,s = 50 ,marker = 'x' ,color = 'r' )
plt.xlim( 4 , 24 )
plt.xlabel( 'Population of City in 10,000s' )
plt.ylabel( 'Profit in $10,000s' );
plt.show()
|

4、定義Loss function:

1 2 3 4 5 6 | def computeCost(x,y,theta = [[ 0 ],[ 0 ]]):
m = y.size
h = x.dot(theta)
j = 0
j = 1.0 / ( 2 * m) * (np. sum (np.square(h - y)))
return j
|
5、定義梯度下降算法:
1 2 3 4 5 6 7 8 9 | def gradientDescent(x,y,theta = [[ 0 ],[ 0 ]],alpha = 0.01 , num_iters = 1500 ):
m = y.size
J_history = np.zeros(num_iters)
for i in range (num_iters):
h = x.dot(theta)
theta = theta - alpha * ( 1.0 / m) * (x.T.dot(h - y))
J_history[i] = computeCost(x,y,theta)
return (theta,J_history)
|
6、計算&畫圖:
1 2 3 4 5 6 7 8 | theta,Cost_J = gradientDescent(xdata,ydata)
print ( 'theta: ' ,theta.ravel()) # theta: [-3.63029144 1.16636235]
plt.figure(figsize = ( 8 , 6 ))
plt.plot(Cost_J)
plt.ylabel( 'Cost J' )
plt.xlabel( 'Iterations' );
plt.show()
|
得到θ的變化曲線:

通過計算我們能夠得到 θ 的兩個值,由此我們能畫出一條與預測直線。
1 2 | xx = np.arange( 5 , 23 ) # 生成直線上的點
yy = theta[ 0 ] + theta[ 1 ] * xx # 計算出直線的方程表達式
|
7、散點圖中畫出直線 與 sklearn得到的結果進行對比:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # 畫出我們自己寫的線性回歸梯度下降收斂的情況
plt.figure(figsize = ( 8 , 6 ))
plt.scatter(xdata[:, 1 ],ydata,s = 50 ,marker = 'x' ,color = 'r' )
plt.plot(xx,yy, label = 'Linear regression (Gradient descent)' ,c = 'b' )
# 和Scikit-learn中的線性回歸對比一下
from sklearn.linear_model import LinearRegression
regr = LinearRegression()
regr.fit(xdata[:, 1 ].reshape( - 1 , 1 ), ydata.ravel())
plt.plot(xx, regr.intercept_ + regr.coef_ * xx, label = 'Linear regression (Scikit-learn GLM)' ,c = 'g' )
plt.xlim( 4 , 24 )
plt.xlabel( 'Population of City in 10,000s' )
plt.ylabel( 'Profit in $10,000s' );
plt.legend(loc = 4 );
plt.show()
|
可以看出兩條直線是非常接近的!

8、進行數據的預測:
1 2 3 4 5 6 | # 預測一下人口為35000和70000的城市的結果
print (theta.T.dot([ 1 , 3.5 ]) * 10000 )
print (theta.T.dot([ 1 , 7 ]) * 10000 )
[ 4519.7678677 ]
[ 45342.45012945 ]
|
補充:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | numpy.c_ # 將切片對象轉換為沿第二軸的連接。
>>> np.c_[np.array([[ 1 , 2 , 3 ]]), 0 , 0 , np.array([[ 4 , 5 , 6 ]])]
array([[ 1 , 2 , 3 , 0 , 0 , 4 , 5 , 6 ]]) # 1行8列!
#######################################
numpy.ravel # 返回一個連續(xù)的扁平數組。
>>> x = np.array([[ 1 , 2 , 3 ], [ 4 , 5 , 6 ]])
>>> print (np.ravel(x))
[ 1 2 3 4 5 6 ]
#######################################
numpy.reshape( - 1 , 1 ) # 為數組提供新形狀,而不更改其數據。
此為: n行 1 列
|
應用二:( Logistic Regression )
1、導入相應的包,設置畫圖格式:
1 2 3 4 | import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
% matplotlib inline
|
2、數據準備
1 2 3 4 | data = np.loadtxt( file , delimiter = delimeter)
X = np.c_[np.ones((data.shape[ 0 ], 1 )), data[:, 0 : 2 ]]
y = np.c_[data[:, 2 ]]
|
3、畫出樣本的散點圖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def plotData(data, label_x, label_y, label_pos, label_neg, axes = None ):
# 獲得正負樣本的下標(即哪些是正樣本,哪些是負樣本)
neg = data[:, 2 ] = = 0
pos = data[:, 2 ] = = 1
if axes = = None :
axes = plt.gca()
axes.scatter(data[pos][:, 0 ], data[pos][:, 1 ], marker = '+' , c = 'k' , s = 60 , linewidth = 2 , label = label_pos)
axes.scatter(data[neg][:, 0 ], data[neg][:, 1 ], c = 'y' , s = 60 , label = label_neg)
axes.set_xlabel(label_x)
axes.set_ylabel(label_y)
axes.legend(frameon = True , fancybox = True );
plt.figure(figsize = ( 8 , 6 ))
plotData(data, 'Exam 1 score' , 'Exam 2 score' , 'Pass' , 'Fail' )
|

4、定義sigmoid函數

1 2 | def sigmoid(z):
return 1 / ( 1 + np.exp( - z) )
|
5、定義損失函數

1 2 3 4 5 6 7 8 9 | def costFunction(theta, X, y):
m = y.size
h = sigmoid(X.dot(theta))
J = - 1.0 * ( 1.0 / m) * (np.log(h).T.dot(y) + np.log( 1 - h).T.dot( 1 - y))
if np.isnan(J[ 0 ]):
return (np.inf)
return J[ 0 ]
|
6、求解剃度函數:
1 2 3 4 5 | def gradient(theta, X, y):
m = y.size
h = sigmoid(X.dot(theta.reshape( - 1 , 1 )))<br>
grad = ( 1.0 / m) * X.T.dot(h - y)<br>
return (grad.flatten())
|
7、最小化損失函數:
1 2 | initial_theta = np.zeros(X.shape[ 1 ])
res = minimize(costFunction, initial_theta, args = (X,y), jac = gradient, options = { 'maxiter' : 400 })
|
8、預測:
1 | sigmoid(np.array([ 1 , 45 , 85 ]).dot(res.x.T))
|
9、畫出決策邊界
1 2 3 4 5 6 7 8 | plt.scatter( 45 , 85 , s = 60 , c = 'r' , marker = 'v' , label = '(45, 85)' )
plotData(data, 'Exam 1 score' , 'Exam 2 score' , 'Admitted' , 'Not admitted' )
x1_min, x1_max = X[:, 1 ]. min (), X[:, 1 ]. max (),
x2_min, x2_max = X[:, 2 ]. min (), X[:, 2 ]. max (),
xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max), np.linspace(x2_min, x2_max))
h = sigmoid(np.c_[np.ones((xx1.ravel().shape[ 0 ], 1 )), xx1.ravel(), xx2.ravel()].dot(res.x))
h = h.reshape(xx1.shape)
plt.contour(xx1, xx2, h, [ 0.5 ], linewidths = 1 , colors = 'b' );
|

10、添加正則項:
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | def costFunctionReg(theta, reg, * args):
m = y.size
h = sigmoid(XX.dot(theta))
J = - 1.0 * ( 1.0 / m) * (np.log(h).T.dot(y) + np.log( 1 - h).T.dot( 1 - y)) + (reg / ( 2.0 * m)) * np. sum (np.square(theta[ 1 :]))
if np.isnan(J[ 0 ]):
return (np.inf)
return (J[ 0 ])
def gradientReg(theta, reg, * args):
m = y.size
h = sigmoid(XX.dot(theta.reshape( - 1 , 1 )))
grad = ( 1.0 / m) * XX.T.dot(h - y) + (reg / m) * np.r_[[[ 0 ]],theta[ 1 :].reshape( - 1 , 1 )]
return (grad.flatten())
|
11、最優(yōu)化:
1 2 | # C = [0.0, 1.0, 100.0]
res2 = minimize(costFunctionReg, initial_theta, args = (C, XX, y), jac = gradientReg, options = { 'maxiter' : 3000 })
|
Kaggle比賽應用:
San Francisco Crime Classification
Predict the category of crimes that occurred in the city by the bay


import pandas as pd
import numpy as np
train = pd.read_csv('\\train.csv')
test = pd.read_csv('\\test.csv')
all_address = list(np.array(train['Address'].tolist() + test['Address'].tolist()))
from sklearn.feature_extraction.text import CountVectorizer
stop_words = ['dr', 'wy', 'bl', 'av', 'st', 'ct', 'ln', 'block', 'of']
vectorizer = CountVectorizer(max_features=300, stop_words=stop_words)
features = vectorizer.fit_transform(all_address).toarray()
X = features[:train.shape[0]]
y = train.Category
#分成80%的訓練集和20%的驗證集
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=44)
from sklearn.linear_model import LogisticRegression
log_model = LogisticRegression()
log_model.fit(X_train,y_train)
results = log_model.predict_proba(X_test)
from sklearn.metrics import log_loss
log_loss_score = log_loss(y_test, results)
print('log loss score: {0}'.format(round(log_loss_score, 3)))
# log loss score: 2.511
# 使用整個train
log_model = LogisticRegression().fit(X=features[:train.shape[0]], y=train.Category)
results = log_model.predict_proba(features[train.shape[0]:])
submission = pd.DataFrame(results)
submission.columns = sorted(train.Category.unique())
submission.set_index(test.Id)
submission.index.name="Id"
submission.to_csv('py_submission_logreg_addr_300.csv')

|