(二十六)项目实战|交易数据异常检测(一)-python数据分析与机器学习实战(学习笔记)

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

1.案例背景和目标
2.样本不均衡解决方案
3.下采样策略

课程来源: python数据分析与机器学习实战-唐宇迪

课程资料:这里所涉及到的练习资料creditcard.csv相关的链接以及密码如下:
链接: https://pan.baidu.com/s/1APgU4cTAaM9zb8_xAIc41Q 密码: xgg7

1.案例背景和目标

这节课主要介绍线性回归以及逻辑回归的算法的运用.首先看一下creditcard.csv里面前5行的数据是怎么样的?

import pandas as pd 
data=pd.read_csv("creditcard.csv")
print(data.head())

输出的结果如下:

   Time        V1        V2        V3        V4        V5        V6        V7  \
0   0.0 -1.359807 -0.072781  2.536347  1.378155 -0.338321  0.462388  0.239599   
1   0.0  1.191857  0.266151  0.166480  0.448154  0.060018 -0.082361 -0.078803   
2   1.0 -1.358354 -1.340163  1.773209  0.379780 -0.503198  1.800499  0.791461   
3   1.0 -0.966272 -0.185226  1.792993 -0.863291 -0.010309  1.247203  0.237609   
4   2.0 -1.158233  0.877737  1.548718  0.403034 -0.407193  0.095921  0.592941   

         V8        V9  ...         V21       V22       V23       V24  \
0  0.098698  0.363787  ...   -0.018307  0.277838 -0.110474  0.066928   
1  0.085102 -0.255425  ...   -0.225775 -0.638672  0.101288 -0.339846   
2  0.247676 -1.514654  ...    0.247998  0.771679  0.909412 -0.689281   
3  0.377436 -1.387024  ...   -0.108300  0.005274 -0.190321 -1.175575   
4 -0.270533  0.817739  ...   -0.009431  0.798278 -0.137458  0.141267   

        V25       V26       V27       V28  Amount  Class  
0  0.128539 -0.189115  0.133558 -0.021053  149.62      0  
1  0.167170  0.125895 -0.008983  0.014724    2.69      0  
2 -0.327642 -0.139097 -0.055353 -0.059752  378.66      0  
3  0.647376 -0.221929  0.062723  0.061458  123.50      0  
4 -0.206010  0.502292  0.219422  0.215153   69.99      0  

[5 rows x 31 columns]

从输出的结果可以看出,数据共有5行31列:

  • time这一列表示交易持续的时间,其实没多大的意义.
  • v1,v2,v3.....v28分别代表特征1,2,3.....28.虽然有数据,但是没表明什么意思,因此这个数据并不是最原始的数据.因为考虑到用户的隐私,对部分数据进行了处理,才进行公开.因此对数据进行压缩,直接变成了v1,v2,v3.....v28可用的特征.
  • Amount代表交易的金额,这个金额相比特征的数据浮动比较大,待会会对Amount这一列的数据进行预处理.
  • Class 这列0代表是正常样本,1代表异常样本.通常情况下将数据分成2部分,一部分是x的特征数据;另一部分是y,当作lable数据,相当于Class中的数据.

注意:拿到数据的时候,要明白自己做一件什么样的事情.比如这里就是做信用卡的欺诈检测.在欺诈数据里面,有正常的数据,也有问题的数据.因此对于这样的问题,我们可以将原始问题分为0类是正常的、1类是异常的,接下来就是对样本的数据进行0和1的分类,相当于二分类的问题.

用这些已经提取好的特征,如何进行建模的操作呢?接下来用逻辑回归,建立一个模型.

首先看一下样本数据的分布规则,一般情况下正常数据出现的情况比较多,异常数据出现的情况比较少.一般99.9%的数据都是正常的,只有那么0.1%的数据出现诈骗或者异常或者其他.因此这个样本数据的检测绝大多数都是正常样本,只有极少数的样本是异常样本.

首先看一下正负样本的比例有多大?

import pandas as pd 
import matplotlib.pyplot as plt

data=pd.read_csv("creditcard.csv")
count_classes = pd.value_counts(data['Class'], sort = True).sort_index()
count_classes.plot(kind="bar")
plt.title("Fraud class histogram")
plt.xlabel("Class")
plt.ylabel("Frequency")

输出结果如下:


从输出的结果可以看出样本数据的差异,正常的样本0大概有28万个;异常的样本1非常少,大概只有那么几百个.

这里涉及到的知识点:
1)value_counts(values,sort = True,ascending = False,normalize = False,bins = None,dropna = True)

  • pd.value_counts 返回一个Series,其索引为唯一值,其值为频率,按计数值降序排列.value_counts为对data每列中出现的数字进行统计.
  • 相当于统计'Class'这列不同的属性值,就会统计0有多少个?1有多少个?

2)用pandas画简单的图也可以的.count_classes.plot(kind="bar")

  • 相当于画条形图.

2.样本不均衡解决方案

这里需要想一下,样本数据不均衡,应该怎么办?而今天的样本数据是极度不均衡的,应该提出什么样的解决方案?这里有两种解决方案,一是过采样,一种是下采样,这是针对样本不均衡最常使用的两种方案.

这里涉及到的知识点:

  • 下采样定义
    就是当数据样本不均衡,想变成均衡的数据,将0和1的数据一样小.之前统计的结果可以看出0的样本有28万个,而1的样本只有几百个.现在将0的数据也变成几百个就可以了.下采样,是使样本的数据同样少.
  • 过采样定义:之前统计的结果可以看出0的样本有28万个,而1的样本只有几百个.0比较多1比较少,对1的样本数据进行生成数列,让生成的数据与0的样本数据一样多.

这两种方案,那种方案稍微的更好一些呢?

之前有提到Amount 这列的数值浮动比较大,有些值比较小,在建机器模型的时候,首先要做一件事情,首先要保证特征分布的差异是差不多的,比如拿v28与Amount 来举例.v28的数据分布的区间是[-1,1],Amount 分布差异比较大.机器学习算法可能有这样的误导,数值比较大的特征,
一些重要程度是偏大一些的;数值比较小的特征,一些重要程度是偏小一些的.因此需要使数据的特征是相当的,避免机器学习算法有误区.

这里并非要求V28与Amount的特征谁更重要一些,因此要对Amount的数据进行规划要么做标准化.可以将Amount的数据做成区间是[0,1]或者[-1,1],这些都是可以的.在sklearn库中有提供好的预处理模块,可以对数据进行预处理操作.

案例代码如下:

from sklearn.preprocessing import StandardScaler
import pandas as pd 

data=pd.read_csv("creditcard.csv")
data['normAmount'] = StandardScaler().fit_transform(data['Amount'].reshape(-1, 1))
data = data.drop(['Time','Amount'],axis=1)
print(data.head())

输出结果如下:

         V1        V2        V3        V4        V5        V6        V7  \
0 -1.359807 -0.072781  2.536347  1.378155 -0.338321  0.462388  0.239599   
1  1.191857  0.266151  0.166480  0.448154  0.060018 -0.082361 -0.078803   
2 -1.358354 -1.340163  1.773209  0.379780 -0.503198  1.800499  0.791461   
3 -0.966272 -0.185226  1.792993 -0.863291 -0.010309  1.247203  0.237609   
4 -1.158233  0.877737  1.548718  0.403034 -0.407193  0.095921  0.592941   

         V8        V9       V10     ...           V21       V22       V23  \
0  0.098698  0.363787  0.090794     ...     -0.018307  0.277838 -0.110474   
1  0.085102 -0.255425 -0.166974     ...     -0.225775 -0.638672  0.101288   
2  0.247676 -1.514654  0.207643     ...      0.247998  0.771679  0.909412   
3  0.377436 -1.387024 -0.054952     ...     -0.108300  0.005274 -0.190321   
4 -0.270533  0.817739  0.753074     ...     -0.009431  0.798278 -0.137458   

        V24       V25       V26       V27       V28  Class  normAmount  
0  0.066928  0.128539 -0.189115  0.133558 -0.021053      0    0.244964  
1 -0.339846  0.167170  0.125895 -0.008983  0.014724      0   -0.342475  
2 -0.689281 -0.327642 -0.139097 -0.055353 -0.059752      0    1.160686  
3 -1.175575  0.647376 -0.221929  0.062723  0.061458      0    0.140534  
4  0.141267 -0.206010  0.502292  0.219422  0.215153      0   -0.073403  

[5 rows x 30 columns]

从输出的结果可以看出,特征数据已经确定好了.

这里涉及到的知识点:

  • StandardScaler()标准化的模块
  • fit_transform是对数据进行变化
  • StandardScaler().fit_transform(data['Amount'].reshape(-1, 1))是对data中的'Amount'这列的数据进行传入到StandardScaler().fit_transform()
  • reshape()是用法如下
    比如[2,3]是2行3列的矩阵,[2,3].reshape(-1,2)会变成[3,2]即就是3行2列的矩阵.因为python会根据3*2共6个数,依据列数(这里2列),会自动计算出行数.因为这里的新列是只有1列,所以要求python自动计算出列的行数.
  • data = data.drop(['Time','Amount'],axis=1),是因为有了'normAmount'这列,而之前的Time这列是没有用的,Amount已经转换成'normAmount'这列,因此要将这两列数据进行丢弃.

3.下采样策略

接下来就是用下采样以及过采样的两种方式,是样本数据进行均衡处理.首先先用下采样的的策略:使0和1的样本数据一样的少,要使0和1的数据一样的少,那么应该怎么做呢?

步骤一:

首先对数据进行区分,将数据分成一个为x,一个为y.

  • x代表是特征数据;前面的:(冒号)是将所有的行样本都取进来, data.columns != 'Class'引进所有的列中,但是不包括'Class'这列.这样就构成了特征数据
  • 对于y列:(冒号)是将所有的行样本都取进来,将data.columns = 'Class',引进'Class'这列当成lable值.
X = data.ix[:, data.columns != 'Class']
y = data.ix[:, data.columns == 'Class']

X输出结果为:

  V1        V2        V3        V4        V5        V6        V7  \
0 -1.359807 -0.072781  2.536347  1.378155 -0.338321  0.462388  0.239599   
1  1.191857  0.266151  0.166480  0.448154  0.060018 -0.082361 -0.078803   
2 -1.358354 -1.340163  1.773209  0.379780 -0.503198  1.800499  0.791461   
3 -0.966272 -0.185226  1.792993 -0.863291 -0.010309  1.247203  0.237609   
4 -1.158233  0.877737  1.548718  0.403034 -0.407193  0.095921  0.592941   

         V8        V9       V10     ...           V20       V21       V22  \
0  0.098698  0.363787  0.090794     ...      0.251412 -0.018307  0.277838   
1  0.085102 -0.255425 -0.166974     ...     -0.069083 -0.225775 -0.638672   
2  0.247676 -1.514654  0.207643     ...      0.524980  0.247998  0.771679   
3  0.377436 -1.387024 -0.054952     ...     -0.208038 -0.108300  0.005274   
4 -0.270533  0.817739  0.753074     ...      0.408542 -0.009431  0.798278   

        V23       V24       V25       V26       V27       V28  normAmount  
0 -0.110474  0.066928  0.128539 -0.189115  0.133558 -0.021053    0.244964  
1  0.101288 -0.339846  0.167170  0.125895 -0.008983  0.014724   -0.342475  
2  0.909412 -0.689281 -0.327642 -0.139097 -0.055353 -0.059752    1.160686  
3 -0.190321 -1.175575  0.647376 -0.221929  0.062723  0.061458    0.140534  
4 -0.137458  0.141267 -0.206010  0.502292  0.219422  0.215153   -0.073403  

[5 rows x 29 columns]

y输出结果为:

   Class
0      0
1      0
2      0
3      0
4      0
  • 涉及知识点:
    ix / loc 可以通过行号和行标签进行索引,比如 df.loc['a'] , df.loc[1], df.ix['a'] , df.ix[1]而iloc只能通过行号索引 , df.iloc[0] 是对的, 而df.iloc['a'] 是错误的.
    loc 和 ix 大部分时候行为都差不多, 但是当假如某个行的索引标签就是一个 INT 比如 1 的时候, loc 优先将 df.loc[1] 理解为行标签为 1 的索引, 而 df.ix[1] 优先将其理解为 行号为 1 的索引(就是第二行).
    为了避免不小心犯错误,建议:
    • 1.当用行号索引的时候, 尽量用 iloc 来进行索引;
      1. 而用标签索引的时候用 loc ,
      1. ix 就别用了

步骤二:

接下来是让0和1一样的少.因为两者的样本数量超级不均衡,因此需要了解1类的样本数量有多少个?

  • 需要计算Class == 1的样本个数
  • fraud_indices = np.array(data[data.Class == 1].index)将Class == 1的样本的索引拿出来.
number_records_fraud = len(data[data.Class == 1])
fraud_indices = np.array(data[data.Class == 1].index)

number_records_fraud输出的结果为:492
fraud_indices 输出的结果为:

[   541    623   4920   6108   6329   6331   6334   6336   6338   6427
   6446   6472   6529   6609   6641   6717   6719   6734   6774   6820
   6870   6882   6899   6903   6971   8296   8312   8335   8615   8617
......
 258403 261056 261473 261925 262560 262826 263080 263274 263324 263877
 268375 272521 274382 274475 275992 276071 276864 279863 280143 280149
 281144 281674]

步骤三:

接下来需要将0类的数据进行随机选择,因此先将将Class == 0的样本的索引拿出来,通过这些索引进行随机的选择.

normal_indices = data[data.Class == 0].index

normal_indices输出的结果为:

Int64Index([     0,      1,      2,      3,      4,      5,      6,      7,
                 8,      9,
            ...
            284797, 284798, 284799, 284800, 284801, 284802, 284803, 284804,
            284805, 284806],
           dtype='int64', length=284315)

步骤四:

将Class == 0的样本的索引索引进行随机的选择.

  • np.random.choice(normal_indices, number_records_fraud, replace = False)对数据进行随机的选择,第1个参数是指待选择的数据,而第2个参数是指选择的个数,第3个参数是否选择代替,这里选择不代替.
  • random_normal_indices = np.array(random_normal_indices)选好了数据之后,将数据(索引)值拿出来并转换成array的格式.
random_normal_indices = np.random.choice(normal_indices, number_records_fraud, replace = False)
random_normal_indices = np.array(random_normal_indices)

random_normal_indices输出的结果为:

[116549   8246  58928 195831  24378 155470   2928 196485   1263 154569
 124579  73439 134119 166158 115654   6207 125430 272877 172843 227905
  98385  64250  42926 282628 103786  20825 232324   2970  38334 121091
......
  33946 109597  26740 209036 233898 109418 167046 153046  30701 251630
  95018  59052 231435 212688  47047 201302  82762  30588 132329 228857
 227541  53627]

random_normal_indices输出的结果为:

[156959  95974 213308 194594 161193  85394   8111 251709 225081  78327
 284065 140468  41842  50913 237823 278143 221350 153415 167686 102469
  56223 143083 251190 144994 172825 261161 237031 122866 174099  13173
......
 147350 109878  13833  33751 284747 254240  49823  43045  42083 173280
 204803  33121 247500 205138 107235 150955 107497 124359 133047 106351
 250517 109529]

步骤五:

接下来,对numpy的数据进行一个合并的操作.这里的数据index的值是等于1,还有index的值是等于0,将这两组数据放在在一起

under_sample_indices = np.concatenate([fraud_indices,random_normal_indices])

under_sample_indices输出结果为:

[   541    623   4920   6108   6329   6331   6334   6336   6338   6427
   6446   6472   6529   6609   6641   6717   6719   6734   6774   6820
   6870   6882   6899   6903   6971   8296   8312   8335   8615   8617
......
 216734 133129  61895 276555  36672  59561 199743 216279 277491  50834
  78442  28713 128264 202477 202553 111711 239937 113963 273641  37351
 136787 192156 225688 239756]
  • np.concatenate()所涉及到的知识点:
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
np.concatenate((a, b), axis=0)
    array([[1, 2],
           [3, 4],
           [5, 6]])
np.concatenate((a, b.T), axis=1)
    array([[1, 2, 5],
           [3, 4, 6]])

步骤六:

index的值是等于1,index的值是等于0,将这些数据合并在一起之后,通过index在原始的数据当中进行并位的操作.

  • under_sample_data是经过完下采样处理之后,可以再将under_sample_data数据分为2部分的数据,一部分是X_undersample数据,一部分是y_undersample数据,分别是代表是特征以及lable.
under_sample_data = data.iloc[under_sample_indices,:]

X_undersample = under_sample_data.ix[:, under_sample_data.columns != 'Class']
y_undersample = under_sample_data.ix[:, under_sample_data.columns == 'Class']

under_sample_data输出的结果为:

              V1        V2         V3        V4        V5        V6  \
541    -2.312227  1.951992  -1.609851  3.997906 -0.522188 -1.426545   
623    -3.043541 -3.157307   1.088463  2.288644  1.359805 -1.064823   
4920   -2.303350  1.759247  -0.359745  2.330243 -0.821628 -0.075788   
......   
224240 -2.706990  0.263766   0.881609  4.615918 -0.637164  1.079700   
99902  -1.284746  0.320887   0.374802 -0.664525  0.433880 -0.653042   
266861 -0.732211  0.644729   1.441944 -0.919455  0.099726  0.190200   

               V7        V8        V9        V10     ...           V21  \
541     -2.537387  1.391657 -2.770089  -2.772272     ...      0.517232   
623      0.325574 -0.067794 -0.270953  -0.838587     ...      0.661696   
4920     0.562320 -0.399147 -0.238253  -1.525412     ...     -0.294166   
..... 
224240   1.342084 -0.001033 -2.052804   2.006310     ...     -0.664714   
99902    1.839785 -0.300557 -0.448643  -0.547502     ...     -0.387583   
266861   0.331085  0.057795  0.726765   0.194685     ...      0.150547   

             V22       V23       V24       V25       V26       V27       V28  \
541    -0.035049 -0.465211  0.320198  0.044519  0.177840  0.261145 -0.143276   
623     0.435477  1.375966 -0.293803  0.279798 -0.145362 -0.252773  0.035764   
4920   -0.932391  0.172726 -0.087330 -0.156114 -0.542628  0.039566 -0.153029   
.....   
224240 -1.410437 -0.740022  0.002338 -0.443197 -0.127586 -0.006104 -0.351641   
99902  -1.019331  0.438280 -0.492716  0.063672  0.038212  0.248317  0.105015   
266861  0.851754 -0.286176 -0.427786 -0.323472  0.528626  0.173683  0.050960   

        Class  normAmount  
541         1   -0.353229  
623         1    1.761758  
4920        1    0.606031  
.....
224240      0    1.082084  
99902       0    0.418201  
266861      0   -0.316447  

[984 rows x 30 columns]

X_undersample输出的结果为:

              V1        V2         V3        V4        V5        V6  \
541    -2.312227  1.951992  -1.609851  3.997906 -0.522188 -1.426545   
623    -3.043541 -3.157307   1.088463  2.288644  1.359805 -1.064823   
.....
244538 -0.454182  1.086067  -2.044538 -1.541637  2.704735  3.207766   
160568  1.994042 -1.245946  -0.750254 -1.051604 -0.787568  0.144334   
161729  2.063641 -0.699814  -1.287431 -1.702303 -0.772118 -1.765008   

               V7        V8        V9        V10     ...           V20  \
541     -2.537387  1.391657 -2.770089  -2.772272     ...      0.126911   
623      0.325574 -0.067794 -0.270953  -0.838587     ...      2.102339   
4920     0.562320 -0.399147 -0.238253  -1.525412     ...     -0.430022   
......
244538   0.045364  1.256304 -0.136446  -0.176591     ...      0.064808   
160568  -1.005092  0.108401 -0.166269   0.835084     ...      0.191989   
161729  -0.018834 -0.374259  2.478122  -1.316819     ...     -0.286771   

             V21       V22       V23       V24       V25       V26       V27  \
541     0.517232 -0.035049 -0.465211  0.320198  0.044519  0.177840  0.261145   
623     0.661696  0.435477  1.375966 -0.293803  0.279798 -0.145362 -0.252773   
4920   -0.294166 -0.932391  0.172726 -0.087330 -0.156114 -0.542628  0.039566   
......
244538  0.377806  1.175611 -0.031673  0.734231 -0.681844 -0.191997  0.509245   
160568  0.023440 -0.178660  0.281183  0.255687 -0.481238 -0.519921 -0.012572   
161729  0.149171  0.853296  0.014144  0.448867  0.360000 -0.665084  0.042658   

             V28  normAmount  
541    -0.143276   -0.353229  
623     0.035764    1.761758  
4920   -0.153029    0.606031  
......
244538  0.313375   -0.349671  
160568 -0.032987    0.026589  
161729 -0.053884   -0.313448  

[984 rows x 29 columns]

y_undersample输出的结果为:

        Class
541         1
623         1
4920        1
......
126998      0
147121      0
22781       0

步骤七:

打印这样的函数,从输出的结果可以看出下采样的数据共有984个,正样本有50%,负样本有50%.通过下采样的方式将0和1不均衡的数据转换成均衡的数据.只是发生了一些代价,产生代价的原因是因为数据是随机生成的,有些数据并非利用到手.

print("Percentage of normal transactions: ", len(under_sample_data[under_sample_data.Class == 0])/len(under_sample_data))
print("Percentage of fraud transactions: ", len(under_sample_data[under_sample_data.Class == 1])/len(under_sample_data))
print("Total number of transactions in resampled data: ", len(under_sample_data))

输出结果为:

Percentage of normal transactions:  0.5
Percentage of fraud transactions:  0.5
Total number of transactions in resampled data:  984

完整的下采样代码如下:

import numpy as np
from sklearn.preprocessing import StandardScaler
import pandas as pd 

data=pd.read_csv("creditcard.csv")
data['normAmount'] = StandardScaler().fit_transform(data['Amount'].reshape(-1, 1))
data = data.drop(['Time','Amount'],axis=1)

X = data.ix[:, data.columns != 'Class']
y = data.ix[:, data.columns == 'Class']
number_records_fraud = len(data[data.Class == 1])
fraud_indices = np.array(data[data.Class == 1].index)
normal_indices = data[data.Class == 0].index
random_normal_indices = np.random.choice(normal_indices, number_records_fraud, replace = False)
random_normal_indices = np.array(random_normal_indices)
print(random_normal_indices)
under_sample_indices = np.concatenate([fraud_indices,random_normal_indices])
under_sample_data = data.iloc[under_sample_indices,:]

X_undersample = under_sample_data.ix[:, under_sample_data.columns != 'Class']
y_undersample = under_sample_data.ix[:, under_sample_data.columns == 'Class']
print("Percentage of normal transactions: ", len(under_sample_data[under_sample_data.Class == 0])/len(under_sample_data))
print("Percentage of fraud transactions: ", len(under_sample_data[under_sample_data.Class == 1])/len(under_sample_data))
print("Total number of transactions in resampled data: ", len(under_sample_data))

思考一下,下采样的操作是否会存在潜在的问题呢?数据量拿出来比较少,肯定会存在一些问题,

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

推荐阅读更多精彩内容