第二十九章 Decision Tree算法(上)

這一篇文章中撤防,討論一種被廣泛使用的分類算法——決策樹(decision tree)耸序。決策樹的優(yōu)勢在于構造過程不需要任何領域知識或參數(shù)設置愚墓,因此在實際應用中决左,對于探測式的知識發(fā)現(xiàn)琅豆,決策樹更加適用朱浴。

決策樹案例

通俗來說七蜘,決策樹分類的思想類似于找對象∥执郑現(xiàn)想象一個女孩的母親要給這個女孩介紹男朋友柄粹,于是有了下面的對話:

女兒:多大年紀了喘鸟?

母親:26。

女兒:長的帥不帥驻右?

母親:挺帥的什黑。

女兒:收入高不?

母親:不算很高堪夭,中等情況愕把。

女兒:是公務員不拣凹?

母親:是,在稅務局上班呢恨豁。

女兒:那好嚣镜,我去見見。

這個女孩的決策過程就是典型的分類樹決策橘蜜。相當于通過年齡菊匿、長相、收入和是否公務員對將男人分為兩個類別:見和不見计福。假設這個女孩對男人的要求是:30歲以下跌捆、長相中等以上并且是高收入者或中等以上收入的公務員,那么這個可以用下圖表示女孩的決策邏輯象颖。

上圖完整表達了這個女孩決定是否見一個約會對象的策略佩厚,其中綠色節(jié)點表示判斷條件,橙色節(jié)點表示決策結果力麸,箭頭表示在一個判斷條件在不同情況下的決策路徑可款,圖中紅色箭頭表示了上面例子中女孩的決策過程。

這幅圖基本可以算是一顆決策樹克蚂,說它“基本可以算”是因為圖中的判定條件沒有量化,如收入高中低等等筋讨,還不能算是嚴格意義上的決策樹埃叭,如果將所有條件量化,則就變成真正的決策樹了悉罕。

有了上面直觀的認識赤屋,我們可以正式定義決策樹了:

決策樹(decision tree)是一個樹結構(可以是二叉樹或非二叉樹)。其每個非葉節(jié)點表示一個特征屬性上的測試壁袄,每個分支代表這個特征屬性在某個值域上的輸出类早,而每個葉節(jié)點存放一個類別。使用決策樹進行決策的過程就是從根節(jié)點開始嗜逻,測試待分類項中相應的特征屬性涩僻,并按照其值選擇輸出分支,直到到達葉子節(jié)點栈顷,將葉子節(jié)點存放的類別作為決策結果逆日。

可以看到,決策樹的決策過程非常直觀萄凤,容易被人理解室抽。目前決策樹已經成功運用于醫(yī)學、制造產業(yè)靡努、天文學坪圾、分支生物學以及商業(yè)等諸多領域晓折。知道了決策樹的定義以及其應用方法,下面介紹決策樹的構造算法兽泄。

決策樹的構造

不同于貝葉斯算法已维,決策樹的構造過程不依賴領域知識,它使用屬性選擇度量來選擇將元組最好地劃分成不同的類的屬性已日。所謂決策樹的構造就是進行屬性選擇度量確定各個特征屬性之間的拓撲結構垛耳。

構造決策樹的關鍵步驟是分裂屬性。所謂分裂屬性就是在某個節(jié)點處按照某一特征屬性的不同劃分構造不同的分支飘千,其目標是讓各個分裂子集盡可能地“純”堂鲜。盡可能“純”就是盡量讓一個分裂子集中待分類項屬于同一類別。分裂屬性分為三種不同的情況:

1护奈、屬性是離散值且不要求生成二叉決策樹缔莲。此時用屬性的每一個劃分作為一個分支。

2霉旗、屬性是離散值且要求生成二叉決策樹痴奏。此時使用屬性劃分的一個子集進行測試,按照“屬于此子集”和“不屬于此子集”分成兩個分支厌秒。

3读拆、屬性是連續(xù)值。此時確定一個值作為分裂點split_point鸵闪,按照>split_point和<=split_point生成兩個分支檐晕。

構造決策樹的關鍵性內容是進行屬性選擇度量,屬性選擇度量是一種選擇分裂準則蚌讼,是將給定的類標記的訓練集合的數(shù)據(jù)劃分D“最好”地分成個體類的啟發(fā)式方法辟灰,它決定了拓撲結構及分裂點split_point的選擇。

屬性選擇度量算法有很多篡石,一般使用自頂向下遞歸分治法芥喇,并采用不回溯的貪心策略。這里介紹ID3和c4.5兩種常用算法凰萨。

ID3算法

從信息論知識中我們直到继控,期望信息越小,信息增益越大沟蔑,從而純度越高湿诊。所以ID3算法的核心思想就是以信息增益度量屬性選擇,選擇分裂后信息增益最大的屬性進行分裂瘦材。下面先定義幾個要用到的概念厅须。

設D為用類別對訓練元組進行的劃分,則D的熵表示為:

其中pi表示第i個類別在整個訓練元組中出現(xiàn)的概率食棕,可以用屬于此類別元素的數(shù)量除以訓練元組元素總數(shù)量作為估計朗和。熵的實際意義表示是D中元組的類標號所需要的平均信息量错沽。

現(xiàn)在我們假設將訓練元組D按屬性A進行劃分,則A對D劃分的期望信息為:

而信息增益即為兩者的差值:

ID3算法就是在每次需要分裂時眶拉,計算每個屬性的增益率千埃,然后選擇增益率最大的屬性進行分裂。下面我們繼續(xù)用SNS社區(qū)中不真實賬號檢測的例子說明如何使用ID3算法構造決策樹忆植。為了簡單起見放可,我們假設訓練集合包含10個元素:

其中s、m和l分別表示小朝刊、中和大耀里。

設L、F拾氓、H和R表示日志密度冯挎、好友密度、是否使用真實頭像和賬號是否真實咙鞍,下面計算各屬性的信息增益房官。

因此日志密度的信息增益是0.276。

用同樣方法得到H和F的信息增益分別為0.033和0.553续滋。

因為F具有最大的信息增益翰守,所以第一次分裂選擇F為分裂屬性,分裂后的結果如下圖表示:

在上圖的基礎上吃粒,再遞歸使用這個方法計算子節(jié)點的分裂屬性潦俺,最終就可以得到整個決策樹。

上面為了簡便徐勃,將特征屬性離散化了,其實日志密度和好友密度都是連續(xù)的屬性早像。對于特征屬性為連續(xù)值僻肖,可以如此使用ID3算法:先將D中元素按照特征屬性排序,則每兩個相鄰元素的中間點可以看做潛在分裂點卢鹦,從第一個潛在分裂點開始臀脏,分裂D并計算兩個集合的期望信息,具有最小期望信息的點稱為這個屬性的最佳分裂點冀自,其信息期望作為此屬性的信息期望揉稚。

C4.5算法

ID3算法存在一個問題,就是偏向于多值屬性熬粗,例如搀玖,如果存在唯一標識屬性ID,則ID3會選擇它作為分裂屬性驻呐,這樣雖然使得劃分充分純凈灌诅,但這種劃分對分類幾乎毫無用處芳来。ID3的后繼算法C4.5使用增益率的信息增益擴充,試圖克服這個偏倚猜拾。

C4.5算法首先定義了“分裂信息”即舌,其定義可以表示成:

其中各符號意義與ID3算法相同,然后挎袜,增益率被定義為:

C4.5選擇具有最大增益率的屬性作為分裂屬性顽聂,其具體應用與ID3類似,不再贅述盯仪。

如果屬性用完了怎么辦

在決策樹構造過程中可能會出現(xiàn)這種情況:所有屬性都作為分裂屬性用光了紊搪,但有的子集還不是純凈集,即集合內的元素不屬于同一類別磨总。在這種情況下嗦明,由于沒有更多信息可以使用了,一般對這些子集進行“多數(shù)表決”蚪燕,即使用此子集中出現(xiàn)次數(shù)最多的類別作為此節(jié)點類別娶牌,然后將此節(jié)點作為葉子節(jié)點。

關于剪枝

在實際構造決策樹時馆纳,通常要進行剪枝诗良,這時為了處理由于數(shù)據(jù)中的噪聲和離群點導致的過分擬合問題。剪枝有兩種:

先剪枝——在構造過程中鲁驶,當某個節(jié)點滿足剪枝條件鉴裹,則直接停止此分支的構造。

后剪枝——先構造完成完整的決策樹径荔,再通過某些條件遍歷樹進行剪枝脆霎。

流程圖形式的決策樹

上圖流程圖就是一個假想的郵件分類系統(tǒng)決策樹,正方形代表判斷模塊睛蛛,橢圓形代表終止模塊鹦马,表示已經得出結論忆肾,可以終止運行。判斷模塊引出的左右箭頭稱為分支客冈,它可以到達另一個判斷模塊或者終止模塊旭从。決策樹的主要優(yōu)勢在于數(shù)據(jù)形式非常容易理解。

優(yōu)點

計算復雜度不高遇绞,對中間值的缺失不敏感,可以處理不相干特征數(shù)據(jù)摹闽,輸出結果易于理解。

缺點

可能會產生過度匹配問題澜汤。

適用數(shù)據(jù)類型

數(shù)值型跟標稱型

ID3算法python2實現(xiàn)

from math import log

import operator

#def createDataSet():自己創(chuàng)建的數(shù)據(jù)舵匾,可作實驗用

#dataSet = [[1, 1, 'yes'],

# [1, 1, 'yes'],

# [1, 0, 'no'],

# [0, 1, 'no'],

# [0, 1, 'no']]

# labels = ['no surfacing','flippers']

#print dataSet

#change to discrete values

#return dataSet, labels

def loadDataSet(fileName): #general function to parse tab -delimited floats

dataMat = [] #assume last column is target value

fr = open(fileName)

for line in fr.readlines():

curLine = line.strip().split(',')

fltLine = list(curLine) #map all elements to float()

dataMat.append(fltLine)

return dataMat

#def createDataSet():

#dataSet = [[1, 1, 'yes'],

#[1, 1, 'yes'],

#[1, 0, 'no'],

#[0, 1, 'no'],

#[0, 1, 'no']]

#labels = ['no surfacing','flippers']

#print dataSet

#change to discrete values

#return dataSet, labels

def calcShannonEnt(dataSet):#計算給定數(shù)據(jù)集的香農熵

numEntries = len(dataSet)#計算數(shù)據(jù)集中實例的總數(shù)

#print numEntries

labelCounts = {}#創(chuàng)建一個數(shù)據(jù)字典

for featVec in dataSet: #the the number of unique elements and their occurance

currentLabel = featVec[-1]#鍵值是最后一列數(shù)值

#print currentLabel

if currentLabel not in labelCounts.keys(): labelCounts[currentLabel] = 0#如果鍵值不存在坐梯,則擴展字典并將當前鍵值加入字典

labelCounts[currentLabel] += 1#當前鍵值加入字典

#print labelCounts

shannonEnt = 0.0

for key in labelCounts:

prob = float(labelCounts[key])/numEntries# 使用所有類標簽的發(fā)生概率計算類別出現(xiàn)的概率

#print prob

shannonEnt -= prob * log(prob,2) #log base 2 用這個概率計算香農熵

#print shannonEnt

return shannonEnt

def splitDataSet(dataSet, axis, value):#劃分數(shù)據(jù)集,dataSet為待劃分的數(shù)據(jù)集谎替,axis為劃分數(shù)據(jù)集的特征蹋辅,value為特征的返回值

retDataSet = []#創(chuàng)建新的list對象

for featVec in dataSet:

#print featVec

if featVec[axis] == value:#將符合特征的數(shù)據(jù)抽取出來

reducedFeatVec = featVec[:axis] #chop out axis used for splitting

#print reducedFeatVec

reducedFeatVec.extend(featVec[axis+1:])#extend()函數(shù)只接受一個列表作為參數(shù)侦另,并將該參數(shù)的每個元素都添加到原有的列表中

#print reducedFeatVec

retDataSet.append(reducedFeatVec)#append()向列表的尾部添加一個元素,任意弃锐,可以是tuple

return retDataSet

def chooseBestFeatureToSplit(dataSet):#遍歷整個數(shù)據(jù)集殿托,循環(huán)計算香農熵和splitDataSet()函數(shù),找到最好的劃分方式

numFeatures = len(dataSet[0]) - 1 #the last column is used for the labels判斷當前數(shù)據(jù)集包含多少特征屬性

baseEntropy = calcShannonEnt(dataSet)#計算整個數(shù)據(jù)集的原始香農熵,保存最初的無序度量值唾戚,用于與劃分完之后的數(shù)據(jù)集計算的熵值進行比較

bestInfoGain = 0.0; bestFeature = -1

for i in range(numFeatures): #iterate over all the features 遍歷數(shù)據(jù)集中的所有特征

featList = [example[i] for example in dataSet]#create a list of all the examples of this feature使用列表推導創(chuàng)建新的列表

uniqueVals = set(featList) #get a set of unique values將數(shù)據(jù)集中所有可能存在的值寫入featlist中待诅,并從列表中創(chuàng)建集合

newEntropy = 0.0

for value in uniqueVals:#遍歷當前特征值中的所有唯一屬性值,

subDataSet = splitDataSet(dataSet, i, value)#對每個特征劃分一次數(shù)據(jù)集

prob = len(subDataSet)/float(len(dataSet))

newEntropy += prob * calcShannonEnt(subDataSet) #計算數(shù)據(jù)集的新熵值募书,并對所有唯一特征值得到的熵求和

infoGain = baseEntropy - newEntropy #calculate the info gain; ie reduction in entropy#信息增益

if (infoGain > bestInfoGain): #compare this to the best gain so far#比較所有特征中的信息增益

bestInfoGain = infoGain #if better than current best, set to best

bestFeature = i#返回最好特征劃分的索引值

return bestFeature #returns an integer

def majorityCnt(classList):

classCount={}#創(chuàng)建鍵值為classList中唯一值的數(shù)據(jù)字典莹捡,字典對象存儲了classList中每個類標簽現(xiàn)的頻率

for vote in classList:

if vote not in classCount.keys(): classCount[vote] = 0

classCount[vote] += 1

sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)#利用operator操作鍵值排序字典

return sortedClassCount[0][0]#返回出現(xiàn)次數(shù)最多的分類名稱

def createTree(dataSet,labels):#創(chuàng)建樹的函數(shù)代碼

classList = [example[-1] for example in dataSet]#創(chuàng)建了名為classList的列表變量,包含所有類標簽

if classList.count(classList[0]) == len(classList): #

return classList[0]#stop splitting when all of the classes are equal

if len(dataSet[0]) == 1: #stop splitting when there are no more features in dataSet

return majorityCnt(classList)

bestFeat = chooseBestFeatureToSplit(dataSet)

bestFeatLabel = labels[bestFeat]

myTree = {bestFeatLabel:{}}#存儲了樹的所有信息

del(labels[bestFeat])#當前數(shù)據(jù)集選取的最好特征存儲在變量bestFeat中齿椅,

featValues = [example[bestFeat] for example in dataSet]#得到列表包含的所有屬性值

uniqueVals = set(featValues)

for value in uniqueVals:#遍歷當前選擇特征包含的所有屬性值

subLabels = labels[:] #copy all of labels, so trees don't mess up existing labels為了保證每次調用函數(shù)createtree()時不改變原始列表的內容启泣,使用新變量subLabels代替原始列表

myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)#遞歸調用函數(shù)cteatetree()得到的返回值插入到字典變量mytree中

return myTree

def classify(inputTree,featLabels,testVec):#遞歸函數(shù)寥茫,

firstStr = inputTree.keys()[0]

secondDict = inputTree[firstStr]

featIndex = featLabels.index(firstStr)#使用index查找當前列表中第一個匹配firstStr變量的元素

key = testVec[featIndex]

valueOfFeat = secondDict[key]

if isinstance(valueOfFeat, dict): #如果到達葉子節(jié)點

classLabel = classify(valueOfFeat, featLabels, testVec)#返回當前節(jié)點的分類標簽

else: classLabel = valueOfFeat

return classLabel

def storeTree(inputTree,filename):#決策樹分類器的存儲

import pickle#pickle序列化對象可以在磁盤上保存對象,并在需要時讀出來

fw = open(filename,'w')

pickle.dump(inputTree,fw)

fw.close()

def grabTree(filename):

import pickle

fr = open(filename)

return pickle.load(fr)

import matplotlib.pyplot as plt

decisionNode = dict(boxstyle="sawtooth", fc="0.8")

leafNode = dict(boxstyle="round4", fc="0.8")

arrow_args = dict(arrowstyle="<-")

def getNumLeafs(myTree):#遍歷整顆樹芭梯,累計葉子節(jié)點的個數(shù)膝迎,并返回數(shù)值

numLeafs = 0

firstStr = myTree.keys()[0]#第一個關鍵字是以第一次劃分數(shù)據(jù)集的類別標簽

secondDict = myTree[firstStr]#表示子節(jié)點的數(shù)值

for key in secondDict.keys():#遍歷整顆樹的所有子節(jié)點

if type(secondDict[key]).__name__=='dict':#test to see if the nodes are dictonaires, if not they are leaf nodes type()函數(shù)判斷子節(jié)點是否為字典類型限次,如果子節(jié)點是字典類型

numLeafs += getNumLeafs(secondDict[key])#則該節(jié)點是一個判斷節(jié)點,遞歸調用getNumLeafs()函數(shù)

else: numLeafs +=1

return numLeafs

def getTreeDepth(myTree):#遍歷過程中遇到判斷節(jié)點的個數(shù)

maxDepth = 0

firstStr = myTree.keys()[0]

secondDict = myTree[firstStr]

for key in secondDict.keys():

if type(secondDict[key]).__name__=='dict':#test to see if the nodes are dictonaires, if not they are leaf nodes

thisDepth = 1 + getTreeDepth(secondDict[key])

else: thisDepth = 1

if thisDepth > maxDepth: maxDepth = thisDepth

return maxDepth

def plotNode(nodeTxt, centerPt, parentPt, nodeType):#執(zhí)行實際的繪圖功能

createPlot.ax1.annotate(nodeTxt, xy=parentPt, xycoords='axes fraction',

xytext=centerPt, textcoords='axes fraction',

va="center", ha="center", bbox=nodeType, arrowprops=arrow_args )#全局繪圖區(qū)

def plotMidText(cntrPt, parentPt, txtString):#計算子節(jié)點與父節(jié)點的中間位置费尽,在父節(jié)點間填充文本信息

xMid = (parentPt[0]-cntrPt[0])/2.0 + cntrPt[0]

yMid = (parentPt[1]-cntrPt[1])/2.0 + cntrPt[1]

createPlot.ax1.text(xMid, yMid, txtString, va="center", ha="center", rotation=30)

def plotTree(myTree, parentPt, nodeTxt):#if the first key tells you what feat was split on計算寬與高

numLeafs = getNumLeafs(myTree) #this determines the x width of this tree計算樹的寬

depth = getTreeDepth(myTree)#計算樹的高

firstStr = myTree.keys()[0] #the text label for this node should be this

cntrPt = (plotTree.xOff + (1.0 + float(numLeafs))/2.0/plotTree.totalW, plotTree.yOff)

plotMidText(cntrPt, parentPt, nodeTxt)#標記子節(jié)點屬性值

plotNode(firstStr, cntrPt, parentPt, decisionNode)

secondDict = myTree[firstStr]

plotTree.yOff = plotTree.yOff - 1.0/plotTree.totalD

for key in secondDict.keys():

if type(secondDict[key]).__name__=='dict':#test to see if the nodes are dictonaires, if not they are leaf nodes

plotTree(secondDict[key],cntrPt,str(key)) #recursion

else: #it's a leaf node print the leaf node

plotTree.xOff = plotTree.xOff + 1.0/plotTree.totalW

plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)

plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))

plotTree.yOff = plotTree.yOff + 1.0/plotTree.totalD

#if you do get a dictonary you know it's a tree, and the first element will be another dict

def createPlot(inTree):#第一個版本的函數(shù)

fig = plt.figure(1, facecolor='white')

fig.clf()

axprops = dict(xticks=[], yticks=[])

createPlot.ax1 = plt.subplot(111, frameon=False, **axprops) #no ticks

createPlot.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropses

plotTree.totalW = float(getNumLeafs(inTree))#全局變量plotTree.totalW存儲樹的寬度

plotTree.totalD = float(getTreeDepth(inTree))#全局變量plotTree.totalD存儲樹的深度

plotTree.xOff = -0.5/plotTree.totalW; plotTree.yOff = 1.0;#使用plotTree.totalW,plotTree.totalD計算樹節(jié)點的擺放位置柏卤,這樣可以將樹繪制在水平方向和垂直方向的中心位置

plotTree(inTree, (0.5,1.0), '')

plt.show()

#def createPlot():

#fig = plt.figure(1, facecolor='white')

#fig.clf()

#createPlot.ax1 = plt.subplot(111, frameon=False) #ticks for demo puropses

#plotNode('a decision node', (0.5, 0.1), (0.1, 0.5), decisionNode)

#plotNode('a leaf node', (0.8, 0.1), (0.3, 0.8), leafNode)

#plt.show()

def retrieveTree(i):#輸出預先存儲的樹信息匀油,避免每次測試都要從數(shù)據(jù)集中創(chuàng)建樹的麻煩,該函數(shù)主要用于測試,返回預定義的樹結構

listOfTrees =[{'no surfacing': {0: 'no', 1: {'flippers': {0: 'no', 1: 'yes'}}}},

{'no surfacing': {0: 'no', 1: {'flippers': {0: {'head': {0: 'no', 1: 'yes'}}, 1: 'no'}}}}

]

return listOfTrees[i]

if __name__ == "__main__":

myMat=loadDataSet('C:\Users\HZF\Desktop\credit.txt')

labels=['A1','A2','A3','A4','A5','A6','A7','A8','A9','A10','A11','A12','A13','A14','A15']

myTree=createTree(myMat,labels)

print myTree

#numLeafs=getNumLeafs(myTree)

maxDepth=getTreeDepth(myTree)

print maxDepth

createPlot(myTree)

#classLabel=classify(myTree,labels,[1,1])

#labels=['age','prescript','astigmatic','tearRate']

#storeTree(myTree,'C:/Users/HZF/Desktop/machinelearninginaction/Ch03/classifierStorage.txt')

#pickle.load(fr)=grabTree('C:/Users/HZF/Desktop/machinelearninginaction/Ch03/classifierStorage.txt')

#print pickle.load(fr)

#print numLeafs

#print maxDepth

#print classLabel

#myMat,labels=createDataSet()

#myMat[0][-1]='maybe'

#print myMat

#shannonEnt=calcShannonEnt(myMat)

#print shannonEnt

#retDataSet=splitDataSet(myMat, 0, 0)

#print retDataSet

#bestFeature=chooseBestFeatureToSplit(myMat)

#print bestFeature

#myTree=createTree(myMat,labels)

#classify(inputTree,featLabels,testVec)

#print myTree

上篇就寫這么多了,中下篇會盡快更新哦!

參考文獻

1蒲每、《機器學習實戰(zhàn)》(書)

2喻括、算法雜貨鋪——分類算法之決策樹(博客)

3双妨、其他網(wǎng)站資料(略)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市泣特,隨后出現(xiàn)的幾起案子挑随,更是在濱河造成了極大的恐慌,老刑警劉巖膏孟,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柒桑,死亡現(xiàn)場離奇詭異噪舀,居然都是意外死亡,警方通過查閱死者的電腦和手機界逛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門纺座,熙熙樓的掌柜王于貴愁眉苦臉地迎上來净响,“玉大人,你說我怎么就攤上這事馋贤〉УВ” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵堤撵,是天一觀的道長羽莺。 經常有香客問我,道長荒给,這世上最難降的妖魔是什么刁卜? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任蛔趴,我火速辦了婚禮,結果婚禮上鱼蝉,老公的妹妹穿的比我還像新娘箫荡。我一直安慰自己,他們只是感情好洁奈,可當我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布睬魂。 她就那樣靜靜地躺著镀赌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪喉钢。 梳的紋絲不亂的頭發(fā)上良姆,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天玛追,我揣著相機與錄音闲延,去河邊找鬼韩玩。 笑死,一個胖子當著我的面吹牛合愈,可吹牛的內容都是我干的击狮。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼寸莫,長吁一口氣:“原來是場噩夢啊……” “哼寞焙!你這毒婦竟也來了?” 一聲冷哼從身側響起捣郊,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤呛牲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后着茸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琐旁,經...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡灰殴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年牺陶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掰伸。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡狮鸭,死狀恐怖多搀,靈堂內的尸體忽然破棺而出酗昼,到底是詐尸還是另有隱情梳猪,我是刑警寧澤蒸痹,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布叠荠,位于F島的核電站,受9級特大地震影響榛鼎,放射性物質發(fā)生泄漏者娱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一推姻、第九天 我趴在偏房一處隱蔽的房頂上張望框沟。 院中可真熱鬧,春花似錦拧晕、人聲如沸梅垄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奈嘿。三九已至吞加,卻和暖如春尽狠,著一層夾襖步出監(jiān)牢的瞬間叶圃,已是汗流浹背掺冠。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留斥黑,地道東北人眉厨。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓憾股,卻偏偏與公主長得像,于是被迫代替她去往敵國和親茴恰。 傳聞我的和親對象是個殘疾皇子有咨,可洞房花燭夜當晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內容