Numpy 是 Python 的一个科学计算包,包含了多维数组以及多维数组的操作
关于Numpy需要知道的几点:
Numpy 的核心是ndarray
对象,这个对象封装了同质数据类型的n维数组。起名 ndarray
的原因就是因为是 n-dimension-array
的简写。
import numpy as np
a = np.array([[0,1,2],[3,4,5],[6,7,8]], dtype=np.float32)
我们来看一下ndarray
如何在内存中储存的:关于数组的描述信息保存在一个数据结构中,这个结构引用两个对象,一块用于保存数据的存储区域和一个用于描述元素类型的dtype
对象。
数据存储区域保存着数组中所有元素的二进制数据,dtype
对象则知道如何将元素的二进制数据转换为可用的值。数组的维数、大小等信息都保存在ndarray
数组对象的数据结构中。
strides
中保存的是当每个轴的下标增加1时,数据存储区中的指针所增加的字节数。例如图中的strides
为12,4,即第0轴的下标增加1时,数据的地址增加12个字节:即a[1,0]的地址比a[0,0]的地址要高12个字节,正好是3个单精度浮点数的总字节数;第1轴下标增加1时,数据的地址增加4个字节,正好是单精度浮点数的字节数。
a = np.array([1, 2, 3]) # 1维数组
print(type(a), a.shape, a[0], a[1], a[2])
a[0] = 5 # 重新赋值
print(a)
<class 'numpy.ndarray'> (3,) 1 2 3
[5 2 3]
b = np.array([[1,2,3],[4,5,6]]) # 2维数组
print(b)
[[1 2 3]
[4 5 6]]
print(b.shape) #可以看形状(非常常用!)
print(b[0, 0], b[0, 1], b[1, 0])
(2, 3)
1 2 4
a = np.zeros((2,2)) # 创建2x2的全0数组
print(a)
[[ 0. 0.]
[ 0. 0.]]
b = np.ones((1,2)) # 创建1x2的全1数组
print(b)
[[ 1. 1.]]
c = np.full((2,2), 7) # 定值数组
print(c)
[[7 7]
[7 7]]
d = np.eye(2) # 对角矩阵(对角元素为1)
print(d)
[[ 1. 0.]
[ 0. 1.]]
e = np.random.random((2,2)) # 2x2的随机数组(矩阵)
print(e)
[[ 0.72776966 0.94164821]
[ 0.04652655 0.2316599 ]]
f = np.empty((2,3,2)) # empty是未初始化的数据,默认为0
print(f)
print(f.shape)
[[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]
[[ 0. 0.]
[ 0. 0.]
[ 0. 0.]]]
(2, 3, 2)
g = np.arange(15) # 用arange可以生成连续的一串元素
print(g)
print(g.shape)
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
(15,)
我们可以用dtype来看numpy数组中元素的类型:
x = np.array([1, 2]) # numpy构建数组的时候自己会确定类型
y = np.array([1.0, 2.0])
z = np.array([1, 2], dtype=np.int64)# 指定用int64构建
print(x.dtype, y.dtype, z.dtype)
int64 float64 int64
int_arr = np.array([1,2,3,4,5])
float_arr = int_arr.astype(np.float)
print(int_arr.dtype)
print(float_arr.dtype)
int32
float64
float_arr = np.array([3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
int_arr = float_arr.astype(dtype = np.int)
print(int_arr)
[ 3 -1 -2 0 12 10]
str_arr = np.array(['1.25', '-9.6', '42'], dtype = np.string_)
float_arr = str_arr.astype(dtype = np.float)
print(float_arr)
[ 1.25 -9.6 42. ]
int_arr = np.arange(10)
float_arr = np.array([.23, 0.270, .357, 0.44, 0.5], dtype = np.float64)
print(int_arr.astype(float_arr.dtype)) #转换为浮点类型 [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
print(int_arr[0], int_arr[1]) # 0 1
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
0 1
当计算和操作数组时,它们的数据有时被复制到新的数组中,有时不复制。这里我们做个区分。
简单赋值不会创建数组对象或其数据的拷贝。
a = np.arange(6)
print(a)
b = a
print(id(a))
print(id(b)) # id(a)和id(b)结果相同
b.shape = 3,2
print(a.shape) # 修改b形状,结果a的形状也变了
[0 1 2 3 4 5]
3169669797808
3169669797808
(3, 2)
不同的数组对象可以共享相同的数据。view
方法创建一个新数组对象,该对象看到相同的数据。与前一种情况不同,新数组的维数更改不会更改原始数据的维数,但是新数组数据更改后,也会影响原始数据。
a = np.arange(6)
c = a.view()
print(c is a) #False
print(c.base is a) #True
print(c.flags.owndata) #False
c.shape =(2,3)
print(a.shape) #(6,)
c[0,1] = 1234
print(a) # [ 0 1234 2 3 4 5]
False
True
False
(6,)
[ 0 1234 2 3 4 5]
copy
方法生成数组及其数据的完整拷贝。
a = np.arange(6)
d = a.copy() # 一个完整的新的数组
print(d is a)
print(d.base is a )
d[0] = 9999
print(a) # 修改数组 d 的值,a不会受影响
False
False
[0 1 2 3 4 5]
import numpy as np
# 创建一个如下格式的3x4数组
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
# 在两个维度上分别按照[:2]和[1:3]进行切片,取需要的部分
# [[2 3]
# [6 7]]
b = a[:2, 1:3]
print(b)
[[2 3]
[6 7]]
# 创建3x4的2维数组/矩阵
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
print(a)
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
多维数组可以从各个维度同时切片
row_r1 = a[1, :] # 第2行,但是得到的是1维输出(列向量)
row_r2 = a[1:2, :] # 1x2的2维输出
row_r3 = a[[1], :] # 同上
print(row_r1, row_r1.shape) #[5 6 7 8] (4,)
print(row_r2, row_r2.shape) #[[5 6 7 8]] (1, 4)
print(row_r3, row_r3.shape) #[[5 6 7 8]] (1, 4)
[5 6 7 8] (4,)
[[5 6 7 8]] (1, 4)
[[5 6 7 8]] (1, 4)
# 试试在第2个维度上切片也一样的:
col_r1 = a[:, 1]
col_r2 = a[:, 1:2]
print(col_r1, col_r1.shape) #[ 2 6 10] (3,)
print()
print(col_r2, col_r2.shape)
[ 2 6 10] (3,)
[[ 2]
[ 6]
[10]] (3, 1)
a = np.array([[1,2], [3, 4], [5, 6]])
# 其实意思就是取(0,0),(1,1),(2,0)的元素组起来
print(a[[0, 1, 2], [0, 1, 0]])
# 下面这个比较直白啦
print(np.array([a[0, 0], a[1, 1], a[2, 0]]))
[1 4 5]
[1 4 5]
# 再来熟悉一下
# 先创建一个2维数组
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
print(a)
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
# 用下标生成一个向量
b = np.array([0, 2, 0, 1])
print(a[np.arange(4), b]) # Print "[ 1 6 7 11]"
[ 1 6 7 11]
# 既然可以取出来,我们当然可以对这些元素操作
a[np.arange(4), b] += 10
print(a)
[[11 2 3]
[ 4 5 16]
[17 8 9]
[10 21 12]]
a = np.array([[1,2], [3, 4], [5, 6]])
bool_idx = (a > 2) # 就是判定一下是否大于2
print(bool_idx) # 返回一个布尔型的3x2数组
[[False False]
[ True True]
[ True True]]
# 用刚才的布尔型数组作为下标就可以去除符合条件的元素啦
print(a[bool_idx])
# 其实一句话也可以完成是不是?
print(a[a > 2])
[3 4 5 6]
[3 4 5 6]
[numpy指南]http://docs.scipy.org/doc/numpy/reference/
[numpy ndarray详解]https://danzhuibing.github.io/py_numpy_ndarray.html
[NumPy-快速处理数据]http://old.sebug.net/paper/books/scipydoc/numpy_intro.html