【機(jī)器學(xué)習(xí)實戰(zhàn)】第8章 預(yù)測數(shù)值型數(shù)據(jù):回歸(Regression)

第8章 預(yù)測數(shù)值型數(shù)據(jù):回歸

<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>

預(yù)測數(shù)值型數(shù)據(jù)回歸首頁

回歸(Regression) 概述

我們前邊提到的分類的目標(biāo)變量是標(biāo)稱型數(shù)據(jù)娄猫,而回歸則是對連續(xù)型的數(shù)據(jù)做出處理,回歸的目的是預(yù)測數(shù)值型數(shù)據(jù)的目標(biāo)值。

回歸 場景

回歸的目的是預(yù)測數(shù)值型的目標(biāo)值。最直接的辦法是依據(jù)輸入寫出一個目標(biāo)值的計算公式宣赔。

假如你想要預(yù)測蘭博基尼跑車的功率大小,可能會這樣計算:

HorsePower = 0.0015 * annualSalary - 0.99 * hoursListeningToPublicRadio

這就是所謂的 回歸方程(regression equation)义起,其中的 0.0015 和 -0.99 稱作 回歸系數(shù)(regression weights)拉背,求這些回歸系數(shù)的過程就是回歸。一旦有了這些回歸系數(shù)默终,再給定輸入椅棺,做預(yù)測就非常容易了。具體的做法是用回歸系數(shù)乘以輸入值齐蔽,再將結(jié)果全部加在一起两疚,就得到了預(yù)測值。我們這里所說的含滴,回歸系數(shù)是一個向量诱渤,輸入也是向量,這些運算也就是求出二者的內(nèi)積谈况。

說到回歸勺美,一般都是指 線性回歸(linear regression)递胧。線性回歸意味著可以將輸入項分別乘以一些常量,再將結(jié)果加起來得到輸出赡茸。

回歸 原理

1缎脾、線性回歸

我們應(yīng)該怎樣從一大堆數(shù)據(jù)里求出回歸方程呢? 假定輸入數(shù)據(jù)存放在矩陣 x 中占卧,而回歸系數(shù)存放在向量 w 中遗菠。那么對于給定的數(shù)據(jù) X1,預(yù)測結(jié)果將會通過 Y = X1^T w 給出』眩現(xiàn)在的問題是辙纬,手里有一些 X 和對應(yīng)的 y,怎樣才能找到 w 呢叭喜?一個常用的方法就是找出使誤差最小的 w 贺拣。這里的誤差是指預(yù)測 y 值和真實 y 值之間的差值,使用該誤差的簡單累加將使得正差值和負(fù)差值相互抵消捂蕴,所以我們采用平方誤差纵柿。

平方誤差可以寫做:

平方誤差

用矩陣表示還可以寫做

平方誤差_2

。如果對 w 求導(dǎo)启绰,得到
平方誤差_3

,令其等于零沟使,解出 w 如下(具體求導(dǎo)過程為: http://blog.csdn.net/nomadlx53/article/details/50849941 ):

回歸系數(shù)的最佳估計計算公式

1.1委可、線性回歸 須知概念

1.1.1、矩陣求逆

因為我們在計算回歸方程的回歸系數(shù)時腊嗡,用到的計算公式如下:

回歸系數(shù)的最佳估計計算公式

需要對矩陣求逆着倾,因此這個方程只在逆矩陣存在的時候適用,我們在程序代碼中對此作出判斷燕少。
判斷矩陣是否可逆的一個可選方案是:

判斷矩陣的行列式是否為 0卡者,若為 0 ,矩陣就不存在逆矩陣客们,不為 0 的話崇决,矩陣才存在逆矩陣。

1.1.2底挫、最小二乘法

最小二乘法(又稱最小平方法)是一種數(shù)學(xué)優(yōu)化技術(shù)恒傻。它通過最小化誤差的平方和尋找數(shù)據(jù)的最佳函數(shù)匹配。

1.2建邓、線性回歸 工作原理

讀入數(shù)據(jù)盈厘,將數(shù)據(jù)特征x、特征標(biāo)簽y存儲在矩陣x官边、y中
驗證 x^Tx 矩陣是否可逆
使用最小二乘法求得 回歸系數(shù) w 的最佳估計

1.3沸手、線性回歸 開發(fā)流程

收集數(shù)據(jù): 采用任意方法收集數(shù)據(jù)
準(zhǔn)備數(shù)據(jù): 回歸需要數(shù)值型數(shù)據(jù)外遇,標(biāo)稱型數(shù)據(jù)將被轉(zhuǎn)換成二值型數(shù)據(jù)
分析數(shù)據(jù): 繪出數(shù)據(jù)的可視化二維圖將有助于對數(shù)據(jù)做出理解和分析,在采用縮減法求得新回歸系數(shù)之后契吉,可以將新擬合線繪在圖上作為對比
訓(xùn)練算法: 找到回歸系數(shù)
測試算法: 使用 R^2 或者預(yù)測值和數(shù)據(jù)的擬合度跳仿,來分析模型的效果
使用算法: 使用回歸,可以在給定輸入的時候預(yù)測出一個數(shù)值栅隐,這是對分類方法的提升塔嬉,因為這樣可以預(yù)測連續(xù)型數(shù)據(jù)而不僅僅是離散的類別標(biāo)簽

1.4、線性回歸 算法特點

優(yōu)點:結(jié)果易于理解租悄,計算上不復(fù)雜谨究。
缺點:對非線性的數(shù)據(jù)擬合不好。
適用于數(shù)據(jù)類型:數(shù)值型和標(biāo)稱型數(shù)據(jù)泣棋。

1.5胶哲、線性回歸 項目案例

1.5.1锥咸、線性回歸 項目概述

根據(jù)下圖中的點淮腾,找出該數(shù)據(jù)的最佳擬合直線。

線性回歸數(shù)據(jù)示例圖

數(shù)據(jù)格式為:

x0          x1          y 
1.000000    0.067732    3.176513
1.000000    0.427810    3.816464
1.000000    0.995731    4.550095
1.000000    0.738336    4.256571
1.5.2凶掰、線性回歸 編寫代碼
def loadDataSet(fileName):                 
    """ 加載數(shù)據(jù)
        解析以tab鍵分隔的文件中的浮點數(shù)
    Returns:
        dataMat :  feature 對應(yīng)的數(shù)據(jù)集
        labelMat : feature 對應(yīng)的分類標(biāo)簽把敢,即類別標(biāo)簽

    """
    # 獲取樣本特征的總數(shù)寄摆,不算最后的目標(biāo)變量 
    numFeat = len(open(fileName).readline().split('\t')) - 1 
    dataMat = []
    labelMat = []
    fr = open(fileName)
    for line in fr.readlines():
        # 讀取每一行
        lineArr =[]
        # 刪除一行中以tab分隔的數(shù)據(jù)前后的空白符號
        curLine = line.strip().split('\t')
        # i 從0到2,不包括2 
        for i in range(numFeat):
            # 將數(shù)據(jù)添加到lineArr List中修赞,每一行數(shù)據(jù)測試數(shù)據(jù)組成一個行向量           
            lineArr.append(float(curLine[i]))
            # 將測試數(shù)據(jù)的輸入數(shù)據(jù)部分存儲到dataMat 的List中
        dataMat.append(lineArr)
        # 將每一行的最后一個數(shù)據(jù)婶恼,即類別,或者叫目標(biāo)變量存儲到labelMat List中
        labelMat.append(float(curLine[-1]))
    return dataMat,labelMat


def standRegres(xArr,yArr):
    '''
    Description:
        線性回歸
    Args:
        xArr :輸入的樣本數(shù)據(jù)柏副,包含每個樣本數(shù)據(jù)的 feature
        yArr :對應(yīng)于輸入數(shù)據(jù)的類別標(biāo)簽勾邦,也就是每個樣本對應(yīng)的目標(biāo)變量
    Returns:
        ws:回歸系數(shù)
    '''

    # mat()函數(shù)將xArr,yArr轉(zhuǎn)換為矩陣 mat().T 代表的是對矩陣進(jìn)行轉(zhuǎn)置操作
    xMat = mat(xArr)
    yMat = mat(yArr).T
    # 矩陣乘法的條件是左矩陣的列數(shù)等于右矩陣的行數(shù)
    xTx = xMat.T*xMat
    # 因為要用到xTx的逆矩陣割择,所以事先需要確定計算得到的xTx是否可逆眷篇,條件是矩陣的行列式不為0
    # linalg.det() 函數(shù)是用來求得矩陣的行列式的,如果矩陣的行列式為0荔泳,則這個矩陣是不可逆的蕉饼,就無法進(jìn)行接下來的運算                   
    if linalg.det(xTx) == 0.0:
        print "This matrix is singular, cannot do inverse" 
        return
    # 最小二乘法
    # http://www.apache.wiki/pages/viewpage.action?pageId=5505133
    # 書中的公式,求得w的最優(yōu)解
    ws = xTx.I * (xMat.T*yMat)            
    return ws


def regression1():
    xArr, yArr = loadDataSet("input/8.Regression/data.txt")
    xMat = mat(xArr)
    yMat = mat(yArr)
    ws = standRegres(xArr, yArr)
    fig = plt.figure()
    ax = fig.add_subplot(111)               #add_subplot(349)函數(shù)的參數(shù)的意思是换可,將畫布分成3行4列圖像畫在從左到右從上到下第9塊
    ax.scatter(xMat[:, 1].flatten(), yMat.T[:, 0].flatten().A[0]) #scatter 的x是xMat中的第二列椎椰,y是yMat的第一列
    xCopy = xMat.copy() 
    xCopy.sort(0)
    yHat = xCopy * ws
    ax.plot(xCopy[:, 1], yHat)
    plt.show()

完整代碼地址: https://github.com/apachecn/MachineLearning/blob/master/src/python/8.PredictiveNumericalDataRegression/regression.py

1.5.3、線性回歸 擬合效果
線性回歸數(shù)據(jù)效果圖

2沾鳄、局部加權(quán)線性回歸

線性回歸的一個問題是有可能出現(xiàn)欠擬合現(xiàn)象慨飘,因為它求的是具有最小均方差的無偏估計。顯而易見,如果模型欠擬合將不能取得最好的預(yù)測效果瓤的。所以有些方法允許在估計中引入一些偏差休弃,從而降低預(yù)測的均方誤差。

一個方法是局部加權(quán)線性回歸(Locally Weighted Linear Regression圈膏,LWLR)塔猾。在這個算法中,我們給預(yù)測點附近的每個點賦予一定的權(quán)重稽坤,然后與 線性回歸 類似丈甸,在這個子集上基于最小均方誤差來進(jìn)行普通的回歸。我們需要最小化的目標(biāo)函數(shù)大致為:

局部加權(quán)線性回歸回歸系數(shù)公式

與 kNN 一樣尿褪,這種算法每次預(yù)測均需要事先選取出對應(yīng)的數(shù)據(jù)子集睦擂。該算法解出回歸系數(shù) w 的形式如下:

局部加權(quán)線性回歸回歸系數(shù)公式

其中 w 是一個矩陣,用來給每個數(shù)據(jù)點賦予權(quán)重杖玲。

LWLR 使用 “核”(與支持向量機(jī)中的核類似)來對附近的點賦予更高的權(quán)重顿仇。核的類型可以自由選擇,最常用的核就是高斯核摆马,高斯核對應(yīng)的權(quán)重如下:

局部加權(quán)線性回歸高斯核

這樣就構(gòu)建了一個只含對角元素的權(quán)重矩陣 w臼闻,并且點 x 與 x(i) 越近,w(i, i) 將會越大囤采。上述公式中包含一個需要用戶指定的參數(shù) k述呐,它決定了對附近的點賦予多大的權(quán)重,這也是使用 LWLR 時唯一需要考慮的參數(shù)蕉毯,下面的圖給出了參數(shù) k 與權(quán)重的關(guān)系市埋。

參數(shù)k與權(quán)重的關(guān)系

上面的圖是 每個點的權(quán)重圖(假定我們正預(yù)測的點是 x = 0.5),最上面的圖是原始數(shù)據(jù)集恕刘,第二個圖顯示了當(dāng) k = 0.5 時,大部分的數(shù)據(jù)都用于訓(xùn)練回歸模型抒倚;而最下面的圖顯示當(dāng) k=0.01 時褐着,僅有很少的局部點被用于訓(xùn)練回歸模型。

2.1托呕、局部加權(quán)線性回歸 工作原理

讀入數(shù)據(jù)含蓉,將數(shù)據(jù)特征x、特征標(biāo)簽y存儲在矩陣x项郊、y中
利用高斯核構(gòu)造一個權(quán)重矩陣 W馅扣,對預(yù)測點附近的點施加權(quán)重
驗證 X^TWX 矩陣是否可逆
使用最小二乘法求得 回歸系數(shù) w 的最佳估計

2.2、局部加權(quán)線性回歸 項目案例

2.2.1着降、局部加權(quán)線性回歸 項目概述

我們?nèi)匀皇褂蒙厦?線性回歸 的數(shù)據(jù)集差油,對這些點進(jìn)行一個 局部加權(quán)線性回歸 的擬合。

局部加權(quán)線性回歸數(shù)據(jù)示例圖

數(shù)據(jù)格式為:

1.000000    0.067732    3.176513
1.000000    0.427810    3.816464
1.000000    0.995731    4.550095
1.000000    0.738336    4.256571
2.2.2、局部加權(quán)線性回歸 編寫代碼
    # 局部加權(quán)線性回歸
def lwlr(testPoint,xArr,yArr,k=1.0):
    '''
        Description:
            局部加權(quán)線性回歸蓄喇,在待預(yù)測點附近的每個點賦予一定的權(quán)重发侵,在子集上基于最小均方差來進(jìn)行普通的回歸。
        Args:
            testPoint:樣本點
            xArr:樣本的特征數(shù)據(jù)妆偏,即 feature
            yArr:每個樣本對應(yīng)的類別標(biāo)簽刃鳄,即目標(biāo)變量
            k:關(guān)于賦予權(quán)重矩陣的核的一個參數(shù),與權(quán)重的衰減速率有關(guān)
        Returns:
            testPoint * ws:數(shù)據(jù)點與具有權(quán)重的系數(shù)相乘得到的預(yù)測點
        Notes:
            這其中會用到計算權(quán)重的公式钱骂,w = e^((x^((i))-x) / -2k^2)
            理解:x為某個預(yù)測點叔锐,x^((i))為樣本點,樣本點距離預(yù)測點越近见秽,貢獻(xiàn)的誤差越大(權(quán)值越大)愉烙,越遠(yuǎn)則貢獻(xiàn)的誤差越小(權(quán)值越姓偶)齿梁。
            關(guān)于預(yù)測點的選取,在我的代碼中取的是樣本點肮蛹。其中k是帶寬參數(shù)勺择,控制w(鐘形函數(shù))的寬窄程度,類似于高斯函數(shù)的標(biāo)準(zhǔn)差伦忠。
            算法思路:假設(shè)預(yù)測點取樣本點中的第i個樣本點(共m個樣本點)省核,遍歷1到m個樣本點(含第i個),算出每一個樣本點與預(yù)測點的距離昆码,
            也就可以計算出每個樣本貢獻(xiàn)誤差的權(quán)值气忠,可以看出w是一個有m個元素的向量(寫成對角陣形式)。
    '''
    # mat() 函數(shù)是將array轉(zhuǎn)換為矩陣的函數(shù)赋咽, mat().T 是轉(zhuǎn)換為矩陣之后旧噪,再進(jìn)行轉(zhuǎn)置操作
    xMat = mat(xArr)
    yMat = mat(yArr).T
    # 獲得xMat矩陣的行數(shù)
    m = shape(xMat)[0]
    # eye()返回一個對角線元素為1,其他元素為0的二維數(shù)組脓匿,創(chuàng)建權(quán)重矩陣weights淘钟,該矩陣為每個樣本點初始化了一個權(quán)重                   
    weights = mat(eye((m)))
    for j in range(m):
        # testPoint 的形式是 一個行向量的形式
        # 計算 testPoint 與輸入樣本點之間的距離,然后下面計算出每個樣本貢獻(xiàn)誤差的權(quán)值
        diffMat = testPoint - xMat[j,:]
        # k控制衰減的速度
        weights[j,j] = exp(diffMat*diffMat.T/(-2.0*k**2))
    # 根據(jù)矩陣乘法計算 xTx 陪毡,其中的 weights 矩陣是樣本點對應(yīng)的權(quán)重矩陣
    xTx = xMat.T * (weights * xMat)
    if linalg.det(xTx) == 0.0:
        print ("This matrix is singular, cannot do inverse")
        return
    # 計算出回歸系數(shù)的一個估計
    ws = xTx.I * (xMat.T * (weights * yMat))
    return testPoint * ws

def lwlrTest(testArr,xArr,yArr,k=1.0):
    '''
        Description:
            測試局部加權(quán)線性回歸米母,對數(shù)據(jù)集中每個點調(diào)用 lwlr() 函數(shù)
        Args:
            testArr:測試所用的所有樣本點
            xArr:樣本的特征數(shù)據(jù),即 feature
            yArr:每個樣本對應(yīng)的類別標(biāo)簽毡琉,即目標(biāo)變量
            k:控制核函數(shù)的衰減速率
        Returns:
            yHat:預(yù)測點的估計值
    '''
    # 得到樣本點的總數(shù)
    m = shape(testArr)[0]
    # 構(gòu)建一個全部都是 0 的 1 * m 的矩陣
    yHat = zeros(m)
    # 循環(huán)所有的數(shù)據(jù)點铁瞒,并將lwlr運用于所有的數(shù)據(jù)點 
    for i in range(m):
        yHat[i] = lwlr(testArr[i],xArr,yArr,k)
    # 返回估計值
    return yHat

def lwlrTestPlot(xArr,yArr,k=1.0):  
    '''
        Description:
            首先將 X 排序,其余的都與lwlrTest相同桅滋,這樣更容易繪圖
        Args:
            xArr:樣本的特征數(shù)據(jù)慧耍,即 feature
            yArr:每個樣本對應(yīng)的類別標(biāo)簽,即目標(biāo)變量,實際值
            k:控制核函數(shù)的衰減速率的有關(guān)參數(shù)蜂绎,這里設(shè)定的是常量值 1
        Return:
            yHat:樣本點的估計值
            xCopy:xArr的復(fù)制
    '''
    # 生成一個與目標(biāo)變量數(shù)目相同的 0 向量
    yHat = zeros(shape(yArr))
    # 將 xArr 轉(zhuǎn)換為 矩陣形式
    xCopy = mat(xArr)
    # 排序
    xCopy.sort(0)
    # 開始循環(huán)栅表,為每個樣本點進(jìn)行局部加權(quán)線性回歸,得到最終的目標(biāo)變量估計值
    for i in range(shape(xArr)[0]):
        yHat[i] = lwlr(xCopy[i],xArr,yArr,k)
    return yHat,xCopy


#test for LWLR
def regression2():
    xArr, yArr = loadDataSet("input/8.Regression/data.txt")
    yHat = lwlrTest(xArr, xArr, yArr, 0.003)
    xMat = mat(xArr)
    srtInd = xMat[:,1].argsort(0)           #argsort()函數(shù)是將x中的元素從小到大排列师枣,提取其對應(yīng)的index(索引)怪瓶,然后輸出
    xSort=xMat[srtInd][:,0,:]
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(xSort[:,1], yHat[srtInd])
    ax.scatter(xMat[:,1].flatten().A[0], mat(yArr).T.flatten().A[0] , s=2, c='red')
    plt.show()

完整代碼地址: https://github.com/apachecn/MachineLearning/blob/master/src/python/8.PredictiveNumericalDataRegression/regression.py

2.2.3、局部加權(quán)線性回歸 擬合效果
局部加權(quán)線性回歸數(shù)據(jù)效果圖

上圖使用了 3 種不同平滑值繪出的局部加權(quán)線性回歸的結(jié)果践美。上圖中的平滑系數(shù) k =1.0洗贰,中圖 k = 0.01,下圖 k = 0.003 陨倡×沧蹋可以看到,k = 1.0 時的模型效果與最小二乘法差不多兴革,k=0.01時該模型可以挖出數(shù)據(jù)的潛在規(guī)律绎晃,而 k=0.003時則考慮了太多的噪聲,進(jìn)而導(dǎo)致了過擬合現(xiàn)象杂曲。

2.3庶艾、局部加權(quán)線性回歸 注意事項

局部加權(quán)線性回歸也存在一個問題,即增加了計算量擎勘,因為它對每個點做預(yù)測時都必須使用整個數(shù)據(jù)集咱揍。

3、線性回歸 & 局部加權(quán)線性回歸 項目案例

到此為止棚饵,我們已經(jīng)介紹了找出最佳擬合直線的兩種方法煤裙,下面我們用這些技術(shù)來預(yù)測鮑魚的年齡。

3.1噪漾、項目概述

我們有一份來自 UCI 的數(shù)據(jù)集合的數(shù)據(jù)硼砰,記錄了鮑魚(一種介殼類水生動物)的年齡。鮑魚年齡可以從鮑魚殼的層數(shù)推算得到欣硼。

3.2夺刑、開發(fā)流程

收集數(shù)據(jù): 采用任意方法收集數(shù)據(jù)
準(zhǔn)備數(shù)據(jù): 回歸需要數(shù)值型數(shù)據(jù),標(biāo)稱型數(shù)據(jù)將被轉(zhuǎn)換成二值型數(shù)據(jù)
分析數(shù)據(jù): 繪出數(shù)據(jù)的可視化二維圖將有助于對數(shù)據(jù)做出理解和分析分别,在采用縮減法求得新回歸系數(shù)之后,可以將新擬合線繪在圖上作為對比
訓(xùn)練算法: 找到回歸系數(shù)
測試算法: 使用 rssError()函數(shù) 計算預(yù)測誤差的大小存淫,來分析模型的效果
使用算法: 使用回歸耘斩,可以在給定輸入的時候預(yù)測出一個數(shù)值,這是對分類方法的提升桅咆,因為這樣可以預(yù)測連續(xù)型數(shù)據(jù)而不僅僅是離散的類別標(biāo)簽

收集數(shù)據(jù): 采用任意方法收集數(shù)據(jù)

準(zhǔn)備數(shù)據(jù): 回歸需要數(shù)值型數(shù)據(jù)括授,標(biāo)稱型數(shù)據(jù)將被轉(zhuǎn)換成二值型數(shù)據(jù)

數(shù)據(jù)存儲格式:

1   0.455   0.365   0.095   0.514   0.2245  0.101   0.15    15
1   0.35    0.265   0.09    0.2255  0.0995  0.0485  0.07    7
-1  0.53    0.42    0.135   0.677   0.2565  0.1415  0.21    9
1   0.44    0.365   0.125   0.516   0.2155  0.114   0.155   10
0   0.33    0.255   0.08    0.205   0.0895  0.0395  0.055   7

分析數(shù)據(jù): 繪出數(shù)據(jù)的可視化二維圖將有助于對數(shù)據(jù)做出理解和分析,在采用縮減法求得新回歸系數(shù)之后,可以將新擬合線繪在圖上作為對比

訓(xùn)練算法: 找到回歸系數(shù)

使用上面我們講到的 局部加權(quán)線性回歸 訓(xùn)練算法荚虚,求出回歸系數(shù)

測試算法: 使用 rssError()函數(shù) 計算預(yù)測誤差的大小薛夜,來分析模型的效果

# test for abloneDataSet
def abaloneTest():
    '''
    Desc:
        預(yù)測鮑魚的年齡
    Args:
        None
    Returns:
        None
    '''
    # 加載數(shù)據(jù)
    abX, abY = loadDataSet("input/8.Regression/abalone.txt")
    # 使用不同的核進(jìn)行預(yù)測
    oldyHat01 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 0.1)
    oldyHat1 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 1)
    oldyHat10 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 10)   
    # 打印出不同的核預(yù)測值與訓(xùn)練數(shù)據(jù)集上的真實值之間的誤差大小
    print "old yHat01 error Size is :" , rssError(abY[0:99], oldyHat01.T)
    print "old yHat1 error Size is :" , rssError(abY[0:99], oldyHat1.T)
    print "old yHat10 error Size is :" , rssError(abY[0:99], oldyHat10.T)

    # 打印出 不同的核預(yù)測值 與 新數(shù)據(jù)集(測試數(shù)據(jù)集)上的真實值之間的誤差大小
    newyHat01 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 0.1)
    print "new yHat01 error Size is :" , rssError(abY[0:99], newyHat01.T)
    newyHat1 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 1)
    print "new yHat1 error Size is :" , rssError(abY[0:99], newyHat1.T)
    newyHat10 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 10)
    print "new yHat10 error Size is :" , rssError(abY[0:99], newyHat10.T)

    # 使用簡單的 線性回歸 進(jìn)行預(yù)測,與上面的計算進(jìn)行比較
    standWs = standRegres(abX[0:99], abY[0:99])
    standyHat = mat(abX[100:199]) * standWs
    print "standRegress error Size is:", rssError(abY[100:199], standyHat.T.A)

完整代碼地址: https://github.com/apachecn/MachineLearning/blob/master/src/python/8.PredictiveNumericalDataRegression/regression.py

根據(jù)我們上邊的測試版述,可以看出:

簡單線性回歸達(dá)到了與局部加權(quán)現(xiàn)行回歸類似的效果梯澜。這也說明了一點,必須在未知數(shù)據(jù)上比較效果才能選取到最佳模型渴析。那么最佳的核大小是 10 嗎晚伙?或許是,但如果想得到更好的效果俭茧,應(yīng)該用 10 個不同的樣本集做 10 次測試來比較結(jié)果咆疗。

使用算法: 使用回歸,可以在給定輸入的時候預(yù)測出一個數(shù)值母债,這是對分類方法的提升午磁,因為這樣可以預(yù)測連續(xù)型數(shù)據(jù)而不僅僅是離散的類別標(biāo)簽

4、縮減系數(shù)來 “理解” 數(shù)據(jù)

如果數(shù)據(jù)的特征比樣本點還多應(yīng)該怎么辦毡们?是否還可以使用線性回歸和之前的方法來做預(yù)測迅皇?答案是否定的,即我們不能再使用前面介紹的方法漏隐。這是因為在計算

的時候會出錯喧半。

如果特征比樣本點還多(n > m),也就是說輸入數(shù)據(jù)的矩陣 x 不是滿秩矩陣青责。非滿秩矩陣求逆時會出現(xiàn)問題挺据。

為了解決這個問題,我們引入了 嶺回歸(ridge regression) 這種縮減方法脖隶。接著是 lasso法扁耐,最后介紹 前向逐步回歸

4.1产阱、嶺回歸

簡單來說婉称,嶺回歸就是在矩陣

上加一個 λI 從而使得矩陣非奇異,進(jìn)而能對
求逆构蹬。其中矩陣I是一個 m * m 的單位矩陣王暗,
對角線上元素全為1,其他元素全為0庄敛。而λ是一個用戶定義的數(shù)值俗壹,后面會做介紹。在這種情況下藻烤,回歸系數(shù)的計算公式將變成:
嶺回歸的回歸系數(shù)計算

嶺回歸最先用來處理特征數(shù)多于樣本數(shù)的情況绷雏,現(xiàn)在也用于在估計中加入偏差头滔,從而得到更好的估計。這里通過引入 λ 來限制了所有 w 之和涎显,通過引入該懲罰項坤检,能夠減少不重要的參數(shù),這個技術(shù)在統(tǒng)計學(xué)中也叫作 縮減(shrinkage)期吓。

嶺回歸

縮減方法可以去掉不重要的參數(shù)早歇,因此能更好地理解數(shù)據(jù)。此外膘婶,與簡單的線性回歸相比缺前,縮減法能取得更好的預(yù)測效果。

這里通過預(yù)測誤差最小化得到 λ: 數(shù)據(jù)獲取之后悬襟,首先抽一部分?jǐn)?shù)據(jù)用于測試衅码,剩余的作為訓(xùn)練集用于訓(xùn)練參數(shù) w。訓(xùn)練完畢后在測試集上測試預(yù)測性能脊岳。通過選取不同的 λ 來重復(fù)上述測試過程逝段,最終得到一個使預(yù)測誤差最小的 λ 。

4.1.1割捅、嶺回歸 原始代碼
def ridgeRegres(xMat,yMat,lam=0.2):
    '''
        Desc:
            這個函數(shù)實現(xiàn)了給定 lambda 下的嶺回歸求解奶躯。
            如果數(shù)據(jù)的特征比樣本點還多,就不能再使用上面介紹的的線性回歸和局部現(xiàn)行回歸了亿驾,因為計算 (xTx)^(-1)會出現(xiàn)錯誤嘹黔。
            如果特征比樣本點還多(n > m),也就是說莫瞬,輸入數(shù)據(jù)的矩陣x不是滿秩矩陣儡蔓。非滿秩矩陣在求逆時會出現(xiàn)問題。
            為了解決這個問題疼邀,我們下邊講一下:嶺回歸喂江,這是我們要講的第一種縮減方法。
        Args:
            xMat:樣本的特征數(shù)據(jù)旁振,即 feature
            yMat:每個樣本對應(yīng)的類別標(biāo)簽获询,即目標(biāo)變量,實際值
            lam:引入的一個λ值拐袜,使得矩陣非奇異
        Returns:
            經(jīng)過嶺回歸公式計算得到的回歸系數(shù)
    '''

    xTx = xMat.T*xMat
    # 嶺回歸就是在矩陣 xTx 上加一個 λI 從而使得矩陣非奇異吉嚣,進(jìn)而能對 xTx + λI 求逆
    denom = xTx + eye(shape(xMat)[1])*lam
    # 檢查行列式是否為零,即矩陣是否可逆蹬铺,行列式為0的話就不可逆尝哆,不為0的話就是可逆。
    if linalg.det(denom) == 0.0:
        print ("This matrix is singular, cannot do inverse")
        return
    ws = denom.I * (xMat.T*yMat)
    return ws


def ridgeTest(xArr,yArr):
    '''
        Desc:
            函數(shù) ridgeTest() 用于在一組 λ 上測試結(jié)果
        Args:
            xArr:樣本數(shù)據(jù)的特征丛塌,即 feature
            yArr:樣本數(shù)據(jù)的類別標(biāo)簽较解,即真實數(shù)據(jù)
        Returns:
            wMat:將所有的回歸系數(shù)輸出到一個矩陣并返回
    '''

    xMat = mat(xArr)
    yMat=mat(yArr).T
    # 計算Y的均值
    yMean = mean(yMat,0)
    # Y的所有的特征減去均值
    yMat = yMat - yMean
    # 標(biāo)準(zhǔn)化 x,計算 xMat 平均值
    xMeans = mean(xMat,0)
    # 然后計算 X的方差
    xVar = var(xMat,0)
    # 所有特征都減去各自的均值并除以方差
    xMat = (xMat - xMeans)/xVar
    # 可以在 30 個不同的 lambda 下調(diào)用 ridgeRegres() 函數(shù)赴邻。
    numTestPts = 30
    # 創(chuàng)建30 * m 的全部數(shù)據(jù)為0 的矩陣
    wMat = zeros((numTestPts,shape(xMat)[1]))
    for i in range(numTestPts):
        # exp() 返回 e^x 
        ws = ridgeRegres(xMat,yMat,exp(i-10))
        wMat[i,:]=ws.T
    return wMat


#test for ridgeRegression
def regression3():
    abX,abY = loadDataSet("input/8.Regression/abalone.txt")
    ridgeWeights = ridgeTest(abX, abY)
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(ridgeWeights)
    plt.show()

完整代碼地址: https://github.com/apachecn/MachineLearning/blob/master/src/python/8.PredictiveNumericalDataRegression/regression.py

4.1.2印衔、嶺回歸在鮑魚數(shù)據(jù)集上的運行效果
嶺回歸的運行效果

上圖繪制除了回歸系數(shù)與 log(λ) 的關(guān)系。在最左邊姥敛,即 λ 最小時奸焙,可以得到所有系數(shù)的原始值(與線性回歸一致);而在右邊彤敛,系數(shù)全部縮減為0与帆;在中間部分的某值將可以取得最好的預(yù)測效果。為了定量地找到最佳參數(shù)值墨榄,還需要進(jìn)行交叉驗證玄糟。另外,要判斷哪些變量對結(jié)果預(yù)測最具有影響力袄秩,在上圖中觀察它們對應(yīng)的系數(shù)大小就可以了阵翎。

4.2、lasso

在增加如下約束時之剧,普通的最小二乘法回歸會得到與嶺回歸一樣的公式:

lasso_1

上式限定了所有回歸系數(shù)的平方和不能大于 λ 郭卫。使用普通的最小二乘法回歸在當(dāng)兩個或更多的特征相關(guān)時,可能會得到一個很大的正系數(shù)和一個很大的負(fù)系數(shù)背稼。正式因為上述限制條件的存在贰军,使用嶺回歸可以避免這個問題。

與嶺回歸類似蟹肘,另一個縮減方法lasso也對回歸系數(shù)做了限定词疼,對應(yīng)的約束條件如下:

lasso_2

唯一的不同點在于,這個約束條件使用絕對值取代了平方和疆前。雖然約束形式只是稍作變化寒跳,結(jié)果卻大相徑庭: 在 λ 足夠小的時候,一些系數(shù)會因此被迫縮減到 0.這個特性可以幫助我們更好地理解數(shù)據(jù)竹椒。

4.3童太、前向逐步回歸

前向逐步回歸算法可以得到與 lasso 差不多的效果,但更加簡單胸完。它屬于一種貪心算法书释,即每一步都盡可能減少誤差。一開始赊窥,所有權(quán)重都設(shè)置為 1爆惧,然后每一步所做的決策是對某個權(quán)重增加或減少一個很小的值。

偽代碼如下:

數(shù)據(jù)標(biāo)準(zhǔn)化锨能,使其分布滿足 0 均值 和單位方差
在每輪迭代過程中: 
    設(shè)置當(dāng)前最小誤差 lowestError 為正無窮
    對每個特征:
        增大或縮小:
            改變一個系數(shù)得到一個新的 w
            計算新 w 下的誤差
            如果誤差 Error 小于當(dāng)前最小誤差 lowestError: 設(shè)置 Wbest 等于當(dāng)前的 W
        將 W 設(shè)置為新的 Wbest
4.3.1扯再、前向逐步回歸 原始代碼
def stageWise(xArr,yArr,eps=0.01,numIt=100):
    xMat = mat(xArr); yMat=mat(yArr).T
    yMean = mean(yMat,0)
    yMat = yMat - yMean     # 也可以規(guī)則化ys但會得到更小的coef
    xMat = regularize(xMat)
    m,n=shape(xMat)
    #returnMat = zeros((numIt,n)) # 測試代碼刪除
    ws = zeros((n,1)); wsTest = ws.copy(); wsMax = ws.copy()
    for i in range(numIt):
        print (ws.T)
        lowestError = inf; 
        for j in range(n):
            for sign in [-1,1]:
                wsTest = ws.copy()
                wsTest[j] += eps*sign
                yTest = xMat*wsTest
                rssE = rssError(yMat.A,yTest.A)
                if rssE < lowestError:
                    lowestError = rssE
                    wsMax = wsTest
        ws = wsMax.copy()
        returnMat[i,:]=ws.T
    return returnMat


#test for stageWise
def regression4():
    xArr,yArr=loadDataSet("input/8.Regression/abalone.txt")
    stageWise(xArr,yArr,0.01,200)
    xMat = mat(xArr)
    yMat = mat(yArr).T
    xMat = regularize(xMat)
    yM = mean(yMat,0)
    yMat = yMat - yM
    weights = standRegres(xMat, yMat.T)
    print (weights.T)

完整代碼地址: https://github.com/apachecn/MachineLearning/blob/master/src/python/8.PredictiveNumericalDataRegression/regression.py

4.3.2芍耘、逐步線性回歸在鮑魚數(shù)據(jù)集上的運行效果
逐步線性回歸運行效果

逐步線性回歸算法的主要優(yōu)點在于它可以幫助人們理解現(xiàn)有的模型并作出改進(jìn)。當(dāng)構(gòu)建了一個模型后熄阻,可以運行該算法找出重要的特征斋竞,這樣就有可能及時停止對那些不重要特征的手機(jī)。最后秃殉,如果用于測試坝初,該算法每100次迭代后就可以構(gòu)建出一個模型,可以使用類似于10折交叉驗證的方法比較這些模型钾军,最終選擇使誤差最小的模型鳄袍。

4.4、小結(jié)

當(dāng)應(yīng)用縮減方法(如逐步線性回歸或嶺回歸)時吏恭,模型也就增加了偏差(bias)拗小,與此同時卻減小了模型的方差。

5砸泛、回歸 項目案例

項目案例1: 預(yù)測樂高玩具套裝的價格

項目概述

Dangler 喜歡為樂高套裝估價十籍,我們用回歸技術(shù)來幫助他建立一個預(yù)測模型。

開發(fā)流程
(1) 收集數(shù)據(jù):用 Google Shopping 的API收集數(shù)據(jù)唇礁。
(2) 準(zhǔn)備數(shù)據(jù):從返回的JSON數(shù)據(jù)中抽取價格勾栗。
(3) 分析數(shù)據(jù):可視化并觀察數(shù)據(jù)。
(4) 訓(xùn)練算法:構(gòu)建不同的模型盏筐,采用逐步線性回歸和直接的線性回歸模型围俘。
(5) 測試算法:使用交叉驗證來測試不同的模型,分析哪個效果最好琢融。
(6) 使用算法:這次練習(xí)的目標(biāo)就是生成數(shù)據(jù)模型界牡。

收集數(shù)據(jù): 使用 Google 購物的 API

由于 Google 提供的 api 失效,我們只能自己下載咯漾抬,將數(shù)據(jù)存儲在了 input 文件夾下的 setHtml 文件夾下

準(zhǔn)備數(shù)據(jù): 從返回的 JSON 數(shù)據(jù)中抽取價格

因為我們這里不是在線的宿亡,就不再是 JSON 了,我們直接解析線下的網(wǎng)頁纳令,得到我們想要的數(shù)據(jù)挽荠。

分析數(shù)據(jù): 可視化并觀察數(shù)據(jù)

這里我們將解析得到的數(shù)據(jù)打印出來,然后觀察數(shù)據(jù)平绩。

訓(xùn)練算法: 構(gòu)建不同的模型

from numpy import *
from bs4 import BeautifulSoup

# 從頁面讀取數(shù)據(jù)圈匆,生成retX和retY列表
def scrapePage(retX, retY, inFile, yr, numPce, origPrc):

    # 打開并讀取HTML文件
    fr = open(inFile)
    soup = BeautifulSoup(fr.read())
    i=1

    # 根據(jù)HTML頁面結(jié)構(gòu)進(jìn)行解析
    currentRow = soup.findAll('table', r="%d" % i)
    while(len(currentRow)!=0):
        currentRow = soup.findAll('table', r="%d" % i)
        title = currentRow[0].findAll('a')[1].text
        lwrTitle = title.lower()

        # 查找是否有全新標(biāo)簽
        if (lwrTitle.find('new') > -1) or (lwrTitle.find('nisb') > -1):
            newFlag = 1.0
        else:
            newFlag = 0.0

        # 查找是否已經(jīng)標(biāo)志出售,我們只收集已出售的數(shù)據(jù)
        soldUnicde = currentRow[0].findAll('td')[3].findAll('span')
        if len(soldUnicde)==0:
            print "item #%d did not sell" % i
        else:
            # 解析頁面獲取當(dāng)前價格
            soldPrice = currentRow[0].findAll('td')[4]
            priceStr = soldPrice.text
            priceStr = priceStr.replace('$','') #strips out $
            priceStr = priceStr.replace(',','') #strips out ,
            if len(soldPrice)>1:
                priceStr = priceStr.replace('Free shipping', '')
            sellingPrice = float(priceStr)

            # 去掉不完整的套裝價格
            if  sellingPrice > origPrc * 0.5:
                    print "%d\t%d\t%d\t%f\t%f" % (yr,numPce,newFlag,origPrc, sellingPrice)
                    retX.append([yr, numPce, newFlag, origPrc])
                    retY.append(sellingPrice)
        i += 1
        currentRow = soup.findAll('table', r="%d" % i)

# 依次讀取六種樂高套裝的數(shù)據(jù)捏雌,并生成數(shù)據(jù)矩陣        
def setDataCollect(retX, retY):
    scrapePage(retX, retY, 'input/8.Regression/setHtml/lego8288.html', 2006, 800, 49.99)
    scrapePage(retX, retY, 'input/8.Regression/setHtml/lego10030.html', 2002, 3096, 269.99)
    scrapePage(retX, retY, 'input/8.Regression/setHtml/lego10179.html', 2007, 5195, 499.99)
    scrapePage(retX, retY, 'input/8.Regression/setHtml/lego10181.html', 2007, 3428, 199.99)
    scrapePage(retX, retY, 'input/8.Regression/setHtml/lego10189.html', 2008, 5922, 299.99)
    scrapePage(retX, retY, 'input/8.Regression/setHtml/lego10196.html', 2009, 3263, 249.99)

測試算法:使用交叉驗證來測試不同的模型跃赚,分析哪個效果最好

# 交叉驗證測試嶺回歸
def crossValidation(xArr,yArr,numVal=10):
    # 獲得數(shù)據(jù)點個數(shù),xArr和yArr具有相同長度
    m = len(yArr)
    indexList = range(m)
    errorMat = zeros((numVal,30))

    # 主循環(huán) 交叉驗證循環(huán)
    for i in range(numVal):
        # 隨機(jī)拆分?jǐn)?shù)據(jù)性湿,將數(shù)據(jù)分為訓(xùn)練集(90%)和測試集(10%)
        trainX=[]; trainY=[]
        testX = []; testY = []

        # 對數(shù)據(jù)進(jìn)行混洗操作
        random.shuffle(indexList)

        # 切分訓(xùn)練集和測試集
        for j in range(m):
            if j < m*0.9: 
                trainX.append(xArr[indexList[j]])
                trainY.append(yArr[indexList[j]])
            else:
                testX.append(xArr[indexList[j]])
                testY.append(yArr[indexList[j]])

        # 獲得回歸系數(shù)矩陣
        wMat = ridgeTest(trainX,trainY)

        # 循環(huán)遍歷矩陣中的30組回歸系數(shù)
        for k in range(30):
            # 讀取訓(xùn)練集和數(shù)據(jù)集
            matTestX = mat(testX); matTrainX=mat(trainX)
            # 對數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化
            meanTrain = mean(matTrainX,0)
            varTrain = var(matTrainX,0)
            matTestX = (matTestX-meanTrain)/varTrain

            # 測試回歸效果并存儲
            yEst = matTestX * mat(wMat[k,:]).T + mean(trainY)

            # 計算誤差
            errorMat[i,k] = ((yEst.T.A-array(testY))**2).sum()

    # 計算誤差估計值的均值
    meanErrors = mean(errorMat,0)
    minMean = float(min(meanErrors))
    bestWeights = wMat[nonzero(meanErrors==minMean)]

    # 不要使用標(biāo)準(zhǔn)化的數(shù)據(jù)纬傲,需要對數(shù)據(jù)進(jìn)行還原來得到輸出結(jié)果
    xMat = mat(xArr); yMat=mat(yArr).T
    meanX = mean(xMat,0); varX = var(xMat,0)
    unReg = bestWeights/varX

    # 輸出構(gòu)建的模型
    print "the best model from Ridge Regression is:\n",unReg
    print "with constant term: ",-1*sum(multiply(meanX,unReg)) + mean(yMat)


# predict for lego's price
def regression5():
    lgX = []
    lgY = []

    setDataCollect(lgX, lgY)
    crossValidation(lgX, lgY, 10)

使用算法:這次練習(xí)的目標(biāo)就是生成數(shù)據(jù)模型

完整代碼地址: https://github.com/apachecn/MachineLearning/blob/master/src/python/8.PredictiveNumericalDataRegression/regression.py

6满败、附加 權(quán)衡偏差和方差

任何時候,一旦發(fā)現(xiàn)模型和測量值之間存在差異叹括,就說出現(xiàn)了誤差葫录。當(dāng)考慮模型中的 “噪聲” 或者說誤差時,必須考慮其來源领猾。你可能會對復(fù)雜的過程進(jìn)行簡化,這將導(dǎo)致在模型和測量值之間出現(xiàn) “噪聲” 或誤差骇扇,若無法理解數(shù)據(jù)的真實生成過程摔竿,也會導(dǎo)致差異的產(chǎn)生。另外少孝,測量過程本身也可能產(chǎn)生 “噪聲” 或者問題继低。下面我們舉一個例子,我們使用 線性回歸局部加權(quán)線性回歸 處理過一個從文件導(dǎo)入的二維數(shù)據(jù)稍走。

生成公式

其中的 N(0, 1) 是一個均值為 0袁翁、方差為 1 的正態(tài)分布。我們嘗試過禁用一條直線來擬合上述數(shù)據(jù)婿脸。不難想到粱胜,直線所能得到的最佳擬合應(yīng)該是 3.0+1.7x 這一部分。這樣的話狐树,誤差部分就是 0.1sin(30x)+0.06N(0, 1) 焙压。在上面,我們使用了局部加權(quán)線性回歸來試圖捕捉數(shù)據(jù)背后的結(jié)構(gòu)抑钟。該結(jié)構(gòu)擬合起來有一定的難度涯曲,因此我們測試了多組不同的局部權(quán)重來找到具有最小測試誤差的解。

下圖給出了訓(xùn)練誤差和測試誤差的曲線圖在塔,上面的曲面就是測試誤差幻件,下面的曲線是訓(xùn)練誤差。我們根據(jù) 預(yù)測鮑魚年齡 的實驗知道: 如果降低核的大小蛔溃,那么訓(xùn)練誤差將變小绰沥。從下圖開看,從左到右就表示了核逐漸減小的過程城榛。

偏差方差圖

一般認(rèn)為揪利,上述兩種誤差由三個部分組成: 偏差、測量誤差和隨機(jī)噪聲狠持。局部加權(quán)線性回歸 和 預(yù)測鮑魚年齡 中疟位,我們通過引入了三個越來越小的核來不斷增大模型的方差。

在縮減系數(shù)來“理解”數(shù)據(jù)這一節(jié)中喘垂,我們介紹了縮減法甜刻,可以將一些系數(shù)縮減成很小的值或直接縮減為 0 绍撞,這是一個增大模型偏差的例子。通過把一些特征的回歸系數(shù)縮減到 0 得院,同時也就減小了模型的復(fù)雜度傻铣。例子中有 8 個特征,消除其中兩個后不僅使模型更易理解祥绞,同時還降低了預(yù)測誤差非洲。對照上圖,左側(cè)是參數(shù)縮減過于嚴(yán)厲的結(jié)果蜕径,而右側(cè)是無縮減的效果两踏。

方差是可以度量的。如果從鮑魚數(shù)據(jù)中取一個隨機(jī)樣本集(例如取其中 100 個數(shù)據(jù))并用線性模型擬合兜喻,將會得到一組回歸系數(shù)梦染。同理,再取出另一組隨機(jī)樣本集并擬合朴皆,將會得到另一組回歸系數(shù)帕识。這些系數(shù)間的差異大小也就是模型方差的反映。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末遂铡,一起剝皮案震驚了整個濱河市肮疗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扒接,老刑警劉巖族吻,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異珠增,居然都是意外死亡超歌,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門蒂教,熙熙樓的掌柜王于貴愁眉苦臉地迎上來巍举,“玉大人,你說我怎么就攤上這事凝垛“妹酰” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵梦皮,是天一觀的道長炭分。 經(jīng)常有香客問我,道長剑肯,這世上最難降的妖魔是什么捧毛? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上呀忧,老公的妹妹穿的比我還像新娘师痕。我一直安慰自己,他們只是感情好而账,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布胰坟。 她就那樣靜靜地躺著,像睡著了一般泞辐。 火紅的嫁衣襯著肌膚如雪笔横。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天咐吼,我揣著相機(jī)與錄音狠裹,去河邊找鬼。 笑死汽烦,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的莉御。 我是一名探鬼主播撇吞,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼礁叔!你這毒婦竟也來了牍颈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤琅关,失蹤者是張志新(化名)和其女友劉穎煮岁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涣易,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡画机,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了新症。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片步氏。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖徒爹,靈堂內(nèi)的尸體忽然破棺而出荚醒,到底是詐尸還是另有隱情,我是刑警寧澤隆嗅,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布界阁,位于F島的核電站,受9級特大地震影響胖喳,放射性物質(zhì)發(fā)生泄漏泡躯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望精续。 院中可真熱鬧坝锰,春花似錦增拥、人聲如沸锭弊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽确垫。三九已至弓颈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間删掀,已是汗流浹背翔冀。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留披泪,地道東北人纤子。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像款票,于是被迫代替她去往敵國和親控硼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容