NumPy
简介
Numpy 是使用 Python 进行科学计算的基础包。它包含如下内容:
-
一个强大的 N 维数组对象
-
复杂的(广播)功能
-
用于集成 C/C++ 和 Fortran 代码的工具
-
有用的线性代数,傅里叶变换和随机数功能
除了明显的科学用途外,NumPy 还可以用作通用数据的高效多维容器。可以定义任意数据类型。这使 NumPy 能够无缝快速地与各种数据库集成
特点
-
numpy 能提供类似于 C 的数组的结构 ndarray,一维的常称为向量 vector,多维的称之为矩阵 matrix。
-
numpy 的数组(向量、矩阵)的各类运算要比 Python 里类似结构类型 list 列表运算处理速度要快很多!
Numpy 和原生 Python 的对比
语法实现对比
# 使用 Python 原生语法
import numpy as np
def python_sum(n):
a = [i**2 for i in range(n)]
b = [i**3 for i in range(n)]
c = []
for i in range(n):
c.append(a[i] + b[i])
return c
# Numpy 实现
def numpy_sum(n):
a = np.arange(n) ** 2
b = np.arange(n) ** 3
return a+b
Numpy 的核心 array 对象
array 对象的背景
- Numpy 的核心数据结构,就叫做 array 就是数组,array 对象可以是一维数组,也可以是多维数组;
- Python 的 List 也可以实现相同的功能,但是 array 比 List 的优点在于性能好、包含数组元数据信息、大量的便捷函数;
- Numpy 成为事实上的 Scipy、Pandas、Scikit-Learn、Tensorflow、PaddlePaddle 等框架的 “通用底层语言”
- Numpy 的 array 和 Python 的 List 的一个区别,是它元素必须都是同一种数据类型,比如都是数字int类型,这也是 Numpy 高性能的一个原因;
array 本身支持的大量操作和函数
- 直接逐元素的加减乘除等算数操作
- 更好用的面向多维的数组索引
- 求 sum/mean 等聚合函数
- 线性代数函数,比如求解逆矩阵、求解方程组
array 数组属性
属性 | 说明 |
---|---|
ndim | 返回 int ;表示数组的维数 |
shape | 返回 tuple ;表示数组的尺寸,对于 n 行 m 列的矩阵,形状为 (n, m) |
size | 返回 int ;表示数组的元素总数,等于数组形状的乘积 |
dtype | 返回 data-type ;描述数组中元素的类型 |
itemsize | 返回 int ;表示数组的每个元素的大小(以字节为单位) |
ndim
X = np.array(
[[1, 2, 3, 4],
[5, 6, 7, 8]]
)
X.ndim
# 2
shape
x = np.array([1, 2, 3, 4, 5, 6, 7, 8])
X = np.array(
[[1, 2, 3, 4],
[5, 6, 7, 8]]
)
x.shape # (8,)
X.shape # (2, 4)
size
x = np.array([1, 2, 3, 4, 5, 6, 7, 8])
X = np.array(
[[1, 2, 3, 4],
[5, 6, 7, 8]]
)
x.size # 8
X.size # 8
dtype
x = np.array([1, 2, 3, 4, 5, 6, 7, 8])
X = np.array(
[[1, 2, 3, 4],
[5, 6, 7, 8]]
)
x.dtype # dtype('int32')
X.dtype # dtype('int32')
创建 array
-
从 Python 的列表 List 和嵌套列表创建 array
import numpy as np # 创建一个一维数组,也就是 Python 的单元素 List x = np.array([1, 2, 3, 4, 5, 6, 7, 8]) x # array([1, 2, 3, 4, 5, 6, 7, 8])
# 创建一个二维数组,也就是 Python 的嵌套 List X = np.array( [[1, 2, 3, 4], [5, 6, 7, 8]] ) X # array([[1, 2, 3, 4],[5, 6, 7, 8]])
-
arange 函数创建
arange([start,] stop[, step,], dtype=None)
import numpy as np a = np.arange(15).reshape(3,5) a ''' array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) '''
np.arange(2, 10, 2) # array([2, 4, 6, 8])
-
ones 函数创建
np.ones(shape, dtype=None, order='C') shape : int or tuple of ints Shape of the new array, e.g. (2, 3) or 2.
np.ones(10) # array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
np.ones((2,3)) ''' array([[1., 1., 1.], [1., 1., 1.]]) '''
-
ones_like 函数创建
创建全是 1 形状相同的数组
ones_like(a, dtype=float, order='C')
x = np.array([1, 2, 3, 4, 5, 6, 7, 8]) X = np.array( [[1, 2, 3, 4], [5, 6, 7, 8]] ) np.ones_like(x) # array([1, 1, 1, 1, 1, 1, 1, 1]) np.ones_like(X) ''' array([[1, 1, 1, 1], [1, 1, 1, 1]]) '''
-
zeros 函数创建
np.zeros(shape, dtype=None, order='C')
np.zeros(10) # array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
np.zeros((2,4)) ''' array([[0., 0., 0., 0.], [0., 0., 0., 0.]]) '''
-
zeros_like 函数创建
创建全是 0 形状相同的数组
zeros_like(a, dtype=float, order='C')
x = np.array([1, 2, 3, 4, 5, 6, 7, 8]) X = np.array( [[1, 2, 3, 4], [5, 6, 7, 8]] ) np.zeros_like(x) # array([0, 0, 0, 0, 0, 0, 0, 0]) np.zeros_like(X) ''' array([[0, 0, 0, 0], [0, 0, 0, 0]]) '''
-
empty 函数创建
empty(shape, dtype=float, order='C')
注意:数据是未初始化的,里面的值可能是随机值不要用
np.empty(10) # array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
-
empty_like 函数创建
empty_like(prototype, dtype=None)
x = np.array([1, 2, 3, 4, 5, 6, 7, 8]) X = np.array( [[1, 2, 3, 4], [5, 6, 7, 8]] ) np.empty_like(x) # array([120, 46, 110, 100, 105, 109, 101, 0]) np.empty_like(X) ''' array([[0, 0, 0, 0], [0, 0, 0, 0]]) '''
-
full 函数创建
np.full(shape, fill_value, dtype=None, order='C')
np.full(10, 666) # array([666, 666, 666, 666, 666, 666, 666, 666, 666, 666])
np.full((2,4), 333) ''' array([[333, 333, 333, 333], [333, 333, 333, 333]]) '''
-
full_like 函数创建
np.full_like(a, fill_value, dtype=None)
x = np.array([1, 2, 3, 4, 5, 6, 7, 8]) np.full_like(x, 666) # array([666, 666, 666, 666, 666, 666, 666, 666])
随机数函数
函数 | 说明 |
---|---|
seed | 确定随机数生成器的种子 |
permutation | 返回一个序列的随机排列或返回一个随机排列的范围 |
shuffle | 对一个序列就地随机排列 |
rand | 产生均匀分布的样本值 |
randint | 从给定的上下限范围内随机选取整数 |
randn | 产生正态分布 (平均值为 0;标准差为 1) 的样本值 |
binomial | 产生二项分布的样本值 |
normal | 产生正态 (高斯) 分布的样本值 |
beta | 产生 Beta 分布的样本值 |
chisquare | 产生卡方分布的样本值 |
gamma | 产生 Gamma 分布的样本值 |
uniform | 产生在 [0, 1) 中均匀分布的样本值 |
randn(d0, d1, ..., dn)
np.random.randn()
# -0.24298859935537268
np.random.randn(3)
# array([-0.630065 , -1.15991332, -0.69356883])
np.random.randn(3, 2)
'''
array([[-0.62787255, -0.01054911],
[ 0.8695556 , -1.39004067],
[ 0.16209569, 2.08941735]])
'''
np.random.randn(3, 2, 4)
'''
array([[[ 0.97915519, -0.04827654, -0.24805357, -1.18815335],
[ 0.81855172, 0.531464 , -0.0455545 , 0.7775499 ]],
[[-1.6144118 , 0.11402734, 0.106872 , 0.80540136],
[-0.49410333, 0.13846393, 0.4897993 , -1.34085886]],
[[ 0.25693092, 0.4697215 , -1.00145574, 0.33612804],
[ 0.68994321, 0.17245859, 0.49834578, 1.37301829]]])
'''
print('numpy.random随机数生成')
import numpy.random as npr
x = npr.randint(0, 2, size = 100000) # 抛硬币
print((x > 0).sum()) # 正面的结果
print(npr.normal(size = (2, 2)))
# 正态分布随机数数组 shape = (2, 2)
'''
numpy.random随机数生成
49720
[[ 0.21193991 -1.33266635]
[-0.71381904 0.40960239]]
'''
# 关于随机数种子
import numpy as np
np.random.seed(10)
# 如果不使用随机数种子,每次执行获得的随机数是不固定的
# 加上随机数种子,每次执行生成的随机数是一样的
t = np.random.randint(0, 20, (3, 4))
print(t)
'''
[[ 9 4 15 0]
[17 16 17 8]
[ 9 0 10 8]]
'''
关于分布:均匀分布:在相同的大小范围内的出现概率是等可能的,也即是随机分布,每个位置上出现的概率是随机的
更多API包括:linspace, logspace, diag, eye, randint, randn, random
通函数
NumPy 提供熟悉的数学函数,例如 sin,cos 和 exp 等。
在 NumPy 中,这些被称为 “通函数”(ufunc)。
在 NumPy 中,这些函数在数组上按元素进行运算,产生一个数组作为输出。
np.mean(data) # 均值
np.std(data) # 标准差
np.var(data) # 方差
np.min(data) # 最小值
np.max(data) # 最大值
np.argmax(t, axis) # 最大值的位置
np.argmin(t, axis) # 最小值的位置
np.ptp(data) # 极值
'''
可对某行或某列的数据统计
方法是在函数中添加一个 axis 参数
0表示每列 1表示每行
'''
多维数组运算
ndarray 对象的运算效率极高,不用编写循环,运算直接应用在元素级上。
import numpy as np
zarten_1 = np.array([[1, 2, 3],[4, 5, 6]])
zarten_2 = zarten_1 * 2
print(zarten_1)
print('\n')
ptint(zarten_2)
'''
[[1 2 3]
[4 5 6]]
[[ 2 4 6]
[ 8 10 12]]
'''
zarten_1 = np.array([[1, 2, 3],[4, 5, 6]])
zarten_2 = np.array([7, 8, 9])
print(zarten_1 + zarten_2)
'''
[[ 8 10 12]
[11 13 15]]
'''
zarten_1 = np.array([[1, 2, 3],[4, 5, 6]])
zarten_2 = np.array([7, 8, 9])
print(zarten_1 > zarten_2)
'''
[[False False False]
[True True True]]
'''
多维数组之间比较,会产生一个布尔类型的数组
一元运算
zarten = np.array([1, 2, 3, 4, 5])
print(np.sqrt(zarten))
print(np.sin(zarten))
# [1. 1.41421356 1.73205081 2. 2.23606798]
# [ 0.84147098 0.90929743 0.14112001 -0.7568025 -0.95892427]
二元运算
zarten_1 = np.array([1, 2, 3, 4, 88])
zarten_2 = np.array([6, 7, 8, 9, 10])
print(np.maximum(zarten_1, zarten_2)) # [ 6 7 8 9 88]
print(np.add(1,2)) # 3
集合运算
numpy 中提供一些针对一维的集合运算,如 unique 函数、in1d 函数等
unique 函数 跟 Python 中的 set 集合类似,但 unique 函数的输出结果是排好序的
zarten_1 = np.array([5, 3, 6, 5, 4, 2, 1, 2])
print(zarten_1)
print('\n')
print(np.unique(zarten_1))
'''
[5 3 6 5 4 2 1 2]
[1 2 3 4 5 6]
'''
in1d()
函数返回一个布尔型数组,用于判断一个数组的元素是否有在另一个数组内
zarten_1 = np.array([5, 3, 6, 5, 4, 2, 1, 2])
print(zarten_1)
print('\n')
print(np.in1d(zarten_1,[5, 3]))
# [5 3 6 5 4 2 1 2]
# [True True False True False False False False]
数组索引查询
-
基础索引
一维数组和 Python 的 list 一样
# 二维数组 X = np.arange(20).reshape(4,5) X ''' array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) '''
# 分别用行坐标、列坐标实现行列筛选 X[0, 0] # 0 x[-1, 2] # 17
''' 可以省略后续索引值,返回的数据是降低一个维度的数组 这里的2其实是要筛选第2行 ''' X[2] # array([10, 11, 12, 13, 14])
# 筛选多行 X[: -1] ''' array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) '''
# 筛选多行 多列 X[: 2, 2: 4] ''' array([[2, 3], [7, 8]]) '''
# 筛选所有行 多列 X[:, 2] ''' array([2, 7, 12, 17]) '''
切片赋值
x = np.array([1, 2, 3, 4, 5, 6, 7, 8]) X = np.array( [[1, 2, 3, 4], [5, 6, 7, 8]] ) x[2: 4] = 666 X[: 1, : 2] = 666 x X ''' array([1, 2, 666, 666, 5, 6, 7, 8]) array([[666, 666, 3, 4], [ 5, 6, 7, 8]]) '''
-
神奇索引
用整数数组进行的索引叫神奇索引
'''一维数组''' x = np.arange(10) x # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) x[[3, 4, 7]] # array([3, 4, 7])
# array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) index = np.array([[0, 2],[1, 3]]) x[index] ''' array([[0, 2], [1, 3]]) '''
''' 实例:获取数组中最大的前 N 个数字 ''' # 随机生成1到100之间的10个数字 arr = np.random.randint(1, 100, 10) # array([92, 16, 12, 57, 1, 66, 26, 55, 68, 84]) # arr.argsort() 会返回排序后的索引index # 取最大值对应的3个下标 arr.argsort()[-3: ] # array([8, 9, 0], dtype=int64) arr[arr.argsort()[-3:]] # array([68, 84, 92])
'''二维数组''' X = np.arange(20).reshape(4,5) ''' array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) '''
# 筛选多行,列可以省略 X[[0, 2]] ''' array([[ 0, 1, 2, 3, 4], [10, 11, 12, 13, 14]]) '''
X[[0, 2], :] ''' array([[ 0, 1, 2, 3, 4], [10, 11, 12, 13, 14]]) '''
# 筛选多列,行不能省略 X[:, [0, 2, 3]] ''' array([[ 0, 2, 3], [ 5, 7, 8], [10, 12, 13], [15, 17, 18]]) '''
# 同时指定行列-列表 # 返回的是[(0, 1), (2, 3), (3, 4)]位置的数字 X[[0, 2, 3], [1, 3, 4]] ''' array([ 1, 13, 19]) '''
# 同时指定行列列表 # 创建一个1*2的矩阵 X[np.array([0, 2]), np.array([1, 3])] X[[0, 2], [1, 3]] ''' array([ 1, 13]) '''
# 创建一个2*3矩阵 X[np.array([[0, 2, 3], [1, 2, 3]]), np.array([[0, 1, 0], [0, 2, 3]])] a = (np.array([[0, 2, 3], [1, 2, 3]]), np.array([[0, 1, 2], [0, 2, 3]])) X[a] ''' array([[ 0, 11, 17], [ 5, 12, 18]]) '''
-
布尔索引
bool
数组可以通过直接指出保留的值(True
)与舍弃的值(False
),来构建输出的数组。bool
数组的shape
需要与被索引的数组shape
严格对齐'''一维数组''' x = np,arange(10) # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) x > 5 # array([False, False, False, False, False, False, True, True, True,True]) x[x > 5] # array([6, 7, 8, 9])
# 实例 把一维数组进行01化处理 # 比如把房价数字,变成“高房价”为1;“低房价”为0 x[x <= 5] = 0 x[x > 5] = 1 x # array([0, 0, 0, 0, 0, 0, 1, 1, 1, 1])
x = np.arange(10) # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) x[x < 5] += 20 x # array([20, 21, 22, 23, 24, 5, 6, 7, 8, 9])
'''二维数组''' X = np.arange(20).reshape(4, 5) X ''' array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) '''
X > 5 ''' array([[False, False, False, False, False], [False, True, True, True, True], [ True, True, True, True, True], [ True, True, True, True, True]]) '''
# X > 5 的 boolean 数组,既有行又有列 # 因此返回的是(行,列)一维结果 X[X > 5] # array([ 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
a = np.arange(15).reshape(3, 5) a ''' array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) ''' a[np.array([True, False, True])] ''' array([[ 0, 1, 2, 3, 4], [10, 11, 12, 13, 14]]) '''
x = np.arange(30).reshape(2, 3, 5) x ''' 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]]]) ''' b = np.array([[True, True, False], [False, True, True]]) x[b] ''' array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [20, 21, 22, 23, 24], [25, 26, 27, 28, 29]]) '''
X = np.arange(20).reshape(4, 5) X ''' array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) ''' # 举例:怎样把第3列大于5的行筛选出来 X[:, 3] # array([ 3, 8, 13, 18]) X[:, 3] > 6 # array([False, True, True, True]) # 这里是按照行进行的筛选 X[X[:, 3] > 10] ''' array([[10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) '''
变换数组的形态 (维度)
改变维度
在对数组进行操作时,经常要改变数组的维度。
在 Numpy 中,常用 reshape
函数改变数组的 “形状” ,也就是改变数组的维度。其参数为一个正整数元组,分别指定数组在每个维度上的大小。
reshape
函数在改变原始数据的形状的同时不改变原始数据的值。如果指定的维度和数组的元素数目不吻合,则函数将抛出异常。
# 创建一维数组
arr = np.arange(12)
print('创建的一维数组为:', arr)
# 创建的一维数组为: [ 0 1 2 3 4 5 6 7 8 9 10 11]
# 设置数组的形状
print('新的一维数组为:', arr.reshape(3, 4))
'''
新的一维数组为: [[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
'''
# 查看数组维度
print('数组维度为:', arr.reshape(3, 4).ndim)
# 数组维度为: 2
增加维度
np.newaxis
关键字,使用索引的语法给数组添加维度
import numpy as np
arr = np.arange(5) # [0, 1, 2, 3, 4]
arr.shape # (5,)
arr[np.newaxis, :] # array([[0, 1, 2, 3, 4]])
arr[np.newaxis, :].shape # (1, 5)
arr[:, np.newaxis]
arr[:, np.newaxis].shape # (5, 1)
np.expand_dims(arr, axis)
和 np.newaxis
实现一样的功能, 给 arr
在 axis
位置添加维度
arr = np.arange(5) # [0, 1, 2, 3, 4]
arr.shape # (5,)
np.expand_dims(arr, axis = 0) # array([[0, 1, 2, 3, 4]])
np.expand_dims(arr, axis = 0).shape # (1, 5)
np.expand_dims(arr, axis = 1)
np.expand_dims(arr, axis = 1).shape # (5, 1)
np.reshape(a, newshape)
给一个维度设置为 1 完成升维