問題描述:
在一個 220*2 的矩陣 A 中,以行為單位(即每行),行與行之間不存在重復(fù)的數(shù)據(jù)×痘妫現(xiàn)已經(jīng)得到了矩陣 A 中的 i 行數(shù)據(jù)構(gòu)成的矩陣 B,求另外 220-i 行數(shù)據(jù)構(gòu)成的矩陣 C 杨何。
問題分析:
很明顯這個問題其實(shí)并不難,我們最容易想到的解決辦法就是for循環(huán)沥邻,一個不行就兩個危虱,兩個不行就三個……但如果要求你盡可能少的使用for循環(huán)時(shí),這個問題又該如何處理呢唐全?
本文實(shí)驗(yàn)環(huán)境:Python 3.6.1 |Anaconda 4.4.0 (64-bit)
方案1
拼接矩陣 + 虛數(shù)轉(zhuǎn)化 + 計(jì)數(shù)器
針對東小羊的這個具體的應(yīng)用場景埃跷,可以一個for循環(huán)也不使用。我們將B矩陣拼接在A矩陣的下方邮利,得到拼接矩陣A_B弥雹,由于只有兩列數(shù)據(jù),所以我們借助虛數(shù)的概念延届,將每一行數(shù)據(jù)轉(zhuǎn)化為一個整體剪勿,再使用計(jì)數(shù)器判斷矩陣A_B中每個元素的個數(shù),其中個數(shù)為1的即是我們要尋找的數(shù)據(jù)方庭。創(chuàng)建 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)) # 測試樣例
############# 關(guān)鍵代碼開始 #############
con_mat = np.concatenate((mat, sample_1), axis=0) # 拼接矩陣
x = con_mat[:, 0] + con_mat[:, 1] * 1j # 利用虛數(shù)
res = np.array(list(Counter(x).values()))
sample_2 = mat[res == 1, :]
############# 關(guān)鍵代碼結(jié)束 #############
print("總的矩陣為:\n", mat)
print("第一部分為:\n", sample_1)
print("第二部分為:\n", sample_2)
上述代碼的缺陷在于厕吉,僅僅只適用于矩陣為兩列的情況,如何讓代碼的魯棒性更強(qiáng)呢械念。
方案2
拼接矩陣 + 元組轉(zhuǎn)化 + 計(jì)數(shù)器
·方案1 中的虛數(shù)轉(zhuǎn)化其實(shí)就是將一行數(shù)據(jù)變?yōu)橐粋€單元头朱,那么同樣的我們可以將 get_others.py
中的虛數(shù)轉(zhuǎn)換部分改變?yōu)?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)) # 測試樣例
############# 關(guān)鍵代碼開始 #############
con_mat = np.concatenate((mat, sample_1), axis=0) # 拼接矩陣
con_row_tuple = [tuple(t) for t in con_mat] # 將矩陣中的每一行轉(zhuǎn)換為tuple類型
res = np.array(list(Counter(con_row_tuple).values()))
sample_2 = mat[res == 1, :]
############# 關(guān)鍵代碼結(jié)束 #############
print("總的矩陣為:\n", mat)
print("第一部分為:\n", sample_1)
print("第二部分為:\n", sample_2)
方案3
元組轉(zhuǎn)化 + 集合運(yùn)算
在前面的基礎(chǔ)上龄减,只要你明白了每一行為一個元素项钮,那么引入集合來進(jìn)行減運(yùn)算也是非常容易理解的了。代碼如下:
import numpy as np
mat = np.arange(20).reshape((10, 2))
sample_1 = np.arange(0, 6).reshape((3, 2)) # 測試樣例
############# 關(guān)鍵代碼開始 #############
mat_tuple_set = set([tuple(t) for t in mat]) # 將矩陣中的每一行轉(zhuǎn)換為tuple類型并將結(jié)果轉(zhuǎn)為集合類型
sample_tuple_set = set([tuple(t) for t in sample_1]) # 將矩陣中的每一行轉(zhuǎn)換為tuple類型并將結(jié)果轉(zhuǎn)為集合類型
sample_2 = np.array([list(t) for t in (mat_tuple_set - sample_tuple_set)]) # 集合相減欺殿,再將結(jié)果轉(zhuǎn)換為二維矩陣形式
############# 關(guān)鍵代碼結(jié)束 #############
print("總的矩陣為:\n", mat)
print("第一部分為:\n", sample_1)
print("第二部分為:\n", sample_2)
利用集合來解決這個問題的思路是不錯的寄纵,但主要在數(shù)據(jù)類型的轉(zhuǎn)換上花了較多時(shí)間。
總結(jié)
通過本文的描述脖苏,二維矩陣按行(列)去重或計(jì)數(shù)有了一定的解決辦法程拭。去重和計(jì)數(shù)問題平常見得比較多的主要出現(xiàn)在一維的列表或數(shù)組中,通過借助 numpy.unique()
棍潘、collections.Counter()
或 轉(zhuǎn)換為 set
類型等等方法進(jìn)行解決恃鞋。