Numpy 学习笔记

Numpy 学习笔记

1. 数组迭代

>>> import numpy as np
>>> A = np.arange(10,19).reshape((3,3))
>>> A
array([[10, 11, 12],
       [13, 14, 15],
       [16, 17, 18]])
>>> for row in A:
...     print(row)
...
[10 11 12]
[13 14 15]
[16 17 18]
>>> for item in A.flat:
...     print(item)
...
10
11
12
13
14
15
16
17
18

2. 形状变换

>>> a = np.random.random(12)
>>> A = a.reshape(3,4)
>>> A
array([[ 0.00981972,  0.94465645,  0.75525121,  0.94323101],
       [ 0.32700473,  0.45826317,  0.35407156,  0.68149831],
       [ 0.26997636,  0.79723574,  0.80910608,  0.64596591]])
>>> a.shape
(12,)

reshape() 函数返回一个新数组,因而可以用来创建新对象。然而如果想通过改变数组的形状来改变原数组对象,需把表示新形状的元祖直接赋给数组的 shape 属性。

>>> a.shape = (2,6)
>>> a
array([[ 0.00981972,  0.94465645,  0.75525121,  0.94323101,  0.32700473,
         0.45826317],
       [ 0.35407156,  0.68149831,  0.26997636,  0.79723574,  0.80910608,
         0.64596591]])

由输出结果来看,上述操作改变了原来数组的形状,而没有返回新对象。改变数组形状的操作是可逆的,ravel() 函数可以把二维数组再变回一维数组,该函数不会产生原数据的副本。flatten() 函数和 ravel() 函数类似,只不过它总是返回原数据的副本。使用 ravel('F') 可以沿 Fortran 格式(列优先)排列。

>>> a = a.ravel()
>>> a
array([ 0.00981972,  0.94465645,  0.75525121,  0.94323101,  0.32700473,
        0.45826317,  0.35407156,  0.68149831,  0.26997636,  0.79723574,
        0.80910608,  0.64596591])

甚至直接改变数组 shape 属性的值也可以。

>>> a.shape = (12)
>>> a
array([ 0.00981972,  0.94465645,  0.75525121,  0.94323101,  0.32700473,
        0.45826317,  0.35407156,  0.68149831,  0.26997636,  0.79723574,
        0.80910608,  0.64596591])

3. 数组操作

3.1 连接数组

可以把多个数组整合在一起形成一个包含这些数组的新数组。Numpy 是用来的栈这个概念,提供了几个运用栈概念的函数。例如,vstack() 函数执行垂直入栈操作,把第二个数组作为行添加到第一个数组,数组朝垂直方向生长(沿轴0)。相反,hstack() 函数执行水平入栈操作,也就是说把第二个数组作为列添加到第一个数组(沿轴1)。而 dstack() 则以面向”深度“的方式对数组进行堆叠(沿轴2)。

>>> A = np.ones((3,3))
>>> B = np.zeros((3,3))
>>> np.vstack((A,B))
array([[ 1.,  1.,  1.],
       [ 1.,  1.,  1.],
       [ 1.,  1.,  1.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.]])
>>> np.hstack((A,B))
array([[ 1.,  1.,  1.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  0.,  0.,  0.]])

另外两个用于多个数组之间栈操作的函数是 column_stack()row_stack() 。这两个函数不同于上面两个。一般来讲,这两个函数把一维数组作为列或行压入栈结构,以形成一个新的二维数组。

>>> a = np.array([0,1,2])
>>> b = np.array([3,4,5])
>>> c = np.array([6,7,8])
>>> np.column_stack((a,b,c))
array([[0, 3, 6],
       [1, 4, 7],
       [2, 5, 8]])
>>> np.row_stack((a,b,c))
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

3.2 数组切分

在 Numpy 中,水平切分用 hsplit() 函数(沿轴0),垂直切分用 vsplit() 函数(沿轴1),深度切分用 dsplit() 函数(沿轴2)。

水平切分数组的意思是把数组按照宽度切分为两部分,例如 $4 \times 4 ​$ 矩阵将被切分为两个 $4 \times 2 ​$ 矩阵。

>>> A = np.arange(16).reshape((4,4))
>>> A
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])
>>> [B,C] = np.hsplit(A,2)
>>> B
array([[ 0,  1],
       [ 4,  5],
       [ 8,  9],
       [12, 13]])
>>> C
array([[ 2,  3],
       [ 6,  7],
       [10, 11],
       [14, 15]])

反之,垂直切分指的是把数组按照高度分为两个部分,例如 $4 \times 4 $ 矩阵将被切分为两个 $2 \times 4 $ 矩阵。

>>> [B,C] = np.vsplit(A,2)
>>> B
array([[0, 1, 2, 3],
       [4, 5, 6, 7]])
>>> C
array([[ 8,  9, 10, 11],
       [12, 13, 14, 15]])

split() 函数更为复杂,可以吧数组分为几个不对称的部分。此外,除了传入数组作为参数外,还得指定被切分部分的索引。如果指定 axis = 1 项,索引为列索引;如果 axis = 0,索引为行索引。

例如,要把矩阵切分为三部分,第一部分为第一列,第二部分为第二列、第三列,而第三部分为最后一列。你需要想下面这样指定索引值。下面的 [1,3] 指的是在索引 1 和 3 的位置分裂。每个索引都是新起的矩阵的第一列。可以想象,如果分为四部分,则可能为 [2,4,7] 这样的形式。

>>> [A1,A2,A3] = np.split(A,[1,3],axis=1)
>>> A1
array([[ 0],
       [ 4],
       [ 8],
       [12]])
>>> A2
array([[ 1,  2],
       [ 5,  6],
       [ 9, 10],
       [13, 14]])
>>> A3
array([[ 3],
       [ 7],
       [11],
       [15]])

也可以按行切分,方法相同。

>>> [A1,A2,A3] = np.split(A,[1,3],axis=0)
>>> A1
array([[0, 1, 2, 3]])
>>> A2
array([[ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> A3
array([[12, 13, 14, 15]])

split() 函数还具有 vsplit()hsplit() 函数的功能。

堆叠辅助类:r_ 和 c_

Numpy 中可以使用 r_c_ ,可以使堆叠操作更为简洁。

In[273]: arr1
Out[273]: 
array([[1, 2, 3],
       [4, 5, 6]])

In[274]: arr2
Out[274]: 
array([[ 7,  8,  9],
       [10, 11, 12]])

In[275]: np.r_[arr1,arr2]
Out[275]: 
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [ 7,  8,  9],
       [10, 11, 12]])

In[276]: np.c_[arr1,arr2]
Out[276]: 
array([[ 1,  2,  3,  7,  8,  9],
       [ 4,  5,  6, 10, 11, 12]])

4. 元素的重复操作:tile 和 repeat

对数组进行重复以产生更大数组的工具主要是 repeat 和 tile 这两个函数。repeat 会将数组中的各个元素重复一定次数,从而产生一个更大数组。默认情况下,如果传入的是一个整数,则个元素就会重复那么多次。如果传入的是一组整数,则各元素就可以重复不同的次数。

>>> arr = np.arange(3)
>>> arr
array([0, 1, 2])
>>> arr.repeat(3)
array([0, 0, 0, 1, 1, 1, 2, 2, 2])
>>> arr.repeat([2,3,4])
array([0, 0, 1, 1, 1, 2, 2, 2, 2])

对于多维数组,还可以让它们的元素沿指定轴重复。注意,如果没有设置轴向,则数组会被扁平化,这可能不会是我们想要的结果。

>>> arr = np.random.randn(2,2)
>>> arr
array([[ 0.15615292,  0.9371598 ],
       [-0.98119804,  1.38609033]])
>>> arr.repeat(2, axis=0)
array([[ 0.15615292,  0.9371598 ],
       [ 0.15615292,  0.9371598 ],
       [-0.98119804,  1.38609033],
       [-0.98119804,  1.38609033]])
>>> arr.repeat(2)
array([ 0.15615292,  0.15615292,  0.9371598 ,  0.9371598 , -0.98119804,
       -0.98119804,  1.38609033,  1.38609033])

tile 的功能是沿指定轴向堆叠数组的副本。可以形象地将其想象成“铺瓷砖”。

>>> arr
array([[ 0.15615292,  0.9371598 ],
       [-0.98119804,  1.38609033]])
>>> np.tile(arr,2)
array([[ 0.15615292,  0.9371598 ,  0.15615292,  0.9371598 ],
       [-0.98119804,  1.38609033, -0.98119804,  1.38609033]])
>>> np.tile(arr,(3,2))
array([[ 0.15615292,  0.9371598 ,  0.15615292,  0.9371598 ],
       [-0.98119804,  1.38609033, -0.98119804,  1.38609033],
       [ 0.15615292,  0.9371598 ,  0.15615292,  0.9371598 ],
       [-0.98119804,  1.38609033, -0.98119804,  1.38609033],
       [ 0.15615292,  0.9371598 ,  0.15615292,  0.9371598 ],
       [-0.98119804,  1.38609033, -0.98119804,  1.38609033]])

5. 花式索引的等价函数:take 和 put

ndarray 有两个方法专门用于获取和设置单个轴向上的选区。

>>> arr = np.arange(10)*100
>>> arr
array([  0, 100, 200, 300, 400, 500, 600, 700, 800, 900])
>>> inds = [7,1,2,6]
>>> arr[inds]
array([700, 100, 200, 600])
>>> arr.take(inds)
array([700, 100, 200, 600])
>>> arr.put(inds,42)
>>> arr
array([  0,  42,  42, 300, 400, 500,  42,  42, 800, 900])
>>> arr.put(inds,[40,41,42,43])
>>> arr
array([  0,  41,  42, 300, 400, 500,  43,  40, 800, 900])

要在其他轴上使用 take,只需传入 axis 关键字即可:

>>> inds = [2,0,2,1]
>>> arr = np.random.randn(2,4)
>>> arr
array([[-1.5522552 ,  0.06600917,  0.49939344, -0.91290739],
       [ 0.25244369, -0.09524362,  2.07720349,  1.31982229]])
>>> arr.take(inds, axis=1)
array([[ 0.49939344, -1.5522552 ,  0.49939344,  0.06600917],
       [ 2.07720349,  0.25244369,  2.07720349, -0.09524362]])

put 不接受 axis 参数,它只会在数组的扁平化版本(一维,C顺序)上进行索引。

6. 间接排序 argsort

使用 argsort()函数, 给定一个或多个键,我们就可以得到一个由整数组成的索引数组,其中的索引值说明了数据在新顺序下的位置。

>>> values = np.array([5,0,1,3,2])
>>> indexer = values.argsort()
>>> indexer
array([1, 2, 4, 3, 0], dtype=int64)
>>> values[indexer]
array([0, 1, 2, 3, 5])

7. 在有序数组中查找元素 numpy.searchsorted

searchsorted 是一个在有序数组上执行二分查找的数组方法。

>>> arr = np.array([0,1,7,12,15])
>>> arr.searchsorted(9)
3
>>> arr.searchsorted([0,8,11,16])
array([0, 3, 3, 5], dtype=int64)
>>> arr = np.array([0,0,0,1,1,1,1])
>>> arr.searchsorted([0,1])
array([0, 3], dtype=int64)
>>> arr.searchsorted([0,1], side='right')
array([3, 7], dtype=int64)

8. 常用的 numpy.linalg 函数

函数 说明
diag 以一维数组的形式返回方阵的对角线(或非对角线)元素,或将一维数组转换为方阵(非对角线元素为0)
dot 矩阵乘法
trace 计算对角线元素的和
det 计算矩阵行列式
eig 计算方阵的本征值和本征向量
inv 计算方阵的逆
qr 计算 QR 分解
svd 计算奇异值分解 (SVD)
solve 解线性方程组 Ax=b,其中 A 为一个方阵
lstsq 计算 Ax=b 的 最小

9. 部分 numpy.random 函数

函数 说明 例子
seed 确定随机数生成器的种子 np.random.seed(0)
permutation 返回一个序列的随机排列或返回一个随机排列的范围 a = np.arange(4) np.random.permutation(a)
shuffle 对一个序列就地随机排列,即改变原变量的值 np.random.shuffle(a); array([1, 0, 2, 3])
rand 产生0~1之间均匀分布的样本值 np.random.rand(2,2)
randint 从给定的上下限范围内随机选取整数,包括下限,不包括上限 np.random.randint(-3,6,(2,2))
randn 产生正态分布(平均值为0,标准差为1)的样本值可以用.mean().std() 方法检测 np.random.randn(2,2)
binomial 产生二项分布的样本值 np.random.binomial(n, p, size)
normal 产生正态(高斯)分布的样本值,第一个参数的期望,第二个参数是标准差 np.random.normal(loc=0.0, scale=1.0, size=None)
beta 产生 Beta 分布的样本值
chisquare 产生卡方分布的样本值
gamma 产生 Gamma 分布的样本值
uniform 产生在 (0,1) 中均匀分布的样本值 np.random.uniform(low, high, size)

Python 内置的字符串方法

方法 说明
count 返回子串在字符串中的出现次数(非重叠)
endwith、startwith 如果字符串以某个后缀结尾(以某个前缀开头),则返回 True
join 将字符串用作连接其他字符串序列的分隔符
index 如果在字符串中找到子串,则返回子串第一个字符所在的位置。如果没有找到,则引发 ValueError
find 如果在字符串中找到子串,则返回第一个发现的子串的第一个字符所在的位置。如果没有找到,则返回 -1
rfind 如果在字符串中找到子串,则返回最后一个发现的子串的第一个字符所在的位置。如果没有找到,则返回 -1
replace 用另一个字符串替换指定子串
strip、rstrip、lstrip 去除空白符(包括换行符)。
split 通过指定的分隔符将字符串拆分为一组子串
lower、upper 分别将字母字符转换为小写或大写
ljust、rjust 用空格(或其他字符)填充字符串的空白侧以返回符合最低宽度的字符串

正则表达式方法

方法 说明
findall、finditer 返回字符串中所有的非重叠匹配模式。findall 返回的是由所有模式组成的列表,而 finditer 则通过一个迭代器逐个返回
match 从字符串起始位置匹配模式,还可以对模式各部分进行分组。如果匹配到模式,则返回一个匹配项对象,否则返回 None
search 扫描整个字符串以匹配模式。如果找到则返回一个匹配项对象。跟 match 不同,其匹配项可以位于字符串的任意位置,而不仅仅是起始位置。m.start() 和 m.end() 分别表示始末位置索引
split 根据找到的模式将字符串拆分为数段
sub、subn 将字符串中所有的 (sub) 或前 n 个 (subn) 模式替换为指定表达式。在替换字符串中可以通过 \1、\2 等符号表示各分组项

Pandas 中矢量化的字符串方法

方法 说明
cat 实现元素级的字符串连接操作,可指定分隔符
contains 返回表示各字符串是否含有指定模式的布尔型数组
count 模式的出现次数
endswith, startswith 相当于对各个元素执行 x.endswith(pattern) 或 x.startswith(pattern)
findall 计算各字符串的模式列表
get 获取各元素的第 i 个字符
join 根据指定的分隔符将 Series 中各元素的字符串连接起来
len 计算各字符串的长度
lower, upper 转换大小写。相当于对各个元素执行 x.lower() 或 x.upper()
match 根据指定的正则表达式对各个元素执行 re.match
pad 在字符串的左边、右边或左右两边添加空白符
center 相当于 pad(side='both')
repeat 重复值。例如,s.str.repeat(3) 相当于对各个字符串执行 x*3
replace 用指定字符串替换找到的模式
slice 对 Series 中的各个字符串进行子串
split 根据分隔符或正则表达式对字符串进行拆分
strip, rstrip, lstrip 去除空白符,包括换行符。相当于对各个元素执行 x.strip()、x.rstrip()、x.lstrip()