更优雅的方式根据值编号列表

时间:2017-04-14 09:51:45

标签: python performance numpy

我想根据值将列表映射到数字。

例如:

['aa', 'b', 'b', 'c', 'aa', 'b', 'a'] -> [0, 1, 1, 2, 0, 1, 3]

我试图通过使用numpy和映射字典来实现这一点。

def number(lst):
    x = np.array(lst)
    unique_names = list(np.unique(x))
    mapping = dict(zip(unique_names, range(len(unique_names)))) # Translating dict
    map_func = np.vectorize(lambda name: d[name])
    return map_func(x)

有更优雅/更快的方法吗?

更新:奖金问题 - 按照维护的顺序执行此操作。

5 个答案:

答案 0 :(得分:3)

您可以使用return_inverse关键字:

x = np.array(['aa', 'b', 'b', 'c', 'aa', 'b', 'a'])
uniq, map_ = np.unique(x, return_inverse=True)
map_
# array([1, 2, 2, 3, 1, 2, 0])

编辑:订单保留版本:

x = np.array(['aa', 'b', 'b', 'c', 'aa', 'b', 'a'])
uniq, idx, map_ = np.unique(x, return_index=True, return_inverse=True)
mxi = idx.max()+1
mask = np.zeros((mxi,), bool)
mask[idx] = True
oidx = np.where(mask)[0]
iidx = np.empty_like(oidx)
iidx[map_[oidx]] = np.arange(oidx.size)
iidx[map_]
# array([0, 1, 1, 2, 0, 1, 3])

答案 1 :(得分:2)

这是一个基于矢量化NumPy的解决方案 -

def argsort_unique(idx):
    # Original idea : http://stackoverflow.com/a/41242285/3293881 by @Andras
    n = idx.size
    sidx = np.empty(n,dtype=int)
    sidx[idx] = np.arange(n)
    return sidx

def map_uniquetags_keep_order(a):
    arr = np.asarray(a)

    sidx = np.argsort(arr)
    s_arr = arr[sidx]

    m = np.concatenate(( [True], s_arr[1:] != s_arr[:-1] ))
    unq = s_arr[m]
    tags = np.searchsorted(unq, arr)
    rev_idx = argsort_unique(sidx[np.searchsorted(s_arr, unq)].argsort())
    return rev_idx[tags]

示例运行 -

In [169]: a = ['aa', 'b', 'b', 'c', 'aa', 'b', 'a'] # String input

In [170]: map_uniquetags_keep_order(a)
Out[170]: array([0, 1, 1, 2, 0, 1, 3])

In [175]: a = [4, 7, 7, 5, 4, 7, 2]                 # Numeric input

In [176]: map_uniquetags_keep_order(a)
Out[176]: array([0, 1, 1, 2, 0, 1, 3])

答案 2 :(得分:1)

使用集删除重复项:

myList = ['a', 'b', 'b', 'c', 'a', 'b']
mySet = set(myList)

然后使用理解构建词典:

mappingDict = {letter:number for number,letter in enumerate(mySet)}

答案 3 :(得分:0)

我使用ASCII值来完成它,因为它很简单。

def number(list):   
    return map(lambda x: ord(x)-97,list)  
l=['a', 'b', 'b', 'c', 'a', 'b']  
print number(l)

输出:

  

[0,1,1,2,0,1]

答案 4 :(得分:0)

如果订单不是问题:

[sorted(set(x)).index(item) for item in x]

# returns:
[1, 2, 2, 3, 1, 2, 0]