如何有效地获取唯一值的索引列表?
问题描述:
是否有一个内置的方法可以帮助我有效地实现以下内容:给定一个数组,我需要一个数组列表,每个列表的索引都指向数组的不同唯一值?如何有效地获取唯一值的索引列表?
如果f
是所需要的功能,
b = f(a)
和
u, idxs = unique(a)
然后
b[i] == where(idxs==i)[0]
我知道pandas.Series.groupby()
可以做到这一点,但它可能不会是有效的当有超过10^5个独特整数时创建一个字典。
答
如果你有numpy的> = 1.9,你可以这样做:
>>> a = np.random.randint(5, size=10)
>>> a
array([0, 2, 4, 4, 2, 4, 4, 3, 2, 1])
>>> unq, unq_inv, unq_cnt = np.unique(a, return_inverse=True, return_counts=True)
>>> np.split(np.argsort(unq_inv), np.cumsum(unq_cnt[:-1]))
[array([0]), array([9]), array([1, 4, 8]), array([7]), array([2, 3, 5, 6])]
>>> unq
array([0, 1, 2, 3, 4])
在早期版本中,你可以得到做一个额外的计数:
>>> unq_cnt = np.bincount(unq_inv)
此外,如果您想确保每个值的索引都已排序,我认为您需要使用稳定的排序,例如np.argsort(unq_inv, kind='mergesort')
你似乎什么是后的思考,我认为这是减少呼叫昂贵的功能,我不认为你需要做你的要求。说你的函数平方,你可以简单地做:
>>> unq, unq_inv = np.unique(a, return_inverse=True)
>>> f_unq = unq**2
>>> f_a = f_unq[unq_inv]
>>> a
array([0, 2, 4, 4, 2, 4, 4, 3, 2, 1])
>>> f_a
array([ 0, 4, 16, 16, 4, 16, 16, 9, 4, 1])
答
也许这样做:
s = argsort(a)
d = diff(a[s])
starts = where(d)[0]
f = [s[starts[i:i+1]] for i in xrange(len(a))]
(代码未被选中)
答
def foo(a):
I=np.arange(a.shape[0])
d={}
while a.shape[0]:
x = a[0]
ii = a==x
d[x] = I[ii]
a = a[~ii]
I = I[~ii]
return d
In [767]: a
Out[767]: array([4, 4, 3, 0, 0, 2, 1, 1, 0, 3])
In [768]: foo(a)
Out[768]:
{0: array([3, 4, 8]),
1: array([6, 7]),
2: array([5]),
3: array([2, 9]),
4: array([0, 1])}
这是不是你想要的那种字典?
对于小型a
这工作正常。
等效字典建筑功能为:
def foo1(a):
unq = np.unique(a)
return {i:np.where(a==i)[0] for i in unq}
副手我看不出unq_inv
有助于构建字典。
foo
比foo1
慢大约30%。我希望通过减少被搜索的数组,每次计算一个值,我可能会获得一些速度。但它看起来像额外的簿记咀嚼时间。并且where
时间可能不会对a
的长度敏感。
对于a2=np.random.randint(5000,size=100000)
运行时间约为2-3秒。
但np.random.randint(50000,size=1000000)
花费时间太长(对于任一版本)。
在进一步的实验,使用collections.defaultdict
一个 '哑' 的方法要快得多(20X):
def food(a):
d = defaultdict(list)
for i,j in enumerate(a):
d[j].append(i)
return d
的 '过大'(1000000)阵列只需要1.1秒;
fyi,pandas.Series对象也有一个“独特”的方法。 – 2014-12-11 00:22:53