问题描述:
在一个 220*2 的矩阵 A 中,以行为单位(即每行),行与行之间不存在重复的数据。现已经得到了矩阵 A 中的 i 行数据构成的矩阵 B,求另外 220-i 行数据构成的矩阵 C 。
问题分析:
很明显这个问题其实并不难,我们最容易想到的解决办法就是 for 循环,一个不行就两个,两个不行就三个…… 但如果要求你尽可能少的使用 for 循环时,这个问题又该如何处理呢?
本文实验环境:Python 3.6.1 |Anaconda 4.4.0 (64-bit)
针对东小羊的这个具体的应用场景,可以一个 for 循环也不使用。我们将 B 矩阵拼接在 A 矩阵的下方,得到拼接矩阵 A_B,由于只有两列数据,所以我们借助虚数的概念,将每一行数据转化为一个整体,再使用计数器判断矩阵 A_B 中每个元素的个数,其中个数为 1 的即是我们要寻找的数据。创建 get_others.py 代码如下:
- import numpy as np
- from collections import Counter
- mat = np.arange(20).reshape((10, 2))
- sample_1 = np.arange(0, 6).reshape((3, 2)) # 测试样例
- ############# 关键代码开始 #############
- con_mat = np.concatenate((mat, sample_1), axis=0) # 拼接矩阵
- x = con_mat[:, 0] + con_mat[:, 1] * 1j # 利用虚数
- res = np.array(list(Counter(x).values()))
- sample_2 = mat[res == 1, :]
- ############# 关键代码结束 #############
- print("总的矩阵为:\n", mat)
- print("第一部分为:\n", sample_1)
- print("第二部分为:\n", sample_2)
上述代码的缺陷在于,仅仅只适用于矩阵为两列的情况,如何让代码的鲁棒性更强呢。
· 方案 1 中的虚数转化其实就是将一行数据变为一个单元,那么同样的我们可以将 get_others.py 中的虚数转换部分改变为 tuple 即可,修改后的代码如下:
- import numpy as np
- from collections import Counter
- mat = np.arange(20).reshape((10, 2))
- sample_1 = np.arange(0, 6).reshape((3, 2)) # 测试样例
- ############# 关键代码开始 #############
- con_mat = np.concatenate((mat, sample_1), axis=0) # 拼接矩阵
- con_row_tuple = [tuple(t) for t in con_mat] # 将矩阵中的每一行转换为tuple类型
- res = np.array(list(Counter(con_row_tuple).values()))
- sample_2 = mat[res == 1, :]
- ############# 关键代码结束 #############
- print("总的矩阵为:\n", mat)
- print("第一部分为:\n", sample_1)
- print("第二部分为:\n", sample_2)
在前面的基础上,只要你明白了每一行为一个元素,那么引入集合来进行减运算也是非常容易理解的了。代码如下:
- import numpy as np
- mat = np.arange(20).reshape((10, 2))
- sample_1 = np.arange(0, 6).reshape((3, 2)) # 测试样例
- ############# 关键代码开始 #############
- mat_tuple_set = set([tuple(t) for t in mat]) # 将矩阵中的每一行转换为tuple类型并将结果转为集合类型
- sample_tuple_set = set([tuple(t) for t in sample_1]) # 将矩阵中的每一行转换为tuple类型并将结果转为集合类型
- sample_2 = np.array([list(t) for t in (mat_tuple_set - sample_tuple_set)]) # 集合相减,再将结果转换为二维矩阵形式
- ############# 关键代码结束 #############
- print("总的矩阵为:\n", mat)
- print("第一部分为:\n", sample_1)
- print("第二部分为:\n", sample_2)
利用集合来解决这个问题的思路是不错的,但主要在数据类型的转换上花了较多时间。
通过本文的描述,二维矩阵按行(列)去重或计数有了一定的解决办法。去重和计数问题平常见得比较多的主要出现在一维的列表或数组中,通过借助 numpy.unique() 、
或 转换为 set 类型等等方法进行解决。
- collections.Counter()
来源: http://www.jianshu.com/p/4f7610d507a4