机器学习笔记:逆置换
1 介绍
- 给定一个排列
p
,它的逆置换(inverse permutation)是一个排列invp
,满足invp[p[i]] = i
和p[invp[i]] = i
对所有i
成立。
2 python实现
'''
计算一个排列的逆排列
给定一个排列 p,它的逆排列是一个排列 invp,满足 invp[p[i]] = i 和 p[invp[i]] = i 对所有 i 成立
'''
def invpermute(p):
"""
inverse permutation
"""
p = np.asarray(p)
invp = np.empty_like(p)
for i in range(p.size):
invp[p[i]] = i
#对于每个 i,设置 invp 在 p[i] 的位置上的值为 i
return invp
3 举例
p = [2, 0, 1]
invp = invpermute(p)
invp
#[1, 2, 0]
- invp的第p[0]个位置(第2个位置)值为0
- invp的第p[1]个位置(第0个位置)值为1
- invp的第p[2]个位置(第1个位置)值为2
反之亦可
- p的第invp[0]个位置(第1个位置)值为0
- p的第invp[1]个位置(第2个位置)值为1
- p的第invp[2]个位置(第0个位置)值为2
4 部分应用
4.1 RNN
- 在处理变长序列数据,特别是当我们使用循环神经网络(RNN)时,建议对序列按长度排序
- RNN处理变长序列时,尽管每个序列的实际长度可能不同,但在单次批处理中,我们需要所有的序列都有相同的长度。为了实现这一点,我们通常会对短的序列进行填充,使其长度与批处理中最长的序列相同。
- 当我们对序列按长度排序时,那些长度相近的序列会被分到同一个批处理中。这意味着我们不需要为很短的序列填充过多的无效数据。
4.1.1 举例
假设我们有如下序列:
seqs = ["apple", "banana", "cherry", "date", "fig"]
他们的长度分别为:
lengths = [5, 6, 6, 4, 3]
为了高效地进行批处理,对这些序列按长度进行排序:
sorted_seqs = ["fig", "date", "apple", "banana", "cherry"]
这时,我们需要一个排列索引(按照长度排序后的索引结果)来跟踪这个排序操作:
idx = [4, 3, 0, 1, 2]
#排序后的第0个元素是原来的第4个元素,以此类推
在RNN处理后,我们得到的输出也是按这个顺序排序的。为了将输出恢复到与原始输入相同的顺序,我们需要使用逆排列:
invp = [2, 3, 4, 1, 0]
'''
invp的计算:
invp的第idx[0](4)个元素是0
invp的第idx[1](3)个元素是1
。。。
'''
使用这个逆排列,我们可以将输出重新排序,使其与原始输入的顺序相匹配。
比如RNN之后,得到的输出序列是
outputs = ["output_fig", "output_date", "output_apple", "output_banana", "output_cherry"]
那么 使用逆排列,我们可以将输出重新排序到原始输入的顺序:
original_order_outputs = [outputs[i] for i in invp]
# 返回:['output_apple', 'output_banana', 'output_cherry', 'output_date', 'output_fig']
这样,original_order_outputs
就和 seqs
的顺序一致了。
所以,通过使用逆置换,我们可以确保无论输入序列如何被排序或重排,我们总是可以使用逆置换来恢复原始的顺序。这在处理与序列关联的目标或标签时非常有用,因为我们需要确保输入和标签的顺序始终保持一致。