numpy用法总结

 

1.Numpy基础数据结构

NumPy数组是一个多维数组对象,称为ndarray。其由两部分组成: ① 实际的数据 ② 描述这些数据的元数据

In [1]:

# 多维数组ndarray

import numpy as np

ar = np.array([1,2,3,4,5,6,7])
print(ar)         # 输出数组,注意数组的格式:中括号,元素之间没有逗号(和列表区分)
print(ar.ndim)     # 输出数组维度的个数(轴数),或者说“秩”,维度的数量也称rank
print(ar.shape)   # 数组的维度,对于n行m列的数组,shape为(n,m)
print(ar.size)     # 数组的元素总数,对于n行m列的数组,元素总数为n*m
print(ar.dtype)   # 数组中元素的类型,类似type()(注意了,type()是函数,.dtype是方法)
print(ar.itemsize) # 数组中每个元素的字节大小,int32l类型字节为4,float64的字节为8
print(ar.data)     # 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。
ar   # 交互方式下输出,会有array(数组)

# 数组的基本属性
# ① 数组的维数称为秩(rank),一维数组的秩为1,二维数组的秩为2,以此类推
# ② 在NumPy中,每一个线性的数组称为是一个轴(axes),秩其实是描述轴的数量:
# 比如说,二维数组相当于是两个一维数组,其中第一个一维数组中每个元素又是一个一维数组
# 所以一维数组就是NumPy中的轴(axes),第一个轴相当于是底层数组,第二个轴是底层数组里的数组。
# 而轴的数量——秩,就是数组的维数。
[1 2 3 4 5 6 7]
1
(7,)
7
int32
4
<memory at 0x0000000005927108>

Out[1]:

array([1, 2, 3, 4, 5, 6, 7])

In [2]:

# 创建数组:array()函数,括号内可以是列表、元组、数组、生成器等

ar1 = np.array(range(10))   # 整型
ar2 = np.array([1,2,3.14,4,5])   # 浮点型
ar3 = np.array([[1,2,3],('a','b','c')])   # 二维数组:嵌套序列(列表,元组均可)
ar4 = np.array([[1,2,3],('a','b','c','d')])   # 注意嵌套序列数量不一会怎么样
print(ar1,type(ar1),ar1.dtype)
print(ar2,type(ar2),ar2.dtype)
print(ar3,ar3.shape,ar3.ndim,ar3.size)     # 二维数组,共6个元素
print(ar4,ar4.shape,ar4.ndim,ar4.size)     # 一维数组,共2个元素
[0 1 2 3 4 5 6 7 8 9] <class 'numpy.ndarray'> int32
[ 1.   2.   3.14 4.   5. ] <class 'numpy.ndarray'> float64
[['1' '2' '3']
['a' 'b' 'c']] (2, 3) 2 6
[[1, 2, 3] ('a', 'b', 'c', 'd')] (2,) 1 2

In [3]:

# 创建数组:arange(),类似range(),在给定间隔内返回均匀间隔的值。

print(np.arange(10))   # 返回0-9,整型
print(np.arange(10.0)) # 返回0.0-9.0,浮点型
print(np.arange(5,12)) # 返回5-11
print(np.arange(5.0,12,2)) # 返回5.0-12.0,步长为2
print(np.arange(10000)) # 如果数组太大而无法打印,NumPy会自动跳过数组的中心部分,并只打印边角:
[0 1 2 3 4 5 6 7 8 9]
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
[ 5 6 7 8 9 10 11]
[ 5.   7.   9. 11.]
[   0   1   2 ..., 9997 9998 9999]

In [4]:

# 创建数组:linspace():返回在间隔[开始,停止]上计算的num个均匀间隔的样本。

ar1 = np.linspace(2.0, 3.0, num=5)
ar2 = np.linspace(2.0, 3.0, num=5, endpoint=False)
ar3 = np.linspace(2.0, 3.0, num=5, retstep=True)

print(ar1,type(ar1))
print(ar2)
print(ar3,type(ar3))

# numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
# start:起始值,stop:结束值
# num:生成样本数,默认为50
# endpoint:如果为真,则停止是最后一个样本。否则,不包括在内。默认值为True。
# retstep:如果为真,返回(样本,步长),其中步长是样本之间的间距 → 输出为一个包含2个元素的元组,第一个元素为array,第二个为步长实际值
[ 2.   2.25 2.5   2.75 3. ] <class 'numpy.ndarray'>
[ 2.   2.2 2.4 2.6 2.8]
(array([ 2. , 2.25, 2.5 , 2.75, 3. ]), 0.25) <class 'tuple'>

In [5]:

# 创建数组:zeros()/zeros_like()/ones()/ones_like()

ar1 = np.zeros(5)  
ar2 = np.zeros((2,2), dtype = np.int)
print(ar1,ar1.dtype)
print(ar2,ar2.dtype)
print('------')
# numpy.zeros(shape, dtype=float, order='C'):返回给定形状和类型的新数组,用零填充。
# shape:数组纬度,二维以上需要用(),且输入参数为整数
# dtype:数据类型,默认numpy.float64
# order:是否在存储器中以C或Fortran连续(按行或列方式)存储多维数据。

ar3 = np.array([list(range(5)),list(range(5,10))])
ar4 = np.zeros_like(ar3)
print(ar3)
print(ar4)
print('------')
# 返回具有与给定数组相同的形状和类型的零数组,这里ar4根据ar3的形状和dtype创建一个全0的数组

ar5 = np.ones(9)
ar6 = np.ones((2,3,4))
ar7 = np.ones_like(ar3)
print(ar5)
print(ar6)
print(ar7)
# ones()/ones_like()和zeros()/zeros_like()一样,只是填充为1
[ 0. 0. 0. 0. 0.] float64
[[0 0]
[0 0]] int32
------
[[0 1 2 3 4]
[5 6 7 8 9]]
[[0 0 0 0 0]
[0 0 0 0 0]]
------
[ 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[[[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]]

[[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]
[ 1. 1. 1. 1.]]]
[[1 1 1 1 1]
[1 1 1 1 1]]

In [6]:

# 创建数组:eye()

print(np.eye(5))
# 创建一个正方的N*N的单位矩阵,对角线值为1,其余为0
[[ 1. 0. 0. 0. 0.]
[ 0. 1. 0. 0. 0.]
[ 0. 0. 1. 0. 0.]
[ 0. 0. 0. 1. 0.]
[ 0. 0. 0. 0. 1.]]

ndarray的数据类型

  • bool 用一个字节存储的布尔类型(True或False)

  • inti 由所在平台决定其大小的整数(一般为int32或int64)

  • int8 一个字节大小,-128 至 127

  • int16 整数,-32768 至 32767

  • int32 整数,-2 31 至 2 32 -1

  • int64 整数,-2 63 至 2 63 - 1

  • uint8 无符号整数,0 至 255

  • uint16 无符号整数,0 至 65535

  • uint32 无符号整数,0 至 2 ** 32 - 1

  • uint64 无符号整数,0 至 2 ** 64 - 1

  • float16 半精度浮点数:16位,正负号1位,指数5位,精度10位

  • float32 单精度浮点数:32位,正负号1位,指数8位,精度23位

  • float64或float 双精度浮点数:64位,正负号1位,指数11位,精度52位

  • complex64 复数,分别用两个32位浮点数表示实部和虚部

  • complex128或complex 复数,分别用两个64位浮点数表示实部和虚部

2.Numpy通用函数

  • 基本操作

In [7]:

# 数组形状:.T/.reshape()/.resize()

ar1 = np.arange(10)
ar2 = np.ones((5,2))
print(ar1,'\n',ar1.T)
print(ar2,'\n',ar2.T)
print('------')
# .T方法:转置,例如原shape为(3,4)/(2,3,4),转置结果为(4,3)/(4,3,2) → 所以一维数组转置后结果不变

ar3 = ar1.reshape(2,5)     # 用法1:直接将已有数组改变形状            
ar4 = np.zeros((4,6)).reshape(3,8)   # 用法2:生成数组后直接改变形状
ar5 = np.reshape(np.arange(12),(3,4))   # 用法3:参数内添加数组,目标形状
print(ar1,'\n',ar3)
print(ar4)
print(ar5)
print('------')
# numpy.reshape(a, newshape, order='C'):为数组提供新形状,而不更改其数据,所以元素数量需要一致!!

ar6 = np.resize(np.arange(5),(3,4))
print(ar6)
# numpy.resize(a, new_shape):返回具有指定形状的新数组,如有必要可重复填充所需数量的元素。
# 注意了:.T/.reshape()/.resize()都是生成新的数组!!!
[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]
[[ 1. 1.]
[ 1. 1.]
[ 1. 1.]
[ 1. 1.]
[ 1. 1.]]
[[ 1. 1. 1. 1. 1.]
[ 1. 1. 1. 1. 1.]]
------
[0 1 2 3 4 5 6 7 8 9]
[[0 1 2 3 4]
[5 6 7 8 9]]
[[ 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 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
------
[[0 1 2 3]
[4 0 1 2]
[3 4 0 1]]

In [8]:

# 数组的复制

ar1 = np.arange(10)
ar2 = ar1
print(ar2 is ar1)
ar1[2] = 9
print(ar1,ar2)
# 回忆python的赋值逻辑:指向内存中生成的一个值 → 这里ar1和ar2指向同一个值,所以ar1改变,ar2一起改变

ar3 = ar1.copy()
print(ar3 is ar1)
ar1[0] = 9
print(ar1,ar3)
# copy方法生成数组及其数据的完整拷贝
# 再次提醒:.T/.reshape()/.resize()都是生成新的数组!!!
True
[0 1 9 3 4 5 6 7 8 9] [0 1 9 3 4 5 6 7 8 9]
False
[9 1 9 3 4 5 6 7 8 9] [0 1 9 3 4 5 6 7 8 9]

In [9]:

# 数组类型转换:.astype()

ar1 = np.arange(10,dtype=float)
print(ar1,ar1.dtype)
print('-----')
# 可以在参数位置设置数组类型

ar2 = ar1.astype(np.int32)
print(ar2,ar2.dtype)
print(ar1,ar1.dtype)
# a.astype():转换数组类型
# 注意:养成好习惯,数组类型用np.int32,而不是直接int32
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.] float64
-----
[0 1 2 3 4 5 6 7 8 9] int32
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.] float64

In [10]:

# 数组堆叠

a = np.arange(5)   # a为一维数组,5个元素
b = np.arange(5,9) # b为一维数组,4个元素
ar1 = np.hstack((a,b)) # 注意:((a,b)),这里形状可以不一样
print(a,a.shape)
print(b,b.shape)
print(ar1,ar1.shape)
a = np.array([[1],[2],[3]])   # a为二维数组,3行1列
b = np.array([['a'],['b'],['c']]) # b为二维数组,3行1列
ar2 = np.hstack((a,b)) # 注意:((a,b)),这里形状必须一样
print(a,a.shape)
print(b,b.shape)
print(ar2,ar2.shape)
print('-----')
# numpy.hstack(tup):水平(按列顺序)堆叠数组

a = np.arange(5)    
b = np.arange(5,10)
ar1 = np.vstack((a,b))
print(a,a.shape)
print(b,b.shape)
print(ar1,ar1.shape)
a = np.array([[1],[2],[3]])  
b = np.array([['a'],['b'],['c'],['d']])  
ar2 = np.vstack((a,b)) # 这里形状可以不一样
print(a,a.shape)
print(b,b.shape)
print(ar2,ar2.shape)
print('-----')
# numpy.vstack(tup):垂直(按列顺序)堆叠数组

a = np.arange(5)    
b = np.arange(5,10)
ar1 = np.stack((a,b))
ar2 = np.stack((a,b),axis = 1)
print(a,a.shape)
print(b,b.shape)
print(ar1,ar1.shape)
print(ar2,ar2.shape)
# numpy.stack(arrays, axis=0):沿着新轴连接数组的序列,形状必须一样!
# 重点解释axis参数的意思,假设两个数组[1 2 3]和[4 5 6],shape均为(3,0)
# axis=0:[[1 2 3] [4 5 6]],shape为(2,3)
# axis=1:[[1 4] [2 5] [3 6]],shape为(3,2)
[0 1 2 3 4] (5,)
[5 6 7 8] (4,)
[0 1 2 3 4 5 6 7 8] (9,)
[[1]
[2]
[3]] (3, 1)
[['a']
['b']
['c']] (3, 1)
[['1' 'a']
['2' 'b']
['3' 'c']] (3, 2)
-----
[0 1 2 3 4] (5,)
[5 6 7 8 9] (5,)
[[0 1 2 3 4]
[5 6 7 8 9]] (2, 5)
[[1]
[2]
[3]] (3, 1)
[['a']
['b']
['c']
['d']] (4, 1)
[['1']
['2']
['3']
['a']
['b']
['c']
['d']] (7, 1)
-----
[0 1 2 3 4] (5,)
[5 6 7 8 9] (5,)
[[0 1 2 3 4]
[5 6 7 8 9]] (2, 5)
[[0 5]
[1 6]
[2 7]
[3 8]
[4 9]] (5, 2)

In [11]:

# 数组拆分 

ar = np.arange(16).reshape(4,4)
ar1 = np.hsplit(ar,2)
print(ar)
print(ar1,type(ar1))
# numpy.hsplit(ary, indices_or_sections):将数组水平(逐列)拆分为多个子数组 → 按列拆分
# 输出结果为列表,列表中元素为数组

ar2 = np.vsplit(ar,4)
print(ar2,type(ar2))
# numpy.vsplit(ary, indices_or_sections)::将数组垂直(行方向)拆分为多个子数组 → 按行拆
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]
[array([[ 0, 1],
      [ 4, 5],
      [ 8, 9],
      [12, 13]]), array([[ 2, 3],
      [ 6, 7],
      [10, 11],
      [14, 15]])] <class 'list'>
[array([[0, 1, 2, 3]]), array([[4, 5, 6, 7]]), array([[ 8, 9, 10, 11]]), array([[12, 13, 14, 15]])] <class 'list'>

In [12]:

# 数组简单运算

ar = np.arange(6).reshape(2,3)
print(ar + 10)   # 加法
print(ar * 2)   # 乘法
print(1 / (ar+1)) # 除法
print(ar ** 0.5) # 幂
# 与标量的运算

print(ar.mean()) # 求平均值
print(ar.max()) # 求最大值
print(ar.min()) # 求最小值
print(ar.std()) # 求标准差
print(ar.var()) # 求方差
print(ar.sum(), np.sum(ar,axis = 0)) # 求和,np.sum() → axis为0,按列求和;axis为1,按行求和
print(np.sort(np.array([1,4,3,2,5,6]))) # 排序
# 常用函数
[[10 11 12]
[13 14 15]]
[[ 0 2 4]
[ 6 8 10]]
[[ 1.         0.5         0.33333333]
[ 0.25       0.2         0.16666667]]
[[ 0.         1.         1.41421356]
[ 1.73205081 2.         2.23606798]]
2.5
5
0
1.70782512766
2.91666666667
15 [3 5 7]
[1 2 3 4 5 6]

3.Numpy索引及切片

  • 核心:基本索引及切片 / 布尔型索引及切片

In [13]:

# 基本索引及切片

ar = np.arange(20)
print(ar)
print(ar[4])
print(ar[3:6])
print('-----')
# 一维数组索引及切片

ar = np.arange(16).reshape(4,4)
print(ar, '数组轴数为%i' %ar.ndim)   # 4*4的数组
print(ar[2], '数组轴数为%i' %ar[2].ndim) # 切片为下一维度的一个元素,所以是一维数组
print(ar[2][1]) # 二次索引,得到一维数组中的一个值
print(ar[1:3], '数组轴数为%i' %ar[1:3].ndim) # 切片为两个一维数组组成的二维数组
print(ar[2,2]) # 切片数组中的第三行第三列 → 10
print(ar[:2,1:]) # 切片数组中的1,2行、2,3,4列 → 二维数组
print('-----')
# 二维数组索引及切片

ar = np.arange(8).reshape(2,2,2)
print(ar, '数组轴数为%i' %ar.ndim)   # 2*2*2的数组
print(ar[0], '数组轴数为%i' %ar[0].ndim) # 三维数组的下一个维度的第一个元素 → 一个二维数组
print(ar[0][0], '数组轴数为%i' %ar[0][0].ndim) # 三维数组的下一个维度的第一个元素下的第一个元素 → 一个一维数组
print(ar[0][0][1], '数组轴数为%i' %ar[0][0][1].ndim)  
# **三维数组索引及切片
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
4
[3 4 5]
-----
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]] 数组轴数为2
[ 8 9 10 11] 数组轴数为1
9
[[ 4 5 6 7]
[ 8 9 10 11]] 数组轴数为2
10
[[1 2 3]
[5 6 7]]
-----
[[[0 1]
[2 3]]

[[4 5]
[6 7]]] 数组轴数为3
[[0 1]
[2 3]] 数组轴数为2
[0 1] 数组轴数为1
1 数组轴数为0

In [14]:

# 布尔型索引及切片

ar = np.arange(12).reshape(3,4)
i = np.array([True,False,True])
j = np.array([True,True,False,False])
print(ar)
print(i)
print(j)
print(ar[i,:]) # 在第一维度做判断,只保留True,这里第一维度就是行,ar[i,:] = ar[i](简单书写格式)
print(ar[:,j]) # 在第二维度做判断,这里如果ar[:,i]会有警告,因为i是3个元素,而ar在列上有4个
# 布尔型索引:以布尔型的矩阵去做筛选

m = ar > 5
print(m) # 这里m是一个判断矩阵
print(ar[m]) # 用m判断矩阵去筛选ar数组中>5的元素 → 重点!后面的pandas判断方式原理就来自此处
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[ True False True]
[ True True False False]
[[ 0 1 2 3]
[ 8 9 10 11]]
[[0 1]
[4 5]
[8 9]]
[[False False False False]
[False False True True]
[ True True True True]]
[ 6 7 8 9 10 11]

In [15]:

# 数组索引及切片的值更改、复制

ar = np.arange(10)
print(ar)
ar[5] = 100
ar[7:9] = 200
print(ar)
# 一个标量赋值给一个索引/切片时,会自动改变/传播原始数组

ar = np.arange(10)
b = ar.copy()
b[7:9] = 200
print(ar)
print(b)
# 复制
[0 1 2 3 4 5 6 7 8 9]
[ 0   1   2   3   4 100   6 200 200   9]
[0 1 2 3 4 5 6 7 8 9]
[ 0   1   2   3   4   5   6 200 200   9]

4.Numpy随机数

  • numpy.random包含多种概率分布的随机样本,是数据分析辅助的重点工具之一

In [16]:

# 随机数生成

samples = np.random.normal(size=(4,4))
print(samples)
# 生成一个标准正太分布的4*4样本值
[[ 0.17875618 -1.19367146 -1.29127688 1.11541622]
[ 1.48126355 -0.81119863 -0.94187702 -0.13203948]
[ 0.11418808 -2.34415548 0.17391121 1.4822019 ]
[ 0.46157021 0.43227682 0.58489093 0.74553395]]

In [17]:

# numpy.random.rand(d0, d1, ..., dn):生成一个[0,1)之间的随机浮点数或N维浮点数组 —— 均匀分布

import matplotlib.pyplot as plt # 导入matplotlib模块,用于图表辅助分析
% matplotlib inline
# 魔法函数,每次运行自动生成图表

a = np.random.rand()
print(a,type(a)) # 生成一个随机浮点数

b = np.random.rand(4)
print(b,type(b)) # 生成形状为4的一维数组

c = np.random.rand(2,3)
print(c,type(c)) # 生成形状为2*3的二维数组,注意这里不是((2,3))

samples1 = np.random.rand(1000)
samples2 = np.random.rand(1000)
plt.scatter(samples1,samples2)
# 生成1000个均匀分布的样本值
0.3671245126484347 <class 'float'>
[ 0.95365841 0.45627035 0.71528562 0.98488116] <class 'numpy.ndarray'>
[[ 0.82284657 0.95853197 0.87376954]
[ 0.53341526 0.17313861 0.18831533]] <class 'numpy.ndarray'>

Out[17]:

<matplotlib.collections.PathCollection at 0x7bb52e8>

img

In [18]:

#  numpy.random.randn(d0, d1, ..., dn):生成一个浮点数或N维浮点数组 —— 正态分布

samples1 = np.random.randn(1000)
samples2 = np.random.randn(1000)
plt.scatter(samples1,samples2)
# randn和rand的参数用法一样
# 生成1000个正太的样本值

Out[18]:

<matplotlib.collections.PathCollection at 0x842ea90>

img

In [19]:

# numpy.random.randint(low, high=None, size=None, dtype='l'):生成一个整数或N维整数数组
# 若high不为None时,取[low,high)之间随机整数,否则取值[0,low)之间随机整数,且high必须大于low
# dtype参数:只能是int类型  

print(np.random.randint(2))
# low=2:生成1个[0,2)之间随机整数  

print(np.random.randint(2,size=5))
# low=2,size=5 :生成5个[0,2)之间随机整数

print(np.random.randint(2,6,size=5))
# low=2,high=6,size=5:生成5个[2,6)之间随机整数  

print(np.random.randint(2,size=(2,3)))
# low=2,size=(2,3):生成一个2x3整数数组,取数范围:[0,2)随机整数

print(np.random.randint(2,6,(2,3)))
# low=2,high=6,size=(2,3):生成一个2*3整数数组,取值范围:[2,6)随机整数  
0
[0 1 1 0 1]
[2 5 2 3 5]
[[0 1 1]
[1 1 1]]
[[4 4 3]
[2 3 3]]

5. Numpy数据的输入输出

  • numpy读取/写入数组数据、文本数据

In [20]:

# 存储数组数据 .npy文件

import os
os.chdir('C:/Users/Hjx/Desktop/')

ar = np.random.rand(5,5)
print(ar)
np.save('arraydata.npy', ar)
# 也可以直接 np.save('C:/Users/Hjx/Desktop/arraydata.npy', ar)
[[ 0.57358458 0.71126411 0.22317828 0.69640773 0.97406015]
[ 0.83007851 0.63460575 0.37424462 0.49711017 0.42822812]
[ 0.51354459 0.96671598 0.21427951 0.91429226 0.00393325]
[ 0.680534   0.31516091 0.79848663 0.35308657 0.21576843]
[ 0.38634472 0.47153005 0.6457086   0.94983697 0.97670458]]

In [21]:

# 读取数组数据 .npy文件

ar_load =np.load('arraydata.npy')
print(ar_load)
# 也可以直接 np.load('C:/Users/Hjx/Desktop/arraydata.npy')
[[ 0.57358458 0.71126411 0.22317828 0.69640773 0.97406015]
[ 0.83007851 0.63460575 0.37424462 0.49711017 0.42822812]
[ 0.51354459 0.96671598 0.21427951 0.91429226 0.00393325]
[ 0.680534   0.31516091 0.79848663 0.35308657 0.21576843]
[ 0.38634472 0.47153005 0.6457086   0.94983697 0.97670458]]

In [22]:

# 存储/读取文本文件

ar = np.random.rand(5,5)
np.savetxt('array.txt',ar, delimiter=',')
# np.savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='', footer='', comments='# '):存储为文本txt文件

ar_loadtxt = np.loadtxt('array.txt', delimiter=',')
print(ar_loadtxt)
# 也可以直接 np.loadtxt('C:/Users/Hjx/Desktop/array.txt')
[[ 0.28280684 0.66188985 0.00372083 0.54051044 0.68553963]
[ 0.9138449   0.37056825 0.62813711 0.83032184 0.70196173]
[ 0.63438739 0.86552157 0.68294764 0.2959724   0.62337767]
[ 0.67411154 0.87678919 0.53732168 0.90366896 0.70480366]
[ 0.00936579 0.32914898 0.30001813 0.66198967 0.04336824]]

Numpy快速上手指南 --- 基础篇

内容索引

  • 1.概览

  • 2.创建数组

  • 3.打印数组

  • 4.基本运算

  • 5.通用函数

  • 6.形状操作

  • 7.函数和方法method总览

1. 概览

Numpy的主要对象是同种元素的多维数组。这是一个所有的元素都是一种类型、通过一个正整数元组索引的元素表格(通常是元素是数字)。在Numpy中维度(dimensions)叫做轴(axes),轴的个数叫做秩(rank)。

例如,在3D空间一个点的坐标[1, 2, 3]是一个秩为1的数组,因为它只有一个轴。那个轴长度为3.又例如,在以下例子中,数组的秩为2(它有两个维度).第一个维度长度为2,第二个维度长度为3.

[[ 1., 0., 0.], [ 0., 1., 2.]]

Numpy的数组类被称作ndarray。通常被称作数组。注意numpy.array和标准Python库类array.array并不相同,后者只处理一维数组和提供少量功能。更多重要ndarray对象属性有:

  • ndarray.ndim

数组轴的个数,在python的世界中,轴的个数被称作秩

  • ndarray.shape

数组的维度。这是一个指示数组在每个维度上大小的整数元组。例如一个nm列的矩阵,它的shape属性将是(2,3),这个元组的长度显然是秩,即维度或者ndim属性

  • ndarray.size

数组元素的总个数,等于shape属性中元组元素的乘积。

  • ndarray.dtype

一个用来描述数组中元素类型的对象,可以通过创造或指定dtype使用标准Python类型。另外Numpy提供它自己的数据类型。

  • ndarray.itemsize

数组中每个元素的字节大小。例如,一个元素类型为float64的数组itemsiz属性值为8(=64/8),又如,一个元素类型为complex32的数组item属性为4(=32/8).

  • ndarray.data

包含实际数组元素的缓冲区,通常我们不需要使用这个属性,因为我们总是通过索引来使用数组中的元素。

例子

In [1]:

from numpy  import *
a = arange(15).reshape(3, 5)
a

Out[1]:

array([[ 0,  1,  2,  3,  4],
      [ 5, 6, 7, 8, 9],
      [10, 11, 12, 13, 14]])

In [2]:

a.shape

Out[2]:

(3, 5)

In [3]:

a.ndim 

Out[3]:

2

In [4]:

a.dtype.name

Out[4]:

'int64'

In [5]:

a.itemsize  

Out[5]:

8

In [6]:

a.size

Out[6]:

15

In [7]:

type(a)

Out[7]:

numpy.ndarray

In [8]:

b = array([6, 7, 8])
b

Out[8]:

array([6, 7, 8])

In [9]:

type(b)

Out[9]:

numpy.ndarray

2. 创建数组

有好几种创建数组的方法。 例如,你可以使用array函数从常规的Python列表和元组创造数组。所创建的数组类型由原序列中的元素类型推导而来。

In [10]:

from numpy  import *
a = array( [2,3,4] )
a

Out[10]:

array([2, 3, 4])

In [11]:

a.dtype 

Out[11]:

dtype('int64')

In [12]:

b = array([1.2, 3.5, 5.1])
b.dtype   # 一个常见的错误包括用多个数值参数调用 array 而不是提供一个由数值组成的列表作为一个参数。

Out[12]:

dtype('float64')

正确创建方式与错误创建方式对比

a = array(1,2,3,4)    # 错误的创建方式  
---------------------------------------------------------------------------  
ValueError                               Traceback (most recent call last)  
<ipython-input-194-501541f17041> in <module>()  
----> 1 a = array(1,2,3,4)   # WRONG  

ValueError: only 2 non-keyword arguments accepted
a = array([1,2,3,4]) # 正确的创建方式

数组将序列包含序列转化成二维的数组,序列包含序列包含序列转化成三维数组等等。

In [13]:

b = array([(1.5,2,3),(4,5,6)])
b

Out[13]:

array([[ 1.5,  2. ,  3. ],
      [ 4. , 5. , 6. ]])

数组类型可以在创建时显示指定

In [14]:

c = array([[1,2],[3,4]], dtype=complex )
c

Out[14]:

array([[ 1.+0.j,  2.+0.j],
      [ 3.+0.j, 4.+0.j]])

通常,数组的元素开始都是未知的,但是它的大小已知。因此,Numpy提供了一些使用占位符创建数组的函数。这最小化了扩展数组的需要和高昂的运算代价。

函数function创建一个全是0的数组,函数ones创建一个全1的数组,函数empty创建一个内容随机并且依赖与内存状态的数组。默认创建的数组类型(dtype)都是float64

In [15]:

zeros((3,4))

Out[15]:

array([[ 0.,  0.,  0.,  0.],
      [ 0., 0., 0., 0.],
      [ 0., 0., 0., 0.]])

In [16]:

ones((2,3,4),dtype=int16)                # dtype can also be specified

Out[16]:

array([[[1, 1, 1, 1],
      [1, 1, 1, 1],
      [1, 1, 1, 1]],

      [[1, 1, 1, 1],
      [1, 1, 1, 1],
      [1, 1, 1, 1]]], dtype=int16)

In [17]:

empty((2,3))

Out[17]:

array([[ 0.,  0.,  0.],
      [ 0., 0., 0.]])

为了创建一个数列,Numpy提供一个类似arange的函数返回数组而不是列表:

In [18]:

arange(10,30,5)

Out[18]:

array([10, 15, 20, 25])

In [19]:

arange( 0, 2, 0.3 )                 # it accepts float arguments

Out[19]:

array([ 0. ,  0.3,  0.6,  0.9,  1.2,  1.5,  1.8])

当arange使用浮点数参数时,由于有限的浮点数精度,通常无法预测获得的元素个数。因此,最好使用函数linspace去接收我们想要的元素个数来代替用range来指定步长。

其它函数array, zeros, zeros_like, ones, ones_like, empty, empty_like, arange, linspace, rand, randn, fromfunction, fromfile参考:NumPy示例

3. 打印数组

当你打印一个数组,NumPy以类似嵌套列表的形式显示它,但是呈以下布局:

  • 最后的轴从左到右打印

  • 次后的轴从顶向下打印

  • 剩下的轴从顶向下打印,每个切片通过一个空行与下一个隔开

  • 一维数组被打印成行,二维数组成矩阵,三维数组成矩阵列表。

In [20]:

a = arange(6)                         # 1d array
print (a)
[0 1 2 3 4 5]

In [21]:

b = arange(12).reshape(4,3)           # 2d array
print (b)
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]

In [22]:

c = arange(24).reshape(2,3,4)         # 3d array
print (c)
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]

[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]

查看形状操作一节获得有关reshape的更多细节

如果一个数组用来打印太大了,NumPy自动省略中间部分而只打印角落

In [23]:

print (arange(10000))
[ 0 1 2 ..., 9997 9998 9999]

In [24]:

print (arange(10000).reshape(100,100))
[[ 0 1 2 ..., 97 98 99]
[ 100 101 102 ..., 197 198 199]
[ 200 201 202 ..., 297 298 299]
...,
[9700 9701 9702 ..., 9797 9798 9799]
[9800 9801 9802 ..., 9897 9898 9899]
[9900 9901 9902 ..., 9997 9998 9999]]

禁用NumPy的这种行为并强制打印整个数组,你可以设置printoptions参数来更改打印选项。

set_printoptions(threshold='nan')

4. 基本运算

数组的算术运算是按元素的。新的数组被创建并且被结果填充

In [25]:

from numpy import *
a = array([20,30,40,50])
b = arange(4)
b

Out[25]:

array([0, 1, 2, 3])

In [26]:

c = a-b
c

Out[26]:

array([20, 29, 38, 47])

In [27]:

b**2

Out[27]:

array([0, 1, 4, 9])

In [28]:

10*sin(a)

Out[28]:

array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])

In [29]:

a<35

Out[29]:

array([ True,  True, False, False], dtype=bool)

不像许多矩阵语言,NumPy中的乘法运算符*指示按元素计算,矩阵乘法可以使用dot函数或创建矩阵对象实现(参见教程中的矩阵章节)

In [30]:

A = array( [[1,1],
[0,1]] )
B = array( [[2,0],
[3,4]] )

A*B # elementwise product

Out[30]:

array([[2, 0],
[0, 4]])

In [31]:

dot(A,B)                    # matrix product

Out[31]:

array([[5, 4],
[3, 4]])

有些操作符像+=和*=被用来更改已存在数组而不创建一个新的数组。

In [32]:

a = ones((2,3), dtype=int)
b = random.random((2,3))
a *= 3
a

Out[32]:

array([[3, 3, 3],
[3, 3, 3]])

In [33]:

b += a
b

Out[33]:

array([[ 3.04610006,  3.25068416,  3.39458014],
[ 3.34956036, 3.30907687, 3.05677917]])

错误的方式

a += b                                  # b is converted to integer type  
a
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-219-2b1a0b731705> in <module>()
----> 1 a += b # b is converted to integer type
2 a

TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int64') with casting rule 'same_kind'

当运算的是不同类型的数组时,结果数组和更普遍和精确的已知,这种行为叫做 upcast

In [34]:

a = ones(3, dtype=int32)
b = linspace(0,pi,3)
b.dtype.name

Out[34]:

'float64'

In [35]:

c = a+b
c

Out[35]:

array([ 1.        ,  2.57079633,  4.14159265])

In [36]:

c.dtype.name

Out[36]:

'float64'

In [37]:

d = exp(c*1j)
d

Out[37]:

array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,
-0.54030231-0.84147098j])

In [38]:

d.dtype.name # 许多非数组运算,如计算数组所有元素之和,被作为ndarray类的方法实现

Out[38]:

'complex128'

In [39]:

a = random.random((2,3))
a

Out[39]:

array([[ 0.58120218,  0.65134515,  0.86005124],
[ 0.47042799, 0.59048742, 0.84672098]])

In [40]:

a.sum() 

Out[40]:

4.0002349566329114

In [41]:

a.min() 

Out[41]:

0.47042798669229968

In [42]:

a.max() 

Out[42]:

0.86005123623089985

这些运算默认应用到数组好像它就是一个数字组成的列表,无关数组的形状。然而,指定axis参数你可以吧运算应用到数组指定的轴上:

In [43]:

b = arange(12).reshape(3,4)
b

Out[43]:

array([[ 0,  1,  2,  3],
      [ 4, 5, 6, 7],
      [ 8, 9, 10, 11]])

In [44]:

b.sum(axis=0)                            # sum of each column

Out[44]:

array([12, 15, 18, 21])

In [45]:

b.min(axis=1)                            # min of each row

Out[45]:

array([0, 4, 8])

In [46]:

b.cumsum(axis=1)                         # cumulative sum along each row
# cumsum累加运算是第一个是第一个,第二个元素是第一个加第二个,以此类推!

Out[46]:

array([[ 0,  1,  3,  6],
[ 4, 9, 15, 22],
[ 8, 17, 27, 38]])

5. 通用函数 ufunc

Numpy提供常见的数学函数如 sin, cosexp。在Numpy中,这些叫作通用函数 ufunc。在Numpy里这些函数作用按数组的元素运算,产生一个数组作为输出。

In [47]:

B = arange(3)
B

Out[47]:

array([0, 1, 2])

In [48]:

exp(B) 

Out[48]:

array([ 1.        ,  2.71828183,  7.3890561 ])

In [49]:

sqrt(B) 

Out[49]:

array([ 0.        ,  1.        ,  1.41421356])

In [50]:

C = array([2., -1., 4.])
add(B, C)  

Out[50]:

array([ 2.,  0.,  6.])

更多函数

all, alltrue, any, apply along axis, argmax, argmin, argsort, average,       
bincount, ceil, clip(举例:np.clip(A,5,9)的意思是矩阵A中,如果大于9的数全用9表示,小于5的数全用5表示), conj, conjugate, corrcoef, cov, cross, cumprod, cumsum,
diff(累差运算,后一个元素减前一个元素得到的列表), dot, floor, inner, inv, lexsort, max, maximum, mean, median, min, minimum,
nonzero, outer, prod, re, round, sometrue, sort, std, sum, trace, transpose,
var, vdot, vectorize, where

索引,切片和迭代

一维数组可以被索引、切片和迭代,就像列表和其它Python序列。

In [51]:

a = arange(10)**3
a  

Out[51]:

array([  0,   1,   8,  27,  64, 125, 216, 343, 512, 729])

In [52]:

a[2] 

Out[52]:

8

In [53]:

a[2:5]

Out[53]:

array([ 8, 27, 64])

In [54]:

a[:6:2] = -1000  # equivalent to a[0:6:2] = -1000; 
a # from start to position 6, exclusive, set every 2nd element to -1000

Out[54]:

array([-1000,     1, -1000,    27, -1000,   125,   216,   343,   512,   729])

In [55]:

a[ : :-1]       # reversed a

Out[55]:

array([  729,   512,   343,   216,   125, -1000,    27, -1000,     1, -1000])

In [97]:

for i in a:
  print (i**(1/3.),end=",")
[ 0.         2.15443469 2.15443469 1.44224957],[ 10.72601467   2.15443469   2.15443469   1.91293118],[ 2.         2.15443469 2.15443469 2.22398009],

多维数组可以每个轴有一个索引。这些索引由一个逗号分割的元组给出。

In [57]:

def f(x,y):
  return 10*x+y
b = fromfunction(f,(5,4),dtype=int)
b

Out[57]:

array([[ 0,  1,  2,  3],
[10, 11, 12, 13],
[20, 21, 22, 23],
[30, 31, 32, 33],
[40, 41, 42, 43]])

In [58]:

b[2,3] 

Out[58]:

23

In [59]:

b[0:5, 1]                       # each row in the second column of b

Out[59]:

array([ 1, 11, 21, 31, 41])

In [60]:

b[ : ,1]                        # equivalent to the previous example

Out[60]:

array([ 1, 11, 21, 31, 41])

In [61]:

b[1:3, : ]                      # each column in the second and third row of b

Out[61]:

array([[10, 11, 12, 13],
[20, 21, 22, 23]])

当少于轴数的索引被提供时,确失的索引被认为是整个切片:

In [62]:

b[-1]                                  # the last row. Equivalent to b[-1,:]

Out[62]:

array([40, 41, 42, 43])

b[i]中括号中的表达式被当作i和一系列:,来代表剩下的轴。NumPy也允许你使用“点”像b[i,...]。

点(…)代表许多产生一个完整的索引元组必要的分号。如果x是秩为5的数组(即它有5个轴),那么:

  • x[1,2,…] 等同于 x[1,2,:,:,:]

  • x[…,3] 等同于 x[:,:,:,:,3]

  • x[4,…,5,:] 等同于 x[4,:,:,5,:]

如下所示

# c = array( [ [[  0,  1,  2],  # a 3D array (two stacked 2D arrays) ... [ 10, 12, 13]]...   
# [[100,101,102], ... [110,112,113]] ] )  
# c.shape (2, 2, 3)  
# c[1,...]   # same as c[1,:,:] or c[1] array([[100, 101, 102], [110, 112, 113]])  
# c[...,2]     # same as c[:,:,2] array([[ 2, 13], [102, 113]])

迭代多维数组是就第一个轴而言的

In [63]:

for row in b:
  print (row)
[0 1 2 3]
[10 11 12 13]
[20 21 22 23]
[30 31 32 33]
[40 41 42 43]

然而,如果一个人想对每个数组中元素进行运算,我们可以使用flat属性,该属性是数组元素的一个迭代器:

In [64]:

for element in b.flat:
print (element,end=",") #
0,1,2,3,10,11,12,13,20,21,22,23,30,31,32,33,40,41,42,43,

更多newaxis, ndenumerate, indices, index exp 参考Numpy示例

6. 形状操作

更改数组的形状

一个数组的形状由它每个轴上的元素个数给出:

In [65]:

a = floor(10*random.random((3,4)))
a

Out[65]:

array([[ 6.,  7.,  4.,  3.],
[ 0., 0., 2., 6.],
[ 7., 7., 8., 6.]])
a.flatten()  # 平铺,结果为[ 3  4  5  6  7  8  9 10 11 12 13 14]

In [66]:

a.shape 

Out[66]:

(3, 4)

一个数组的形状可以被多种命令修改:

In [67]:

a.ravel() # flatten the array

Out[67]:

array([ 6.,  7.,  4.,  3.,  0.,  0.,  2.,  6.,  7.,  7.,  8.,  6.])

In [68]:

a.shape = (6, 2)
a.transpose()

Out[68]:

array([[ 6.,  4.,  0.,  2.,  7.,  8.],
[ 7., 3., 0., 6., 7., 6.]])

ravel()展平的数组元素的顺序通常是 C风格 的,就是说,最右边的索引变化得最快,所以元素a[0,0]之后是a[0,1]。如果数组被改变形状(reshape)成其它形状,数组仍然是 C风格 的。Numpy通常创建一个以这个顺序保存数据的数组,所以ravel()将总是不需要复制它的参数。但是如果数组是通过切片其它数组或有不同寻常的选项时,它可能需要被复制。函数reshape()ravel()还可以被同过一些可选参数构建成 FORTRAN风格 的数组,即最左边的索引变化最快。

reshape函数改变参数形状并返回它,而resize函数改变数组自身。

In [69]:

a

Out[69]:

array([[ 6.,  7.],
[ 4., 3.],
[ 0., 0.],
[ 2., 6.],
[ 7., 7.],
[ 8., 6.]])

In [70]:

a.resize((2,6))
a

Out[70]:

array([[ 6.,  7.,  4.,  3.,  0.,  0.],
[ 2., 6., 7., 7., 8., 6.]])

如果在改变形状操作中一个维度被给做-1,其维度将自动被计算

更多 shape, reshape, resize, ravel 参考Numpy示例

组合(stack)不同的数组

几种方法可以沿不同轴将数组堆叠在一起:

In [71]:

a = floor(10*random.random((2,2)))
a

Out[71]:

array([[ 1.,  5.],
[ 6., 7.]])

In [72]:

b = floor(10*random.random((2,2)))
b

Out[72]:

array([[ 5.,  5.],
[ 4., 5.]])

In [73]:

vstack((a,b))

Out[73]:

array([[ 1.,  5.],
[ 6., 7.],
[ 5., 5.],
[ 4., 5.]])

In [74]:

hstack((a,b))

Out[74]:

array([[ 1.,  5.,  5.,  5.],
[ 6., 7., 4., 5.]])

函数column_stack以列将一维数组合成二维数组,它等同与vstack对一维数组。

In [75]:

column_stack((a,b))   # With 2D arrays

Out[75]:

array([[ 1.,  5.,  5.,  5.],
[ 6., 7., 4., 5.]])

In [76]:

a=array([4.,2.])
b=array([2.,8.])
a[:,newaxis] # This allows to have a 2D columns vector变成垂直的二维数组
a[newaxis,:] # 变成水平的二维数组[[4.,2.]]

Out[76]:

array([[ 4.],
[ 2.]])
array([[ 4., 2.]]

In [77]:

column_stack((a[:,newaxis],b[:,newaxis]))

Out[77]:

array([[ 4.,  2.],
[ 2., 8.]])

In [78]:

vstack((a[:,newaxis],b[:,newaxis])) # The behavior of vstack is different

Out[78]:

array([[ 4.],
[ 2.],
[ 2.],
[ 8.]])

row_stack函数,另一方面,将一维数组以行组合成二维数组。

对那些维度比二维更高的数组,hstack沿着第二个轴组合,vstack沿着第一个轴组合,concatenate允许可选参数给出组合时沿着的轴。使用concatenate时,axis=0默认为0,如一维数组拼接,由原来[1,2]和[3,4]拼成[1,2,3,4],如果是二维数组,则代表多个矩阵纵向合并。!!

axis=1代表对应列的位置拼接成同一行

在复杂情况下,r_[]c_[]对创建沿着一个方向组合的数很有用,它们允许范围符号(“:”):

In [79]:

r_[1:4,0,4]   

Out[79]:

array([1, 2, 3, 0, 4])

当使用数组作为参数时,r_c_的默认行为和vstackhstack很像,但是允许可选的参数给出组合所沿着的轴的代号。

更多函数hstack, vstack, column_stack, row_stack, concatenate, c_, r_ 参见Numpy示例.

将一个数组分割(split)成几个小数组

使用hsplit你能将数组沿着它的水平轴分割,或者指定返回相同形状数组的个数,或者指定在哪些列后发生分割:

In [80]:

a = floor(10*random.random((2,12)))
a

Out[80]:

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

In [81]:

hsplit(a,3)   # Split a into 3

Out[81]:

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

In [82]:

hsplit(a,(3,4))   # Split a after the third and the fourth column

Out[82]:

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

vsplit沿着纵向的轴分割,array split允许指定沿哪个轴分割。

复制和视图

当运算和处理数组时,它们的数据有时被拷贝到新的数组有时不是。这通常是新手的困惑之源。这有三种情况:

  • 完全不拷贝 简单的赋值不拷贝数组对象或它们的数据。

In [83]:

a = arange(12)
b = a # no new object is created
b is a # a and b are two names for the same ndarray object

Out[83]:

True

In [84]:

b.shape = 3,4    # changes the shape of a
a.shape

Out[84]:

(3, 4)

Python 传递不定对象作为参考,所以函数调用不拷贝数组。

In [85]:

def f(x):
print (id(x))

In [86]:

id(a)                           # id is a unique identifier of an object

Out[86]:

4538177536

In [87]:

f(a)
4538177536
  • 视图(view)和浅复制 不同的数组对象分享同一个数据。视图方法创造一个新的数组对象指向同一数据。

In [88]:

c = a.view()
c is a

Out[88]:

False

In [89]:

c.base is a                        # c is a view of the data owned by a

Out[89]:

True

In [90]:

c.flags.owndata

Out[90]:

False

In [91]:

c.shape = 2,6                      # a's shape doesn't change
a.shape

Out[91]:

(3, 4)

In [92]:

c[0,4] = 1234                      # a's data changesa
a

Out[92]:

array([[   0,    1,    2,    3],
[1234, 5, 6, 7],
[ 8, 9, 10, 11]])

切片数组返回它的一个视图:

In [93]:

s = a[ : , 1:3]     # spaces added for clarity; could also be written "s = a[:,1:3]"
s[:] = 10 # s[:] is a view of s. Note the difference between s=10 and s[:]=10
a

Out[93]:

array([[   0,   10,   10,    3],
[1234, 10, 10, 7],
[ 8, 10, 10, 11]])
  • 深复制 这个方法完全复制数组和它的数据

In [94]:

d = a.copy()                          # a new array object with new data is created
d is a

Out[94]:

False

In [95]:

d.base is a                           # d doesn't share anything with a

Out[95]:

False

In [96]:

d[0,0] = 9999
a

Out[96]:

array([[   0,   10,   10,    3],
[1234, 10, 10, 7],
[ 8, 10, 10, 11]])

7. 函数和方法method总览

这是个Numpy函数和方法分类排列目录。这些名字链接到Numpy示例,你可以看到这些函数起作用

创建数组

arange, array, copy(这里的拷贝与正常不同,是深拷贝), empty, empty_like, eye, fromfile, fromfunction, identity,   
linspace, logspace, mgrid, ogrid, ones, ones_like, r , zeros, zeros_like

转化

astype, atleast 1d, atleast 2d, atleast 3d, mat

操作

array split, column stack, concatenate, diagonal, dsplit, dstack, hsplit, hstack, item,   
newaxis, ravel, repeat, reshape, resize, squeeze, swapaxes, take, transpose, vsplit, vstack

询问

all, any, nonzero, where

排序

argmax, argmin, argsort, max, min, ptp, searchsorted, sort

运算

choose, compress, cumprod累乘, cumsum, inner, fill, imag, prod, put, putmask, real, sum

基本统计

cov, mean, std, var

基本线性代数

cross, dot, outer, svd, vdot

Numpy快速上手指南 --- 进阶篇

内容索引

  • 1.广播法则

  • 2.花哨的索引和索引技巧

  • 3.线性代数

  • 4.技巧和提示

1. 广播法则(rule)

广播法则能使通用函数有意义地处理不具有相同形状的输入。

  • 广播第一法则:如果所有的输入数组维度不都相同,一个“1”将被重复地添加在维度较小的数组上直至所有的数组拥有一样的维度。

  • 广播第二法则:确定长度为1的数组沿着特殊的方向表现地好像它有沿着那个方向最大形状的大小。对数组来说,沿着那个维度的数组元素的值理应相同。

应用广播法则之后,所有数组的大小必须匹配。更多细节可以从这个[文档找到]。

2. 花哨的索引和索引技巧

Numpy比普通Python序列提供更多的索引功能。除了索引整数和切片,正如我们之前看到的,数组可以被整数数组和布尔数组索引。

通过数组索引

In [1]:

from numpy import * 
a = arange(12)**2 # the first 12 square numbers
i = array( [ 1,1,3,8,5 ] ) # an array of indices
a[i] # the elements of a at the positions i

Out[1]:

array([ 1,  1,  9, 64, 25])

In [2]:

j = array( [ [ 3, 4], [ 9, 7 ] ] )         # a bidimensional array of indices
a[j] # the same shape as j

Out[2]:

array([[ 9, 16],
[81, 49]])

当被索引数组a是多维的时,每一个唯一的索引数列指向a的第一维5。以下示例通过将图片标签用调色版转换成色彩图像展示了这种行为。

In [3]:

palette = array( [ [0,0,0],                # 黑色
[255,0,0], # 红色
[0,255,0], # 绿色
[0,0,255], # 蓝色
[255,255,255] ] ) # 白色
image = array( [ [ 0, 1, 2, 0 ], # each value corresponds to a color in the palette
[ 0, 3, 4, 0 ] ] )
palette[image] # the (2,4,3) color image

Out[3]:

array([[[  0,   0,   0],
[255, 0, 0],
[ 0, 255, 0],
[ 0, 0, 0]],

[[ 0, 0, 0],
[ 0, 0, 255],
[255, 255, 255],
[ 0, 0, 0]]])

我们也可以给出不不止一维的索引,每一维的索引数组必须有相同的形状。

In [4]:

a = arange(12).reshape(3,4)
a

Out[4]:

array([[ 0,  1,  2,  3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])

In [5]:

i = array( [ [0,1],                        # indices for the first dim of a
[1,2] ] )

In [6]:

j = array( [ [2,1],                        # indices for the second dim
[3,3] ] )

In [7]:

a[i,j]                                     # i and j must have equal shape

Out[7]:

array([[ 2,  5],
[ 7, 11]])

In [8]:

a[i,2]

Out[8]:

array([[ 2,  6],
[ 6, 10]])

In [9]:

a[:,j]                                     # i.e., a[ : , j]

Out[9]:

array([[[ 2,  1],
[ 3, 3]],

[[ 6, 5],
[ 7, 7]],

[[10, 9],
[11, 11]]])

自然,我们可以把i和j放到序列中(比如说列表)然后通过list索引。

In [10]:

l = [i,j]
a[l] # 与 a[i,j] 相等

Out[10]:

array([[ 2,  5],
[ 7, 11]])

然而,我们不能把i和j放在一个数组中,因为这个数组将被解释成索引a的第一维

s = array( [i,j] )  
a[s] # not what we want
# ---------------------------------------------------------------------------
# IndexError Traceback (most recent call last)
# <ipython-input-100-b912f631cc75> in <module>()
# ----> 1 a[s]

# IndexError: index (3) out of range (0<=index<2) in dimension 0
a[tuple(s)] # same as a[i,j]

另一个常用的数组索引用法是搜索时间序列最大值6。

In [12]:

time = linspace(20, 145, 5)                 # time scale
data = sin(arange(20)).reshape(5,4) # 4 time-dependent series
time

Out[12]:

array([  20.  ,   51.25,   82.5 ,  113.75,  145.  ])

In [13]:

data

Out[13]:

array([[ 0.        ,  0.84147098,  0.90929743,  0.14112001],
[-0.7568025 , -0.95892427, -0.2794155 , 0.6569866 ],
[ 0.98935825, 0.41211849, -0.54402111, -0.99999021],
[-0.53657292, 0.42016704, 0.99060736, 0.65028784],
[-0.28790332, -0.96139749, -0.75098725, 0.14987721]])

In [14]:

ind = data.argmax(axis=0)                   # index of the maxima for each series
ind

Out[14]:

array([2, 0, 3, 1])

In [15]:

time_max = time[ ind]                       # times corresponding to the maxima
data_max = data[ind, range(data.shape[1])] # => data[ind[0],0], data[ind[1],1]...
time_max

Out[15]:

array([  82.5 ,   20.  ,  113.75,   51.25])

In [16]:

data_max

Out[16]:

array([ 0.98935825,  0.84147098,  0.99060736,  0.6569866 ])

In [17]:

all(data_max == data.max(axis=0))   # True

Out[17]:

True

你也可以使用数组索引作为目标来赋值:

In [18]:

a = arange(5)
a

Out[18]:

array([0, 1, 2, 3, 4])

In [19]:

a[[1,3,4]] = 0
a

Out[19]:

array([0, 0, 2, 0, 0])

然而,当一个索引列表包含重复时,赋值被多次完成,保留最后的值:

In [20]:

a = arange(5)
a[[0,0,2]]=[1,2,3]
a

Out[20]:

array([2, 1, 3, 3, 4])

这足够合理,但是小心如果你想用Python的+=结构,可能结果并非你所期望:

In [21]:

a = arange(5)
a[[0,0,2]]+=1
a

Out[21]:

array([1, 1, 3, 3, 4])

即使0在索引列表中出现两次,索引为0的元素仅仅增加一次。这是因为Python要求a+=1a=a+1等同

通过布尔数组索引

当我们使用整数数组索引数组时,我们提供一个索引列表去选择。通过布尔数组索引的方法是不同的我们显式地选择数组中我们想要和不想要的元素。 我们能想到的使用布尔数组的索引最自然方式就是使用和原数组一样形状的布尔数组。

In [22]:

a = arange(12).reshape(3,4)
b = a > 4
b # b is a boolean with a's shape

Out[22]:

array([[False, False, False, False],
[False, True, True, True],
[ True, True, True, True]], dtype=bool)

In [23]:

a[b]    # 1d array with the selected elements

Out[23]:

array([ 5,  6,  7,  8,  9, 10, 11])

这个属性在赋值时非常有用:

In [24]:

a[b] = 0    # All elements of 'a' higher than 4 become 0
a

Out[24]:

array([[0, 1, 2, 3],
[4, 0, 0, 0],
[0, 0, 0, 0]])

你可以参考曼德博集合示例看看如何使用布尔索引来生成曼德博集合的图像。

第二种通过布尔来索引的方法更近似于整数索引;对数组的每个维度我们给一个一维布尔数组来选择我们想要的切片。

In [25]:

a = arange(12).reshape(3,4)
b1 = array([False,True,True]) # first dim selection
b2 = array([True,False,True,False]) # second dim selection
a[b1,:] # selecting rows

Out[25]:

array([[ 4,  5,  6,  7],
[ 8, 9, 10, 11]])

In [26]:

a[b1]                                     # same thing

Out[26]:

array([[ 4,  5,  6,  7],
[ 8, 9, 10, 11]])

In [27]:

a[:,b2]                                   # selecting columns

Out[27]:

array([[ 0,  2],
[ 4, 6],
[ 8, 10]])

In [28]:

a[b1,b2]                                  # a weird thing to do

Out[28]:

array([ 4, 10])

注意一维数组的长度必须和你想要切片的维度或轴的长度一致,在之前的例子中,b1是一个秩为1长度为三的数组(a的行数),b2(长度为4)与a的第二秩(列)相一致。

ix_()函数

ix_函数可以为了获得多元组的结果而用来结合不同向量。例如,如果你想要用所有向量abc元素组成的三元组来计算a+b*c

In [29]:

a = array([2,3,4,5])
b = array([8,5,4])
c = array([5,4,6,8,3])
ax,bx,cx = ix_(a,b,c)

In [30]:

ax

Out[30]:

array([[[2]],

[[3]],

[[4]],

[[5]]])

In [31]:

bx

Out[31]:

array([[[8],
[5],
[4]]])

In [32]:

cx 

Out[32]:

array([[[5, 4, 6, 8, 3]]])

In [33]:

ax.shape, bx.shape, cx.shape

Out[33]:

((4, 1, 1), (1, 3, 1), (1, 1, 5))

In [34]:

result = ax+bx*cx
result

Out[34]:

array([[[42, 34, 50, 66, 26],
[27, 22, 32, 42, 17],
[22, 18, 26, 34, 14]],

[[43, 35, 51, 67, 27],
[28, 23, 33, 43, 18],
[23, 19, 27, 35, 15]],

[[44, 36, 52, 68, 28],
[29, 24, 34, 44, 19],
[24, 20, 28, 36, 16]],

[[45, 37, 53, 69, 29],
[30, 25, 35, 45, 20],
[25, 21, 29, 37, 17]]])

In [35]:

result[3,2,4] 

Out[35]:

17

In [36]:

a[3]+b[2]*c[4] 

Out[36]:

17

你也可以实行如下简化:

In [37]:

def ufunc_reduce(ufct, *vectors):
vs = ix_(*vectors)
r = ufct.identity
for v in vs:
r = ufct(r,v)
return r

然后这样使用它:

In [38]:

ufunc_reduce(add,a,b,c)

Out[38]:

array([[[15, 14, 16, 18, 13],
[12, 11, 13, 15, 10],
[11, 10, 12, 14, 9]],

[[16, 15, 17, 19, 14],
[13, 12, 14, 16, 11],
[12, 11, 13, 15, 10]],

[[17, 16, 18, 20, 15],
[14, 13, 15, 17, 12],
[13, 12, 14, 16, 11]],

[[18, 17, 19, 21, 16],
[15, 14, 16, 18, 13],
[14, 13, 15, 17, 12]]])

这个reduceufunc.reduce(比如说add.reduce)相比的优势在于它利用了广播法则,避免了创建一个输出大小乘以向量个数的参数数组。

用字符串索引

参见 RecordArray

线性代数

简单数组运算

In [39]:

from numpy import *
from numpy.linalg import *
a = array([[1.0, 2.0], [3.0, 4.0]])
print (a)
[[ 1. 2.]
[ 3. 4.]]

In [40]:

a.transpose()

Out[40]:

array([[ 1.,  3.],
[ 2., 4.]])

In [41]:

inv(a)

Out[41]:

array([[-2. ,  1. ],
[ 1.5, -0.5]])

In [42]:

u = eye(2) # unit 2x2 matrix; "eye" represents "I"
u

Out[42]:

array([[ 1.,  0.],
[ 0., 1.]])

In [43]:

j = array([[0.0, -1.0], [1.0, 0.0]])
dot (j, j) # matrix product

Out[43]:

array([[-1.,  0.],
[ 0., -1.]])

In [44]:

trace(u)  # trace

Out[44]:

2.0

In [45]:

y = array([[5.], [7.]])
solve(a, y)

Out[45]:

array([[-3.],
[ 4.]])

In [46]:

eig(j)
# Parameters:
# square matrix
# Returns
# The eigenvalues, each repeated according to its multiplicity.
# The normalized (unit "length") eigenvectors, such that the
# column ``v[:,i]`` is the eigenvector corresponding to the
# eigenvalue ``w[i]``

Out[46]:

(array([ 0.+1.j,  0.-1.j]),
array([[ 0.70710678+0.j , 0.70710678-0.j ],
[ 0.00000000-0.70710678j, 0.00000000+0.70710678j]]))

矩阵类

这是一个关于矩阵类的简短介绍。

In [47]:

A = matrix('1.0 2.0; 3.0 4.0')
A

Out[47]:

matrix([[ 1.,  2.],
[ 3., 4.]])

In [48]:

type(A)  # file where class is defined

Out[48]:

numpy.matrixlib.defmatrix.matrix

In [49]:

A.T  # transpose

Out[49]:

matrix([[ 1.,  3.],
[ 2., 4.]])

In [50]:

X = matrix('5.0 7.0')
Y = X.T
Y

Out[50]:

matrix([[ 5.],
[ 7.]])

In [51]:

print (A*Y)  # matrix multiplication
[[ 19.]
[ 43.]]

In [52]:

print (A.I)  # inverse
[[-2. 1. ]
[ 1.5 -0.5]]

In [53]:

solve(A, Y)  # solving linear equation

Out[53]:

matrix([[-3.],
[ 4.]])

索引:比较矩阵和二维数组

注意Numpy中数组和矩阵有些重要的区别。Numpy提供了两个基本的对象:一个N维数组对象和一个通用函数对象。其它对象都是建构在它们之上 的。特别的,矩阵是继承自Numpy数组对象的二维数组对象。对数组和矩阵,索引都必须包含合适的一个或多个这些组合:整数标量、省略号 (ellipses)、整数列表;布尔值,整数或布尔值构成的元组,和一个一维整数或布尔值数组。矩阵可以被用作矩阵的索引,但是通常需要数组、列表或者 其它形式来完成这个任务。

像平常在Python中一样,索引是从0开始的。传统上我们用矩形的行和列表示一个二维数组或矩阵,其中沿着0轴的方向被穿过的称作行,沿着1轴的方向被穿过的是列。9

让我们创建数组和矩阵用来切片:

In [54]:

A = arange(12)
A

Out[54]:

array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

In [55]:

A.shape = (3,4)
M = mat(A.copy())
print (type(A)," ",type(M))
<class 'numpy.ndarray'> <class 'numpy.matrixlib.defmatrix.matrix'>

In [56]:

print (A)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]

In [57]:

print (M)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]

现在,让我们简单的切几片。基本的切片使用切片对象或整数。例如,A[:]M[:]的求值将表现得和Python索引很相似。然而要注意很重要的一点就是Numpy切片数组不创建数据的副本;切片提供统一数据的视图。

In [58]:

print (A[:])
print (A[:].shape)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
(3, 4)

In [59]:

print (M[:])
print (M[:].shape)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
(3, 4)

现在有些和Python索引不同的了:你可以同时使用逗号分割索引来沿着多个轴索引。

In [60]:

print (A[:,1])
print (A[:,1].shape)
[1 5 9]
(3,)

In [61]:

print (M[:,1]); 
print (M[:,1].shape)
[[1]
[5]
[9]]
(3, 1)

注意最后两个结果的不同。对二维数组使用一个冒号产生一个一维数组,然而矩阵产生了一个二维矩阵。10 例如,一个M[2,:]切片产生了一个形状为(1,4)的矩阵,相比之下,一个数组的切片总是产生一个最低可能维度11的数组。例如,如果C是一个三维数组,C[...,1]产生一个二维的数组而C[1,:,1]产生一个一维数组。从这时开始,如果相应的矩阵切片结果是相同的话,我们将只展示数组切片的结果。

假如我们想要一个数组的第一列和第三列,一种方法是使用列表切片:

In [62]:

A[:,[1,3]]

Out[62]:

array([[ 1,  3],
[ 5, 7],
[ 9, 11]])

稍微复杂点的方法是使用 take() 方法 method:

In [63]:

A[:,].take([1,3],axis=1)

Out[63]:

array([[ 1,  3],
[ 5, 7],
[ 9, 11]])

如果我们想跳过第一行,我们可以这样:

In [64]:

A[1:,].take([1,3],axis=1)

Out[64]:

array([[ 5,  7],
[ 9, 11]])

或者我们仅仅使用A[1:,[1,3]]。还有一种方法是通过矩阵向量积(叉积)。

In [65]:

A[ix_((1,2),(1,3))]

Out[65]:

array([[ 5,  7],
[ 9, 11]])

为了读者的方便,在次写下之前的矩阵:

In [66]:

A[ix_((1,2),(1,3))]

Out[66]:

array([[ 5,  7],
[ 9, 11]])

现在让我们做些更复杂的。比如说我们想要保留第一行大于1的列。一种方法是创建布尔索引:

In [67]:

A[0,:]>1

Out[67]:

array([False, False,  True,  True], dtype=bool)

In [68]:

A[:,A[0,:]>1]

Out[68]:

array([[ 2,  3],
[ 6, 7],
[10, 11]])

就是我们想要的!但是索引矩阵没这么方便。

In [69]:

M[0,:]>1

Out[69]:

matrix([[False, False,  True,  True]], dtype=bool)

<center>indice太多造成无法索引</center>

M[:,M[0,:]>1]  
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-65-79db943ff8d4> in <module>()
----> 1 M[:,M[0,:]>1]

~/anaconda/lib/python3.6/site-packages/numpy/matrixlib/defmatrix.py in __getitem__(self, index)
316
317 try:
--> 318 out = N.ndarray.__getitem__(self, index)
319 finally:
320 self._getitem = False

IndexError: too many indices for array

这个过程的问题是用“矩阵切片”来切片产生一个矩阵12,但是矩阵有个方便的A属性,它的值是数组呈现的。所以我们仅仅做以下替代:

In [70]:

M[:,M.A[0,:]>1]

Out[70]:

matrix([[ 2,  3],
[ 6, 7],
[10, 11]])

如果我们想要在矩阵两个方向有条件地切片,我们必须稍微调整策略,代之以:

In [71]:

A[A[:,0]>2,A[0,:]>1]

Out[71]:

array([ 6, 11])

In [72]:

M[M.A[:,0]>2,M.A[0,:]>1]

Out[72]:

matrix([[ 6, 11]])

我们需要使用向量积ix_:

In [73]:

A[ix_(A[:,0]>2,A[0,:]>1)]

Out[73]:

array([[ 6,  7],
      [10, 11]])

In [74]:

M[ix_(M.A[:,0]>2,M.A[0,:]>1)]

Out[74]:

matrix([[ 6,  7],
[10, 11]])

技巧和提示

下面我们给出简短和有用的提示。

"自动" 改变形状

更改数组的维度,你可以省略一个尺寸,它将被自动推导出来。

In [75]:

a = arange(30)
a.shape = 2,-1,3 # -1 means "whatever is needed"
a.shape

Out[75]:

(2, 5, 3)

In [76]:

a

Out[76]:

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]]])

向量组合(stacking)

我们如何用两个相同尺寸的行向量列表构建一个二维数组?在 MATLAB 中这非常简单:如果 xy 是两个相同长度的向量,你仅仅需要做 m=[x;y]。在 Numpy 中这个过程通过函数 column_stackdstackhstackvstack 来完成,取决于你想要在那个维度上组合。例如:

In [77]:

x = arange(0,10,2)
x

Out[77]:

array([0, 2, 4, 6, 8])

In [78]:

y = arange(5)  
y

Out[78]:

array([0, 1, 2, 3, 4])

In [79]:

m = vstack([x,y])           
m                                      

Out[79]:

array([[0, 2, 4, 6, 8],
      [0, 1, 2, 3, 4]])

In [80]:

xy = hstack([x,y])     
xy

Out[80]:

array([0, 2, 4, 6, 8, 0, 1, 2, 3, 4])

直方图(histogram)

Numpyhistogram函数应用到一个数组返回一对变量:直方图数组和箱式向量。注意:matplotlib也有一个用来建立直方图的函数(叫作hist,正如matlab中一样)与Numpy中的不同。 主要的差别是pylab.hist自动绘制直方图,而numpy.histogram仅仅产生数据

In [81]:

import numpy
import pylab
# Build a vector of 10000 normal deviates with variance 0.5^2 and mean 2
mu, sigma = 2, 0.5
v = numpy.random.normal(mu,sigma,10000)
# Plot a normalized histogram with 50 bins
pylab.hist(v, bins=50, normed=1)  
pylab.title('Matplotlib Version')# matplotlib version (plot)
pylab.show()
# Compute the histogram with numpy and then plot it
(n, bins) = numpy.histogram(v, bins=50, normed=True) # NumPy version (no plot)
pylab.plot(.5*(bins[1:]+bins[:-1]), n)
pylab.title('Numpy Version')
pylab.show()

img

img

 

 

task4-当Pandas遇上Numpy

https://www.heywhale.com/mw/project/604f1f86df26380015a06faa

posted @ 2022-08-10 09:21  peanut321  阅读(184)  评论(0编辑  收藏  举报