NumPy库的介绍与使用(三)

十一、线性代数

线性代数(如:矩阵乘法、矩阵分解、行列式以及其他方阵数学等)是任何数组库的重要组成部分。不像某些语言(如:MATLAB),通过*对两个二维数组相乘得到的是一个元素级的积,而不是矩阵点积。因此NumPy提供了一个用于矩阵乘法的dot()函数。
例子1:
m行k列的数组 点乘 k行n列的数组 得到一个m行n列的数组。(k必须对应相等)

x = np.array([[1, 2, 3], [4, 5, 6]])
y = np.array([[6, 23], [-1, 7], [8, 9]])
print(x.dot(y))
# np.dot(x, y)
[[ 28  64]
 [ 67 181]]

例子2:
多维数组乘以一维数组,结果得到一维数组

np.dot(x, np.ones(3))
# [6., 5.]

NumPy中有一组标准的矩阵分解运算以及诸如求:逆、行列式等。他们跟MATLAB和R等语言所使用的是相同的行业标准级Fortran库,如:BLAS、LAPACK、Inter MKL等等,它也取决于你的Numpy版本。

from numpy.linalg import inv, qr
import numpy as np

X = np.random.randn(5, 5)
mat = X.T.dot(X)
print(inv(mat))
# 逆矩阵
[[ 2.38676625  0.0383446   1.22607032 -1.22301455  1.0457165 ]
 [ 0.0383446   0.89091613 -0.85883745 -0.98421099  1.40459633]
 [ 1.22607032 -0.85883745  2.17537261  0.88836567 -1.83227867]
 [-1.22301455 -0.98421099  0.88836567  2.70466106 -3.56901905]
 [ 1.0457165   1.40459633 -1.83227867 -3.56901905  5.19884975]]
 
result = mat.dot(inv(mat))
print(result)
# 结果为单位矩阵(矩阵 点乘 它的逆矩阵)
[[ 1.00000000e+00 -1.35244046e-16 -4.33027096e-16 -9.40317599e-16
   6.35775695e-17]
 [-9.61938278e-17  1.00000000e+00  1.45119917e-16  4.27620132e-16
   1.34304975e-15]
 [-1.96936202e-15 -1.45718601e-15  1.00000000e+00  3.04388831e-15
  -1.89553893e-15]
 [-7.19491779e-17 -3.02262390e-16  8.72327184e-16  1.00000000e+00
  -6.47110058e-16]
 [ 1.21385063e-16 -1.67329489e-16 -4.21602789e-16 -2.27367980e-16
   1.00000000e+00]]

q, r = qr(mat)
print(r)
# 上三角矩阵
[[-3.61408516  0.84443702  3.54093823 -3.47532695 -0.63147377]
 [ 0.         -3.6491614  -2.81565423 -7.12586627 -4.94495531]
 [ 0.          0.         -1.76235213 -5.81463287 -4.72452019]
 [ 0.          0.          0.         -1.50171095 -1.05653428]
 [ 0.          0.          0.          0.          0.14713904]]

print(q)
# 标准正交列矩阵
[[-0.85043878 -0.01382966 -0.41096514  0.16368423  0.28439014]
 [-0.05424249 -0.77067525  0.12413786 -0.54821699  0.29523778]
 [ 0.4553698  -0.30573961 -0.80115779  0.23297692  0.05504161]
 [ 0.09014986  0.53724225 -0.35238216 -0.73203806  0.20782411]
 [ 0.24150151  0.15415076  0.22286869  0.28724144  0.88641777]]

常用的np.linalg()函数

函数说明
diag以一维数组的形式返回方阵的对角线(或非对角线)元素,或将一维数组转换为方阵(非对角线元素为0)
dot矩阵乘法
trace计算对角线元素和
det计算矩阵行列式
eig计算方阵的本征值和本征向量
inv计算方阵的逆
pinv计算方阵的Moore-Penrose伪逆
qr计算QR分解
svd计算奇异值分解(SVD)
solve解线性方程组Ax=b,其中A为一个方阵
lstsq计算Ax=b的最小二乘解

十二、数组文件

Numpy能够读写磁盘上的文本数据或二进制数据。

1. 二进制格式保存

默认情况下,数组是以未压缩的原始二进制格式保存在扩展名为.npy的文件中。

NumPy 为ndarray对象引入了一个简单的文件格式。 这个npy文件在磁盘文件中,存储重建ndarray所需的数据、图形、dtype和其他信息,以便正确获取数组,即使该文件在具有不同架构的另一台机器上。

读写磁盘数组数据的三个主要函数:

# 单文件存储,文件结尾:.npy
np.save(file, array, allow_pickle=True, fix_imports=True)
# 多文件压缩存储,文件结尾:.npz
np.savez(file, *args, **kwds)

# 读取
np.load(file, mmap_mode=None, allow_pickle=False, fix_imports=True,
         encoding='ASCII')

若文件路径末尾没有主动加上扩展名.npy,则该扩展名会被自动加上。然后就可以通过np.load()读取磁盘上的数组。
例子:

(1). 单文件

存储:

arr1 = np.array([3, 9, 7, 3, 1, 5, 8, 1])
np.save("my_array", arr1)

在这里插入图片描述
读取:

print(np.load('my_array.npy'))
# [3 9 7 3 1 5 8 1]

(2). 多文件

存储:

arr1 = np.array([3, 9, 7, 3, 1, 5, 8, 1])
arr2 = np.array([1, 2, 3, 4, 5, 6])
np.savez("my_zip", a=arr1, b=arr2)

在这里插入图片描述
读取:

result = np.load('my_zip.npz')
print(result['b'])
# [1 2 3 4 5 6]

save()和load()函数接受一个附加的布尔参数allow_pickles。 Python 中的pickle用于在保存到磁盘文件或从磁盘文件读取之前,对对象进行序列化和反序列化。

2. 文本格式保存

以简单文本文件格式存储和获取数组数据,是通过savetxt()和loadtx()函数完成的。

# 存储
np.savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='',
            footer='', comments='# ', encoding=None)
# np.genfromtxt与np.savetxt类似,只不过是面向结构化数组和缺失数据处理
参数说明
fname取的文件名
X数组对象名
fmt字符串或者字符串序列,如:(%10.5f),其他复杂格式可参考底层代码
delimiter列分隔符,一般为’,'逗号分隔
newline行分隔符
header头注,写在文件开头
footer角注,写在文件结尾
comments标注符号,写在header和footer前面,默认为’#’,也可写成’numpy.loadtxt’等
encoding编码输出文件
np.loadtxt(fname, dtype=float, comments='#', delimiter=None,
            converters=None, skiprows=0, usecols=None, unpack=False,
            ndmin=0, encoding='bytes', max_rows=None)
参数说明
dtype输出文件数据类型,默认为float
converters一个字典,映射列序号给一个函数,该函数可以解析字符串为目标值
skiprows整型。跳过的行,默认为0行
usecols整型或者元组序列。主动选择要读取的列。
unpack返回被转化过的数组。默认False
ndim整型,返回至少该维度的数组
maxrows返回’skiprows’行后,读取’maxrows’行后的内容。默认读取所有行。

例子:

arr1 = np.array([3, 9, 7, 3, 1, 5, 8, 1])
np.savetxt("my_txt", arr1)
np.loadtxt('my_txt')
# [3. 9. 7. 3. 1. 5. 8. 1.]

3. 数据的CSV文件存取

(1)CSV文件

CSV (Comma-Separated Value,逗号分隔值)
CSV是一种常见的文件格式,用来存储批量数据。
在这里插入图片描述

(2)如何将数组写入CSV文件?

np.savetxt(frame, array, fmt='%.18e', delimiter=None) #介绍部分参数
参数说明
frame文件、字符串或产生器,可以是.gz或.bz2的压缩文件。
array存入文件的数组。
fmt写入文件的格式,例如:%d、%.2f 、%.18e。
delimiter分割字符串,默认是任何空格。

例子:

a = np.arange(18).reshape(2,9)
"""
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8],
       [ 9, 10, 11, 12, 13, 14, 15, 16, 17]])
"""
np.savetxt('a.csv', a, fmt='%d', delimiter=',') #将数组保存成CSV文件

fo = open('a.csv',"r") #打开a.csv文件

for line in fo:
    print(line) #在屏幕上显示文件内容
"""    
0,1,2,3,4,5,6,7,8
9,10,11,12,13,14,15,16,17
"""
fo.close() #关闭文件

(3)如何读取CSV文件到数组?

np.loadtxt(frame, dtype=np.float, delimiter=None, unpack=FaIse) #介绍部分参数
参数说明
frame文件、字符串或产生器,可以是.gz或.bz2的压缩文件。
dtype数据类型,可选。
delimiter分割字符串,默认是任何空格。
unpack如果True,读入属性将分别写入不同变量。

例子:

b = np.loadtxt('a.csv', delimiter=',')
print(b)
"""
array([[ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.],
       [ 9., 10., 11., 12., 13., 14., 15., 16., 17.]])
"""
b = np.loadtxt('a.csv', dtype=np.int, delimiter=',') #改变数据类型

print(b)
""" 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8],
       [ 9, 10, 11, 12, 13, 14, 15, 16, 17]])
"""
c = np.loadtxt('a.csv', dtype=np.int, delimiter=',', unpack=True)
print(c)
"""
array([[ 0,  9],
       [ 1, 10],
       [ 2, 11],
       [ 3, 12],
       [ 4, 13],
       [ 5, 14],
       [ 6, 15],
       [ 7, 16],
       [ 8, 17]])
"""
q,w,e,r,t,y,u,i,o = np.loadtxt('a.csv', dtype=np.int, delimiter=',', unpack=True) #读入到不同数组
print(q)
# array([0, 9])
print(o)
# array([ 8, 17])

(4)CSV文件的局限性

CSV只能有效存储一维和二维数组,也就是说np.savetxt()和np.loadtxt()只能有效存取一维和二维数组。

4. 多维数据的存取

(1) 任意维度数据存取

a.tofile(frame, sep=", format='%s')
参数说明
frame文件、字符串或产生器,可以是.gz或.bz2的压缩文件。
sep数据分割字符串,如果是空串,写入文件为二进制。
format写入数据的格式。

例子:

a = np.arange(24).reshape(2,3,4)
print(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]]])
"""
a.tofile("b.dat", sep=',', format='%d')
f = open("b.dat", 'r')
for line in f:
    print(line) #显示文件内容
# 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
f.close()

(2)读取文件还原数据

np.fromfile(frame, dtype=float, count=-1, sep=")
参数说明
frame文件、字符串或产生器,可以是.gz或.bz2的压缩文件。
dtype数据类型,可选。
count读入元素个数,-1表示读入整个文件。
sep数据分割字符串,如果是空船,写入文件为二进制。

读取文本文件

a = np.arange(24).reshape(2,3,4)
a.tofile("b.dat", sep=',', format='%d') #生成文本文件,维度信息丢失
c = np.fromfile("b.dat", dtype=np.int, sep=',')
print(c)
"""
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])
"""
c = np.fromfile("b.dat", dtype=np.int, sep=',').reshape(2,3,4) #变换数组维度
print(c)
"""
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]]])
"""

读取二进制文件

a = np.arange(24).reshape(2,3,4)
a.tofile("b.dat", format='%d') #生成二进制文件,维度信息丢失
c = np.fromfile("b.dat", dtype=np.int)
print(c)
"""
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])
"""
c = np.fromfile("b.dat", dtype=np.int).reshape(2,3,4) #变换数组维度
print(c)
"""
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]]])
"""

注意:
①该方法读取时需要知道存入文件时数组的维度元素类型;②a.tofile()和np.fromfile()可以配合使用达到数据缓存的目的;③可以通过元数据文件来存储额外信息。

十三、副本和视图

在执行函数时,其中一些返回输入数组的副本,而另一些返回视图。 当内容物理存储在另一个位置时,称为副本。 另一方面,如果提供了相同内存内容的不同视图,我们将其称为视图

1. 无复制

简单的赋值不会创建数组对象的副本。 相反,它使用原始数组的相同id()来访问它。 id()返回 Python 对象的通用标识符,类似于 C 中的指针。

此外,一个数组的任何变化都反映在另一个数组上。 例如,一个数组的形状改变也会改变另一个数组的形状。
例子:

 
import numpy as np 
a = np.arange(6)  
print('我们的数组是:')
print(a)
# [0 1 2 3 4 5]
print('调用 id() 函数:')
print(id(a))
# 139747815479536
print('a 赋值给 b:')
b = a 
print(b)
print('b 拥有相同 id():')
print(id(b))
# 139747815479536
print('修改 b 的形状:')
b.shape =  3,2  
print(b)
"""
[[0 1]
 [2 3]
 [4 5]]
"""
print('a 的形状也修改了:')
print(a)
"""
[[0 1]
 [2 3]
 [4 5]]
"""

2. 视图或浅复制

NumPy 拥有ndarray.view()方法,它是一个新的数组对象,并可查看原始数组的相同数据。 与前一种情况不同,新数组的维数更改不会更改原始数据的维数。
例子:

 
import numpy as np 
# 最开始 a 是个 3X2 的数组
a = np.arange(6).reshape(3,2)  
print  '数组 a:'  
print a 
print  '创建 a 的视图:' 
b = a.view()  
print b 
print  '两个数组的 id() 不同:'  
print  'a 的 id():'  
print id(a)  
print  'b 的 id():'  
print id(b)  
# 修改 b 的形状,并不会修改 a
b.shape =  2,3  
print  'b 的形状:'  
print b 
print  'a 的形状:'  
print a

3. 深复制

ndarray.copy()函数创建一个深层副本。 它是数组及其数据的完整副本,不与原始数组共享。
例子:

import numpy as np 
a = np.array([[10,10],  [2,3],  [4,5]])  
print('数组 a:')
print(a)
"""
[[10 10]
 [ 2 3]
 [ 4 5]]
"""
print('创建 a 的深层副本:' 
b = a.copy()  
print('数组 b:')
print(b)
"""
[[10 10]
 [ 2 3]
 [ 4 5]]
"""
# b 与 a 不共享任何内容  
print('我们能够写入 b)来写入 a 吗?')
print(b is a)
# False
print('修改 b)的内容:' 
b[0,0]  =  100  
print('修改后的数组 b:')
print(b)
"""
[[100 10]
 [ 2 3]
 [ 4 5]]
"""
print('a 保持不变:')
print(a)
"""
[[10 10]
 [ 2 3]
 [ 4 5]]
"""

十四、位操作

下面是 NumPy 包中可用的位操作函数。

函数说明
bitwise_and对数组元素执行位与操作
bitwise_or对数组元素执行位或操作
invert计算位非
left_shift向左移动二进制表示的位
right_shift向右移动二进制表示的位

1. bitwise_and

通过np.bitwise_and()函数对输入数组中的整数的二进制表示的相应位执行位与运算。
例子

 
import numpy as np 
print('13 和 17 的二进制形式:')
a,b = 13,17 
print(bin(a), bin(b))
 # 0b1101 0b10001
print('13 和 17 的位与:')
print(np.bitwise_and(13, 17))
# 1

你可以使用下表验证此输出。 考虑下面的位与真值表。

ABAND
111
100
010
000
1101
AND
10001
result00001

2. bitwise_or

通过np.bitwise_or()函数对输入数组中的整数的二进制表示的相应位执行位或运算。
例子

 
import numpy as np 
a,b = 13,17 
print('13 和 17 的二进制形式:')
print(bin(a), bin(b))
# 0b1101 0b10001
print('13 和 17 的位或:')
print(np.bitwise_or(13, 17))
# 
29

你可以使用下表验证此输出。 考虑下面的位或真值表。

ABOR
111
101
011
000
1101
OR
10001
result11101

3. invert

此函数计算输入数组中整数的位非结果。 对于有符号整数,返回补码。
例子

 
import numpy as np 
 
print('13 的位反转,其中 ndarray 的 dtype 是 uint8:')
print(np.invert(np.array([13], dtype = np.uint8)))
# [242]
# 比较 13 和 242 的二进制表示,我们发现了位的反转
print('13 的二进制表示:')
print(np.binary_repr(13, width = 8))
# 00001101
print('242 的二进制表示:')
print(np.binary_repr(242, width = 8))
# 11110010

请注意,np.binary_repr()函数返回给定宽度中十进制数的二进制表示。

4. left_shift

numpy.left shift()函数将数组元素的二进制表示中的位向左移动到指定位置,右侧附加相等数量的 0。
例子

 
import numpy as np 
 
print('将 10 左移两位:')
print(np.left_shift(10,2))
# 40
print('10 的二进制表示:')
print(np.binary_repr(10, width = 8))
# 00001010
print('40 的二进制表示:')
print(np.binary_repr(40, width = 8))
# 00101000
#  '00001010' 中的两位移动到了左边,并在右边添加了两个 0。

5.right_shift

numpy.right_shift()函数将数组元素的二进制表示中的位向右移动到指定位置,左侧附加相等数量的 0。
例子

 
import numpy as np 
 
print('将 40 右移两位:')
print(np.right_shift(40,2))
# 10
print('40 的二进制表示:')
print(np.binary_repr(40, width = 8))
# 00101000
print('10 的二进制表示:')
print(np.binary_repr(10, width = 8))
# 00001010
#  '00001010' 中的两位移动到了右边,并在左边添加了两个 0。

参考:
NumPy库的介绍与使用教程
Python之Numpy详细教程
NumPy — 从零到入门

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值