2016-12-01 729 views
2

我有一種類似於SQL搜索的任務。我有包含以下一維數組(約1百萬個元素)通過ID1標識的「表」:匹配兩個numpy數組以找到相同的元素

ID1, z, e, PA, n 

另一個「表」,其中包含由ID2確定了以下一維數組(約1.5百萬個元素):

ID2, RA, DEC 

我想匹配ID1ID2找到常見的形成含有ID, z, e, PA, n, RA, DEC另一個「表」。 ID1中的大多數元素可以在ID2中找到,但不是全部,否則我可以使用numpy.in1d(ID1,ID2)來完成它。任何人都可以快速完成這項任務?

例如:

ID1, z, e, PA, n 
101, 1.0, 1.2, 1.5, 1.8 
104, 1.5, 1.8, 2.2, 3.1 
105, 1.4, 2.0, 3.3, 2.8 

ID2, RA, DEC 
101, 4.5, 10.5 
107, 90.1, 55.5 
102, 30.5, 3.3 
103, 60.1, 40.6 
104, 10.8, 5.6 

輸出應該

ID, z, e, PA, n, RA, DEC 
101, 1.0, 1.2, 1.5, 1.8, 4.5, 10.5 
104, 1.5, 1.8, 2.2, 3.1, 10.8, 5.6 
+0

添加一個可運行的樣本和預期的o/p? – Divakar

+1

熊貓是合併/加入數據集的合適位置:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.merge.html – cel

回答

1

那麼你可以使用np.in1d與兩個陣列/表的第一列交換了位置,這樣我們將有兩個掩碼索引到數組中進行選擇。然後,只需疊加的結果 -

mask1 = np.in1d(a[:,0], b[:,0]) 
mask2 = np.in1d(b[:,0], a[:,0]) 
out = np.column_stack((a[mask1], b[mask2,1:])) 

採樣運行 -

In [44]: a 
Out[44]: 
array([[ 101. , 1. , 1.2, 1.5, 1.8], 
     [ 104. , 1.5, 1.8, 2.2, 3.1], 
     [ 105. , 1.4, 2. , 3.3, 2.8]]) 

In [45]: b 
Out[45]: 
array([[ 101. , 4.5, 10.5], 
     [ 102. , 30.5, 3.3], 
     [ 103. , 60.1, 40.6], 
     [ 104. , 10.8, 5.6], 
     [ 107. , 90.1, 55.5]]) 

In [46]: mask1 = np.in1d(a[:,0], b[:,0]) 

In [47]: mask2 = np.in1d(b[:,0], a[:,0]) 

In [48]: np.column_stack((a[mask1], b[mask2,1:])) 
Out[48]: 
array([[ 101. , 1. , 1.2, 1.5, 1.8, 4.5, 10.5], 
     [ 104. , 1.5, 1.8, 2.2, 3.1, 10.8, 5.6]]) 
+0

非常感謝。其實我想匹配的是'ID'。我嘗試了'mask1 = np.in1d(ID1,ID2)'和'mask2 = np.in1d(ID2,ID1)',但是'ID1 [mask1]'與ID2 [mask2]'大小不同。你知道爲什麼會發生這種情況嗎? –

+0

@HuanianZhang如果ID1和ID2是ID陣列,那不應該發生。你確定他們是一維數組嗎? – Divakar

+0

謝謝。我假設'ID1'和'ID2'不是唯一的。有一些重複的元素,這應該解釋爲什麼'ID1 [mask1]'與'ID2 [mask2]'有不同的大小,它們是1D數組,但是元素是18位長整數。 –

1

假設你的第二個表,表B,進行排序,你可以做一個排序查找,然後檢查索引的元素其實是發現:

idx = np.searchsorted(B[:-1, 0], A[:, 0]) 
found = A[:, 0] == B[idx, 0] 
np.hstack((A[found, :], B[idx[found], 1:])) 

結果:

array([[ 101. , 1. , 1.2, 1.5, 1.8, 4.5, 10.5], 
     [ 104. , 1.5, 1.8, 2.2, 3.1, 10.8, 5.6]]) 

排除了B索引的最後一個元素,以簡化A中的項超出B中的最終元素的情況。如果沒有它,返回的索引可能會大於B的長度並導致索引錯誤。

+0

非常感謝。其實'ID'沒有排序。他們是18位數字的整數。 –

+0

18位長整數適合64位,但不適用於53位,所以鍵列需要是整數,而不是浮點雙。熊貓數據結構使得使用混合類型數組變得更加容易,或者您可以將您的關鍵列與其他數據分開。 – Neapolitan

+0

爲了簡化代碼,請事先對ID2表進行排序。 searchsorted和in1d都需要排序表,儘管in1d會在內部進行排序。如果您要多次執行連接操作,將節省維護排序表的時間。 – Neapolitan

1

使用熊貓:

import pandas as pd 

id1 = pd.read_csv('id1.txt') 
id2 = pd.read_csv('id2.txt') 
df = id1.merge(id2.sort_values(by='ID2').drop_duplicates('ID2').rename(columns={'ID2':'ID1'})) 
print(df) 

產地:

ID1 z e PA n RA DEC 
0 101 1.0 1.2 1.5 1.8 4.5 10.5 
1 104 1.5 1.8 2.2 3.1 10.8 5.6 

對於大型數據集,你可能需要做東西的地方:

# [Optional] sort locations and drop duplicates 
id2.sort_values(by='ID2', inplace=True) 
id2.drop_duplicates('ID2', inplace=True) 

# columns that you are merging must have the same name 
id2.rename(columns={'ID2':'ID1'}, inplace=True) 

# perform the merge 
df = id1.merge(id2) 

沒有drop_duplicates你得到一個每個項目排:

df = id1.merge(id2.rename(columns={'ID2':'ID1'})) 
print(id2) 
print(df) 

,並提供:

ID2 RA DEC 
0 101 4.5 10.5 
1 107 90.1 55.5 
2 102 30.5 3.3 
3 103 60.1 40.6 
4 104 10.8 5.6 
5 103 60.1 40.6 
6 104 10.9 5.6 
    ID1 z e PA n RA DEC 
0 101 1.0 1.2 1.5 1.8 4.5 10.5 
1 104 1.5 1.8 2.2 3.1 10.8 5.6 
2 104 1.5 1.8 2.2 3.1 10.9 5.6 

請注意,此解決方案保留了列的不同的類型:

>>> id1.ID1.dtype 
dtype('int64') 
>>> id1[' z'].dtype 
dtype('float64') 

既然你的標題行那些在逗號後有空格空格成爲列名的一部分,因此需要使用id1 ['z']來引用第二列。通過修改讀取語句,這不再是必要的:

>>> id1 = pd.read_csv('id1.txt', skipinitialspace=True) 
>>> id1.z.dtype 
dtype('float64') 
+0

我使用'np.unique'去除重複的元素。 –

+0

如果你把它放在一個數組中(你需要爲'np.unique'做),那麼所有的列必須具有相同的格式,它只給你16位數的id,而不是你使用64位數的20位數。位整數。你表示ID可能是18位數,所以雙精度是不夠的。 – Neapolitan

相關問題