1. 什么是np?
在Python的科学计算库中,numpy(np)是最重要和最基础的库之一。它是一个用 Python 进行科学计算的核心库,提供了高效的多维数组类型及其相关功能。
numpy最基本的数据结构是ndarray——n-dimensions array object,也就是多维数组。numpy中的函数和操作都是针对多维数组展开的。因此,熟练地使用numpy的多维数组,也就迈出了Python科学计算的第一步。
2. 如何创建ndarray?
2.1 从常规Python列表或元组中创建
使用numpy.array()可从普通Python列表或元组中创建数组,并将它们转化成ndarray对象。下面是一个简单的例子:
import numpy as np
a = np.array([1,2,3])
print(a)
输出结果为:[1 2 3]
此外,可以使用多维列表来创建ndarray:
b = np.array([[1, 2], [3, 4]])
print(b)
输出结果为:
[[1 2]
[3 4]]
在创建时,也可以通过指定dtype参数来指定数组元素的数据类型。例如如下代码创建一个2x2的整数类型数组:
c = np.array([[1, 2], [3, 4]], dtype=complex)
print(c)
输出结果为:
[[1.+0.j 2.+0.j]
[3.+0.j 4.+0.j]]
2.2 使用numpy提供的函数创建
numpy还提供了一些函数用来创建多维数组。例如:
# 创建一个元素为0的3x4的浮点数类型数组
d = np.zeros((3, 4))
print(d)
# 创建一个元素为1的2x3的整数类型数组
e = np.ones((2, 3), dtype=int)
print(e)
# 创建一个一维等差数列,从0开始,以2为步长,不包括10
f = np.arange(0, 10, 2)
print(f)
# 创建一个由随机数构成的2x3的数组
g = np.random.random((2, 3))
print(g)
运行结果为:
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[1 1 1]
[1 1 1]]
[0 2 4 6 8]
[[0.72777646 0.75447913 0.34044335]
[0.81508116 0.00245057 0.89333391]]
2.3 其它方式创建
除了上面介绍的方式,还有其它一些方式来创建多维数组。例如,使用numpy.eye()可以创建一个对角线元素为1,其它元素为0的n x n矩阵:
h = np.eye(3)
print(h)
输出结果为:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
3. ndrray的属性
ndarray数组的重要性质有:shape、dtype、size等。接下来我们分别介绍这几个属性的含义。
3.1 shape
ndarray.array.shape表示数组的维度,它返回一个元组。此元组的长度就是数组的维度数,即ndim属性(下面会介绍)。例如:
i = np.array([[1, 2], [3, 4]])
print(i.shape)
输出结果为:
(2, 2)
如果一个数组的shape是(2, 3, 4),则它包含两个二维数组,每个二维数组又有3个一维数组,每个一维数组里面有4个元素。
3.2 dtype
ndarray对象有一个dtype属性,它用来描述数组中元素的数据类型。numpy支持的数据类型有:float、complex、bool、string等等。dtype是numpy在创建数组时自动推断出来的,也可以自定义。例如:
j = np.array([1, 2, 3], dtype=np.int32)
print(j.dtype)
输出结果为:
int32
另外还有一种情况:使用方法库中的数据类型。例如:
k = np.array([1, 2, 3], dtype=np.float64)
l = np.array([1, 2, 3], dtype=np.complex64)
print(k.dtype)
print(l.dtype)
输出结果为:
float64
complex64
3.3 itemsize
ndarray对象的itemsize属性返回数组中每个元素的字节大小。例如:
m = np.array([1, 2, 3], dtype=np.float64)
print(m.itemsize)
输出结果为:
8
这里的8是指每个元素占用的字节数。因为8个字节能够存储一个64位的浮点数。同理,32位的整型会占用4个字节,而64位的整型会占用8个字节。
4. ndarrary的操作
4.1 索引和切片
和Python的原生列表一样,numpy多维数组的索引下标也是从0开始的。如下面的代码所示:
n = np.array([[1, 2], [3, 4], [5, 6]])
print(n[0, 0])
print(n[2, 1])
输出结果为:
1
6
ndarray的切片是从原数组中即刻取出一些特定的子数组。下面的代码展示如何使用切片获取第一和第二行,第一和第二列:
o = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(o[:2, 1:])
# 对于切片取出的子数组,各维度的长度可以一起使用整数或者冒号来指定.
p = np.array([[[ 0, 1, 2], [ 3, 4, 5]],
[[ 6, 7, 8], [ 9, 10, 11]]])
print(p.shape)
print(p[1,:,:2])
输出结果为:
[[2 3]
[5 6]]
(2, 2, 3)
[[6 7]
[9 10]]
4.2 数组转置和换轴
转置是重塑数据的一种特殊方式。可以通过调用数组的T属性来转置一个数组,也可以使用transpose方法来指定轴的顺序进行转置操作。
q = np.array([[1, 2], [3, 4]])
print(q.T)
r = np.arange(24).reshape((2, 3, 4))
print(r.transpose((1, 0, 2)))
输出结果为:
[[1 3]
[2 4]]
[[[ 0 1 2 3]
[12 13 14 15]
[24 25 26 27]]
[[ 4 5 6 7]
[16 17 18 19]
[28 29 30 31]]
[[ 8 9 10 11]
[20 21 22 23]
[32 33 34 35]]]
上面的代码中,transpose()函数的参数(1, 0, 2)意味着将第一个轴转换为第二个轴,第二个轴转换为第一个轴,扩展到第三个轴。
4.3 数组重塑
numpy数组的.shape属性提供了一个这样的属性可以将数组的形状重塑,它不修改原始数组的数据。例如:
s = np.arange(15).reshape((3, 5))
print(s)
输出结果为:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]]
4.4 连接和分割数组
numpy中的concatenate函数可以沿着一个已有的轴将数组连结在一起.
t1 = np.array([[1,2,3],[4,5,6]])
t2 = np.array([[7,8,9],[10,11,12]])
print(np.concatenate([t1, t2], axis=0))
输出结果为:
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
np.split函数,和concatenate相反,是在一个特定轴上将一个数组分裂成多个小数组。下面的代码将一个数组分裂成三个等份:
u = [1, 2, 3, 99, 99, 3, 2, 1]
u1, u2, u3 = np.split(u, [3, 5])
print(u1, u2, u3)
输出结果为:
[1 2 3] [99 99] [3 2 1]
np.vsplit和np.hsplit函数用于水平和竖直方向分割数组。
5. ufunc(通用函数)
ufunc是一种能对数组的每个元素进行操作的函数。这些操作可以是简单的运算(如:+、-、*、/),指数、对数、三角函数等等。
例如,下面代码对数组的每个元素进行平方根计算
v = np.sqrt([1, 4, 9])
print(v)
输出结果为:
[1. 2. 3.]
numpy是使用C写成的,所以它的ufunc(不像Python中简单操作)是在数据内存中执行的,而不是通过一个解释器间接地进行循环。
6. 广播
广播是numpy对不同形状的数组进行数学运算的方式,对数组的某个维度进行扩展,使其具有相同的shape值,然后再element-wise做运算,以便完成需要的计算。
例如,有两个数组:
w = np.array([1.0, 2.0, 3.0])
x = np.array([2.0, 2.0, 2.0])
我们希望对它们进行element-wise求积。使用广播来计算这个运算,代码如下:
y = w * x
print(y)
输出结果为:
[2. 4. 6.]
这样的代码被称作代码的广播(有时也叫隐式的复制)。
如果两个数组的shape不同,numpy会寻找两个arrays的shape是否可以在某些维度上进行广播。规则是,如果两个arrays的后缘维度(即从末尾开始算起的维度)的轴长度相符或其中一方的长度为1,则认为它们是广播兼容(对于数字,复数或者布尔型)。广播会对缺失的地方补1,直到两个arrays的shape保持一致。
7. slicing和masking
slicing:就是你按照一定位置和步长获取一个数组的概念。
例如下面代码获取数组中在第二行及以下的元素组成的子矩阵:
z1 = np.array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]])
z2 = z1[1:3]
print(z2)
输出结果为:
[[3 4 5]
[6 7 8]]
masking:是指你基于一定的条件从一个数组中获取一些元素而快速生成一个新的数组。
例如下面的代码使用掩码mask来检索指定条件(例如,获取数组中所有大于5的值)的数组。
z3 = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
z4 = z3[z3 > 5]
print(z4)
输出结果为:
[6 7 8 9]
以上就是numpy中常见的操作,包括数组的创建、操作等。熟练地掌握这些常见操作,将帮助我们更高效地进行数据处理。