前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >机器学习入门 3-10 Numpy中的比较和Fancy Indexing

机器学习入门 3-10 Numpy中的比较和Fancy Indexing

作者头像
触摸壹缕阳光
发布2022-11-08 13:24:04
5240
发布2022-11-08 13:24:04
举报

Fancy Indexing

首先创建一个向量。

代码语言:javascript
复制
import numpy as np

x = np.arange(16)

我们可以对向量进行和 Python 列表一样的索引和切片操作。

代码语言:javascript
复制
x[3]   # 索引第4个元素
x[3:9]   # 索引第4~9个元素(包左不包右)
x[3:9:2] # 在第4~9个元素中,每隔2个元素索引一个值(包左不包右)

如果我们想索引向量中 "第4,6,9 个元素",上面的索引和切片操作显然不能满足我们的需求。比较直观的想法是直接将三个位置的元素索引出来,然后再存储到一个新的向量中。

代码语言:javascript
复制
np.array([x[3], x[5], x[8]])

不过这种调用方式显然不够简洁,方便。因此,NumPy 提供了 Fancy Indexing。

代码语言:javascript
复制
index = np.array([3, 5, 8])
print(x[index]) # [3 5 8]

创建一个元素值为索引位置的向量 index,直接通过 x[index] 来进行索引。通过结果也可以看出,np.array([x[3], x[5], x[8]) 和这种 Fancy Indexing 的方式是等价。

如果指定 index 为一个二维矩阵。

代码语言:javascript
复制
index = np.array([[0, 2],
                  [1, 3]])
print(x[index])
'''
[[0 2]
 [1 3]]
'''

按照 index 为一个一维向量为例,上面的 Fancy Indexing 方式与下面代码执行的结果一样。

代码语言:javascript
复制
np.array([[x[0], x[2]],
          [x[1], x[3]]])

Fancy Indexing 不仅能够应用在一维的向量中,而且还适用于二维的矩阵。

代码语言:javascript
复制
X = x.reshape(4, -1)
print(X)
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]
'''

我们想要索引矩阵中的某几个元素,只需要传入这几个元素所在的行和列。

代码语言:javascript
复制
row = np.array([0, 1, 2])
col = np.array([1, 2, 3])
print(X[row, col])
'''
[ 1  6 11]
'''

在二维矩阵中需要确定某个元素的位置,需要明确这个元素的行标和列标。对于 row = np.array([0, 1, 2])col = np.array([1, 2, 3]) 而言,在二维矩阵中索引元素的位置为 [0,1], [1, 2], [2, 3]

我们也可以只对某一行的某些列进行索引,比如下面就是对矩阵第一行中的第二、三、四列的元素进行索引。

代码语言:javascript
复制
print(X[0, col])
'''
[1 2 3]
'''

下面是对矩阵中前两行中的第二、三、四列的元素进行索引。

代码语言:javascript
复制
print(X[:2, col])
'''
[[1 2 3]
 [5 6 7]]
'''

索引 index 数组不仅局限具体的索引位置,我们还可以使用 bool 值来决定对应位置是否被索引。比如,我们想要索引第二、三行中的第一、三、四列。除了可以使用 col = np.array([0, 2, 3]),还可以使用 bool 数组。(True 表示对应位置进行索引,而 False 则表示对应位置不进行索引)

代码语言:javascript
复制
col = np.array([True, False, True, True])
print(X[1:3, col])
'''
[[ 4  6  7]
 [ 8 10 11]]
'''

numpy.array 比较

使用 bool 来进行 Fancy Indexing 比较常见,很多时候我们会对数据进行批量的比较,这种批量比较的返回值就是 bool 数组。

代码语言:javascript
复制
print(x < 3)
'''
[ True  True  True False False False False False False False False False
 False False False False]
'''

x < 3 将 x 中的所有元素都和 3 进行比较,返回的是一个和 x 相同形状的 bool 数组。

  • 当 x 中的某个元素小于 3,则在 bool 数组中对应位置返回 True;
  • 当 x 中的某个元素大于等于 3,则在 bool 数组中对应位置返回 False。

类似的,我们可以对所有的比较运算符进行这种操作。

代码语言:javascript
复制
x > 3
x <= 3
x >= 3
x == 3
x != 3

对于这种比较运算符,我们可以与加减乘除进行结合实现更加复杂的逻辑。

代码语言:javascript
复制
print(2 * x == 24 - 4 * x)
'''
[False False False False  True False False False False False False False
 False False False False]
'''

对于这种比较运算符,我们同样可以应用在二维矩阵上。

代码语言:javascript
复制
X = x.reshape(4, -1)
print(X)
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]
'''
代码语言:javascript
复制
print(X < 6)
'''
[[ True  True  True  True]
 [ True  True False False]
 [False False False False]
 [False False False False]]
'''

此时,在二维矩阵上的比较运算符,返回的是一个与二维矩阵相同形状的 bool 数组。

这种比较有什么意义呢?假设现在将下面的一维向量赋予实际的意义,收集 16 个孩子的年龄。换句话说,收集 16 个样本,每个样本只有 1 个特征。

代码语言:javascript
复制
x = np.arange(16)
print(x)
'''
[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15]
'''

如果我们想统计,年龄小于等于 3 岁孩子的个数。

代码语言:javascript
复制
print(np.sum(x <= 3)) # 4

NumPy 中有一个 np.cout_nonzero 函数,能够统计传入函数的数组中有多少个非零元素,对于传入的是 bool 数组,对应的 True 就是 1,False 就是 0。

代码语言:javascript
复制
print(np.cout_nonzero(x <= 3)) # 4

还可以通过 np.any 函数看数组中是否有为零的元素。传入 np.any 的数组,只要有一个是非零元素,则返回 True,否则返回 False。对于传入的是 bool 数组,对应的 True 就是 1,False 就是 0。

代码语言:javascript
复制
print(np.any(x == 0)) # True

使用 np.any 来判断数组中是否年龄都小于 0 呢?

  • 只要有任何一个样本的年龄小于 0 时,则 np.any 就会返回 True;
  • 当样本中的年龄都大于等于 0时,则 np.any 就返回 False。
代码语言:javascript
复制
print(np.any(x < 0)) # False

np.any 相对应的还有 np.all,只有当传入的 bool 数组中的元素全部都为 True,np.all 才会返回 True,其余情况返回 False。

代码语言:javascript
复制
print(np.all(x >= 0)) # True
print(np.all(x > 0))  # False

同样,上面的方法依然适用于矩阵。

代码语言:javascript
复制
X = x.reshape(4, -1)
print(X)
'''
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]
'''

如果我们想看看矩阵中的元素有多少个偶数。

代码语言:javascript
复制
print(np.sum(X % 2 == 0)) # 8

类似的,对于矩阵这种多维数组,我们可以指定运算的维度。

代码语言:javascript
复制
print(np.sum(X % 2 == 0, axis = 1)) # 沿着列的方向,每一行有多少个偶数
'''
[2 2 2 2]
'''

print(np.sum(X % 2 == 0, axis = 0)) # 沿着行的方向,每一列有多少个偶数
'''
[4 0 4 0]
'''

对于矩阵这种多维数组,np.anynp.all 也可以指定运算的维度。

代码语言:javascript
复制
print(np.all(X > 0, axis = 1)) # 沿着列的方向,看的是每一行
'''
[False  True  True  True]
'''

第 0 行不满足所有的元素都大于 0,因为第 0 行中有一个元素值等于 0。

对于这些比较操作,我们可以进行组合操作。

代码语言:javascript
复制
x = np.arange(16)
print(x)
'''
[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15]
'''

统计孩子年龄大于 3 且小于 10 的个数。

代码语言:javascript
复制
print(np.sum((x > 3) & (x < 10))) # 6

需要注意的是,此处使用的是位运算符 &,不是使用的条件运算符 &&(条件运算符连接的是两个条件)。x > 3x < 10 返回的是两个形状相同的布尔数组,这里希望两个布尔数组按照相应的索引位置进行与的运算,相当于把两个布尔数组中的每个元素看成是一个位。如果使用条件运算符会抛出异常:

代码语言:javascript
复制
print(np.sum((x > 3) && (x < 10)))
'''
    print(np.sum((x > 3) && (x < 10)))
                          ^
SyntaxError: invalid syntax
'''

类似的位运算符还有 |, ~。统计孩子年龄是偶数或者年龄大于 10 的个数。

代码语言:javascript
复制
print(np.sum((x % 2 == 0) | (x > 10))) # 11

统计孩子年龄不等于 0 的个数。

代码语言:javascript
复制
print(np.sum(~(x == 0))) # 15

布尔数组能够作为 Fancy Indexing 的索引数组非常方便。找出年龄小于 5 岁的孩子。

代码语言:javascript
复制
print(x[x < 5])
'''
[0 1 2 3 4]
'''

找出年龄是偶数的孩子。

代码语言:javascript
复制
print(x[x % 2 == 0])
'''
[ 0,  2,  4,  6,  8, 10, 12, 14]
'''

或者对于一个矩阵,抽出行的最后一个元素能够 3 整除的行,列无要求。

代码语言:javascript
复制
print(X[X[:,3] % 3 == 0, :])
'''
[[ 0  1  2  3]
 [12 13 14 15]]
'''

Pandas

对于更加高级的表格进行处理,通常使用 Pandas 库。不过,在 sklearn 中封装的机器学习算法往往接收的数据类型是 NumPy 数组。因此,我们使用 sklearn 实现机器学习算法通常会依照下面的流程:

  • 使用 Pandas 库对数据进行一系列的预处理操作;
  • 将预处理后的数据转换成 NumPy 数组;
  • 使用 sklearn 对 NumPy 数组进行机器学习算法。

References:

Python3入门机器学习 经典算法与应用: https://coding.imooc.com/class/chapter/169.html#Anchor

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-06-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AI机器学习与深度学习算法 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • numpy.array 比较
  • Pandas
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档