python:numpy(4)

本文详细介绍了Python Numpy库中的一些高级操作,包括布尔型索引、花式索引、直接赋值、视图与深拷贝的概念,以及位运算如bitwise_and、bitwise_or、invert等函数的使用。此外,还讨论了二进制的进制转换和线性代数相关操作,如矩阵的行列式、求解线性方程组以及计算逆矩阵等。
  • 高级索引

布尔型索引

可以通过比较运算符来产生一个布尔型数组。
对同样大小的布尔型数组,可以利用&(和)、|(或)、-(非)进行运算。

data = np.random.randn(7, 4)
print(data)
print(data > 0)
print((data > -1) & (data < 1))
[[ 0.59711287  0.35911118  0.80925994 -1.60744802]
 [ 1.4904879   0.1192616  -0.83902824  0.37876663]
 [-0.26166516 -0.49346625  0.18346839  0.70833643]
 [ 0.32048212 -0.69056052 -0.29403945 -0.14632815]
 [-0.08186285 -0.49594495  0.12816477  1.27712333]
 [ 0.44620341 -1.57771506 -0.78073316 -0.38668016]
 [-0.66192819 -1.30421999  1.00875952  1.0798795 ]]
[[ True  True  True False]
 [ True  True False  True]
 [False False  True  True]
 [ True False False False]
 [False False  True  True]
 [ True False False False]
 [False False  True  True]]
[[ True  True  True False]
 [False  True  True  True]
 [ True  True  True  True]
 [ True  True  True  True]
 [ True  True  True False]
 [ True False  True  True]
 [ True False False False]]

利用布尔型索引的功能,可以快速进行筛选。
定义一个名称数组,长度为7,并假设上述data中的每一行与名称数组中的名字一一对应。

names = np.array(['ben', 'tom', 'ben', 'jeremy', 'jeremy', 'tom', 'ben'])
print(names)
print(data[names == 'ben'])
print(data[(names == 'ben') | (names == 'tom')])
print(data[data > 0])
['ben' 'tom' 'ben' 'jeremy' 'jeremy' 'tom' 'ben']
[[ 0.59711287  0.35911118  0.80925994 -1.60744802]
 [-0.26166516 -0.49346625  0.18346839  0.70833643]
 [-0.66192819 -1.30421999  1.00875952  1.0798795 ]]
[[ 0.59711287  0.35911118  0.80925994 -1.60744802]
 [ 1.4904879   0.1192616  -0.83902824  0.37876663]
 [-0.26166516 -0.49346625  0.18346839  0.70833643]
 [ 0.44620341 -1.57771506 -0.78073316 -0.38668016]
 [-0.66192819 -1.30421999  1.00875952  1.0798795 ]]
[0.59711287 0.35911118 0.80925994 1.4904879  0.1192616  0.37876663 0.18346839 0.70833643 0.32048212 0.12816477 1.27712333 0.44620341
 1.00875952 1.0798795 ]
花式索引
#对于使用一维整型数组作为索引,如果目标是一维数组,那么索引的结果就是对应位置的元素;如果目标是二维数组,那么就是对应下标的行。
print(names[[4, 3, 2, 1]])
print(names[[-1, -2, -3, -4]])
print(data[[3, 1]])
print(data[[3, 1, 2], [0, 2, 1]])
#一次性传入两个列表:[3,1,2]、[0,2,1],最终选取出三个元素,其在data数组中的位置分别是(3, 0)、(1, 2)、(2, 1)。并没有和切片索引一样,返回一个矩形区域。
#下面是得到矩形区域的一个这种的办法:
print(data[[3,1,2][:,[0,2,1]]])
['jeremy' 'jeremy' 'ben' 'tom']
['ben' 'tom' 'jeremy' 'jeremy']
[[ 0.32048212 -0.69056052 -0.29403945 -0.14632815]
 [ 1.4904879   0.1192616  -0.83902824  0.37876663]]
[ 0.32048212 -0.83902824 -0.49346625]
[[ 0.32048212 -0.29403945 -0.69056052]
 [-0.26166516  0.18346839 -0.49346625]
 [ 1.4904879  -0.83902824  0.1192616 ]]
  • 副本与试图

视图是指对数据的引用,通过该引用亦便可访问、操作原有数据,但原有数据不会产生拷贝。如果我们对视图进行修改,它会影响到原始数据,物理内存在同一位置。
副本是一个数据的完整的拷贝,如果我们对副本进行修改,它不会影响到原始数据,物理内存不在同一位置。

直接赋值
a = np.arange(12)
print("数组a:", a)
print("数组a的id:", id(a))
b = a
print("数组b:", b)
print("数组b的id:", id(b))
a.shape=(3,4)
print(a)
print(b)
数组a: [ 0  1  2  3  4  5  6  7  8  9 10 11]
数组a的id3027713941216
数组b: [ 0  1  2  3  4  5  6  7  8  9 10 11]
数组b的id3027713941216
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

直接赋值地址是一样的;改变a的形状,b跟着改变。改变b的性质,a跟着改变。

视图或浅拷贝
a = np.arange(6).reshape(3, 2)
print("数组a:", a)
print("数组a的id:", id(a))
b = a.view()
print("数组b:", b)
print("数组b的id:", id(b))
b.shape=(2,3)
print(b)
print(a)

数组a: [[0 1]
 [2 3]
 [4 5]]
数组a的id: 2141095934672
数组b: [[0 1]
 [2 3]
 [4 5]]
数组b的id: 2141135964000
[[0 1 2]
 [3 4 5]]
[[0 1]
 [2 3]
 [4 5]]

视图地址不一样;改变a的形状,b不改变。改变b的形状,a不改变

arr = np.arange(12)
a = arr[3:]
b = arr[3:]
print("修改前的切片a:", a)
print("修改前的切片b:", b)
a[1] = 123
b[2] = 234
print("修改后的切片a:", a)
print("修改后的切片b:", b)
print("修改后的原数组arr:", arr)
修改前的切片a: [ 3  4  5  6  7  8  9 10 11]
修改前的切片b: [ 3  4  5  6  7  8  9 10 11]
修改后的切片a: [  3 123 234   6   7   8   9  10  11]
修改后的切片b: [  3 123 234   6   7   8   9  10  11]
修改后的原数组arr: [  0   1   2   3 123 234   6   7   8   9  10  11]

我们可以发现:变量 a,b 都是 arr 的一部分视图,对视图的修改会直接反映到原数据和相关切片中。

副本或深拷贝
a = np.array([[0, 1], [2, 3], [4, 5]])
b = a.copy()
print(a)
print(b)
print(id(a))
print(id(b))
b[0, 0] = 100
print(a)
print(b)
[[0 1]
 [2 3]
 [4 5]]
[[0 1]
 [2 3]
 [4 5]]
2820242562624
2820247665360
[[0 1]
 [2 3]
 [4 5]]
[[100   1]
 [  2   3]
 [  4   5]]

副本的地址不一样;改变b的值,a不改变。改变a的值,b不改变。

a = np.array([[0, 1], [2, 3], [4, 5]])
b = a.copy()
c = a
d = a.view()
print(b is a)
print(c is a)
print(d is a)
False
True
False
  • 位运算

bitwise_and 对数组元素执行位与操作
bitwise_or 对数组元素执行位或操作
invert 按位取反
left_shift 向左移动二进制表示的位
right_shift 向右移动二进制表示的位

numpy.bitwise_and函数

numpy.bitwise_and 函数对数组中整数的二进制形式执行位与运算。

a, b = 13, 17
print(np.bitwise_and(a, b))
# 解释:按位与都是1才是1
print("a的二进制为:", bin(a))
print("b的二进制为:", bin(b))
#   a的二进制为:01101
#   b的二进制为:10001
#   按位与:    00001
1
a的二进制为: 0b1101
b的二进制为: 0b10001
numpy.bitwise_or 函数

numpy.bitwise_or 函数对数组中整数的二进制形式执行位或运算。

a, b = 13, 17
print(np.bitwise_or(a, b))
# 解释:按位或只要有1就是1
print("a的二进制为:", bin(a))
print("b的二进制为:", bin(b))
#   a的二进制为:01101
#   b的二进制为:10001
#   按位或:    11101
29
a的二进制为: 0b1101
b的二进制为: 0b10001
numpy.invert函数

numpy.invert函数对数组中整数进行位取反运算,即 0 变成 1,1 变成 0。
对于有符号整数,取该二进制数的补码,然后 加1。二进制数,最高位为0表示正数,最高位为 1 表示负数。

print("1的二进制表示", np.binary_repr(1, width=8))
print("1的位反转", np.invert(1))
# 解释:
# 1的二进制码位                00000001
# 按位取反位                   11111110
# 最高位为1表示负数,其他位取反    10000001
# 末位加1得其补码               10000010
# 转换回十进制                  -2
1的二进制表示 00000001
1的位反转 -2
numpy.left_shift 函数

numpy.left_shift 函数将数组元素的二进制形式向左移动到指定位置,右侧附加相等数量的 0。

print("10的二进制表示", np.binary_repr(10, width=8))
print("10左移2位的结果:", np.left_shift(10,2))
# 解释:
#10的二进制为: 00001010
#左移两位为:   00101000
print(int('00101000',2))
10的二进制表示 00001010
10左移2位的结果: 40
40
numpy.right_shift函数

numpy.right_shift 函数将数组元素的二进制形式向右移动到指定位置,左侧附加相等数量的 0。

print("40的二进制表示", np.binary_repr(40, width=8))
print("40右移2位的结果:", np.right_shift(40, 2))
# 解释:
# 40的二进制为: 00101000
# 左移两位为:   00001010
print(int('00001010', 2))
40的二进制表示 00101000
40右移2位的结果: 10
10
进制转换
print(bin(10))  # 10转2
print(oct(10))  # 10转8
print(hex(10))  # 10转16
print(int('1010', 2))  # 2转10
print(int('37', 8))  # 8转10
print(int('4a', 16))  # 16转10
0b1010
0o12
0xa
10
31
74
  • 线性代数

二元运算

Numpy 提供了一系列可以用于线性代数运算的函数,具体如下:
dot 两个数组的点积,即元素对应相乘。
vdot 两个向量的点积
inner 两个数组的内积
matmul 两个数组的矩阵积
determinant 数组的行列式
solve 求解线性矩阵方程
inv 计算矩阵的乘法逆矩阵

对于两个一维数组,dot() 函数计算的是这两个数组对应下标元素的乘积和,也称之为內积。对于二维数组,计算的是两个数组的矩阵乘积。

a = np.array([1, 2, 3, 4])
b = np.array([6, 7, 8, 9])
print(np.dot(a, b))
# 80=1*6+2*7+3*8+4*9
A = np.array([[1, 2, 3], [4, 5, 6]])
B = np.array([[11, 22], [33, 44], [55, 66]])
print(np.dot(A, B))
# (2,3)*(3,2)=(2,2)
80
[[242 308]
 [539 704]]

numpy.vdot() 函数是求两个向量的点积,即对应位置的元素乘积求和。

B = np.array([[11, 22], [33, 44], [55, 66]])
C = np.array([[1, 2], [3, 4], [5, 6]])
print(np.vdot(B, C))
1001

numpy.inner() 函数返回一维数组的向量内积。对于更高的维度,它返回最后一个轴上的元素乘积之和。

B = np.array([[11, 22], [33, 44], [55, 66]])
C = np.array([[1, 2], [3, 4], [5, 6]])
print(np.inner(B, C))
[[ 55 121 187]
 [121 275 429]
 [187 429 671]]
#解释
 #[
 #   11*1+22*2=55, 11*3+22*4=121, 11*5+22*6=187
  #  33*1+44*2=121, 33*3+44*4=275, 33*5+44*6=429
   # 55*1+66*2=187, 55*3+66*4=429, 55*5+66*6=671
#]

numpy.matmul 函数返回两个数组的矩阵乘积。对于二维数组,其计算结果与dot一致。

B = np.array([[11, 22], [33, 44], [55, 66]])
print(np.matmul(A,B))
[[242 308]
 [539 704]]
线代求解

numpy.linalg.det() 函数计算输入矩阵的行列式。
行列式在线性代数中是非常有用的值。 它从方阵的对角元素计算。 对于 2×2 矩阵,它是左上和右下元素的乘积与其他两个的乘积的差。换句话说,对于矩阵 [[a,b],[c,d]],行列式计算为 ad-bc。 较大的方阵被认为是 2×2 矩阵的组合。

M = np.array([[6, 2, 1], [4, -2, 15], [12, 8, 7]])
print(M)
print(np.linalg.det(M))
-444.0000000000004

numpy.linalg.solve() 函数给出了矩阵形式的线性方程的解。

# x + y + z =10
# 2x + y = 6
# 3y -2z = 2
# 转换成矩阵
A = np.array([[1, 1, 1], [2, 1, 0], [0, 3, -2]])
b = np.array([[10], [6], [2]])
print(np.linalg.solve(A, b))
# x=1  y=4  z=5
[[1.]
 [4.]
 [5.]]

numpy.linalg.inv() 函数计算矩阵的乘法逆矩阵。逆矩阵的概念如下:设 A 是数域上的一个 n 阶矩阵,若在相同数域上存在另一个 n 阶矩阵 B,使得: AB=BA=E ,则我们称 B 是 A 的逆矩阵,而A则被称为可逆矩阵。注意:E 为单位矩阵。
利用逆矩阵,可以换一种思路求解 2.2 中的方程组的解:
对于矩阵 A,假设逆矩阵为 F,则有:x=Fb。因此方程组的解为:

A = np.array([[1, 1, 1], [2, 1, 0], [0, 3, -2]])
b = np.array([[10], [6], [2]])
print("计算A的逆矩阵:")
F = np.linalg.inv(A)
print("A的逆矩阵F:", F)
print("方程组的解为:", np.matmul(F, b))
计算A的逆矩阵:
A的逆矩阵F: [[-0.25   0.625 -0.125]
 [ 0.5   -0.25   0.25 ]
 [ 0.75  -0.375 -0.125]]
方程组的解为: [[1.]
 [4.]
 [5.]]

小结:
1.高级索引
比较运算符生成布尔类型数组
比较运算符与布尔类型索引
花式索引
2.副本与视图
直接赋值
.view()视图
.copy()副本
3.位运算
numpy.bitwise_and()位与
numpy.bitwise_or()位或
numpy.invert()取反
numpy.left_shift()左移
numpy.right_shift()右移
进制转换:
bin()10转2
oct() 10转8
hex() 10转16
int('1010', 2) 2转10
int('37', 8) 8转10
int('4a', 16) 16转10
4.线性代数
numpy.dot()两个数组的点积一维数组对应元素相乘加和,多维数组为矩阵乘法。
numpy.vdot()对应元素相乘求和。对于维度不一致的矩阵,如果其元素个数相等,则可以进行 vdot 点积运算;因为在 vdot运算过程中,会首先将矩阵展开。
numpy.inner()一维数组的向量内积。对于更高的维度,它返回最后一个轴上的元素乘积之和。
numpy.matmul()两个数组的矩阵乘积。
numpy.linalg.det()计算行列式。
numpy.linalg.solve()计算线性方程的解。
numpy.linalg.inv()计算矩阵的逆矩阵。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值