Numpy学习笔记

Numpy(Numerical Python的简称)是高性能科学计算和数据分析的基础包。

Numpy具有如下功能:

  1. ndarray数组:一个具有矢量算术运算和复杂广播能力的多维数组,具有快速且节省空间的特点。
  2. 对整组数据进行快速运算的标准数学函数(无需编写循环)。
  3. 线性代数、随机数生成以及傅里叶变换功能。
  4. 读写磁盘数据、操作内存映射文件。

本质上,Numpy期望用户在执行“向量”操作时,像使用“标量”一样轻松。

基础数据类型:ndarray数组
ndarray数组是Numpy的基础数据结构,可以灵活、高效地处理多个元素的操作。
Python中的list列表也可以非常灵活的处理多个元素的操作,但效率却非常低。与之比较,ndarray数组具有如下特点:

  1. ndarray数组中所有元素的数据类型相同、数据地址连续,批量操作数组元素时速度更快。而list列表中元素的数据类型可能不同,需要通过寻址方式找到下一个元素。
  2. ndarray数组支持广播机制,矩阵运算时不需要写for循环。
  3. Numpy底层使用C语言编写,内置并行计算功能,运行速度高于Python代码。
    案例:
import numpy as np
a = [1, 2, 3, 4, 5]
b = [2, 3, 4, 5, 6]
#   a+1
a = np.array([1, 2, 3, 4, 5])
a = a + 1     
#结果:array([2, 3, 4, 5, 6])
#   a+b
b = np.array([2, 3, 4, 5, 6])
c = a + b
#结果:array([ 3,  5,  7,  9, 11])
d = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
c = np.array([ 4,  6,  8, 10, 12])
#   d+c
e = d + c
#结果,广播机制自动扩展:array([[ 5,  8, 11, 14, 17],
       [10, 13, 16, 19, 22]])

创建ndarray数组

创建ndarray数组最简单的方式就是使用array函数,它接受一切序列型的对象(包括其他数组),然后产生一个新的含有传入数据的numpy数组。下面通过实例体会下array、arange、zeros、ones四个主要函数的用法。

# 导入numpy
import numpy as np

# 从list创建array 
a = [1,2,3,4,5,6]  # 创建简单的列表
b = np.array(a)    # 将列表转换为数组
#结果,array([1, 2, 3, 4, 5, 6])
# 通过np.arange创建
# 通过指定start, stop (不包括stop),interval来产生一个1维的ndarray
a = np.arange(0, 10, 2)
#结果,array([0, 2, 4, 6, 8])
# 创建全0的ndarray
a = np.zeros([3,3])
#结果,array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])
# 创建全1的ndarray
a = np.ones([3,3])
#结果,array([[1., 1., 1.],
       [1., 1., 1.],
       [1., 1., 1.]])

查看ndarray数组的属性
ndarray的属性包括shape、dtype、size和ndim等,通过如下代码可以查看ndarray数组的属性。

  • shape:数组的形状 ndarray.shape,1维数组(N, ),二维数组(M, N),三维数组(M, N, K)。
  • dtype:数组的数据类型。
  • size:数组中包含的元素个数 ndarray.size,其大小等于各个维度的长度的乘积。
  • ndim:数组的维度大小,ndarray.ndim, 其大小等于ndarray.shape所包含元素的个数。
a = np.ones([3, 3])
print('a, dtype: {}, shape: {}, size: {}, ndim: {}'.format(a.dtype, a.shape, a.size, a.ndim))
#结果:a, dtype: float64, shape: (3, 3), size: 9, ndim: 2

改变ndarray数组的数据类型和形状
创建ndarray之后,可以对其数据类型或形状进行修改,代码如下所示。

a = np.ones([3, 3])
# 转化数据类型
b = a.astype(np.int64)
print('b, dtype: {}, shape: {}'.format(b.dtype, b.shape))
#结果:b, dtype: int64, shape: (3, 3)
# 改变形状
c = a.reshape([1, 9])
print('c, dtype: {}, shape: {}'.format(c.dtype, c.shape))
#结果: c, dtype: float64, shape: (1, 9)

标量和ndarray数组之间的运算
标量和ndarray数组之间的运算主要包括除法、乘法、加法和减法运算,用标量与数组的每一个元素做运算。
两个ndarray数组之间的运算
两个ndarray数组之间的运算主要包括减法、加法、乘法、除法和开根号运算,用两个数组对应位置的元素做运算。数组开根号,arr ** 0.5,将每个位置的元素都开根号。

一维ndarray数组的索引和切片
从表面上看,一维数组跟Python列表的功能类似,它们重要区别在于:数组切片产生的新数组,还是指向原来的内存区域,数据不会被复制,视图上的任何修改都会直接反映到源数组上。将一个标量值赋值给一个切片时,该值会自动传播到整个选区。

 数组切片产生的新数组,还是指向原来的内存区域,数据不会被复制。
# 视图上的任何修改都会直接反映到源数组上。
a = np.arange(30)
arr_slice = a[4:7]
arr_slice[0] = 100
a, arr_slice
#结果:(array([  0,   1,   2,   3, 100,   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]), array([100,   5,   6]))
# 通过copy给新数组创建不同的内存空间
a = np.arange(30)
arr_slice = a[4:7]
arr_slice = np.copy(arr_slice)
arr_slice[0] = 100
a, arr_slice
#结果:(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]),
 array([100,   5,   6]))

多维ndarray数组的索引和切片
多维ndarray数组的索引和切片具有如下特点:
在多维数组中,各索引位置上的元素不再是标量而是多维数组。
以逗号隔开的索引列表来选取单个元素。
在多维数组中,如果省略了后面的索引,则返回对象会是一个维度低一点的ndarray。

# 创建一个多维数组
a = np.arange(30)
arr3d = a.reshape(5, 3, 2)
arr3d
#结果: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]]])
# 只有一个索引指标时,会在第0维上索引,后面的维度保持不变
arr3d[0]
#结果:array([[0, 1],
       [2, 3],
       [4, 5]])
# 两个索引指标
arr3d[0][1]
#结果:array([2, 3])
# 两个索引指标
arr3d[0, 1]
#结果:array([2, 3])
# 创建一个数组
a = np.arange(24)
a
#结果: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])
# reshape成一个二维数组
a = a.reshape([6, 4])
a
#结果: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]])
# 使用for语句生成list
[k for k in range(0, 6, 2)]
[0, 2, 4]
# 结合上面列出的for语句的用法
# 使用for语句对数组进行切片
# 下面的代码会生成多个切片构成的list
# k in range(0, 6, 2) 决定了k的取值可以是0, 2, 4
# 产生的list的包含三个切片
# 第一个元素是a[0 : 0+2],
# 第二个元素是a[2 : 2+2],
# 第三个元素是a[4 : 4+2]
slices = [a[k:k+2] for k in range(0, 6, 2)]
slices
#结果:[array([[0, 1, 2, 3],
        [4, 5, 6, 7]]), array([[ 8,  9, 10, 11],
        [12, 13, 14, 15]]), array([[16, 17, 18, 19],
        [20, 21, 22, 23]])]
slices[0]
#结果:array([[0, 1, 2, 3],
       [4, 5, 6, 7]])

ndarray数组的统计方法
可以通过数组上的一组数学函数对整个数组或某个轴向的数据进行统计计算。主要包括如下统计方法:

  • mean:计算算术平均数,零长度数组的mean为NaN。
  • std和var:计算标准差和方差,自由度可调(默认为n)。
  • sum :对数组中全部或某轴向的元素求和,零长度数组的sum为0。
  • max和min:计算最大值和最小值。
  • argmin和argmax:分别为最大和最小元素的索引。
  • cumsum:计算所有元素的累加。
  • cumprod:计算所有元素的累积。
# 计算均值,使用arr.mean() 或 np.mean(arr),二者是等价的
arr = np.array([[1,2,3], [4,5,6], [7,8,9]])
arr.mean(), np.mean(arr)
(5.0, 5.0)
# 求和
arr.sum(), np.sum(arr)
(45, 45)
# 求最大值
arr.max(), np.max(arr)
(9, 9)
# 求最小值
arr.min(), np.min(arr)
(1, 1)
# 指定计算的维度
# 沿着第1维求平均,也就是将[1, 2, 3]取平均等于2,[4, 5, 6]取平均等于5,[7, 8, 9]取平均等于8
arr.mean(axis = 1)
array([2., 5., 8.])
# 沿着第0维求和,也就是将[1, 4, 7]求和等于12,[2, 5, 8]求和等于15,[3, 6, 9]求和等于18
arr.sum(axis=0)
array([12, 15, 18])
# 沿着第0维求最大值,也就是将[1, 4, 7]求最大值等于7,[2, 5, 8]求最大值等于8,[3, 6, 9]求最大值等于9
arr.max(axis=0)
array([7, 8, 9])
# 沿着第1维求最小值,也就是将[1, 2, 3]求最小值等于1,[4, 5, 6]求最小值等于4,[7, 8, 9]求最小值等于7
arr.min(axis=1)
array([1, 4, 7])
# 计算标准差
arr.std()
2.581988897471611
# 计算方差
arr.var()
6.666666666666667
# 找出最大元素的索引
arr.argmax(), arr.argmax(axis=0), arr.argmax(axis=1)
(8, array([2, 2, 2]), array([2, 2, 2]))
# 找出最小元素的索引
arr.argmin(), arr.argmin(axis=0), arr.argmin(axis=1)
(0, array([0, 0, 0]), array([0, 0, 0]))

创建随机ndarray数组
创建随机ndarray数组主要包含设置随机种子、均匀分布和正态分布三部分内容,具体代码如下所示。

# 可以多次运行,观察程序输出结果是否一致
# 如果不设置随机数种子,观察多次运行输出结果是否一致
np.random.seed(10)
a = np.random.rand(3, 3)
a
array([[0.77132064, 0.02075195, 0.63364823],
       [0.74880388, 0.49850701, 0.22479665],
       [0.19806286, 0.76053071, 0.16911084]])

# 生成均匀分布随机数,随机数取值范围在[0, 1)之间
a = np.random.rand(3, 3)
a
array([[0.08833981, 0.68535982, 0.95339335],
       [0.00394827, 0.51219226, 0.81262096],
       [0.61252607, 0.72175532, 0.29187607]])
# 生成均匀分布随机数,指定随机数取值范围和数组形状
a = np.random.uniform(low = -1.0, high = 1.0, size=(2,2))
a
array([[ 0.83554825,  0.42915157],
       [ 0.08508874, -0.7156599 ]])
# 生成标准正态分布随机数
a = np.random.randn(3, 3)
a
array([[ 1.484537  , -1.07980489, -1.97772828],
       [-1.7433723 ,  0.26607016,  2.38496733],
       [ 1.12369125,  1.67262221,  0.09914922]])
In [68]
# 生成正态分布随机数,指定均值loc和方差scale
a = np.random.normal(loc = 1.0, scale = 1.0, size = (3,3))
a
array([[2.39799638, 0.72875201, 1.61320418],
       [0.73268281, 0.45069099, 1.1327083 ],
       [0.52385799, 2.30847308, 1.19501328]])

随机打乱ndarray数组顺序
随机打乱1维ndarray数组顺序,发现所有元素位置都被打乱了,代码如下所示。

# 生成一维数组
a = np.arange(0, 30)
print('before random shuffle: ', a)
# 打乱一维数组顺序
np.random.shuffle(a)
print('after random shuffle: ', a)
('before random shuffle: ', 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]))
('after random shuffle: ', array([10, 21, 26,  7,  0, 23,  2, 17, 18, 20, 12,  6,  9,  3, 25,  5, 13,
       14, 24, 29,  1, 28, 11, 15, 27, 16, 19,  4, 22,  8]))

随机打乱2维ndarray数组顺序,发现只有行的顺序被打乱了,列顺序不变,代码如下所示。

# 生成一维数组
a = np.arange(0, 30)
# 将一维数组转化成2维数组
a = a.reshape(10, 3)
print('before random shuffle: \n{}'.format(a))
# 打乱一维数组顺序
np.random.shuffle(a)
print('after random shuffle: \n{}'.format(a))
before random shuffle: 
[[ 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]]
after random shuffle: 
[[15 16 17]
 [12 13 14]
 [27 28 29]
 [ 3  4  5]
 [ 9 10 11]
 [21 22 23]
 [18 19 20]
 [ 0  1  2]
 [ 6  7  8]
 [24 25 26]]
随机选取元

随机选取元素

# 随机选取部分元素
a = np.arange(30)
b = np.random.choice(a, size=5)
b
array([ 0, 24, 12,  5,  4])

线性代数
线性代数(如矩阵乘法、矩阵分解、行列式以及其他方阵数学等)是任何数组库的重要组成部分,Numpy中实现了线性代数中常用的各种操作,并形成了numpy.linalg线性代数相关的模块。本节主要介绍如下函数:

  • diag:以一维数组的形式返回方阵的对角线(或非对角线)元素,或将一维数组转换为方阵(非对角线元素为0)。
  • dot:矩阵乘法。
  • trace:计算对角线元素的和。
  • det:计算矩阵行列式。
  • eig:计算方阵的特征值和特征向量。
  • inv:计算方阵的逆。
# numpy.linalg  中有一组标准的矩阵分解运算以及诸如求逆和行列式之类的东西
# np.linalg.diag 以一维数组的形式返回方阵的对角线(或非对角线)元素,
# 或将一维数组转换为方阵(非对角线元素为0)
e = np.diag(d)
f = np.diag(e)
print('d: \n{}'.format(d))
print('e: \n{}'.format(e))
print('f: \n{}'.format(f))
d: 
[[ 42  48  54]
 [114 136 158]
 [186 224 262]]
e: 
[ 42 136 262]
f: 
[[ 42   0   0]
 [  0 136   0]
 [  0   0 262]]
# 矩阵相乘
a = np.arange(12)
b = a.reshape([3, 4])
c = a.reshape([4, 3])
# 矩阵b的第二维大小,必须等于矩阵c的第一维大小
d = b.dot(c) # 等价于 np.dot(b, c)
print('a: \n{}'.format(a))
print('b: \n{}'.format(b))
print('c: \n{}'.format(c))
print('d: \n{}'.format(d))
a: 
[ 0  1  2  3  4  5  6  7  8  9 10 11]
b: 
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
c: 
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
d: 
[[ 42  48  54]
 [114 136 158]
 [186 224 262]]
# trace, 计算对角线元素的和
g = np.trace(d)
g
440
# det,计算行列式
h = np.linalg.det(d)
h
1.3642420526593978e-11
# eig,计算特征值和特征向量
i = np.linalg.eig(d)
i
(array([4.36702561e+02, 3.29743887e+00, 3.13152204e-14]),
 array([[ 0.17716392,  0.77712552,  0.40824829],
        [ 0.5095763 ,  0.07620532, -0.81649658],
        [ 0.84198868, -0.62471488,  0.40824829]]))
# inv,计算方阵的逆
tmp = np.random.rand(3, 3)
j = np.linalg.inv(tmp)
j
array([[-0.59449952,  1.39735912, -0.06654123],
       [ 1.56034184, -0.40734618, -0.48055062],
       [ 0.10659811, -0.62164179,  1.30437759]])

Numpy保存和导入文件

# 使用np.fromfile从文本文件'housing.data'读入数据
# 这里要设置参数sep = ' ',表示使用空白字符来分隔数据
# 空格或者回车都属于空白字符,读入的数据被转化成1维数组
d = np.fromfile('./work/housing.data', sep = ' ')
d
array([6.320e-03, 1.800e+01, 2.310e+00, ..., 3.969e+02, 7.880e+00,
       1.190e+01])

Numpy提供了save和load接口,直接将数组保存成文件(保存为.npy格式),或者从.npy文件中读取数组。

 产生随机数组a
a = np.random.rand(3,3)
np.save('a.npy', a)

# 从磁盘文件'a.npy'读入数组
b = np.load('a.npy')

# 检查a和b的数值是否一样
check = (a == b).all()
check
True
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值