NumPy 基础:数组和矢量计算

NumPy 基础:数组和矢量计算

NumPy 的 ndarray : 一种多维数组对象

import numpy as np
data = np.array()
data.shape  #对象的结构,如(2,3)
data.dtype  #对象元素的数据类型
data.ndim  #对象的维度

创建ndarray

data = []  #创建一个list对象
arr = np.array(data)  #传递一个list对象创建ndarray对象
np.zeros(10)  #创建长度为10的全0数组
np.ones(10)  #创建长度为10的全1数组
np.zeros((3,6))  #创建3行6列的全0二维数组
np.arrange(10)  #对应python内置的range函数  

数组创建函数

函数 说明
array 将输入数据(列表、元祖、数组或其他序列类型)转换为ndarray。
asarray 将输入转换为ndarray,如果输入本身就是一个ndarray就不进行复制。
arrange 类似于内置的range。
ones、ones_like 根据指定的形状和dtype创建一个全1数组。ones_like以另一个数组为参数。
zeros、zeros_like 同上
empty、empty_like 创建新数组,只分配内存空间但不填充任何值。
eye、identity 创建一个正方的NxN单位矩阵(对角线为1,其余为0)

ndarray的数据类型

arr1 = np.array([1, 2, 3], dtype=np.float64)
arr2 = np.array([1, 2, 3], dtype=np.int32)
float_arr1 = arr1.astype(np.float64)  #data.astype()显式转换数据类型
float_arr2 = arr2.astype(arr1.dtype)

调用astype无论如何都会常见一个新的数组(原始数组的一份拷贝),即使新dtype跟老dtype相同也是如此。

基本的索引和切片

一维数组跟Python列表的功能差不多,跟列表最重要的区别在于,数组切片是原始数组的视图,并非拷贝。如果要想得到的是ndarray切片的一个副本而非视图,就需要显式的进行复制操作,例如==arr[5:8].copy()==。

以下两种方式是等价的

arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr2d[0][2]
arr2d[0, 2]

切片索引

ndarray的切片语法跟Python列表这样的一维对象差不多。高维度对象的花样更多,可以在一个或多个轴上进行切片,也可以跟整数索引混合使用。

arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

arr2d
Out: 
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

arr2d[:2]
Out: 
array([[1, 2, 3],
       [4, 5, 6]])

arr2d[:2,1:]
Out: 
array([[2, 3],
       [5, 6]])

布尔型索引

names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
data = randn(7,4)  //使用numpy.random中的randn函数生成一些正态分布的随机数据。
data
Out: 
array([[-0.29387507,  0.17205361,  0.66953008,  1.52117065],
       [ 1.10443341,  1.38657273, -0.07698117,  0.14266073],
       [ 0.76090409,  0.971822  , -0.32016532,  0.8410247 ],
       [-0.16898366,  0.18393705, -0.68519614,  1.22744236],
       [ 0.50100988, -0.75611675,  0.18750586, -1.64240784],
       [-0.3859573 ,  0.53440464, -0.74281885,  0.83665929],
       [-0.52089554,  0.65959834, -0.17651269, -1.58237464]])
names == 'Bob'
Out: array([ True, False, False,  True, False, False, False], dtype=bool)

data[names == 'Bob']
Out: 
array([[-0.29387507,  0.17205361,  0.66953008,  1.52117065],
       [-0.16898366,  0.18393705, -0.68519614,  1.22744236]])

布尔型数组的长度必须跟被索引的轴长度一致。还可以跟切片、整数(或整数序列)混合使用:

data[names == 'Bob',2:]
Out: 
array([[ 0.66953008,  1.52117065],
       [-0.68519614,  1.22744236]])

要选择“Bob”以外的其他值,既可以使用不等于号(!=),也可以通过负号(-)对条件进行否定:

data[names != 'Bob']
data[-(names == 'Bob')]

如果需要对布尔条件进行组合使用,可以使用&(和)、|(或)之类的布尔算数运算符即可:

mask = (names == 'Bob') | (names == 'Will')

mask
Out: array([ True, False,  True,  True,  True, False, False], dtype=bool)

data[mask]
Out: 
array([[-0.29387507,  0.17205361,  0.66953008,  1.52117065],
       [ 0.76090409,  0.971822  , -0.32016532,  0.8410247 ],
       [-0.16898366,  0.18393705, -0.68519614,  1.22744236],
       [ 0.50100988, -0.75611675,  0.18750586, -1.64240784]])

通过布尔型索引选取数组中的数据,总是创建数据的副本,即使返回一模一样的数组也是如此。
==Python关键字and和or在布尔型数组中无效。==

可以对数组中的一些符合条件的数据进行重新赋值:

data[data < 0] = 0

data
Out: 
array([[ 0.        ,  0.17205361,  0.66953008,  1.52117065],
       [ 1.10443341,  1.38657273,  0.        ,  0.14266073],
       [ 0.76090409,  0.971822  ,  0.        ,  0.8410247 ],
       [ 0.        ,  0.18393705,  0.        ,  1.22744236],
       [ 0.50100988,  0.        ,  0.18750586,  0.        ],
       [ 0.        ,  0.53440464,  0.        ,  0.83665929],
       [ 0.        ,  0.65959834,  0.        ,  0.        ]])

花式索引

即利用整数数组进行索引。

为了以特定的书序选取行子集,只需传入一个用于指定顺序的整数列表或ndarray即可:

arr = np.empty((8, 4))
for i in range(8):
    arr[i] = i
arr
Out: 
array([[ 0.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  1.],
       [ 2.,  2.,  2.,  2.],
       [ 3.,  3.,  3.,  3.],
       [ 4.,  4.,  4.,  4.],
       [ 5.,  5.,  5.,  5.],
       [ 6.,  6.,  6.,  6.],
       [ 7.,  7.,  7.,  7.]])

arr[[4, 3, 0, 6]]
Out: 
array([[ 4.,  4.,  4.,  4.],
       [ 3.,  3.,  3.,  3.],
       [ 0.,  0.,  0.,  0.],
       [ 6.,  6.,  6.,  6.]])

一次传入多个索引数组返回的是一个以为数组,其中的元素对应各个索引元组:

arr = np.arange(32).reshape((8, 4))
arr
Out: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23],
       [24, 25, 26, 27],
       [28, 29, 30, 31]])
       
arr[[1, 5, 7, 2], [0, 3, 1, 2]]  #返回的是元素(1,0)、(5,3)、(7,1)和(2,2)。
Out: array([ 4, 23, 29, 10])

我们可以通过以下方式获取矩阵的行列子集:

arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]]
Out: 
array([[ 4,  7,  5,  6],
       [20, 23, 21, 22],
       [28, 31, 29, 30],
       [ 8, 11,  9, 10]])

还可以通过使用np.ix函数,它可以将两个一维整数数组转换为一个用于选取方形区域的所引器:

arr[np.ix_([1, 5, 7, 2], [0, 3, 1, 2])]
Out: 
array([[ 4,  7,  5,  6],
       [20, 23, 21, 22],
       [28, 31, 29, 30],
       [ 8, 11,  9, 10]])

==花式索引总是将数据复制到新数组中。==

数组转置和轴对换

==转置是重塑的一种特殊形式,它返回的事源数据的视图(不会进行任何复制操作)==。数组不仅有transppose方法,还有一个特殊的T属性:

arr = np.arange(15).reshape((3, 5))
arr
Out: 
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])

arr.T
Out: 
array([[ 0,  5, 10],
       [ 1,  6, 11],
       [ 2,  7, 12],
       [ 3,  8, 13],
       [ 4,  9, 14]])
       
arr = np.random.randn(6, 3)
np.dot(arr.T, arr)  #利用np.dot计算矩阵内积X.T*X

对于高维数组,transpose需要得到一个由轴编号组成的元组才能对这些轴进行转置(比较费脑子):

arr = np.arange(16).reshape((2, 2, 4))
arr
Out: 
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]]])

arr.transpose(1,0,2)
Out: 
array([[[ 0,  1,  2,  3],
        [ 8,  9, 10, 11]],

       [[ 4,  5,  6,  7],
        [12, 13, 14, 15]]])

ndarray还有一个swapaxes方法,它接受一对轴编号:

arr
Out: 
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]]])

arr.swapaxes(1,2)
Out: 
array([[[ 0,  4],
        [ 1,  5],
        [ 2,  6],
        [ 3,  7]],

       [[ 8, 12],
        [ 9, 13],
        [10, 14],
        [11, 15]]])

通用函数:快速的元素级数组函数

一元ufunc

函数 说明
abs、fabs 计算整数、浮点数或复数的绝对值。对于复数数值,可以使用更快的fabs。
sqrt 计算各元素的平方根
square 计算各元素的平方
exp 计算各元素的指数e^x
log、log10、log2、log1p 分别为自然对数、底数为10的log、底数为2的log、log(1 + x)
sign 计算各元素的正负号:1(正数)、0(零)、-1(负数)
ceil 计算各元素的ceiling值
floor 计算各元素的floor值
rint 四舍五入到正数,保留dtype
modf 将数组的小数和整数部分以两个独立数组的形式返回
isnan 返回一个表示“哪些值是NaN”的布尔型数组
isfinite、isinf 分别返回一个表示“哪些元素是有穷的”或“哪些元素是无穷的”的布尔型数组
cos、cosh、sin、sinh、tan、tanh 普通型和双曲型三角函数
arccos、arccosh、arcsin、arcsinh、arctan、arctanh 反三角函数
logical_not 计算各元素not x的真值。想到与-arr

二元ufunc

函数 说明
add 将数组中对应的元素相加
subtract 从第一个数组中减去第二个数组中的元素
multiply 数组元素相乘
divide、floor_divide 除法或向下圆整除法
power 对第一个数组中的元素A,根据第二个数组中的相应元素B,计算A的B次方
maximum、fmax 元素级的最大值计算。fmax忽略NaN
minmum、fmin 元素级的最小值计算。fmin忽略NaN
mod 元素级的求模计算
copysign 将第二个数组中的值得负号复制到第一个数组中的值
greate、greate_equal、less、less_equal、equal、not_equal 执行元素级的比价运算,最终产生布尔型的数组。相当于运算符>、>=、<、<=、==、!=
logical_and、logical_or、logical_xor 执行元素级的真值逻辑运算。相当于中缀运算符&、 、^

利用数组进行数据处理

将条件逻辑表述为数组运算

numpy.where 函数是三元表达式 x if condition else y 的矢量化版本。

xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])
result = [(x if c else y)
   .....: for x, y, c in zip(xarr, yarr, cond)]
result
Out: [1.1000000000000001, 2.2000000000000002, 1.3, 1.3999999999999999, 2.5]

这样做会有许多问题。首先,对于大的数组,它不会很快(因为所有的工作都是有纯Python来做的)。其次,对于多维数组,它不能工作。使用 np.where 你可以像这样非常简洁的编写:

result = np.where(cond, xarr, yarr)
result
Out: array([ 1.1, 2.2, 1.3, 1.4, 2.5])

np.where 的第一个和第二个参数不需要是数组;它们中的一个或两个可以是纯量。 在数据分析中 where 的典型使用是生成一个新的数组,其值基于另一个数组。假如你有一个矩阵,其数据是随机生成的,你想要把其中的正值替换为2,负值替换为-2,使用 np.where 非常容易:

arr = randn(4, 4)
arr
Out:
array([[ 0.6372, 2.2043, 1.7904, 0.0752],
       [-1.5926, -1.1536, 0.4413, 0.3483],
       [-0.1798, 0.3299, 0.7827, -0.7585],
       [ 0.5857, 0.1619, 1.3583, -1.3865]])
np.where(arr > 0, 2, -2)
Out:
array([[ 2, 2, 2, 2],
       [-2, -2, 2, 2],
       [-2, 2, 2, -2],
       [ 2, 2, 2, -2]])

np.where(arr > 0, 2, arr) # 仅设置正值为 2
Out:
array([[ 2. , 2. , 2. , 2. ],
       [-1.5926, -1.1536, 2. , 2. ],
       [-0.1798, 2. , 2. , -0.7585],
       [ 2. , 2. , 2. , -1.3865]])

np.where 可以嵌套使用。

数学统计方法

一组数学函数,计算整个数组或一个轴向上数据的统计,和数组函数一样是容易访问的。聚合(通常被称为 reductions ),如 sum , mean ,标准偏差 std 可以使用数组实例的方法,也可以使用顶层NumPy的函数:

arr = randn(5,4)
arr
Out: 
array([[ 0.39013323, -0.65003199, -1.7659255 ,  0.50657869],
       [ 1.49064958, -2.12313076, -0.06437275, -1.74020972],
       [ 0.58393273, -2.54944833,  1.3207072 ,  0.4929906 ],
       [ 0.29181077,  0.24600015, -0.88524769,  0.1694354 ],
       [-1.29550423, -0.67156125,  0.04152137,  0.6270823 ]])

arr.mean()
Out: -0.27922950905899768

np.mean(arr)
Out: -0.27922950905899768

arr.sum()
Out: -5.5845901811799532

np.sum(arr)
Out: -5.5845901811799532

像 mean 和 sun 函数可以有一个可选的 axis参数,它对给定坐标轴进行统计,结果数组将会减少一个维度:

arr.mean(axis=1)
Out[84]: array([-0.37981139, -0.60926591, -0.03795445, -0.04450034, -0.32461545])
arr.sum(0)
Out[86]: array([ 1.46102209, -5.74817217, -1.35331736,  0.05587727])

像 cumsum 和 cumprod 这些函数并不聚集,而是产生一个中间结果组成的数组:

arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
arr.cumsum(axis=0)
Out: 
array([[ 0,  1,  2],
       [ 3,  5,  7],
       [ 9, 12, 15]])
arr.cumprod(axis=0)
Out: 
array([[ 0,  1,  2],
       [ 0,  4, 10],
       [ 0, 28, 80]])

数学统计方法清单

方法 描述
sum 对数组的所有或一个轴向上的元素求和。零长度的数组的和为灵。
mean 算术平均值。灵长度的数组的均值为NaN。
std, var 标准差和方差,有可选的调整自由度(默认值为n)。
min, max 最大值和最小值
argmin, argmax 索引最小和最大元素。
cumsum 从0元素开始的累计和。
cumprod 从1元素开始的累计乘。

用于布尔型数组的方法

在上面的方法中,布尔值被强制为1( True )和0a( False )。因此, sum 经常被用来作为对一个布尔数组中的 True 计数的手段:

arr = randn(100)
(arr > 0).sum() # 正值的个数
Out: 44

有两个额外的方法, any 和 all ,对布尔数组尤其有用。 any 用来测试一个数组中是否有一个或更多的 True ,而 all 用来测试所有的值是否为 True :

bools = np.array([False, False, True, False])
bools.any()
Out: True
bools.all()
Out: False

==这些方法这些方法也可以工作在非布尔型数组上,非零元素作为 True 。==

排序

arr.sort(axis=None)会就地排序修改数组本身,而np.sort(arr,axis=None)返回的是数组的已排序数组。计算数组分位数最简单的方法是对其进行排序,然后选取特定位置的值:

large_arr = randn(1000)
large_arr.sort()
large_arr[int(0.05 * len(large_arr))] # 5% 分位点
Out: -1.5791023260896004

唯一化以及其他的集合逻辑

Numpy有一些基本的针对一维ndarrays的集合操作。最常使用的一个可能是 np.unique ,它返回一个数组的经过排序的 unique 值:

names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
np.unique(names)
Out:
array(['Bob', 'Joe', 'Will'],
      dtype='|S4')
ints = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4])
np.unique(ints)
Out: array([1, 2, 3, 4])

另一个函数 np.in1d 用于测试一个数组中的值在另一个数组中的成员资格,返回一个布尔型数组:

values = np.array([6, 0, 0, 3, 2, 5, 6])
np.in1d(values, [2, 3, 6])
Out: array([ True, False, False, True, True, False, True], dtype=bool)
函数 说明
unique(x) 计算x单一的元素,并对结果排序
intersect1d(x, y) 计算x和y相同的元素,并对结果排序
union1d 结合x和y的元素,并对结果排序
in1d(x, y) 得到一个布尔数组指示x中的每个元素是否在y中
setdiff1d(x, y) 差集,在x中但不再y中的集合
setxor1d(x, y) 对称差集,不同时在两个数组中的元素

用于数组的文件输入输出

NumPy 能够保存数据到磁盘和从磁盘加载数据,不论数据是文本或二进制的。

将数组以二进制格式保存到磁盘

np.save 和 np.load 是两个主力功能,有效的保存和加载磁盘数据。数组默认保存为未经过压缩的原始二进制数据,文件扩展名为 .npy :

arr = np.arange(10)
np.save('some_array', arr)

如果文件路进并不是以 .npy 结尾,扩展名将会被自动加上。在磁盘上的数组可以使用 np.load 加载:

np.load('some_array.npy')
Out: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

可以使用 np.savez 并以关键字参数传递数组来保存多个数组到一个zip的归档文件中:

np.savez('array_archive.npz', a=arr, b=arr)

加载一个 .npz 文件时,会得到一个字典对象,该对象会对各个数组进行延时加载:

arch = np.load('array_archive.npz')
arch['b']
Out: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

存取文本文件

从文件加载文本是一个相当标准的任务。对一个新人来说,Python的文件加读取和写入函数的景象可能有一点儿混乱,因此我将主要集中在pandas的 read_csv 和 read_table 函数上。有时使用 np.loadtxt 或更专门的 np.genfromtxt 对于加载数据到普通的 NumPy 数组是很有用的。

# Windows下用type
!cat array_ex.txt
0.580052,0.186730,1.040717,1.134411
0.194163,-0.636917,-0.938659,0.124094
-0.126410,0.268607,-0.695724,0.047428
-1.484413,0.004176,-0.744203,0.005487
2.302869,0.200131,1.670238,-1.881090
-0.193230,1.047233,0.482803,0.960334

# 直接将文件加载到一个二维数组中
arr = np.loadtxt('array_ex.txt', delimiter=',')
arr
Out:
array([[ 0.5801, 0.1867, 1.0407, 1.1344],
[ 0.1942, -0.6369, -0.9387, 0.1241],
[-0.1264, 0.2686, -0.6957, 0.0474],
[-1.4844, 0.0042, -0.7442, 0.0055],
[ 2.3029, 0.2001, 1.6702, -1.8811],
[-0.1932, 1.0472, 0.4828, 0.9603]])

np.savatxt 执行相反的操作:将数组写到以某种分隔符隔开的文本文件中。 genfromtxt 与 loadtxt 相似,但是它是面向结构数组和缺失数据处理的。

线性代数

dot 函数,是数组的一个方法和 numpy 命名空间中的一个函数,用来进行矩阵乘法运算:

x = np.array([[1., 2., 3.], [4., 5., 6.]])
In [195]: y = np.array([[6., 23.], [-1, 7], [8, 9]])

x.dot(y) # 等价于 np.dot(x, y)
Out:
array([[ 28., 64.],
       [ 67., 181.]])

numpy.linalg 有一个关于矩阵分解和像转置和行列式等的一个标准集合。

from numpy.linalg import inv, qr

常见numpy.linalg

函数 描述
diag 返回一个方阵的对角线(或非对角线)元素为一个一维数组,或者转换一个一维数组到一个方阵(非对角线元素为零)
dot 矩阵乘积
trace 计算对角线上元素的和
det 计算矩阵行列式
eig 计算方阵的特征值和特征向量
inv 计算方阵的逆
pinv 计算方阵 Moore-Penrose 伪逆
qr 计算 QR 分解
svd 计算奇异值分解(SVD)
solve 求解线性系统方程 Ax = b 的x,其中A是一个方阵
lstsq 计算 y = Xb 的最小二乘解

随机数生成

numpy.random 模块对 Python 内置的 random 进行了补充,增加了一些用于高效生成多种概率分布的样本值得函数。

numpy.random 函数

函数 说明
seed 确定随机数生成数的种子
permutation 返回一个序列的随机排列或返回一个随机排列的范围
shuffle 对一个序列就地随机排列
rand 产生均匀分布的样本值
randint 从给定的上下限范围内(不包括上限)随机选取整数
randn 产生标准正态分布的样本值
binomial 产生二项分布的样本值
normal 产生正态(高斯)分布的样本值
beta 产生Beta分布的样本值
chisquare 产生卡方分布的样本值
gamma 产生Gamma分布的样本值
uniform 产生在[0,1]中均匀分布的样本值

模拟随机漫步

多个随机漫步

nwalks = 5000
nsteps = 1000
draws = np.random.randint(0, 2, size=(nwalks, nsteps)) # 0 or 1
steps = np.where(draws > 0, 1, -1)
walks = steps.cumsum(1)
walks
Out:
array([[ 1, 0, 1, ..., 8, 7, 8],
       [ 1, 0, -1, ..., 34, 33, 32],
       [ 1, 0, -1, ..., 4, 5, 4],
       ...,
       [ 1, 2, 1, ..., 24, 25, 26],
       [ 1, 2, 3, ..., 14, 13, 14],
       [ -1, -2, -3, ..., -24, -23, -22]])

# 我们可以获得所有游走的最大和最小值     
walks.max() In [229]: walks.min()
Out: 138 Out[229]: -133

# 在这些游走中,让我们来计算到达30或-30的最短时间。这有一点儿狡猾,
# 因为不是所有的5000个游走都能到达30。我们可以使用 any 方法来检测
hits30 = (np.abs(walks) >= 30).any(1)
hits30
Out: array([False, True, False, ..., False, True, False], dtype=bool)
hits30.sum() # 30或-30的个数
Out: 3410

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

推荐阅读更多精彩内容