欢迎关注公众号【Python开发实战】, 获取更多内容!

工具-numpy

numpy是使用Python进行数据科学的基础库。numpy以一个强大的N维数组对象为中心,它还包含有用的线性代数,傅里叶变换和随机数函数。

线性代数

numpy中二维的ndarray可以在Python中高效地表示矩阵,下面将介绍一些主要的矩阵运算。

导入numpy

import numpy as np

矩阵转置

当秩大于等于2时,T属性相当于调用transpose()函数。

m1 = np.arange(10).reshape(2, 5)
m1

输出:

array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
m1.T

输出:

array([[0, 5],
[1, 6],
[2, 7],
[3, 8],
[4, 9]])
m1.transpose()

输出:

array([[0, 5],
[1, 6],
[2, 7],
[3, 8],
[4, 9]])

T属性对秩为0(空)或秩为1的ndarray没有影响。

m2 = np.arange(5)
m2

输出:

array([0, 1, 2, 3, 4])
m2.T

输出:

array([0, 1, 2, 3, 4])

可以将一维的ndarray重塑为单行的二维矩阵,进而得到转置。

m2r = m2.reshape(1, 5)
m2r

输出:

array([[0, 1, 2, 3, 4]])
m2r.T

输出:

array([[0],
[1],
[2],
[3],
[4]])

矩阵乘法

dot()方法可以计算两个矩阵的乘法,矩阵乘法需要满足左边矩阵的列数必须等于右边矩阵的行数。

n1 = np.arange(10).reshape(2, 5)
n1

输出:

array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
n2 = np.arange(15).reshape(5, 3)
n2

输出:

array([[ 0,  1,  2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14]])
n1.dot(n2)

输出:

array([[ 90, 100, 110],
[240, 275, 310]])

注意:n1*n2不是矩阵乘法,而是按元素乘积。

矩阵的逆与伪逆

许多线性代数函数在numpy中都可用。linalg模块中的inv函数可以计算一个方阵的逆。

import numpy.linalg as linalg
m3 = np.array([[1, 2, 3], [5, 7, 11], [21, 29, 31]])
m3

输出:

array([[ 1,  2,  3],
[ 5, 7, 11],
[21, 29, 31]])
linalg.inv(m3)

输出:

array([[-2.31818182,  0.56818182,  0.02272727],
[ 1.72727273, -0.72727273, 0.09090909],
[-0.04545455, 0.29545455, -0.06818182]])

也可以通过pinv函数来计算伪逆。

linalg.pinv(m3)

输出:

array([[-2.31818182,  0.56818182,  0.02272727],
[ 1.72727273, -0.72727273, 0.09090909],
[-0.04545455, 0.29545455, -0.06818182]])

单位矩阵

矩阵与其逆矩阵相乘返回一个单位矩阵,下面的例子会有很小的浮点误差。

m3.dot(linalg.inv(m3))

输出:

array([[ 1.00000000e+00, -5.55111512e-17,  0.00000000e+00],
[-2.98372438e-16, 1.00000000e+00, -5.55111512e-17],
[ 5.78009862e-15, 1.27675648e-15, 1.00000000e+00]])

可以通过eye函数来创建一个N×N大小的单位矩阵。

np.eye(3)

输出:

array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])

QR分解

linalg模块中的qr函数可以计算一个矩阵的QR分解(正交三角分解)。

q, r = linalg.qr(m3)
q

输出:

array([[-0.04627448,  0.98786672,  0.14824986],
[-0.23137241, 0.13377362, -0.96362411],
[-0.97176411, -0.07889213, 0.22237479]])
r

输出:

array([[-21.61018278, -29.89331494, -32.80860727],
[ 0. , 0.62427688, 1.9894538 ],
[ 0. , 0. , -3.26149699]])
q.dot(r)

输出:

array([[ 1.,  2.,  3.],
[ 5., 7., 11.],
[21., 29., 31.]])

矩阵的行列式

linalg模块中的det函数可以计算矩阵的行列式。

linalg.det(m3)

输出:

43.99999999999999

特征值和特征向量

linalg模块中的eig函数可以计算一个方阵的特征值和特征向量。

eigenvalues, eigenvetors = linalg.eig(m3)
eigenvalues # λ

输出:

array([42.26600592, -0.35798416, -2.90802176])
eigenvetors # v

输出:

array([[-0.08381182, -0.76283526, -0.18913107],
[-0.3075286 , 0.64133975, -0.6853186 ],
[-0.94784057, -0.08225377, 0.70325518]])
m3.dot(eigenvetors) - eigenvalues * eigenvetors     # m3.v -λ*v= 0

输出:

array([[ 9.76996262e-15,  2.22044605e-16, -3.10862447e-15],
[ 7.10542736e-15, 2.02615702e-15, -1.11022302e-15],
[ 2.84217094e-14, 5.11049536e-15, -4.88498131e-15]])

奇异值分解

linalg模块中的svd函数可以计算矩阵的奇异值分解。

m4 = np.array([[1, 0, 0, 0, 2], [0, 0, 3, 0, 0], [0, 0, 0, 0, 0], [0, 2, 0, 0, 0]])
m4

输出:

array([[1, 0, 0, 0, 2],
[0, 0, 3, 0, 0],
[0, 0, 0, 0, 0],
[0, 2, 0, 0, 0]])
U, S_diag, V = linalg.svd(m4)
U

输出:

array([[ 0.,  1.,  0.,  0.],
[ 1., 0., 0., 0.],
[ 0., 0., 0., -1.],
[ 0., 0., 1., 0.]])
S_diag   # Σ对角线上的值

输出:

array([3.        , 2.23606798, 2.        , 0.        ])
V

输出:

array([[-0.        ,  0.        ,  1.        ,  0.        ,  0.        ],
[ 0.4472136 , 0. , 0. , 0. , 0.89442719],
[-0. , 1. , 0. , 0. , 0. ],
[ 0. , 0. , 0. , 1. , 0. ],
[-0.89442719, 0. , 0. , 0. , 0.4472136 ]])

svd函数只返回Σ对角线上的值,完整的矩阵可以这样创建:

S = np.zeros((4, 5))
S[np.diag_indices(4)] = S_diag # np.diag_indices函数返回索引以访问(4,4)数组的主对角线。
S # Σ

输出:

array([[3.        , 0.        , 0.        , 0.        , 0.        ],
[0. , 2.23606798, 0. , 0. , 0. ],
[0. , 0. , 2. , 0. , 0. ],
[0. , 0. , 0. , 0. , 0. ]])
U.dot(S).dot(V)  # U.Σ.V = m4

输出:

array([[1., 0., 0., 0., 2.],
[0., 0., 3., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 2., 0., 0., 0.]])

对角线和轨迹

m3

输出:

array([[ 1,  2,  3],
[ 5, 7, 11],
[21, 29, 31]])
np.diag(m3)  # 返回m3对角线上的元素值

输出:

array([ 1,  7, 31])
np.trace(m3)   # 相当于 np.diag(m3).sum()

输出:

39
np.diag(m3).sum()

输出:

39

求解线性标量方程组

linalg模块中的solve函数可以求解线性标量方程组, 例如如下方程组

  • 2x + 6y = 6
  • 5x + 3y = -9
coeffs = np.array([[2, 6], [5, 3]])
depvars = np.array([6, -9])
solution = linalg.solve(coeffs, depvars)
solution

输出:

array([-3.,  2.])

可以验证一下求解:

coeffs.dot(solution), depvars

输出:

(array([ 6., -9.]), array([ 6, -9]))

还可以通过另一个方式验证求解。

np.allclose(coeffs.dot(solution), depvars)   # np.allclose比较两个ndarray的每一个元素是否都相等

输出:

True

矢量化

如果坚持进行ndarray操作,而不是一次一个地对单个的元素极性操作,那么代码的效率要高的多, 这就叫做矢量化。这样,可以从numpy的许多优化中受益。

例如,要根据公式sin(xy/40.5)生成一个768×1024的ndarray,一个不好的选择就是使用嵌套循环进行计算。

import math
data = np.empty((768, 1024))
for y in range(768):
for x in range(1024):
data[y, x] = math.sin(x*y/40.5)
data

输出:

array([[0.        , 0.        , 0.        , ..., 0.        , 0.        ,
0. ],
[0. , 0.02468885, 0.04936265, ..., 0.07705885, 0.1016508 ,
0.12618078],
[0. , 0.04936265, 0.09860494, ..., 0.15365943, 0.20224852,
0.25034449],
...,
[0. , 0.03932283, 0.07858482, ..., 0.6301488 , 0.59912825,
0.56718092],
[0. , 0.06398059, 0.12769901, ..., 0.56844086, 0.51463783,
0.45872596],
[0. , 0.08859936, 0.17650185, ..., 0.50335246, 0.42481591,
0.34293805]])

上面的方法虽然可行,但是效率非常低,因为循环是在纯Python中进行的。现在我们把这个方法矢量化,首先,使用numpy的meshgrid函数,该函数可以根据坐标向量生成坐标矩阵。

x_coords = np.arange(1024)
y_coords = np.arange(768)
X, Y = np.meshgrid(x_coords, y_coords)
X

输出:

array([[   0,    1,    2, ..., 1021, 1022, 1023],
[ 0, 1, 2, ..., 1021, 1022, 1023],
[ 0, 1, 2, ..., 1021, 1022, 1023],
...,
[ 0, 1, 2, ..., 1021, 1022, 1023],
[ 0, 1, 2, ..., 1021, 1022, 1023],
[ 0, 1, 2, ..., 1021, 1022, 1023]])
Y

输出:

array([[  0,   0,   0, ...,   0,   0,   0],
[ 1, 1, 1, ..., 1, 1, 1],
[ 2, 2, 2, ..., 2, 2, 2],
...,
[765, 765, 765, ..., 765, 765, 765],
[766, 766, 766, ..., 766, 766, 766],
[767, 767, 767, ..., 767, 767, 767]])
X.shape, Y.shape

输出:

((768, 1024), (768, 1024))

X和Y都是768×1024的ndarray,X中所有的值对应水平轴的坐标, Y中所有的值对应垂直轴的坐标。现在可以简单地使用ndarray运算计算结果。

data = np.sin(X*Y/40.5)
data

输出:

array([[0.        , 0.        , 0.        , ..., 0.        , 0.        ,
0. ],
[0. , 0.02468885, 0.04936265, ..., 0.07705885, 0.1016508 ,
0.12618078],
[0. , 0.04936265, 0.09860494, ..., 0.15365943, 0.20224852,
0.25034449],
...,
[0. , 0.03932283, 0.07858482, ..., 0.6301488 , 0.59912825,
0.56718092],
[0. , 0.06398059, 0.12769901, ..., 0.56844086, 0.51463783,
0.45872596],
[0. , 0.08859936, 0.17650185, ..., 0.50335246, 0.42481591,
0.34293805]])

保存和加载

numpy可以方便地以二进制或文本格式来保存和加载ndarray。

二进制格式 .npy

下面创建一个随机的ndarray,并保存。

a = np.random.rand(2, 3)
a

输出:

array([[0.76953407, 0.79648012, 0.8868019 ],
[0.88131806, 0.57297333, 0.70059907]])
np.save('my_array', a)

由于文件名不包含扩展名,因此numpy会自动添加扩展名为.npy,下面查看一下文件内容:

with open('my_array.npy', 'rb') as f:
content = f.read()
content

输出:

b"\x93NUMPY\x01\x00v\x00{'descr': '<f8', 'fortran_order': False, 'shape': (2, 3), }                                                          \n0L\xbb\xe8\x05\xa0\xe8?\x13s\x00\xdf\xc3|\xe9?\xdd\x05\xf4`\xae`\xec?S\x0e\xad\xee\xc13\xec?\x03\xa6E)\xccU\xe2?\x97\xc6\xdc\xbcNk\xe6?"

想要把该文件加载到numpy数组中只需要调用load函数。

a_loaded = np.load('my_array.npy')
a_loaded

输出:

array([[0.76953407, 0.79648012, 0.8868019 ],
[0.88131806, 0.57297333, 0.70059907]])

文本格式

现在以文本格式来保存ndarray。

np.savetxt('my_array.csv', a)

现在查看一下文件内容:

with open('my_array.csv', 'rt') as f:
print(f.read())

输出:

7.695340676822350900e-01 7.964801173689884939e-01 8.868019002549619723e-01
8.813180600777265061e-01 5.729733282179839682e-01 7.005990685194828371e-01

这是以制表符作为分隔符的csv文件,还可以设置不同的分隔符。

np.savetxt('my_array.csv', a, delimiter=',')

再查看一下文件内容

with open('my_array.csv', 'rt') as f:
print(f.read())

输出:

7.695340676822350900e-01,7.964801173689884939e-01,8.868019002549619723e-01
8.813180600777265061e-01,5.729733282179839682e-01,7.005990685194828371e-01

加载该文件,只需要调用loadtxt函数。

a_loaded = np.loadtxt('my_array.csv', delimiter=',')
a_loaded

输出:

array([[0.76953407, 0.79648012, 0.8868019 ],
[0.88131806, 0.57297333, 0.70059907]])

压缩格式 .npz

还可以在一个压缩文件中保存多个ndarray。

b = np.arange(24).reshape(2, 3, 4)
b

输出:

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]]])
np.savez('my_arrays', my_a=a, my_b=b)

现在看一下文件内容,文件的扩展名.npz已经自动添加。

with open('my_arrays.npz', 'rb') as f:
content = f.read()
repr(content)[:180] + '[...]'

输出:

'b"PK\\x03\\x04\\x14\\x00\\x00\\x00\\x00\\x00\\x00\\x00!\\x00&\\xa9j\\xe4\\xb0\\x00\\x00\\x00\\xb0\\x00\\x00\\x00\\x08\\x00\\x00\\x00my_a.npy\\x93NUMPY\\x01\\x00v\\x00{\'descr\': \'<f8\', \'fortran_order\': False, \'s[...]'

然后可以这样加载这个文件。

my_arrays = np.load('my_arrays.npz')
my_arrays

输出:

<numpy.lib.npyio.NpzFile at 0x93b8080>

这是一个类似字典的对象,它会懒加载ndarray。

my_arrays.keys()

输出:

['my_a', 'my_b']
my_arrays['my_a']

输出:

array([[0.76953407, 0.79648012, 0.8868019 ],
[0.88131806, 0.57297333, 0.70059907]])
my_arrays['my_b']

输出:

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]]])

numpy教程06---ndarray的进阶操作的更多相关文章

  1. Numpy进阶操作

    目录 1. 如何获取满足条设定件的索引 2. 如何将数据导入和导出csv文件 3. 如何保存和加载numpy对象 4. 如何按列或行拼接numpy数组 5. 如何按列对numpy数组进行排序 6. 如 ...

  2. Django笔记&教程 6-4 forms进阶操作,重写forms方法

    Django 自学笔记兼学习教程第6章第4节--forms进阶操作,重写forms方法 点击查看教程总目录 1 - 重写clean方法 在本章第三节中,我们举了个注册学生账号的例子,里面我们使用模型来 ...

  3. 转:Numpy教程

    因为用到theano写函数的时候饱受数据结构困扰 于是上网找了一篇numpy教程(theano的数据类型是基于numpy的) 原文排版更好,阅读体验更佳: http://phddreamer.blog ...

  4. numpy教程

    [转]CS231n课程笔记翻译:Python Numpy教程 原文链接:https://zhuanlan.zhihu.com/p/20878530 译者注:本文智能单元首发,翻译自斯坦福CS231n课 ...

  5. Python 机器学习库 NumPy 教程

    0 Numpy简单介绍 Numpy是Python的一个科学计算的库,提供了矩阵运算的功能,其一般与Scipy.matplotlib一起使用.其实,list已经提供了类似于矩阵的表示形式,不过numpy ...

  6. [译]Vulkan教程(06)验证层

    [译]Vulkan教程(06)验证层 What are validation layers? 什么是验证层? The Vulkan API is designed around the idea of ...

  7. Pandas和Numpy的一些金融相关的操作(一)

    Pandas和Numpy的一些金融相关的操作 给定一个净值序列,求出最大回撤 # arr是一个净值的np.ndarray i = np.argmax( (np.maximum.acumulate(ar ...

  8. Django框架06 /orm多表操作

    Django框架06 /orm多表操作 目录 Django框架06 /orm多表操作 1. admin相关操作 2. 创建模型 3. 增加 4. 删除 5. 修改 6. 基于对象的跨表查询 7. 基于 ...

  9. NumPy 教程目录

    NumPy 教程目录 1 Lesson1--NumPy NumPy 安装 2 Lesson2--NumPy Ndarray 对象 3 Lesson3--NumPy 数据类型 4 Lesson4--Nu ...

  10. [原创]Scala学习:数组的基本操作,数组进阶操作,多维数组

    1.Scala中提供了一种数据结构-数组,其中存储相同类型的元素的固定大小的连续集合.数组用于存储数据的集合,但它往往是更加有用认为数组作为相同类型的变量的集合 2 声明数组变量: 要使用的程序的数组 ...

随机推荐

  1. UOJ188题解

    我们先枚举一个最大质因子,然后设 \(dp[n][k]\) 为 \(n\) 以内使用了 \(pri[k]\) 以内的质数的数的最大质因子之和,答案就是: \[\sum_{k\leq n}dp[\lfl ...

  2. G1垃圾回收器在并发场景调优

    一.序言 目前企业级主流使用的Java版本是8,垃圾回收器支持手动修改为G1,G1垃圾回收器是Java 11的默认设置,因此G1垃圾回收器可以用很长时间,现阶段垃圾回收器优化意味着针对G1垃圾回收器优 ...

  3. 《前端运维》一、Linux基础--04Shell变量

    这一篇文章,我们就要开始学习正式的Shell语言部分的内容.那在开始之前,我们回忆一下,javascript语言,大体都包含了哪些内容?比如数据类型(对象.字符串.数值),数据结构(对象.数组).运算 ...

  4. nf-Press —— 在线文档也可以加载组件和编写代码

    如果帮助文档可以加载组件,那么在介绍的同时就可以运行演示demo,是不是很酷? 如果可以在线修改运行代码,那么是不是更容易理解? 上一篇 https://www.cnblogs.com/jyk/p/1 ...

  5. python psutila模块

    #!/usr/bin/env python #coding:utf-8 # qianxiao996精心制作 #博客地址:https://blog.csdn.net/qq_36374896 import ...

  6. Python编写简易木马程序(转载乌云)

    Python编写简易木马程序 light · 2015/01/26 10:07 0x00 准备 文章内容仅供学习研究.切勿用于非法用途! 这次我们使用Python编写一个具有键盘记录.截屏以及通信功能 ...

  7. go语言学习入门篇 3-- 程序执行流程

    先看下 Go 语言的程序结构: package main // 当前包名 import "fmt" // 导入程序中使用到的包 // 初始化函数 func init() { // ...

  8. ubuntu16 和ubuntu18安装及设置静态ip

    1.准备ubuntu16镜像2.安装:https://zhuanlan.zhihu.com/p/1447048653.安装ubuntu后,sudo passwd root这个命令建立root用户的密码 ...

  9. Mybatis框架基础入门(五)--输入映射和输出映射

    1.parameterType(输入类型) 1.1 传递简单类型 使用#{}占位符,或者${}进行sql拼接. <select id="caseCountByQueryCaseVo&q ...

  10. spring-boot-learning-监听事件

    Springboot扩展了Spring的ApplicatoionContextEvent,提供了事件: ApplicationStartingEvent:框架启动事件 ApplicationEnvir ...