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

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

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

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

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

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

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

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


正則項有多種方式選擇,常采用的有:
L1正則:|θj|
L2正則:θj2
Logistic 回歸(Logistic Regression)
采用線性回歸解決分類問題時,往往會遇到模型健壯性低,遇到噪聲時,受干擾嚴重。
 
我們可以對舊的線性回歸算法來進行適當?shù)男薷膩淼玫轿覀兿胍暮瘮?shù)。
引入sigmoid 函數(shù):

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

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

1.線性判定邊界:
假設線性函數(shù)為: ,

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

定義損失函數(shù):

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

定義損失函數(shù)為:

該函數(shù)的圖像如下:

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

加入正則項:

二分類與多分類
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、數(shù)據(jù)準備: ??下載地址
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']] # 轉(zhuǎn)換成numpy 形式
ydata = np.c_[df['y']]
|
3、畫出數(shù)據(jù)的散點圖:
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、進行數(shù)據(jù)的預測:
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_ # 將切片對象轉(zhuǎn)換為沿第二軸的連接。
>>> 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ù)的扁平數(shù)組。
>>> x = np.array([[1, 2, 3], [4, 5, 6]])
>>> print(np.ravel(x))
[1 2 3 4 5 6]
#######################################
numpy.reshape(-1,1) # 為數(shù)組提供新形狀,而不更改其數(shù)據(jù)。
此為: 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、數(shù)據(jù)準備
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函數(shù)

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

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、求解剃度函數(shù):
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、最小化損失函數(shù):
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')

|