Numpy速通笔记

Numpy可以高效处理大数组的数据,因为:

  1. Numpy在一个连续的内存块中存储数据,独立于其他Python内置对象。Numpy是C写的,有优化,比Python内置序列使用的内存少
  2. 可以在整个数组上进行复杂运算,不需要for循环
    下面的代码可以看出,同样的数据量,numpy比原生list快几十倍。
import numpy as np
import time

my_arr = np.arange(1000000)
my_list = list(range(1000000))
start = time.time()
for _ in range(10):
    my_arr = my_arr * 2
end = time.time()
print(end-start) # 0.014997482299804688
start = time.time()
for _ in range(10):
    my_list = [x * 2 for x in my_list]
end = time.time()
print(end-start) # 0.7048995494842529

ndarray

ndarray = n + d(dimension) + array,即N维数组。这个数组里所有元素都是同一类型的,用.dtype可以看到类型。

>>> import numpy as np
>>> data = np.random.randn(2, 3)
>>> print(data)
[[ 0.70162402  0.00711845  0.83315757]
 [-1.1485004   1.19954043 -0.26478855]]
>>> data.shape
(2, 3)
>>> data.dtype
dtype('float64')
print(data * 10) # 每个元素都x10
print(data + data) # 对应位置相加

创建ndarray

# 使用list创建。如果是嵌套的,说明是多维数据
>>> data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
>>> arr2 = np.array(data2)
# 也可以用np.asarray(data2),一样的效果
>>> arr2
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])
>>> arr2.ndim
2
>>> arr2.shape
(2, 4)
>>> arr2.dtype
dtype('int32')

# 创建全0数组。创建时需要输入每个维度上的size,多维度的时候要用元组
>>> np.zeros(5)
array([0., 0., 0., 0., 0.])
# 仿照对象的维度创造全0数组
np.zeros_like(对象)

# 创建全1数组
>>> np.ones((2,3))
array([[1., 1., 1.],
       [1., 1., 1.]])
# 仿照对象的维度创造全1数组
>>> np.ones_like(data2)
array([[1, 1, 1, 1],
       [1, 1, 1, 1]])

# empty创建的是没有值的数组,只是分配空间。empty_like()同理
>>> np.empty((2, 3, 1))
array([[[1.],
        [1.],
        [1.]],

       [[1.],
        [1.],
        [1.]]])

# 使用指定值填充所有位置。第一个参数是维度,第二个是指定值。full_like同理
>>> np.full((2,3),4)
array([[4, 4, 4],
       [4, 4, 4]])
>>> np.full_like(data2, 4)
array([[4, 4, 4, 4],
       [4, 4, 4, 4]])
       
# eye和identity都是创造NxN单位矩阵(对角线是1,其余是0)
>>> np.eye(3)
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])
>>> np.identity(3)
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

# np.arange是range的np版,但是返回的是一个ndarray
>>> np.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

# 使用astype可以修改数据类型
>>> arr2.astype(np.float32)
array([[1., 2., 3., 4.],
       [5., 6., 7., 8.]], dtype=float32)

数组运算

大小相等的ndarray之间的任何算术运算都是应用到元素级的,即一一对应操作。比如两个ndarray加减乘除和比较(对应为位置返回True/False)

ndarray与标量之间的算术运算也是元素级的,比如1/arr就是每个元素被1除,arr ** 0.5就是每个元素开方。

通用函数ufunc

就是对ndarray中数据执行元素级运算的函数

ufunc有一个可选参数out,所以可以将out写为ndarray的名字,以实现原地操作。比如 np.sqrt(arr, arr)

np.modf会返回浮点数组的小数和整数部分

>>> arr = np.random.randn(7) * 5
>>> arr
array([ 2.89470277, -7.35643986,  8.69725165, 11.98482889, -6.53072422,
       -3.27780558,  4.71749496])
>>> remainder, whole_part = np.modf(arr)
>>> remainder
array([ 0.89470277, -0.35643986,  0.69725165,  0.98482889, -0.53072422,
       -0.27780558,  0.71749496])
>>> whole_part
array([ 2., -7.,  8., 11., -6., -3.,  4.])

abs/fabs:计算绝对值。对于非复数,使用fabs更快
square/sqrt:平方与开方。开方的时候复数对象会产出nan,报warning但继续执行
exp、log、log10、log2、log1p:最后一个是log(1+x),log是以e为底
sign:计算每个元素的符号,1,0,-1
ceil/floor
rint:四舍五入到最近的整数
isnan:判断是不是nan,返回bool数组,同理isfinite isinf
cos、cosh、sin、sinh、tan、tanh、arccos、arccosh、arcsin、arcsinh、arctan、arctanh

二元:
add、subtract、multiply、divide、floor_divide、power、maximum、fmax(取最大值,但是忽略NaN)、minimum、fmin(取最小只,忽略NaN)、mod、copysign(将第二个数组的符号复制给第一个数组)、greater/greater_equal/less/less_equal/equal/not_equal、logical_and、logical_or、logical_xor

索引与切片

index和切片跟原生List类似,不同的是,切片是“引用”,修改切片会影响到原来的值。如果切片时需要得到副本,应该用arr[5:8].copy()。
默认是引用是因为复制需要消耗内存,而Numpy经常要处理大量的数据,显然复制的消耗太大了。

>>> arr = np.arange(10)
>>> arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> arr[5:8]
array([5, 6, 7])
# 使用单一值赋值切片时会“广播”
>>> arr[5:8] = 12
>>> arr
array([ 0,  1,  2,  3,  4, 12, 12, 12,  8,  9])
# 再取一个切片
>>> d = arr[0:1]
>>> d
array([0])
# 对切片中某个位置赋值
>>> d[0] = -1
# 直接影响原数组,说明是引用
>>> arr
array([-1,  1,  2,  3,  4, 12, 12, 12,  8,  9])

# 二维数组
>>> arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> arr2d[0][2]
3
>>> arr2d[0,2]
3
# 可以一次传入多个切片
>>> arr2d[:2, 1:]
array([[2, 3],
       [5, 6]])

# 如果是用列表切片,表示切特定行
>>> arr2d[[0,2]]
array([[1, 2, 3],
       [7, 8, 9]])
# 如果传入多个列表,就按维度切:
>>> arr2d[[0,2], [0,1]]
array([1, 8])

布尔型切片

# bool切片,除了==还有!=,也可以用 ~(names == 'Bob')
>>> names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
>>> names == 'Bob'
array([ True, False, False,  True, False, False, False])
>>> data
array([[ 0.90597376,  0.48901929, -1.29117936, -0.54704399],
       [ 1.3251687 , -0.97710089,  1.18568268,  0.58076217],
       [ 0.38585117,  0.51111432, -0.36119234, -0.55018491],
       [ 1.23013959, -0.60359478, -0.84073159, -1.03601213],
       [-0.60764054, -0.17980566, -0.10172273,  0.26845593],
       [ 0.4917044 , -0.2176951 ,  0.63413077,  0.17411876],
       [-0.29955537,  0.89073944,  0.27782948,  0.85028906]])
# 可以看到是选取了为True的行作为索引
>>> data[names=='Bob', 2:]
array([[-1.29117936, -0.54704399],
       [-0.84073159, -1.03601213]])
# 可以起个名字。。
>>> cond = names == 'Bob'
>>> data[~cond]
array([[ 1.3251687 , -0.97710089,  1.18568268,  0.58076217],
       [ 0.38585117,  0.51111432, -0.36119234, -0.55018491],
       [-0.60764054, -0.17980566, -0.10172273,  0.26845593],
       [ 0.4917044 , -0.2176951 ,  0.63413077,  0.17411876],
       [-0.29955537,  0.89073944,  0.27782948,  0.85028906]])
# ~cond切的行,1再切列
>>> data[~cond, 1]
array([-0.97710089,  0.51111432, -0.17980566, -0.2176951 ,  0.89073944])
# 组合条件可以使用& |, 不能用and or
>>> mask = (names == 'Bob') | (names == 'Will')

# 将data中所有负值都设为0
>>> data[data < 0] = 0
>>> data
array([[0.90597376, 0.48901929, 0.        , 0.        ],
       [1.3251687 , 0.        , 1.18568268, 0.58076217],
       [0.38585117, 0.51111432, 0.        , 0.        ],
       [1.23013959, 0.        , 0.        , 0.        ],
       [0.        , 0.        , 0.        , 0.26845593],
       [0.4917044 , 0.        , 0.63413077, 0.17411876],
       [0.        , 0.89073944, 0.27782948, 0.85028906]])

数组转置和轴对换

二维数组的转置用arr.T,产生新的拷贝

>>> 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]])
# 或者用transpose,需要输入一个由轴编号组成的元组
# 下面表示把0轴和1轴调换,跟.T的效果一样
arr.transpose(1,0)
arr.transpose((1,0))

还可以用.swaoaxes()方法,需要输入一对轴编号。也是返回视图/引用,不会进行复制。

绘制函数图像

Numpy速通笔记_第1张图片

>>> pts = np.arange(-5,5,0.01)
>>> xs, ys = np.meshgrid(pts, pts)
>>> 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]])
>>> xs
array([[-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       ...,
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99]])
>>> z = np.sqrt(xs ** 2 + ys ** 2)
>>> import matplotlib.pyplot as plt
>>> plt.imshow(z);plt.colorbar()
<matplotlib.image.AxesImage object at 0x000001DF26F272B0>
<matplotlib.colorbar.Colorbar object at 0x000001DF2A6D8F40>
>>> plt.show()

数组运算(列表推导)

np.where(条件bool数组,正确时的取值,else时的取值)。后两个参数不一定是数组,也可以是标量值

>>> 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])
>>> np.where(cond, xarr, yarr)
array([1.1, 2.2, 1.3, 1.4, 2.5])

将数组中大于0的值替换为2,否则为-2:

 np.where(arr > 0, 2, -2)

而且,替换值也可以是ndarray,比如如果 np.where(arr > 0, 2, arr)表示,如果某个位置的数值<=0,那么该位置的值就保持不变。

统计

需要注意的是,axis=1计算的是行,axis=0计算的是列

>>> arr = np.random.randn(5, 4)
>>> arr
array([[-0.84075089, -0.75502507,  1.28231228,  0.64605601],
       [-1.0410616 , -0.98069774, -0.44841819,  0.33743376],
       [-0.20403139, -1.73880457, -1.79108436,  1.47435236],
       [-0.36401451,  0.73726505, -0.8924274 , -2.01459786],
       [ 0.26463865,  0.57256931,  0.37323712,  0.91512178]])
# 计算均值
>>> arr.mean()
-0.22339636293037574
>>> np.mean(arr)
-0.22339636293037574
# 计算总和
>>> arr.sum()
-4.4679272586075145
# 注意,axis=1是计算行的,axis=0是计算列的
>>> arr.mean(axis = 1)
array([ 0.08314808, -0.53318594, -0.56489199, -0.63344368,  0.53139172])
>>> arr.sum(axis=1)
array([ 0.33259233, -2.13274377, -2.25956796, -2.53377473,  2.12556687])
>>> arr.sum(axis=0)
array([-2.18521974, -2.16469302, -1.47638054,  1.35836604])

>>> arr = np.array([0,1,2,3,4,5,6,7])
# 计算累加
>>> arr.cumsum()
array([ 0,  1,  3,  6, 10, 15, 21, 28])
>>> arr = np.arange(9).reshape(3,3)
>>> arr
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
# 列向的累加(竖)
>>> arr.cumsum(axis=0)
array([[ 0,  1,  2],
       [ 3,  5,  7],
       [ 9, 12, 15]])
# 累乘
>>> arr.cumprod(axis=0)
array([[ 0,  1,  2],
       [ 0,  4, 10],
       [ 0, 28, 80]])

std、var、min、max、argmin(最小元素的索引)、argmax(最大元素的索引)
.any()检查是否存在True或者非0元素,.all()检查是否所有都是True或者所有都非0。
bool的True会被当成1,所以可以用sum计算True的个数:

>>> bools = np.array([False, False, True, False, True])
>>> bools.sum()
2

排序

arr.sort()是就地的,默认升序。多维的时候默认是按行,即1,如果按列用0。
np.sort()返回的是副本

>>> arr = np.random.randn(5, 3)
>>> arr
array([[ 0.05913053,  2.46861144, -2.08584111],
       [ 0.69658644, -0.5621056 , -0.12076698],
       [ 0.23630043, -2.56341922, -0.55533511],
       [-0.51205824, -0.17731922, -0.27384838],
       [ 1.22365087,  0.24846602, -1.20284707]])
>>> arr.sort(1)
>>> arr
array([[-2.08584111,  0.05913053,  2.46861144],
       [-0.5621056 , -0.12076698,  0.69658644],
       [-2.56341922, -0.55533511,  0.23630043],
       [-0.51205824, -0.27384838, -0.17731922],
       [-1.20284707,  0.24846602,  1.22365087]])
>>> arr.sort()
>>> arr
array([[-2.08584111,  0.05913053,  2.46861144],
       [-0.5621056 , -0.12076698,  0.69658644],
       [-2.56341922, -0.55533511,  0.23630043],
       [-0.51205824, -0.27384838, -0.17731922],
       [-1.20284707,  0.24846602,  1.22365087]])
>>> arr.sort(0)
>>> arr
array([[-2.56341922, -0.55533511, -0.17731922],
       [-2.08584111, -0.27384838,  0.23630043],
       [-1.20284707, -0.12076698,  0.69658644],
       [-0.5621056 ,  0.05913053,  1.22365087],
       [-0.51205824,  0.24846602,  2.46861144]])

集合

unique(x):类似set,返回结果是有序的
intersect1d(x, y):计算公共元素,返回有序结果
union1d(x, y):并集,有序
in1d(x, y):计算x中每个元素是否属于y
setdiff1d(x, y):x - y
setxor1d(x, y):xor

数据的导入与保存

使用save时,默认情况下,数组是以未压缩的原始二进制格式保存在扩展名为.npy的文件中的。

np.save('xxx', arr)
arr = np.load('xxx.npy')

# 保存多个数组
np.savez('array_archive.npz', a=arr, b=arr)
arch = np.load('array_archive.npz')
b = arch['b']

# 如果希望压缩数据,则
np.savez_compressed('arrays_compressed.npz', a=arr, b=arr)

线性代数

# 矩阵乘法,也可以 x @ y
np.dot(arr.T, arr)

numpy.linalg是线性代数库,跟matlab、R用的是一样的
diag 以1d数组的形式返回方阵的对角线元素,或将1d数组转换为方阵(非对角线为0)
trace 计算对角线元素的和
det 计算矩阵行列式
eig 计算方阵的本征值和本征向量
inv 计算方阵的逆
pinv 计算矩阵的Moore-Penrose伪逆
qr 计算QR分解
svd 计算奇异值分解
solve 解Ax=b,其中A是方阵
lstsq 计算Ax=b的最小二乘解

伪随机数生成

# 设置全局的随机种子
np.random.seed(123)
# 如果想用单独的随机种子,可以创建单独的生成器:
rng = np.random.RandomState(1234)
rng.randn(10)

# 标准正态分布,4x4
samples = np.random.normal(size=(4, 4))
# 等价于: 但是np的会更快
from random import normalvariate
samples = [normalvariate(0, 1) for _ in range(100)]

permutation 返回一个随机排列
shuffle 就地随机排列
rand 产生均匀分布的样本
randint 从给定的范围内随机选取整数
randn 正态分布,mean=0 std=1
beta/chisquare/gamma/uniform/normal/binomial 几种分布

你可能感兴趣的:(python大法好,numpy,笔记)