2016-12-01 731 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

相关问题