泰坦尼克号乘客存活分析

摘要

      1912年4月15日,在首次航行期间,泰坦尼克号撞上冰山后沉没,2224名乘客和机组人员中有1502人遇难。这场轰动的悲剧震惊国际社会,在这次海难中导致死亡率高的原因之一是没有足够的救生艇给乘客和机组人员,幸存者非常的少。

       此次分析主要是采用python语言,数据是在kaggle网站上进行下载,kaggle网站是著名的数据分析竞赛网站,它举行了很多数据分析比赛。网站给出两个文件,一个用于训练,一个用于测试提交,由于进行测试的文件没有标记,所以采用第一个文件进行下面的分析,让数据更具说服力以及准确性。本次论文分析主要先对下载的数据进行分析,对数据进行预处理,如对缺失值的处理和对数据进行清洗等,然后进行机器学习得出结论。

关键词:python;数据分析;机器学习;

1.引言

       数据分析是指用适当的统计分析方法对收集来的大量数据进行分析,将它们加以汇总和理解并消化,以求最大化地开发数据的功能,发挥数据的作用。数据分析是为了提取有用信息和形成结论而对数据加以详细研究和概括总结的过程。而机器学习是专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能,它是人工智能的核心,是使计算机具有智能的根本途径。

       数据分析与机器学习的组合在如今大数据时代非常的热门,比如苹果公司研发的siri和谷歌人工智能围棋程序AlphaGo,而大数据+机器学习正是AlphoGo取胜的关键。本次课程设计,就是通过对泰坦尼克号的现有数据进行数据的处理和分析,再通过机器学习来进行结论的验证。论文分为数据分析、数据处理、特征工程、机器学习、总结和展望这么几个部分。

2.数据分析

2.1数据初探

         首先是对数据进行导入和定义分析,数据来自于著名的数据分析竞赛网站Kaggle:

import pandas as pd

data = pd.read_csv("data/titan_train.csv")

数据特征定义具体如下:

      - PassengerId:乘客编号  

      - Survived: 是否存活(1-存活,0-未存活)  

      - PClass:船舱等级(1,2,3等舱位)  

      - Name: 乘客姓名(包括Mr,Mrs,Miss,Master等)  

      - Sex:性别  

      - Age: 年龄  

      - SibSp:  同船的堂兄弟或姐妹个数  

      - Parch:  直系亲属(父母或者孩子)数量  

       - Ticket: 船票编号信息  

       - Fare: 票价

      - Cabin: 船舱编号  

      - Embarked: 登船港口(S,C,Q)

data.info()

图2.1 数据查询

以上结果表明:

     A.  一共891位乘客;

    B.  一共12个特征(12个数据列);

    C.  年龄,船舱编号,登船港口有缺失值,登船港口的缺失值较大;

    D.  数据有数值类型,也有字符串类型。

data.describe()

图2.2 数据描述

data.loc[data["Age"]==0.42,:]

data.loc[data["Age"]==80, :]

图2.3 年龄最小旅客数据定位
图2.4 年龄最大旅客数据定位

从上述结果可看出:

    A.   年龄有缺失值,还有一些非数值类的无法描述;

    B.乘客编号的统计值没有意义;

    C. 有38.4%的乘客获救;

    D.平均年龄29.7,最小的乘客0.42岁,最大的乘客80岁,他们两个都获救了,可见年龄是一个重要的特征;

    E. 2,3等船舱乘客居多,50%以上的乘客是3等舱;

    F. 票价均值为32,但最贵的票竟高达512。

2.2 数据初分析

       每个乘客有12个特征,哪些特征是对分析和预测更有用,首先画图来看看乘客的各个特征与存活结果之间的关系:

%matplotlib inline

import matplotlib.pyplot as plt

plt.rcParams["font.sans-serif"] = ["SimHei"]

plt.rcParams["axes.unicode_minus"] = False

fig = plt.figure(figsize=(12,8))

fig.set(alpha=0.2) 

# 设置子图模式(2行3列的网格模式),第一幅图获救情况的柱状图

plt.subplot2grid((2,3),(0,0))

data["Survived"].value_counts().plot(kind="bar")

plt.title("获救情况(1为获救)")

plt.ylabel("人数") 

#绘制船舱等级分布柱状图

plt.subplot2grid((2,3),(0,1))

data["Pclass"].value_counts().plot(kind="bar")

plt.title("乘客船舱等级分布")

plt.ylabel("人数") 

#绘制获救和年龄之间的关系的散点图

plt.subplot2grid((2,3),(0,2))

plt.scatter(data["Survived"],data["Age"])

plt.title("获救乘客的年龄分布(1为获救)")

plt.ylabel("人数")plt.grid(b=True,which="major",axis="y") 

# 绘制各船舱等级乘客的年龄分布

plt.subplot2grid((2,3),(1,0),colspan=2)

data.loc[data["Pclass"]==1,"Age"].plot(kind="kde")

data.loc[data["Pclass"]==2,"Age"].plot(kind="kde")

data.loc[data["Pclass"]==3,"Age"].plot(kind="kde")

plt.title("各船舱等级的年龄分布曲线")

plt.xlabel("年龄")

plt.ylabel("密度")

plt.legend(["头等舱","2等舱","3等舱"], loc="best") 

#绘制各港口登船人数的分布

plt.subplot2grid((2,3),(1,2))

data["Embarked"].value_counts().plot(kind="bar")

plt.title("各港口登船人数的分布")

图2.5 特征与存活结果之间的关系数据可视化

以上图形分析结果表明:

     A.  大多数乘客未获救;

     B.  3等舱乘客超过一半,2等舱最少;

     C.  60岁以上获救概率较低;

     D.  2,3等舱主要是20-30岁的乘客,头等舱主要是40岁以上;

     E.  S港口登船人数最多,S:英国南安普敦,C:法国瑟堡-奥克特维尔,Q:爱尔兰-昆士敦(Queenstown) ,绝大多数人从始港口出发。

#计算各等级获救和遇难的人数

s_0 = data.loc[data["Survived"]==0,"Pclass"].value_counts()

s_1 = data.loc[data["Survived"]==1,"Pclass"].value_counts()

# 绘制层叠柱状图

df = pd.DataFrame({"获救":s_1,"未获救":s_0})

df.plot(kind="bar",stacked=True)

plt.title("各船舱等级的获救情况")

plt.ylabel("人数")

图2.6 各等级获救和遇难人数数据可视化

从柱状图中可以清晰的看出:头等舱获救比例非常高,3等舱获救比例非常低。

#计算男女性别获救和遇难的人数

s_0 = data.loc[data["Survived"]==0,"Sex"].value_counts()

s_1 = data.loc[data["Survived"]==1,"Sex"].value_counts()

# 绘制层叠柱状图

df = pd.DataFrame({"获救":s_1,"未获救":s_0})

df.plot(kind="bar",stacked=True)

plt.title("乘客性别与获救的关系")

plt.ylabel("人数")

图2.7 性别获救和遇难人数数据可视化

显然,女性获救比例远远高于男性。

plt.title("根据舱位等级和性别分析获救情况")

plt.xticks([])

plt.yticks([]) 

# 女性1,2等舱

ax1 = fig.add_subplot(221)

data.Survived[data.Sex=="female"][data.Pclass!=3].value_counts().plot(kind="bar",color="red")

ax1.set_xticklabels(["获救","未获救"],rotation=0)

ax1.legend(["女性/高级舱"],loc="best") 

# 女性3等舱

ax2 = fig.add_subplot(222)

data.Survived[data.Sex=="female"][data.Pclass==3].value_counts().plot(kind="bar",color="yellow")

ax2.set_xticklabels(["获救","未获救"],rotation=0)

ax2.legend(["女性/低级舱"],loc="best") 

# 男性1,2等舱

ax3 = fig.add_subplot(223)

data.Survived[data.Sex=="male"][data.Pclass!=3].value_counts().plot(kind="bar",color="green")

ax3.set_xticklabels(["未获救","获救"],rotation=0)

ax3.legend(["男性/高级舱"],loc="best") 

# 男性3等舱

ax4 = fig.add_subplot(224)

data.Survived[data.Sex=="male"][data.Pclass==3].value_counts().plot(kind="bar",color="blue")

ax4.set_xticklabels(["未获救","获救"],rotation=0)

ax4.legend(["男性/低级舱"],loc="best")

图2.8 船舱等级和性别获救和遇难人数数据可视化1
图2.9 船舱等级和性别获救和遇难人数数据可视化2

上图可以得出以下结论:

     A. 高级舱(1,2等舱的女性几乎全部获救);

     B. 低级舱女性获救一半左右;

     C. 男性高级舱获救比例30%不到;  

     D. 男性低级舱获救比例不到20%;  

     E. 可见性别也是评判是否能获救的重要指标。

#计算各港口等船的乘客获救和遇难的人数

s_0 = data.Embarked[data.Survived==0].value_counts()

s_1 = data.Embarked[data.Survived==1].value_counts()

# 绘制层叠柱状图

df = pd.DataFrame({"获救":s_1,"未获救":s_0})

df.plot(kind="bar",stacked=True)

plt.title("乘客登船港口与获救的关系")plt.ylabel("人数")

图2.10 各港口登船旅客获救和遇难人数数据可视化

       登录港口似乎和获救没有直接的关系,但C港(法国瑟堡-奥克特维尔,是泰坦尼克号的始发港口)登录的乘客获救概率较高一些。

#堂兄弟姐妹的数量对获救有没有影响?

g = data.groupby(["SibSp","Survived"])

df = pd.DataFrame(g.count()["PassengerId"])

df

图2.11 兄弟数量获救和遇难人数数据可视化1

#父母孩子的数量对获救的影响

g = data.groupby(["Parch","Survived"])

df = pd.DataFrame(g.count()["PassengerId"])

df

图2.12 兄弟数量获救和遇难人数数据可视化2

父母孩子数量超过3个,以及兄弟姐妹超过4个的几乎全部遇难。

#计算有无船舱编号获救和遇难的人数

s_c = data.Survived[pd.notnull(data.Cabin)].value_counts()

s_nc = data.Survived[pd.isnull(data.Cabin)].value_counts()

#绘制层叠柱状图

df = pd.DataFrame({"有编号":s_c,"无编号":s_nc}).transpose()

df.plot(kind="bar",stacked=True)

plt.title("有无船舱编号与获救的关系")

plt.ylabel("人数")

图2.13 无船舱编号获救和遇难人数数据可视化

船舱编号缺失值太多,但还是可以看出有编号的乘客获救率更高。

data.pivot_table(values='Survived',index=['Pclass','Sex'],aggfunc=np.mean)

plt.figure(figsize=(10,5))

sns.pointplot(data=data,x='Pclass',y='Survived',hue='Sex',ci=None)

plt.show()

图2.14 船舱等级和性别获救和遇难人数数据可视化

从上折线图可看出:

    A.  在各个船舱中,女性的存活率明显都大于男性;

    B. 一二等船舱中女性存活率接近,且远大于三等舱;

    C. 一等舱的男性存活率远大于二三等舱,二三等舱男性存活率接近。

data['AgeGroup'] = pd.cut(data['Age'],5)

data.AgeGroup.value_counts(sort=False)

data.pivot_table(values='Survived',index='AgeGroup',columns='Sex',aggfunc=np.mean)

plt.figure(figsize= (10 ,5))

sns.pointplot(data=data,x="AgeGroup",y="Survived",hue="Sex",ci=None,

             markers=["^", "o"], linestyles=["-", "--"])

plt.xticks(rotation=60)

plt.show()

图2.15 各年龄段和性别获救和遇难人数数据可视化

       从上折线图可看出青少年及女性的生还率更高(想起电影里,船长说的:让小孩跟妇女先走),男性生还的基本上都是青少年。

3.数据处理

       根据以上对数据及特征进行分析后,现在需要对数据进行预处理,对有缺失值的特征进行处理,通过对数据进行统计可看出,其中有缺失值的特征有年龄、船舱编号和登船港口。

       首先是对年龄缺失值的处理,因为年龄跨度较大,大到80岁,小到四个月,因此在这对年龄的缺失值进行采用取年龄平均值的方式进行填充处理;

#求年龄的均值

import numpy as np

aver_age = round(np.mean(data.Age),1)

aver_age

#填充年龄缺失值

data.loc[pd.isnull(data.Age),"Age"] = aver_age

       接着是对于船舱编号的处理,因为从上面的分析可看出船舱是否有编号对存活率也有一定的影响,但由于船舱编号不一长短也不一样,不利于后面的机器学习,因此统一将有编号的设为yes,无编号的设为no。

data.loc[pd.notnull(data.Cabin),"Cabin"] = "Yes"

data.loc[pd.isnull(data.Cabin), "Cabin"] = "No"

data.Cabin.value_counts()

       最后是对登船港口缺失值的处理,从上面的统计可看出,登船港口缺失值较少,因此可直接用登船港口人数最多的“S”港进行填充。

data.loc[pd.isnull(data.Embarked),"Embarked"] = "S"

       最后统计一下可看出,所有特征项已无缺失值,除了前面数据分析时加入的AgeGroup,在后面的特征工程会将其删除。

图3.1 查看数据填充结果

4.特征工程

       特征工程指的是把原始数据转变为模型的训练数据的过程,它的目的就是获取更好的训练数据特征,使得机器学习模型逼近这个上限。经过上面的数据分析和数据处理后,我们已经完成对数据的缺失值的处理和特征的分析,下一步是对文本字段进行处理,在这使用的是One-Hot:独热编码,涉及到Embarked, Cabin, Sex和Pclass,不需要的字段包括PassengerId,,Name和Ticket。

首先对字段进行One-Hot编码:

# Sex字段的One-Hot编码

d_sex = pd.get_dummies(data.Sex,prefix="Sex")

# Cabin字段的One-Hot编码

d_cabin = pd.get_dummies(data.Cabin,prefix="Cabin")

# Embarked字段的One-Hot编码

d_embarked = pd.get_dummies(data.Embarked,prefix="Embarked")

# Pclass字段的One-Hot编码

d_pclass = pd.get_dummies(data.Pclass,prefix="Pclass")

      下面使用计算得到的One-Hot编码字段替代数据中原有字段,拼接数据框,将新生成的字段导入数据集中:

#拼接数据框,将新生成的字段加入到数据集中

df = pd.concat([data,d_sex,d_cabin,d_embarked,d_pclass],axis=1)

df.head()

图4.1 导入独热编码

      下一步是删除数据集中被替代的列(Sex,Cabin,Embarked,Pclass)以及不需要的列(PassengerId,Name,Ticket):

df.drop(["Sex","Cabin","Embarked","Pclass","PassengerId","Name","Ticket"],axis=1,inplace=True)

df.head()

图4.2 删除不需要的列

      删除前面数据分析时不小心加入的AgeGroup:

df.drop(["AgeGroup",],axis=1,inplace=True)

df.head()

图4.3 删除“AgeGroup”列

       接着,观察到Age和Fare这两个特征的取值量级较大,需要进行标准化。常用的标准化手段包括正态分布标准化,最大最小值标准化,在此采用了后者:

#最大最小值标准化(让取值在0-1之间)

#(x-min)/(max-min)

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()

Age_scale = scaler.fit_transform(df.Age.values.reshape(-1,1))

Fare_scale = scaler.fit_transform(df.Fare.values.reshape(-1,1))

df["Age_scale"] = Age_scale

df["Fare_scale"] = Fare_scale

df.drop(["Age","Fare"],axis=1,inplace=True)

df.head()

图4.4 数据标准化

       最后再将数据进行保存,至此我们特征工程的工作就完成了,主要是删除与目标(是否获救)明显没有关系的特征,然后是对字符特征和无序的分类特征进行One-Hot编码。

5. 机器学习

       通过上面的数据分析、数据处理和特征工程的建模后,接下来是进行机器学习,主要为数据集的准备、划分训练集和测试集以及机器学习分类算法,最主要的是对算法的选择。

首先准备数据:

#准备数据,X代表数据,y代表目标(是否获救)

X = df.iloc[:,1:].values

y = df.iloc[:,0].values

下面是对数据集进行划分:

#划分训练集和测试集

from sklearn.model_selection import train_test_split

X_train,X_test,y_train,y_test = train_test_split(X, y, test_size=0.3, random_state=33)

print(X_train.shape, X_test.shape,y_train.shape,y_test.shape)

(623, 14) (268, 14) (623,) (268,)

      接下来是机器学习算法的选择,算法有很多,在这先选择KNN算法、逻辑回归算法、决策树算法、支持向量机算法和随机森林算法进行比对,选择最佳的算法。

KNN算法:

# KNN分类算法

from sklearn.neighbors import KNeighborsClassifier

#建模

knn = KNeighborsClassifier(n_neighbors=7, p=1)

#学习

knn.fit(X_train, y_train)

#评估

print("模型参数:", knn)

print("模型测试准确度:", knn.score(X_test,y_test))

print("模型训练准确度:", knn.score(X_train, y_train))

图5.1 KNN算法模型

逻辑回归算法:

#逻辑回归算法

from sklearn.linear_model import LogisticRegression

#建模

lr = LogisticRegression(penalty='l1')

#学习

lr.fit(X_train, y_train)

#评估

print("模型参数:", lr)

print("模型测试准确度:", lr.score(X_test,y_test))

print("模型训练准确度:", lr.score(X_train, y_train))

图5.2 逻辑回归算法模型

决策树算法:

#决策树算法

from sklearn.tree import DecisionTreeClassifier

#建模

dtc = DecisionTreeClassifier(splitter="random")

#学习

dtc.fit(X_train,y_train)

#评估

print("模型参数:", dtc)

print("模型测试准确度:", dtc.score(X_test,y_test))

print("模型训练准确度:", dtc.score(X_train, y_train))

图5.3 决策树算法模型

支持向量机算法:

#支持向量机算法

from sklearn.svm import SVC

#建模

svc = SVC(gamma=0.1,C=15)

#学习

svc.fit(X_train,y_train)

#评估

print("模型参数:", dtc)

print("模型测试准确度:", svc.score(X_test,y_test))

print("模型训练准确度:", svc.score(X_train, y_train))

图5.4 支持向量机算法模型

随机森林算法:

#随机森林算法

from sklearn.ensemble import RandomForestClassifier

#建模

rfc = RandomForestClassifier( n_estimators=33)

#学习

rfc.fit(X_train,y_train)

#评估

print("模型参数:", rfc)

print("模型测试准确度:", rfc.score(X_test,y_test))

print("模型训练准确度:", rfc.score(X_train, y_train))

图5.5 随机森林算法模型

       从上面机器学习算法模型得分中,可以看出决策树算法和随机森林算法的测试集得分跟训练集得分相差太大,可能是学习过度,产生了过拟合想象。在剩下的KNN算法、逻辑回归算法和支持向量机算法中,训练集得分和测试集得分基本接近,可见拟合较好,下面进行交叉验证。

KNN算法:

# KNN

import numpy as np

from sklearn.neighbors import KNeighborsClassifier

from sklearn.model_selection import  cross_val_score

knn = KNeighborsClassifier()

scores = cross_val_score(knn, X, y, cv=5)

print(scores)

print("交叉验证平均分:",np.mean(scores))

图5.6 KNN算法交叉验证得分

逻辑回归算法:

#逻辑回归

import numpy as np

from sklearn.linear_model import LogisticRegression

from sklearn.model_selection import  cross_val_score

lr = LogisticRegression(penalty="11")

scores = cross_val_score(knn, X, y, cv=10)

print(scores)

print("交叉验证平均分:",np.mean(scores))

图5.7 逻辑回归算法交叉验证得分

支持向量机算法:

#支持向量机

import numpy as np

from sklearn.svm import SVC

from sklearn.model_selection import  cross_val_score

svc = SVC(gamma=0.08, C=15, kernel="poly", degree=2)

scores = cross_val_score(svc, X, y, cv=10)

print(scores)

print("交叉验证平均分:",np.mean(scores))

图5.8 支持向量机算法交叉验证得分

综上交叉验证得分,可见支持向量机的算法是更好的,不会过拟合也不会学习不足。

       选定了最佳算法后,采用网格搜索的方式确定来最优参数,确定最优的参数建模后采用最优参数建模并用k折验证得到评估的平均分。

网格搜索:

from sklearn.model_selection import GridSearchCV

from sklearn.svm import SVC

svc = SVC()

params = {

    "C":[1,5,10,15,20,30,50,70,100],

    "gamma":[0.0001, 0.001, 0.005, 0.01, 0.05, 0.1],

    "kernel":["rbf", "linear","poly","sigmoid"],

    "degree":[2,3,4,5]

}

grid = GridSearchCV(svc, params, scoring="accuracy")

grid.fit(X, y)

print(grid.best_score_)

print(grid.best_params_)

图5.9 网格搜索

k折验证:

import numpy as np

from sklearn.svm import SVC

from sklearn.model_selection import  cross_val_score

svc = SVC(gamma=0.1, C=70, kernel="rbf", degree=2)

scores = cross_val_score(svc, X, y, cv=10)

print(scores)

print("交叉验证平均分:",np.mean(scores))

图5.10 k折验证

不知道为什么使用网格搜索的最佳参数模型反而验证分数降低了。

6.总结和展望

      通过这个课程设计,加深了对python语言的学习,python不仅仅是一门编程语言,它的功能非常的强大,不仅可以编程,还可以进行数据分析、数据可视化操作、机器学习等。

      在这个课程设计中,我选择的是对泰坦尼克号沉船旅客存活率进行分析,内容较多,运用的知识比较广泛,主要是在数据分析这一部分的内容会比较多,后面也因为时间原因,没有对多个特征进行综合分析,比如存活率是否与年龄性别综合相关呢?是否与头衔跟性别相关呢?也有因为个人能力问题只能分析到这个程度。在数据可视化这一部分,也因为时间问题没有深入去分析哪些图形可视化能更直观的表达分析的结果,图形画的较为单一,基本都为柱状图。在机器学习这一部分也因为没有深入学习,所以在进行网格搜索调参的时候出现了验证分数比自己随机选择的参数分数还低的情况,这个部分我一直没找到原因,这也是一个课程设计最大的一个不足的地方。

       完成这个课程设计论文,我觉得不仅是对python语言更加的熟练,也增加了自己数据分析和数据可视化方面的能力,还有对机器学习的初步涉略。即使这个课程结束了,我还是会继续深入学习python,深入学习机器学习。

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