第8-1节层次聚类法|写给程序员的数据挖掘实践指南-学习笔记

文章原创,最近更新:2018-09-06

1.关于本书
2.关于作者
3.内容简介
4.案例

引言:网上找资料觉得这本书挺通俗易懂的,刚好可以跟《机器学习实战》相关章节结合一起学习。

本案例所涉及到的数据集dog.csv,可在官方网站直接下载.

暂时未写完,后续再补充.

学习参考链接:
1.面向程序员的数据挖掘指南

1.关于本书

写给程序员的数据挖掘实践指南:豆瓣评分:7.4分
作者: [美] Ron Zacharski
出版社: 人民邮电出版社
原作名: A Programmer's Guide to Data Mining
译者: 王斌
出版年: 2015-10-24

2.关于作者

Ron Zacharski是一名软件开发工程师,曾在威斯康辛大学获美术学士学位,之后还在明尼苏达大学获得了计算机科学博士学位。博士后期间,他在爱丁堡大学研究语言学。正是基于广博的学识,他不仅在新墨西哥州立大学的计算研究实验室工作,期间还接触过自然语言处理相关的项目,而该实验室曾被《连线》杂志评为机器翻译研究领域翘楚。除此之外,他还曾教授计算机科学、语言学、音乐等课程,是一名博学多才的科技达人。

3.内容简介

本书是写给程序员的一本数据挖掘指南,可以帮助读者动手实践数据挖掘、集体智慧并构建推荐系统。全书共8章,介绍了数据挖掘的基本知识和理论、协同过滤、内容过滤及分类、算法评估、朴素贝叶斯、非结构化文本分类以及聚类等内容。本书采用“在实践中学习”的方式,用生动的图示、大量的表格、简明的公式、实用的Python代码示例,阐释数据挖掘的知识和技能。每章还给出了习题和练习,帮助读者巩固所学的知识。

4.案例分析

4.1 getMedian()

这个函数主要是计算中位数,那么如何计算中位数呢?
确定中位数,必须将总体各单位的标志值按大小顺序排列,最好是编制出变量数列。这里有两种情况:
对于未分组的原始资料,首先必须将标志值按大小排序。设排序的结果为:


则中位数就可以按下面的方式确定:

比如案例中的数据
20.0, 16.0, 18.0, 27.0, 8.0, 25.0, 23.0, 32.0, 21.0, 19.0, 6.0
首先对数据进行大小排序后,结果如下:
6.0, 8.0, 16.0, 18.0, 19.0, 20.0, 21.0, 23.0, 25.0, 27.0, 32.0
数据共有11个,则中位数是第6个数字,即这个数字是20.0

用代码表示以上的过程,如下:

def getMedian(alist):
    """计算中位数"""
    tmp=alist[:]
    tmp.sort()
    alen = len(tmp)
    if (alen % 2) == 1:
        return tmp[alen // 2]
    else:
        return (tmp[alen // 2] + tmp[(alen // 2) - 1]) / 2

测试代码及其结果如下:

alist=[20.0, 16.0, 18.0, 27.0, 8.0, 25.0, 23.0, 32.0, 21.0, 19.0, 6.0]

getMedian(alist)
Out[7]: 20.0

4.2 normalizeColumn()

这个函数主要是计算修正的标准分,标准分的计算过程如下:

  • 对于未分组的原始资料,首先必须将标志值按大小排序,找出中位数.
  • 每个数据的标准差的计算如下:

\frac{每一数据-中位数}{\frac{\sum |每一数据-中位数|}{数据的个数}}
用本文所使用的案例进行分析,用狗的高度和重量来进行聚类:

数据标准化对比图

那么这个结果是怎么产生的呢?
首先我们查看一下数据
第1列的数据,即狗的高度:20.0, 16.0, 18.0, 27.0, 8.0, 25.0, 23.0, 32.0, 21.0, 19.0, 6.0
第2列的数据,即狗的重量:45.0, 20.0, 35.0, 120.0, 8.0, 78.0, 70.0, 160.0, 50.0, 65.0, 7.0
Border Collie狗的身高标准差为:
=\frac{每一数据-中位数}{\frac{\sum |每一数据-中位数|}{数据的个数}}

=\frac{20-20}{\frac{|20-20|+|16-20|+|18-20|+|27-20|+|8-20|+|25-20|+|23-20|+|32-20|+|21-20|+|19-20|+|6-20|}{11}}

=\frac{0}{\frac{61}{11}}

=0

用代码表示以上的过程,如下:

def normalizeColumn(column):
    """计算修正的标准分"""
    median = getMedian(column)
    asd = sum([abs(x - median) for x in column]) / len(column)
    result = [(x - median) / asd for x in column]
    return result

测试代码及其结果如下:

alist=[20.0, 16.0, 18.0, 27.0, 8.0, 25.0, 23.0, 32.0, 21.0, 19.0, 6.0]

getMedian(alist)
Out[10]: 20.0

normalizeColumn(alist)
Out[11]: 
[0.0,
 -0.721311475409836,
 -0.360655737704918,
 1.262295081967213,
 -2.163934426229508,
 0.901639344262295,
 0.540983606557377,
 2.163934426229508,
 0.180327868852459,
 -0.180327868852459,
 -2.524590163934426]

4.3 filedocument()

这个函数主要分为两部分

  • 从文件中读取数据
  • 标准化特征列
从文件中读取数据

数据文件是CSV格式的(以逗号分隔),第一行是列名,第一列是犬种,第二列之后是特征值:


我们用Python的列表结构来存储这些数据,data[0]用来存放所有记录的分类,如data[0][0]是Border Collie,data[0][1]是Boston Terrier。data[1]则是所有记录的高度,data[2]是重量。

特征列的数据都会转换成浮点类型,如data[1][0]是20.0,data[2][0]是45.0等。在读取数据时就需要对其进行标准化。此外,我们接下来会使用“下标”这个术语,如第一条记录Border Collie的下标是0,第二条记录Boston Terrier下标是1等。

需要使用代码将数据分割成这样:

[['Border Collie', 'Boston Terrier', 'Brittany Spaniel', 'Bullmastiff', 'Chihuahua', 'German Shepherd', 'Golden Retriever', 'Great Dane', 'Portuguese Water Dog', 'Standard Poodle', 'Yorkshire Terrier'], 
[20.0, 16.0, 18.0, 27.0, 8.0, 25.0, 23.0, 32.0, 21.0, 19.0, 6.0],
 [45.0, 20.0, 35.0, 120.0, 8.0, 78.0, 70.0, 160.0, 50.0, 65.0, 7.0]]

以下有四种方案可以达到以上要求的效果:
方案1

def filedocument(filename):
    data = []
    data1=[]
    data2=[]
    data3=[]
    data4=[]
    file= open(filename)
    lines = file.readlines()
    file.close()
    for line in lines[1:]:
        cells = line.strip().split(",")
        data.append(cells)
    for i in range(0,len(data)):
        data1.append(data[i][0])
        data2.append(float(data[i][1]))
        data3.append(float(data[i][2]))
    data4.append(data1)
    data4.append(data2)
    data4.append(data3)
    return data4

方案2

def filedocument(filename):
    data=[]
    data1=[]
    data2=[]
    data3=[]
    file= open(filename)
    lines=file.readlines()
    for line in lines[1:]:
        cells= line.strip().split(",")
        data1.append(cells[0])
        data2.append(float(cells[1]))
        data3.append(float(cells[2]))
    data.append(data1)
    data.append(data2)
    data.append(data3)
    return data

方案3

def filedocument(filename):
    file=open(filename)
    lines=file.readlines()
    header=lines[0].strip().split(",")
    data=[[] for i in range(len(header))]
    for line in lines[1:]:
        cells=line.strip().split(",")
        for cell in range(len(cells)):
            if cell ==0: 
                data[cell].append(cells[cell])
            else:
                data[cell].append(float(cells[cell]))
    return data

方案4

def filedocument(filename):
    filename = 'dog.csv'
    file=open(filename)
    lines=file.readlines()
    file.close()
    header=lines[0].strip().split(",")
    cols = len(header)
    data=[[] for i in range(len(header))]
    for line in lines[1:]:
       cells=line.strip().split(",")
       toggle=0
       for cell in range(cols):
           if toggle ==0: 
                data[cell].append(cells[cell])
                toggle=1
           else:
               data[cell].append(float(cells[cell]))
    return data

以上四种方案,测试代码及其结果都一样,具体如下:

filename = 'dog.csv'
print(filedocument(filename))

runfile('C:/Users/Administrator/Desktop/untitled1.py', wdir='C:/Users/Administrator/Desktop')
[['Border Collie', 'Boston Terrier', 'Brittany Spaniel', 'Bullmastiff', 'Chihuahua', 'German Shepherd', 'Golden Retriever', 'Great Dane', 'Portuguese Water Dog', 'Standard Poodle', 'Yorkshire Terrier'], 
[20.0, 16.0, 18.0, 27.0, 8.0, 25.0, 23.0, 32.0, 21.0, 19.0, 6.0], 
[45.0, 20.0, 35.0, 120.0, 8.0, 78.0, 70.0, 160.0, 50.0, 65.0, 7.0]]

本案例采用的是第4种方案.

标准化特征列

依据从文件中读取数据相关代码的基础上,标准化特征列

def filedocument(filename):
    #1.从文件中读取数据
    file=open(filename)
    lines=file.readlines()
    file.close()
    header=lines[0].strip().split(",")
    cols = len(header)
    data=[[] for i in range(len(header))]
    for line in lines[1:]:
       cells=line.strip().split(",")
       toggle=0
       for cell in range(cols):
           if toggle ==0: 
                data[cell].append(cells[cell])
                toggle=1
           else:
               data[cell].append(float(cells[cell]))
     #2.标准化特征列          
    for i in range(1,cols):
       data[i]=normalizeColumn(data[i])
       
    return data

测试代码及其结果如下:

filename = 'dog.csv'
print(filedocument(filename))

[['Border Collie', 'Boston Terrier', 'Brittany Spaniel', 'Bullmastiff', 'Chihuahua', 'German Shepherd', 'Golden Retriever', 'Great Dane', 'Portuguese Water Dog', 'Standard Poodle', 'Yorkshire Terrier'],
[0.0, -0.721311475409836, -0.360655737704918, 1.262295081967213, -2.163934426229508, 0.901639344262295, 0.540983606557377, 2.163934426229508, 0.180327868852459, -0.180327868852459, -2.524590163934426], 
[-0.1455026455026455, -0.8730158730158729, -0.43650793650793646, 2.0370370370370368, -1.222222222222222, 0.8148148148148148, 0.582010582010582, 3.201058201058201, 0.0, 0.43650793650793646, -1.2513227513227512]]

与我们之前计算的结果是一致的,具体如下:


4.4 distance()

这个函数主要计算每个犬种与其它犬种的距离.

还是以下截图的数据,作为案例:


以Border Collie为例,我们需要计算它和其它犬种的距离,保存在Python字典里:


{1: ((0, 1), 1.0244), # Border Collie(下标为0)和Boston Terrier(下标为1)之间的距离为1.0244
2: ((0, 2), 0.463), # Border Collie和Brittany Spaniel(下标为2)之间的距离为0.463
...
10: ((0, 10), 2.756)} # Border Collie和Yorkshire Terrier的距离为2.756


通过手工计算,发现Border Collie最近的分类及距离:这对犬种是(0, 8),即下标为0的Border Collie和下标为8的Portuguese WD,距离是0.232。

这个距离是怎么计算出来的呢?

注意:我们这里的距离指的是欧几里德距离,具体公式如下:
欧几里得空间中,点x =(x1,...,xn)和 y =(y1,...,yn)之间的欧氏距离为


由此可以计算出这对犬种是(0, 8),即下标为0的Border Collie和下标为8的Portuguese WD的距离是0.232的具体过程,如下:

  • Border Collie的下标为0,则高度与重量的坐标为(0,-0.1455)

  • Portuguese WD下标为8,,则高度与重量的坐标为(0.1803,0)

d(0,8):=\sqrt{(0-0.1803)^{2}+(-0.1455-0)^{2}}\approx 0.232

因此由此类推,可以得到每个犬种之间的距离,具体可以参见如下截图:
注意:图中高亮了一些最短距离

每种犬种与其它犬种之间的距离

那么如何通过代码对以上过程进行展示呢?具体如下:

def distance(filename,i,j):
    data=filedocument(filename)
    cols=len(data)
    sumSquares=0
    for k in range(1,cols):
        sumSquares +=pow((data[k][i]-data[k][j]),2)
    return math.sqrt(sumSquares)

测试代码及其结果如下:

filename = 'dog.csv'
a=distance(filename,1,2)
print(a)

0.5662258734585477

由此可以知道Boston Terrier和Brittany Spaniel这两种犬种之间的距离是约等于0.566,与我们手工计算的每种犬种与其它犬种之间的距离中的截图结果是一致的.

4.5 queue()

这个函数主要是初始化优先队列

什么又叫优先队列呢?
普通的队列有“先进先出”的规则,比如向队列先后添加Moa、Suzuka、Yui,取出时得到的也是Moa、Suzuka、Yui:



而对于优先队列,每个元素都可以附加一个优先级,从队列中取出时会得到优先级最高的元素。比如说,我们定义年龄越小优先级越高,以下是插入过程:



取出的第一个元素是Yui,因为她的年龄最小:

我们看看Python中如何使用优先队列:

这里需要特别说明,queue是python自带的一个库,不需要安装.

>>> from queue import PriorityQueue           # 加载优先队列类
>>> singersQueue = PriorityQueue()            # 创建对象
>>> singersQueue.put((16, 'Suzuka Nakamoto')) # 插入元素
>>> singersQueue.put((15, 'Moa Kikuchi'))
>>> singersQueue.put((14, 'Yui Mizuno'))
>>> singersQueue.put((17, 'Ayaka Sasaki'))
>>> singersQueue.get() # 获取第一个元素,即最年轻的歌手Yui。
(14, 'Yui Mizuno')
>>> singersQueue.get() # 获取第二个元素
(15, 'Moa Kikuchi')
>>> singersQueue.get() # 获取第三个元素
(16, 'Suzuka Nakamoto')
>>> singersQueue.get() # 获取第四个元素
(17, 'Ayaka Sasaki')

在介绍优先队列时,我用了歌手的年龄举例,如果他们的年龄相等,取出的顺序又是怎样的呢?



可以看到,如果年龄相等,优先队列会根据记录中的第二个元素进行判断,即歌手的姓名,并按字母顺序返回,如Avaka会比Moa优先返回。

在犬种示例中,我们让距离成为第一优先级,下标成为第二优先级。因此,我们插入到优先队列的一条完整记录是这样的:


优先队列记录

既然知道了距离,也知道了优先排队的方法,以及优先队列数据记录展现的形式,那么如何用代码来表示上述犬种的优先排队呢?

继续依据从文件中读取数据以及标准化特征列相关代码的基础上,对犬种进行优先排队.具体如下:

def queue(filename):
    data=filedocument(filename)
    queue = PriorityQueue()
    counter=0
    for i in  range(len(data[0])):
        minDistance=99999
        nearestNeighbor = 0
        neighbors={}
        for j in  range(len(data[0])):
            if i!=j:
                dist=distance(filename,i,j)
                if i <j:
                    Pair=(i,j)
                else:
                    Pair=(j,i)
                neighbors[j]=(Pair,dist)
                if dist < minDistance:
                    minDistance = dist
                    nearestNeighbor = j
                
        if i < nearestNeighbor:
            nearestPair = (i, nearestNeighbor)
        else:
            nearestPair = (nearestNeighbor, i)
            queue.put((minDistance, counter,
                                [[data[0][i]], nearestPair, neighbors]))
        print((minDistance, counter,
                           [[data[0][i]], nearestPair, neighbors]))

测试代码及其结果如下:

filename = 'dog.csv'
a=queue(filename)

(0.23170921460558744, 0, [['Border Collie'], (0, 8), {1: ((0, 1), 1.0244831578726061), 2: ((0, 2), 0.4634184292111748), 3: ((0, 3), 2.5212830741150487), 4: ((0, 4), 2.4170099809294157), 5: ((0, 5), 1.3172559097276118), 6: ((0, 6), 0.9066083822525246), 7: ((0, 7), 3.9852329543899034), 8: ((0, 8), 0.23170921460558744), 9: ((0, 9), 0.6093065384986165), 10: ((0, 10), 2.756155583828758)}])
(0.5662258734585477, 1, [['Boston Terrier'], (1, 2), {0: ((0, 1), 1.0244831578726061), 2: ((1, 2), 0.5662258734585477), 3: ((1, 3), 3.52180392892288), 4: ((1, 4), 1.4842863782160383), 5: ((1, 5), 2.34152552705655), 6: ((1, 6), 1.9262634448032971), 7: ((1, 7), 4.9922663664881854), 8: ((1, 8), 1.255033952393085), 9: ((1, 9), 1.416868332017332), 10: ((1, 10), 1.8425336150695488)}])
(0.4634184292111748, 2, [['Brittany Spaniel'], (0, 2), {0: ((0, 2), 0.4634184292111748), 1: ((1, 2), 0.5662258734585477), 3: ((2, 3), 2.958444540501654), 4: ((2, 4), 1.9670182935759584), 5: ((2, 5), 1.7774131489151734), 6: ((2, 6), 1.3602696349205545), 7: ((2, 7), 4.42780339457414), 8: ((2, 8), 0.6951276438167623), 9: ((2, 9), 0.8914453739980573), 10: ((2, 10), 2.3122576377780506)}])
(1.2743232406392442, 3, [['Bullmastiff'], (3, 5), {0: ((0, 3), 2.5212830741150487), 1: ((1, 3), 3.52180392892288), 2: ((2, 3), 2.958444540501654), 4: ((3, 4), 4.728828561272353), 5: ((3, 5), 1.2743232406392442), 6: ((3, 6), 1.6240049967240762), 7: ((3, 7), 1.4723786121140605), 8: ((3, 8), 2.306550008240866), 9: ((3, 9), 2.154728377283816), 10: ((3, 10), 5.015357411324655)}])
(0.3618278622956078, 4, [['Chihuahua'], (4, 10), {0: ((0, 4), 2.4170099809294157), 1: ((1, 4), 1.4842863782160383), 2: ((2, 4), 1.9670182935759584), 3: ((3, 4), 4.728828561272353), 5: ((4, 5), 3.6806605973096675), 6: ((4, 6), 3.2514362328001205), 7: ((4, 7), 6.1883647684231375), 8: ((4, 8), 2.64374599170132), 9: ((4, 9), 2.5857456785133), 10: ((4, 10), 0.3618278622956078)}])
(0.4292672500331769, 5, [['German Shepherd'], (5, 6), {0: ((0, 5), 1.3172559097276118), 1: ((1, 5), 2.34152552705655), 2: ((2, 5), 1.7774131489151734), 3: ((3, 5), 1.2743232406392442), 4: ((4, 5), 3.6806605973096675), 6: ((5, 6), 0.4292672500331769), 7: ((5, 7), 2.699545586269829), 8: ((5, 8), 1.0882157079364436), 9: ((5, 9), 1.1461976899425346), 10: ((5, 10), 4.000996511500954)}])
(0.4292672500331769, 6, [['Golden Retriever'], (5, 6), {0: ((0, 6), 0.9066083822525246), 1: ((1, 6), 1.9262634448032971), 2: ((2, 6), 1.3602696349205545), 3: ((3, 6), 1.6240049967240762), 4: ((4, 6), 3.2514362328001205), 5: ((5, 6), 0.4292672500331769), 7: ((6, 7), 3.081132875082385), 8: ((6, 8), 0.6846961944627522), 9: ((6, 9), 0.7358405156052383), 10: ((6, 10), 3.571953758580651)}])
(1.4723786121140605, 7, [['Great Dane'], (3, 7), {0: ((0, 7), 3.9852329543899034), 1: ((1, 7), 4.9922663664881854), 2: ((2, 7), 4.42780339457414), 3: ((3, 7), 1.4723786121140605), 4: ((4, 7), 6.1883647684231375), 5: ((5, 7), 2.699545586269829), 6: ((6, 7), 3.081132875082385), 8: ((7, 8), 3.7658290695451373), 9: ((7, 9), 3.6246798304633625), 10: ((7, 10), 6.46575277734129)}])
(0.23170921460558744, 8, [['Portuguese Water Dog'], (0, 8), {0: ((0, 8), 0.23170921460558744), 1: ((1, 8), 1.255033952393085), 2: ((2, 8), 0.6951276438167623), 3: ((3, 8), 2.306550008240866), 4: ((4, 8), 2.64374599170132), 5: ((5, 8), 1.0882157079364436), 6: ((6, 8), 0.6846961944627522), 7: ((7, 8), 3.7658290695451373), 9: ((8, 9), 0.5662258734585477), 10: ((8, 10), 2.9803339061376346)}])
(0.5662258734585477, 9, [['Standard Poodle'], (8, 9), {0: ((0, 9), 0.6093065384986165), 1: ((1, 9), 1.416868332017332), 2: ((2, 9), 0.8914453739980573), 3: ((3, 9), 2.154728377283816), 4: ((4, 9), 2.5857456785133), 5: ((5, 9), 1.1461976899425346), 6: ((6, 9), 0.7358405156052383), 7: ((7, 9), 3.6246798304633625), 8: ((8, 9), 0.5662258734585477), 10: ((9, 10), 2.888656805320768)}])
(0.3618278622956078, 10, [['Yorkshire Terrier'], (4, 10), {0: ((0, 10), 2.756155583828758), 1: ((1, 10), 1.8425336150695488), 2: ((2, 10), 2.3122576377780506), 3: ((3, 10), 5.015357411324655), 4: ((4, 10), 0.3618278622956078), 5: ((5, 10), 4.000996511500954), 6: ((6, 10), 3.571953758580651), 7: ((7, 10), 6.46575277734129), 8: ((8, 10), 2.9803339061376346), 9: ((9, 10), 2.888656805320768)}])

4.6 cluster()

这个函数的主要作用是最近距离聚类,直到剩余一个元素为止.

可参照如下截图的数据进行聚类.


什么叫聚类呢?
第一步:我们找到距离最近的两个元素,对他们进行聚类:


第二步:再找出距离最近的两个元素,进行聚类:


第三步:继续重复上面的步骤:


第四步:继续查找距离最近的元素,发现Border Collie已经属于一

这叫树状图,可以用来表示聚类。

你能在下图的基础上继续完成聚类吗?



哈哈,做对了没有.具体结果如下:



通过以上的小案例,是否已经找到了聚类的方法呢?对以上过程总结如下:

我们从优先队列中取出两个元素,对它们进行合并。如合并Border Collie和Portuguese WD后,会形成一个新的分类:

['Border Collie', 'Portuguese WD']

然后我们需要计算新的分类和其它分类之间的距离,方法是对取出的两个分类的距离字典进行合并。如第一个分类的距离字段是distanceDict1,第二个分类的是distanceDict2,新的距离字段是newDistanceDict:

初始化newDistanceDict
对于distanceDict1的每一个键值对:
    如果这个键在distanceDict2中存在:
        如果这个键在distanceDict1中的距离要比在distanceDict2中的距离小:
            将distanceDict1中的距离存入newDistanceDict
        否则:
            将distanceDict2中的距离存入newDistanceDict
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 31,914评论 2 89
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,856评论 25 707
  • Maven实战之Maven仓库 Maven仓库作用 仓库,顾名思义就是存放物品的地方。在Maven中,我们可以将其...
    颜洛滨阅读 732评论 3 6
  • 仲夏的午后,烈阳灼灼,蝉鸣如斯。炽热的温度让人心里莫名的有了些许焦躁。而此时凌云山庄里,一位华服公子悠闲地躺在...
    忆昔_15c3阅读 253评论 0 0
  • 不知道怎么继续下去,可还是要继续 想要好好毕业,好好工作,好好生活 人这一辈子,很短也很长 你要活的自己觉得值,要...
    斜山望白鸥阅读 116评论 0 0