NumPy 基础使用

8 minute read

Published:

下面介绍关于 NumPy 的基本函数使用。

在机器学习中不要使用一维数组,请使用二维矩阵!

请注意函数返回的是否是一维数组

请注意浅拷贝与深拷贝的区别

请注意设置 dtype

数据类型转换请使用 astype(),不要直接修改 dtype

numpy 中 array 和 asarray 的区别

array 和 asarray 都可以将结构数据转化为 ndarray,但是主要区别就是当数据源是 ndarray 时,array 仍然会 copy 出一个副本,占用新的内存,但 asarray 不会,返回的是视图。

创建数组

不要创建一维数组,请创建二维矩阵

import numpy as np

# 创建数组
a = np.array([[1, 2, 3], [4, 5, 6]])        # int64
b = np.array([[1.0, 2.0, 3.0], [4, 5, 6]])  # float64

# 设置 dtype: np.int32, np.float32, np.complex
# 注意:由于 torch 默认创建 int 是 64 位的,float 是 32 位的,也要指定 dtype。
a = np.array([1, 2, 3], dtype=np.int64)     # int64
b = np.array([1, 2, 3], dtype=np.float32)   # float32
c = np.array([1, 2, 3], dtype=np.complex)   # complex

# a = np.array(1, 2, 3)  # wrong


# 下面两种的不同
a = np.array([[1, 2, 3]])
print(a.shape)  # (1, 3)
a = np.array([1, 2, 3])
print(a.shape)  # (3,)


# 下面两种的不同
a = np.random.randn(3, 1)
print(a.shape)  # (3, 1)
a = np.random.randn(3)
print(a.shape)  # (3,)


# 创建全零数组 类型都是float64
a = np.zeros((4, 3))  # 数据全为 0,4 行 3 列


# 创建全 1 数组
b = np.ones((4, 3))  # 数据全为 0,4 行 3 列


# 用 arange 创建连续数组:
a = np.arange(1, 11, 2)  # 1~10 的数据,2 步长,[1, 3, 5, 7, 9]


# 用 linspace 创建线段型数据:
a = np.linspace(0, np.pi, 3)  # [0., 1.57079633, 3.14159265]

创建随机数组

# 标准正态分布
a = np.random.randn(2,3)
a = np.random.standard_normal(size=(2,3))

# 正态分布:均值为 loc,标准差为 scale
a = np.random.normal(loc=0.0, scale=1.0, size=(2,3))

# 均匀分布:[0,1) 之间的的随机浮点数
a = np.random.rand(2,3)
a = np.random.ranf(size=(2,3))
a = np.random.random(size=(2,3))
a = np.random.random_sample(size=(2,3))

# 均匀分布:[low, high) 之间的的随机浮点数
np.random.uniform(low=2, high=6, size=(2,3))#指定均匀分布

# 均匀分布:[low, high) 之间的随机整数
a = np.random.randint(low=2, high=6, size=(2,3))

# 均匀分布:[low, high] 之间的随机整数
a = np.random.random_integers(low=2, high=6, size=(2,3))

# 均匀分布:从给定的列表中随机选择
# a : 1-D array-like or int
# replace : Whether the sample is with or without replacement
# p : 1-D array-like, The probabilities associated with each entry in a.
np.random.choice(a=[1, 2, 3], size=(2,3), replace=True, p=[0.1,0.2,0.7])

# 随机打乱数组(in-place)
# 如果 a 为多维数组,只沿第一条轴打乱。
a = [1, 2, 3, 4, 5]
b = np.random.shuffle(a)
print(a)        # [3, 1, 5, 4, 2]
print(type(a))  # <class 'list'>
print(b)        # None

# 随机打乱数组(not in-place)
# 如果 a 为多维数组,只沿第一条轴打乱。
a = [1, 2, 3, 4, 5]
b = np.random.permutation(a)
print(a)        # [3, 1, 5, 4, 2]
print(type(a))  # <class 'list'>
print(b)        # [3 4 2 5 1]
print(type(b))  # <class 'numpy.ndarray'>

创建网格数据

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0,1000,20)
y = np.linspace(0,500,20)

X, Y = np.meshgrid(x, y)

plt.plot(X, Y,
         color='limegreen',  # 设置颜色为limegreen
         marker='.',         # 设置点类型为圆点
         linestyle='')       # 设置线型为空,也即没有线连接点
plt.grid(True)
plt.show()

array 常用的属性

# 维度
print('number of dim:', a.ndim)


# 行数和列数 (list对象没有shape这个属性)
print('shape :', a.shape)
[row, col] = a.shape


# 对应维度的长度
print('shape :', a.shape[n])


# 元素个数
print('size:', a.size)


# 数据类型
print('dtype:', a.dtype)

数据类型转换

numpy 中的数据类型转换,只能用函数 astype(),不能直接改原数据的 dtype,否则会改变数组维度!。

a = np.array([1, 2, 3], dtype=np.int32)  # int32
b = a.astype(np.float32)                 # float32

维度改变

将 1 维转换成 2 维

print(a[np.newaxis,:])        # [[1 1 1]] 

print(a[np.newaxis,:].shape)  # (1, 3)

print(a[:,np.newaxis])        # [[1], [1], [1]]

print(a[:,np.newaxis].shape)  # (3, 1)

改变形状

# reshape 改变数据的形状 但元素的 size 是不变的
a = np.arange(12).reshape(3, 4)    # 0~11 的数据,3 行 4 列
# a = np.arange(12).reshape(2, 4)  # wrong

矩阵拉平

a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([[1], [2], [3]])


# np.flatten() 返回一份拷贝,对拷贝所做修改不会影响原始矩阵
print(a.flatten())  # [1, 2, 3, 4, 5, 6]
print(b.flatten())  # [1, 2, 3]


# np.ravel() 返回的是视图,修改时会影响原始矩阵 
print(a.ravel())    # [1, 2, 3, 4, 5, 6]
print(b.flatten())  # [1, 2, 3]


# np.squeeze() 只能对维数为1的维度降维, 返回的是视图,修改时会影响原始矩阵 
print(a.squeeze())  # [[1, 2, 3], [4, 5, 6]]
print(b.squeeze())  # [1, 2, 3]


# np.reshape(-1) 返回的是视图,修改时会影响原始矩阵 
print(a.reshape(-1))  # [[1, 2, 3, 4, 5, 6]]
print(b.reshape(-1))  # [1, 2, 3]

基本运算

numpy 的数组类被称为 ndarray,ndarray 的基本运算大都是对应位置的两个元素之间进行运算,除了 dot (矩阵乘法)

a = np.array([10, 20, 30])

b = np.arange(1, 4)

c = a + b  # [11, 22, 33]

d = a - b  # [9, 18, 27]

e = a * b  # [10, 40, 90]

f = np.dot(a, b)  # 另一种写法 f = a.dot(b) # 140

g = b**2   # [1, 4, 9]

broadcasting

矩阵转置

a = np.array([[1, 2, 3], [4, 5, 6]])

print(a.T)
print(np.transpose(a))


# 但是对 1 维数组来说,这样求得的转置是不对的,得先 reshape 成二维数组
b = np.array([1, 1, 1])
print(b.shape)    # (3,)
print(b.T.shape)  # (3,)
print(np.transpose(b).shape)  # (3,)

c = b[:, np.newaxis]
print(c.shape)    # (3, 1)
print(c.T.shape)  # (1, 3)
print(np.transpose(c).shape)  # (1, 3)

舍入函数

np.around()  # 函数返回指定数字的四舍五入值。

np.floor()   # 返回数字的下舍整数。

np.ceil()    # 返回数字的上入整数。

*np.dot()np.multiply() 区别

 listnp.arraynp.mat()
*error点乘叉乘
np.dot()一维内积,其他叉乘一维内积,其他叉乘叉乘
np.multiply()点乘点乘点乘

参数 axis

axis 用来指明将要进行的运算是沿着哪个轴执行, 通常 numpy 里面的一些降维操作(aggregate functions)需要我们指定对应的维度,比如 sum 函数表示对哪个维度求和,max 表示对哪个维度求最大值。通常当我们在这些函数里面指定了 axis=n 时,那么函数输出的数组当中,原来的第 n 维就被消除了,沿着该轴的方向走去执行操作。

求最值

求矩阵和/最小值/最大值,axis 指定维度,不指定默认整个矩阵

a = np.array([[1, 2, 3], [4, 5, 6]]) 

print(a.sum())        # 21

print(a.sum(axis=0))  # [5, 7, 9]

print(a.sum(axis=1))  # [6, 15]

print(a.min())        # 1

print(a.min(axis=0))  # [1, 2, 3]

print(a.min(axis=1))  # [1, 4]

print(a.max())        # 6

print(a.max(axis=0))  # [4, 5, 6]

print(a.max(axis=1))  # [3, 6]

索引

在索引的时候不要写成 [][] 的形式,要使用 [,]

a = np.arange(12).reshape(3,4)
"""
[[ 0,  1,  2,  3],
 [ 4,  5,  6,  7],
 [ 8,  9, 10, 11]]
"""


# 求最小/最大元素的索引,索引的是平铺数组,可输入参数 axis
print(np.argmin(a))  # 0
print(np.argmax(a))  # 11
print(np.argmin(a, axis=0))  # [0 0 0 0]
print(np.argmax(a, axis=1))  # [3 3 3]


# 获取多维数组最值索引
index = np.unravel_index(a.argmax(), a.shape)  # (2, 3)


# 一维索引  
print(a[0])  # [0 1 2 3]


# 二维索引  
print(a[0][1])      # 1
print(a[0, 1])      # 1
print(a[1, 1:3])    # [5 6]
print(a[1, :])      # [4 5 6 7]
print(a[:, -1])     # [3 7 11]
print(a[:, 1:3])    # [[1  2], [5  6], [9 10]]
print(a[:, 1:3:2])  # [[1], [5], [9]],列从索引 1 开始到索引 3 停止,间隔为 2
print(a[:, [1, 2]])  # [[1  2], [5  6], [9 10]]
print(a[[0, 1], [1, 2]])  # [1, 6]


# 布尔索引
print(a[a > 5])  # [ 6,  7,  8,  9, 10, 11]


# 数组遍历
[row, col] = a.shape
for i in range(row):
	for j in range(col):
  	print(a[i, j])

    
numpy.where()  # 函数返回输入数组中满足给定条件的元素的索引。

拼接

1 维数组拼接

建议使用 np.vstack()、np.hstack()、np.stack()

a = np.array([1, 1, 1])
b = np.array([2, 2, 2])


# 对比 np.vstack() 和 np.hstack()
print(np.vstack((a, b)))
"""
[[1 1 1]
 [2 2 2]]
"""

print(np.hstack((a, b)))  # [1 1 1 2 2 2]


# 对比 np.concatenate()
print(np.concatenate((a, b), axis=0))  # [1 1 1 2 2 2]

print(np.concatenate((a, b), axis=1))  # wrong


# 对比 np.append()
print(np.append(a, b, axis=0))  # [1 1 1 2 2 2]

print(np.append(a, b, axis=1))  # wrong


# 对比 np.r_() 和 np.c_()
print(np.r_[a, b])  # [1 1 1 2 2 2]

print(np.c_[a, b])	
"""
[[1 2]
 [1 2]
 [1 2]]
"""


# 对比 np.stack()
print(np.stack((a, b)))
"""
[[1 1 1]
 [2 2 2]]
"""
print(np.stack((a, b)).shape)  # (2, 3)

2 维矩阵拼接

建议使用 np.vstack()、np.hstack()、np.stack()

a = np.array([[1, 1, 1]])
b = np.array([[2, 2, 2]])


# 对比 np.vstack() 和 np.hstack()
print(np.vstack((a, b)))
"""
[[1 1 1]
 [2 2 2]]
"""

print(np.hstack((a, b)))  # [[1 1 1 2 2 2]]


# 对比 np.concatenate()
print(np.concatenate((a, b), axis=0))
"""
[[1 1 1]
 [2 2 2]]
"""

print(np.concatenate((a, b),axis=1))  # [[1 1 1 2 2 2]]


# 对比 np.append()
print(np.append(a, b, axis=0))
"""
[[1 1 1]
 [2 2 2]]
"""

print(np.append(a, b, axis=1))  # [[1 1 1 2 2 2]]


# 对比 np.r_() 和 np.c_()
print(np.r_[a, b])
"""
[[1 1 1]
 [2 2 2]]
"""

print(np.c_[a, b])  # [[1 1 1 2 2 2]]


# 对比 np.stack()
print(np.stack((a, b)))
"""
[[[1 1 1]]
 [[2 2 2]]]
"""
print(np.stack((a, b)).shape)  # (2, 1, 3)

矩阵分割

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

# 矩阵等量分割
print(np.split(a, 2, axis=1))  # 纵向分割
"""
[array([[0, 1],
       [4, 5],
       [8, 9]]), 
 array([[ 2,  3],
       [ 6,  7],
       [10, 11]])]
"""

print(np.split(a, 3, axis=0))  # 横向分割
"""
[array([[0, 1, 2, 3]]),
 array([[4, 5, 6, 7]]), 
 array([[ 8,  9, 10, 11]])]
"""

# print(np.split(a, 3, axis=1))	# wrong,矩阵只有 4 列,企图在纵向分割成 3 份,无法等量分割


# 矩阵不等量分割
print(np.array_split(a, 3, axis=1))
"""
[array([[0, 1],
       [4, 5],
       [8, 9]]),
 array([[ 2],
       [ 6],
       [10]]),
 array([[ 3],
       [ 7],
       [11]])]
"""

NumPy IO

a = np.arange(0, 10)
np.savetxt("out.txt", a, fmt="%s", delimiter=",")  # 改为保存为字符串,以逗号分隔
b = np.loadtxt("out.txt", delimiter=",")  # load 时也要指定为逗号分隔

占用内存大小

import numpy as np
import sys

a = np.array([1, 1, 1],dtype=np.int64)
b = np.array([],dtype=np.int64)

print(a.nbytes)          # 24
print(sys.getsizeof(a))  # 128

print(b.nbytes)          # 0
print(sys.getsizeof(b))  # 104

参考资料及致谢

NumPy 官方文档

NumPy 教程

第二周:numpy和pandas

np.ravel()和np.flatten()

numpy中的ravel()、flatten()、squeeze()的用法与区别

NumPy 副本和视图

详解Numpy中的数组拼接、合并操作(concatenate, append, stack, hstack, vstack, r_, c_等)

numpy矩阵遍历

numpy.meshgrid()理解

numpy各种生成随机数的方法

Numpy 随机数

细说Python中numpy的nbytes方法