比numpy的in1d掩码函数更好:有序数组?

时间:2013-03-07 19:18:15

标签: python performance sorting numpy mask

此操作需要尽可能快地应用为包含数百万个元素的实际数组。这是问题的简单版本。

所以,我有一个随机的唯一整数数组(通常是数百万个元素)。

  

totalIDs = [5,4,3,1,2,9,7,6,8 ...]

我有另一个数组(通常是成千上万)独特的整数,我可以创建一个掩码。

subsampleIDs1 = [5,1,9]
subsampleIDs2 = [3,7,8]
subsampleIDs3 = [2,6,9]
...

我可以使用numpy来做

  

mask = np.in1d(totalIDs,subsampleIDs,assume_unique = True)

然后我可以使用掩码提取我想要的另一个数组的信息(比如第0列包含我想要的那个)。

  

variable = allvariables [mask] [:,0]

现在假设两个数组中的ID都是唯一的,有没有办法显着提高速度。构建与数百万个ID(totalIDs)匹配的几千个点(subsampleIDs)的掩码需要很长时间。

我想过要经历一次并写出一个索引的二进制文件(以加快未来的搜索)。

for i in range(0,3):
    mask = np.in1d(totalIDs,subsampleIDs,assume_unique=True)
    index[mask] = i

其中X在subsampleIDsX中。然后我可以这样做:

for i in range(0,3):
    if index[i] == i:
        rowmatch = i
        break

variable = allvariables[rowmatch:len(subsampleIDs),0]

正确?但这也很慢,因为循环中有一个条件可以找到它第一次匹配的时间。有没有更快的方法来查找数字首次出现在有序数组中,因此条件不会减慢循环?

2 个答案:

答案 0 :(得分:3)

我建议你在Pandas中使用DataFrame。 DataFrame的索引是totalID,您可以通过以下方式选择subsampleID:df.ix[subsampleIDs]

首先创建一些测试数据:

import numpy as np
N = 2000000
M = 5000
totalIDs = np.random.randint(0, 10000000, N)
totalIDs = np.unique(totalIDs)
np.random.shuffle(totalIDs)
v1 = np.random.rand(len(totalIDs))
v2 = np.random.rand(len(totalIDs))

subsampleIDs = np.random.choice(totalIDs, M)
subsampleIDs = np.unique(subsampleIDs)
np.random.shuffle(subsampleIDs)

然后将数据转换为DataFrame:

import pandas as pd
df = pd.DataFrame(data = {"v1":v1, "v2":v2}, index=totalIDs) 
df.ix[subsampleIDs]

DataFrame使用哈希表将索引映射到它的位置,速度非常快。

答案 1 :(得分:1)

这种索引通常最好使用DB(具有适当的列索引)来执行。

另一个想法是将totalIDs排序一次,作为预处理阶段,并实现您自己的in1d版本,这样可以避免对所有内容进行排序。 in1d的numpy实现(至少在我安装的版本中)非常简单,并且应该易于复制和修改。

编辑:

或者,更好的是,使用桶排序(或基数排序)。这应该给你O(N + M),N是totalIDs的大小,M是sampleIDs的大小(通过改变桶的数量你可以玩的常数的倍数)。在这里,你可以只将totalIDs拆分为一个桶,这样就可以得到一个漂亮的O(N + M1 + M2 + ...)。

不幸的是,我不知道一个笨拙的实现,但我确实找到了这个:http://en.wikipedia.org/wiki/Radix_sort#Example_in_Python