numpy 基础:数组和矢量运算
xiaoyao
NumPy是在⼀个连续的内存块中存储数据,独⽴于其他Python内置对象。NumPy的C语⾔编写的算法库可以操作内存,⽽不必进⾏类型检查或其它前期⼯作。⽐起Python的内置序列,NumPy数组使⽤的内存更少。NumPy可以在整个数组上执⾏复杂的计算,⽽不需要Python的for循环。
# 导入packages
import numpy as np
np.random.seed(12345)
import matplotlib.pyplot as plt
plt.rc('figure', figsize=(10, 6))
np.set_printoptions(precision=4, suppress=True)
import warnings
warnings.filterwarnings('ignore')
# 为了显示出性能的差异,这里建立一个包含一百万整数的数组,以及一个等价的python列表
import numpy as np
my_arr = np.arange(1000000)
my_list = list(range(1000000))
# my_arr, my_list
%time for _ in range(10): my_arr2 = my_arr * 2
%time for _ in range(10): my_list2 = [x * 2 for x in my_list]
# 各个序列分别乘以2
Wall time: 19.5 ms
Wall time: 737 ms
可以看到,基于numpy的算法,实际上比纯python块10到100倍数,甚至更快,而且使用的内存更少
ndarray:一种多维数组对象
ndarray对象是一个快速而灵活的大数据集容器,可以利用这种数组对整块数据执行一些数学运算,语法和标量元素之间的运算一样。ndarray是一个通用的同构数据多维容器,即:其中的所有元素类型相同。每个数组都有一个shape和一个dtype对象
import numpy as np
# Generate some random data
data = np.random.randn(2, 3) # 产生数据的维度,非负
data
array([[ 0.0929, 0.2817, 0.769 ],
[ 1.2464, 1.0072, -1.2962]])
# 执行数学运算,作用到元素级别
data + data
array([[ 0.1858, 0.5635, 1.538 ],
[ 2.4929, 2.0144, -2.5924]])
data * 10
array([[ 0.9291, 2.8175, 7.6902],
[ 12.4643, 10.0719, -12.9622]])
print(data.shape,
data.dtype)
(2, 3) float64
创建ndarray
最简单的方法是使用array函数。它接受一切序列型的对象(包括其他数组),然后产生一个新的含有传入数据的Numpy数组
# 从列表创建ndarray
data1 = [6, 7.5, 8, 0, 1]
arr1 = np.array(data1)
arr1
array([6. , 7.5, 8. , 0. , 1. ])
arr1.dtype
dtype('float64')
# 转换生成一个多维数组
data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
arr2 = np.array(data2)
arr2
array([[1, 2, 3, 4],
[5, 6, 7, 8]])
# data2是列表的列表,numpy数组arr2的两个维度的shape是从data2引入的。可以使用ndim属性和shape属性加以验证
print(arr2.ndim,
arr2.shape)
2 (2, 4)
# np.array会尝试为新建的数组推断出一个较为合适的数据类型。数据类型保存在一个特殊的dtype对象中。
print(arr1.dtype,
arr2.dtype)
float64 int32
# zeros和ones分别可以创建指定长度或者形状的全0或者全1的数组。empty可以创建一个没有任何具体值的数组
print(np.zeros(10,),
np.zeros((3, 6)),
np.empty((2, 3, 2)))
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [[0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0.]] [[[1.0947e-311 2.4703e-322]
[0.0000e+000 0.0000e+000]
[0.0000e+000 1.3137e-076]]
[[5.2737e-091 1.2796e+161]
[9.9884e-048 9.1533e-071]
[3.9991e+252 1.4645e-075]]]
np.empty会返回全0的数组的说法是不安全的。很多情况下,他返回的都是一些未初始化的垃圾值
# arange是python内置函数range的数组版
np.arange(15)
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
函数 | 说明 |
---|---|
array | 将输入数据(元组,列表,数组或者其他序列类型)转换为ndarray.要么推断出dtype,要么特别指定dtype.默认直接复制输入数据 |
asarray | 将输入转换为ndarray,若输入本身就是一个ndarray,就不进行复制 |
arange | 类似于内置的range,但返回的是一个ndarray, |
ones,ones_like | 创建全1数组/以另一个数组为参数,根据其形状和dtype创建一个全1数组 |
zeros,zeros_like | 类似于ones,ones_like,这里产生的是全0数组 |
empty,empty_like | 创建新数组,只分配内存空间但不填充任何值 |
full, full_like | 使用fill value中的所有值,根据指定的形状和dtype创建一个数组。full_like使用另一个数组,用相同的形状和dtype |
eye, identity | 创建一个单位阵,方针 |
ndarray的数据类型
arr1 = np.array([1, 2, 3], dtype=np.float64)
arr2 = np.array([1, 2, 3], dtype=np.int32)
print(arr1.dtype,
arr2.dtype)
float64 int32
# 可以通过ndarray的astype方法明确的将一个数组从一个dtype转换成另一个dtype
arr = np.array([1, 2, 3, 4, 5])
arr.dtype
dtype('int32')
float_arr = arr.astype(np.float64)
float_arr.dtype
dtype('float64')
float_arr
array([1., 2., 3., 4., 5.])
# 将浮点数转换成整数,小数部分将会被截取删除,这里没有进行四舍五入
arr = np.array([3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
print(arr)
arr.astype(np.int32)
[ 3.7 -1.2 -2.6 0.5 12.9 10.1]
array([ 3, -1, -2, 0, 12, 10])
# 如果某字符串数组表示的内容全都是数字,也可以使用astype将其转换为数值形式
numeric_strings = np.array(['1.25', '-9.6', '42'], dtype=np.string_)
numeric_strings.astype(float)
array([ 1.25, -9.6 , 42. ])
numeric_strings.dtype
dtype('S4')
使用np.string_的时候要小心,因为Numpy的字符串数据是大小固定的,发生截取的时候,不会发出警告
int_array = np.arange(10)
calibers = np.array([.22, .270, .357, .380, .44, .50], dtype=np.float64)
int_array.astype(calibers.dtype)
array([0., 1., 2., 3., 4., 5., 6., 7., 8., 9.])
empty_uint32 = np.empty(8, dtype='u4')
empty_uint32
array([ 0, 1075314688, 0, 1075707904, 0,
1075838976, 0, 1072693248], dtype=uint32)
调用astype总会创建一个新的数组,即使他们之间的dtype相同
numpy数组的运算
矢量化:不用写循环就可以对数据执行批量运算
arr = np.array([[1., 2., 3.], [4., 5., 6.]])
arr
array([[1., 2., 3.],
[4., 5., 6.]])
print(arr * arr,'\n',
arr - arr)
[[ 1. 4. 9.]
[16. 25. 36.]]
[[0. 0. 0.]
[0. 0. 0.]]
print(1 / arr,'\n',
arr ** 0.5)
[[1. 0.5 0.3333]
[0.25 0.2 0.1667]]
[[1. 1.4142 1.7321]
[2. 2.2361 2.4495]]
# 大小相同的数组之间的比较会产生布尔值数组, 大小不同的数组之间的运算叫做广播
arr2 = np.array([[0., 4., 1.], [7., 2., 12.]])
print(arr2)
print(arr2 > arr)
[[ 0. 4. 1.]
[ 7. 2. 12.]]
[[False True False]
[ True False True]]
切片和索引
arr = np.arange(10)
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
与列表不同,数组切片是原始数组的视图,意味着数据不会被复制,因此视图上的任何修改都会直接反映到源数组上
print(arr[5],
arr[5:8])
arr[5:8] = 12
arr
5 [5 6 7]
array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
arr_slice = arr[5:8]
arr_slice
array([12, 12, 12])
arr_slice[1] = 12345
arr
array([ 0, 1, 2, 3, 4, 12, 12345, 12, 8,
9])
arr_slice[:] = 64
arr
array([ 0, 1, 2, 3, 4, 64, 64, 64, 8, 9])
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr2d[2]
array([7, 8, 9])
print(arr2d[0][2], # 两种形式是等价的
arr2d[0, 2])
3 3
# 三维数组,
arr3d = np.array([[[1, 2, 3], [4, 5, 6]],
[[7, 8, 9], [10, 11, 12]]])
arr3d
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
arr3d.shape
(2, 2, 3)
arr3d[0]
array([[1, 2, 3],
[4, 5, 6]])
old_values = arr3d[0].copy()
arr3d[0] = 42
arr3d
array([[[42, 42, 42],
[42, 42, 42]],
[[ 7, 8, 9],
[10, 11, 12]]])
arr3d[0] = old_values
arr3d
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
arr3d[1, 0] # 访问索引以(1, 0)开头的值
array([7, 8, 9])
# 和上面的等价,实际上,先放为第二个(下标1)元素,再访问其中的第一个(下标0)元素
x = arr3d[1]
print(x,
x[0])
[[ 7 8 9]
[10 11 12]] [7 8 9]
切片索引
print(arr,
arr[1:6])
[ 0 1 2 3 4 64 64 64 8 9] [ 1 2 3 4 64]
print(arr2d,'\n',
arr2d[:2])
[[1 2 3]
[4 5 6]
[7 8 9]]
[[1 2 3]
[4 5 6]]
arr2d[:2, 1:]
array([[2, 3],
[5, 6]])
arr2d[1, :2]
array([4, 5])
arr2d[:2, 2]
array([3, 6])
arr2d[:, :1]
array([[1],
[4],
[7]])
arr2d[:2, 1:] = 0
arr2d
array([[1, 0, 0],
[4, 0, 0],
[7, 8, 9]])
布尔型索引Boolean Indexing
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
data = np.random.randn(7, 4)
print(names,'\n',
data)
['Bob' 'Joe' 'Will' 'Bob' 'Will' 'Joe' 'Joe']
[[-0.6525 -1.2183 -1.3326 1.0746]
[ 0.7236 0.69 1.0015 -0.5031]
[-0.6223 -0.9212 -0.7262 0.2229]
[ 0.0513 -1.1577 0.8167 0.4336]
[ 1.0107 1.8249 -0.9975 0.8506]
[-0.1316 0.9124 0.1882 2.1695]
[-0.1149 2.0037 0.0296 0.7953]]
names == 'Bob'
array([ True, False, False, True, False, False, False])
# 上述布尔型数组可以用于数组索引
data[names == 'Bob']
array([[-0.6525, -1.2183, -1.3326, 1.0746],
[ 0.0513, -1.1577, 0.8167, 0.4336]])
print(data[names == 'Bob', 2:],'\n',
data[names == 'Bob', 3])
[[-1.3326 1.0746]
[ 0.8167 0.4336]]
[1.0746 0.4336]
print(names != 'Bob')
data[~(names == 'Bob')]
[False True True False True True True]
array([[ 0.7236, 0.69 , 1.0015, -0.5031],
[-0.6223, -0.9212, -0.7262, 0.2229],
[ 1.0107, 1.8249, -0.9975, 0.8506],
[-0.1316, 0.9124, 0.1882, 2.1695],
[-0.1149, 2.0037, 0.0296, 0.7953]])
cond = names == 'Bob'
cond
array([ True, False, False, True, False, False, False])
data[~cond]
array([[ 0.7236, 0.69 , 1.0015, -0.5031],
[-0.6223, -0.9212, -0.7262, 0.2229],
[ 1.0107, 1.8249, -0.9975, 0.8506],
[-0.1316, 0.9124, 0.1882, 2.1695],
[-0.1149, 2.0037, 0.0296, 0.7953]])
mask = (names == 'Bob') | (names == 'Will')
mask
array([ True, False, True, True, True, False, False])
data
array([[-0.6525, -1.2183, -1.3326, 1.0746],
[ 0.7236, 0.69 , 1.0015, -0.5031],
[-0.6223, -0.9212, -0.7262, 0.2229],
[ 0.0513, -1.1577, 0.8167, 0.4336],
[ 1.0107, 1.8249, -0.9975, 0.8506],
[-0.1316, 0.9124, 0.1882, 2.1695],
[-0.1149, 2.0037, 0.0296, 0.7953]])
data[mask]
array([[-0.6525, -1.2183, -1.3326, 1.0746],
[-0.6223, -0.9212, -0.7262, 0.2229],
[ 0.0513, -1.1577, 0.8167, 0.4336],
[ 1.0107, 1.8249, -0.9975, 0.8506]])
data[data < 0] = 0
data
array([[0. , 0. , 0. , 1.0746],
[0.7236, 0.69 , 1.0015, 0. ],
[0. , 0. , 0. , 0.2229],
[0.0513, 0. , 0.8167, 0.4336],
[1.0107, 1.8249, 0. , 0.8506],
[0. , 0.9124, 0.1882, 2.1695],
[0. , 2.0037, 0.0296, 0.7953]])
data[names != 'Joe'] = 7
data
array([[7. , 7. , 7. , 7. ],
[0.7236, 0.69 , 1.0015, 0. ],
[7. , 7. , 7. , 7. ],
[7. , 7. , 7. , 7. ],
[7. , 7. , 7. , 7. ],
[0. , 0.9124, 0.1882, 2.1695],
[0. , 2.0037, 0.0296, 0.7953]])
花式索引–利用整数数组进行索引
arr = np.empty((8, 4))
for i in range(8):
arr[i] = i
arr
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]] # 整数数组作为索引
array([[4., 4., 4., 4.],
[3., 3., 3., 3.],
[0., 0., 0., 0.],
[6., 6., 6., 6.]])
arr[[-3, -5, -7]]
array([[5., 5., 5., 5.],
[3., 3., 3., 3.],
[1., 1., 1., 1.]])
arr = np.arange(32).reshape((8, 4))
arr
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]]
array([ 4, 23, 29, 10])
上面返回的是:(1, 0), (5, 3), (7, 1), (2, 2)
arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]] # 先找出下标为1, 5, 7, 2的行,然后对所有的行,选出0, 3, 1, 2对应的列
array([[ 4, 7, 5, 6],
[20, 23, 21, 22],
[28, 31, 29, 30],
[ 8, 11, 9, 10]])
数组转置和轴对换
arr = np.arange(15).reshape((3, 5))
arr
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
arr.T
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])
arr = np.random.randn(6, 3)
arr
array([[ 0.1181, -0.7485, 0.585 ],
[ 0.1527, -1.5657, -0.5625],
[-0.0327, -0.929 , -0.4826],
[-0.0363, 1.0954, 0.9809],
[-0.5895, 1.5817, -0.5287],
[ 0.457 , 0.93 , -1.5693]])
arr.T
array([[ 0.1181, 0.1527, -0.0327, -0.0363, -0.5895, 0.457 ],
[-0.7485, -1.5657, -0.929 , 1.0954, 1.5817, 0.93 ],
[ 0.585 , -0.5625, -0.4826, 0.9809, -0.5287, -1.5693]])
# 利用np.dot计算矩阵的内积
np.dot(arr.T, arr)
array([[ 0.596 , -0.8442, -0.4421],
[-0.8442, 8.4411, -0.33 ],
[-0.4421, -0.33 , 4.5959]])
arr = np.arange(16).reshape((2, 2, 4))
arr
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
# 这里第一个轴北换成了第二个,第二个轴被换成了第一个,最后一个轴不变
arr.transpose((1, 0, 2))
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15]]])
arr.T
array([[[ 0, 8],
[ 4, 12]],
[[ 1, 9],
[ 5, 13]],
[[ 2, 10],
[ 6, 14]],
[[ 3, 11],
[ 7, 15]]])
print(arr,'\n',
arr.swapaxes(1, 2))
[[[ 0 1 2 3]
[ 4 5 6 7]]
[[ 8 9 10 11]
[12 13 14 15]]]
[[[ 0 4]
[ 1 5]
[ 2 6]
[ 3 7]]
[[ 8 12]
[ 9 13]
[10 14]
[11 15]]]
arr.swapaxes(0, 1)
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15]]])
通用函数:快速的元素级数组函数
arr = np.arange(10)
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
print(np.sqrt(arr),'\n',
np.exp(arr))
[0. 1. 1.4142 1.7321 2. 2.2361 2.4495 2.6458 2.8284 3. ]
[ 1. 2.7183 7.3891 20.0855 54.5982 148.4132 403.4288
1096.6332 2980.958 8103.0839]
x = np.random.randn(8)
y = np.random.randn(8)
print(x,
y,
np.maximum(x, y)) # np.maxinum计算了x和y中元素级别最大的元素
[-1.0225 -0.4028 0.2205 -0.1934 0.6692 -1.649 -2.2528 -1.1668] [ 0.3536 0.7021 -0.2746 -0.1391 0.1077 -0.6065 -0.4171 -0.017 ] [ 0.3536 0.7021 0.2205 -0.1391 0.6692 -0.6065 -0.4171 -0.017 ]
arr = np.random.randn(7) * 5
arr
array([-6.1207, -9.0042, 8.1737, 4.945 , 2.2897, 2.7758, 6.5336])
# modf就是:python内置函数divmod的矢量化版本,他会返回浮点数数组的小数和整数部分
remainder, whole_part = np.modf(arr)
print(remainder,
whole_part)
[-0.1207 -0.0042 0.1737 0.945 0.2897 0.7758 0.5336] [-6. -9. 8. 4. 2. 2. 6.]
print(arr)
np.sqrt(arr)
[-6.1207 -9.0042 8.1737 4.945 2.2897 2.7758 6.5336]
array([ nan, nan, 2.859 , 2.2237, 1.5132, 1.6661, 2.5561])
# ufuncs接受out选项参数,可以让其再数组的原地进行操作,
print(np.sqrt(arr, arr))
arr
[ nan nan 2.859 2.2237 1.5132 1.6661 2.5561]
array([ nan, nan, 2.859 , 2.2237, 1.5132, 1.6661, 2.5561])
利用数组进行数据处理
利用数组表达式代替循环的做法,通常被称为矢量化,矢量化数组运算要比等价的纯python方式快几个数量级
points = np.arange(-5, 5, 0.01) # 1000 equally spaced points
# np.meshgrid函数接受两个一维数组,并产生两个二维矩阵,对应于两个数组中所有的(x, y)对
xs, ys = np.meshgrid(points, points)
ys
array([[-5. , -5. , -5. , ..., -5. , -5. , -5. ],
[-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99],
[-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98],
...,
[ 4.97, 4.97, 4.97, ..., 4.97, 4.97, 4.97],
[ 4.98, 4.98, 4.98, ..., 4.98, 4.98, 4.98],
[ 4.99, 4.99, 4.99, ..., 4.99, 4.99, 4.99]])
z = np.sqrt(xs ** 2 + ys ** 2)
z
array([[7.0711, 7.064 , 7.0569, ..., 7.0499, 7.0569, 7.064 ],
[7.064 , 7.0569, 7.0499, ..., 7.0428, 7.0499, 7.0569],
[7.0569, 7.0499, 7.0428, ..., 7.0357, 7.0428, 7.0499],
...,
[7.0499, 7.0428, 7.0357, ..., 7.0286, 7.0357, 7.0428],
[7.0569, 7.0499, 7.0428, ..., 7.0357, 7.0428, 7.0499],
[7.064 , 7.0569, 7.0499, ..., 7.0428, 7.0499, 7.0569]])
# 利用matplotlib创建此二维数组的可视化
import matplotlib.pyplot as plt
plt.imshow(z, cmap=plt.cm.gray); plt.colorbar()
plt.title("Image plot of $\sqrt{x^2 + y^2}$ for a grid of values")
Text(0.5, 1.0, 'Image plot of $\\sqrt{x^2 + y^2}$ for a grid of values')
plt.draw()
<Figure size 720x432 with 0 Axes>
plt.close('all')
将条件逻辑表述为数组运算
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])
根据cond中的值选取xarr和yarr的值,当cond中的值为True,选取xarr,否则选取yarr
result = [(x if c else y)
for x, y, c in zip(xarr, yarr, cond)]
result
[1.1, 2.2, 1.3, 1.4, 2.5]
上述的问题就是:对大数组的处理速度不是很快,且无法用到多维数组之上。可以优化使用为:np.where
mp.where函数是三元表达式 x if condition else y 的矢量化版本
result = np.where(cond, xarr, yarr)
result
array([1.1, 2.2, 1.3, 1.4, 2.5])
arr = np.random.randn(4, 4)
arr
arr > 0
array([[False, False, True, False],
[ True, True, False, True],
[False, False, False, True],
[ True, False, True, False]])
arr
array([[-0.4406, -0.3014, 0.4988, -0.824 ],
[ 1.3206, 0.508 , -0.6534, 0.187 ],
[-0.3917, -0.2723, -0.0171, 0.6803],
[ 0.6355, -0.7572, 0.7181, -0.3043]])
# 将所有正值替换为2, 将所有负值替换为-2
np.where(arr > 0, 2, -2)
array([[-2, -2, 2, -2],
[ 2, 2, -2, 2],
[-2, -2, -2, 2],
[ 2, -2, 2, -2]])
# 仅仅替换其中的正值
np.where(arr > 0, 2, arr) # set only positive values to 2
array([[-0.4406, -0.3014, 2. , -0.824 ],
[ 2. , 2. , -0.6534, 2. ],
[-0.3917, -0.2723, -0.0171, 2. ],
[ 2. , -0.7572, 2. , -0.3043]])
数学和统计方法
arr = np.random.randn(5, 4)
arr
array([[-1.6778, 0.427 , -1.5637, -0.3675],
[ 1.0459, 1.22 , -0.2477, -0.4162],
[-0.1167, -1.8448, 2.0687, -0.777 ],
[ 1.4402, -0.1106, 1.2274, 1.9208],
[ 0.7464, 2.2247, -0.6794, 0.7274]])
print(arr.mean(),'\n',
np.mean(arr),'\n',
arr.sum())
0.2623475822569136
0.2623475822569136
5.246951645138273
arr.mean(axis=1) # 行的均值
# arr.sum(axis=0) # 列的均值
array([-0.7955, 0.4005, -0.1674, 1.1194, 0.7548])
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])
arr.cumsum()
array([ 0, 1, 3, 6, 10, 15, 21, 28], dtype=int32)
其他如cumsum和cumprod之类的⽅法则不聚合,⽽是产⽣⼀个
由中间结果组成的数组:
arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
arr
# arr.cumsum(axis=0)
# arr.cumprod(axis=1)
array([[ 0, 1, 2],
[ 3, 5, 7],
[ 9, 12, 15]], dtype=int32)
用于布尔型数组的方法
arr = np.random.randn(100)
(arr > 0).sum() # Number of positive values
40
any用于统计数组中是否存在一个或者多个True,而all则检查数组中所有的值是否都是True
bools = np.array([False, False, True, False])
bools.any()
bools.all()
False
排序
arr = np.random.randn(6)
arr
arr.sort()
arr
arr = np.random.randn(5, 3)
arr
arr.sort(1)
arr
large_arr = np.random.randn(1000)
large_arr.sort()
large_arr[int(0.05 * len(large_arr))] # 5% quantile
唯一化以及其他的集合逻辑
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
np.unique(names)
ints = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4])
np.unique(ints)
sorted(set(names))
values = np.array([6, 0, 0, 3, 2, 5, 6])
np.in1d(values, [2, 3, 6])
用于数组的文件输入输出
arr = np.arange(10)
np.save('some_array', arr)
np.load('some_array.npy')
np.savez('array_archive.npz', a=arr, b=arr)
arch = np.load('array_archive.npz')
arch['b']
np.savez_compressed('arrays_compressed.npz', a=arr, b=arr)
!rm some_array.npy
!rm array_archive.npz
!rm arrays_compressed.npz
线性代数
x = np.array([[1., 2., 3.], [4., 5., 6.]])
y = np.array([[6., 23.], [-1, 7], [8, 9]])
x
y
x.dot(y)
np.dot(x, y)
np.dot(x, np.ones(3))
x @ np.ones(3)
from numpy.linalg import inv, qr
X = np.random.randn(5, 5)
mat = X.T.dot(X)
inv(mat)
mat.dot(inv(mat))
q, r = qr(mat)
r
伪随机数生成
samples = np.random.normal(size=(4, 4))
samples
from random import normalvariate
N = 1000000
%timeit samples = [normalvariate(0, 1) for _ in range(N)]
%timeit np.random.normal(size=N)
np.random.seed(1234)
rng = np.random.RandomState(1234)
rng.randn(10)
随机漫步
import random
position = 0
walk = [position]
steps = 1000
for i in range(steps):
step = 1 if random.randint(0, 1) else -1
position += step
walk.append(position)
plt.figure()
plt.plot(walk[:100])
np.random.seed(12345)
nsteps = 1000
draws = np.random.randint(0, 2, size=nsteps)
steps = np.where(draws > 0, 1, -1)
walk = steps.cumsum()
walk.min()
walk.max()
(np.abs(walk) >= 10).argmax()
一次模拟多个随机漫步
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
walks.max()
walks.min()
hits30 = (np.abs(walks) >= 30).any(1)
hits30
hits30.sum() # Number that hit 30 or -30
crossing_times = (np.abs(walks[hits30]) >= 30).argmax(1)
crossing_times.mean()
steps = np.random.normal(loc=0, scale=0.25,
size=(nwalks, nsteps))