【问题标题】:More Elegant way to number a list according to values根据值对列表进行编号的更优雅的方式
【发布时间】:2017-09-10 13:48:17
【问题描述】:

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

例如:

['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)

有没有更优雅/更快的方法来做到这一点?

更新:奖励问题 - 按照维护的顺序进行。

【问题讨论】:

  • 它们不一定是字母...我是说一般情况
  • 但您似乎也希望继续查看预期的样本输出,而 func number 无法实现,对吧?
  • @Divakar 好吧,起初我并没有太担心。现在我觉得值得考虑

标签: python performance numpy


【解决方案1】:

使用集合删除重复项:

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

然后使用理解构建你的字典:

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

【讨论】:

  • 请注意,集合没有保证顺序,因此这不一定映射 a -> 0、b -> 1 等。
  • 谢谢。我认为 np.unique 可能更快,但实际上并非如此。
  • 安装python包pypi.python.org/pypi/orderedset你仍然可以有一个有序集
【解决方案2】:

您可以使用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])

【讨论】:

  • 我做同样的事情,map_ 打印为array([1, 2, 2, 3, 1, 2, 0])
  • 知道如何将这种逐行应用于二维矩阵吗?
  • @Josh.F 你的意思是寻找唯一的行吗?然后可以使用np.uniqueaxis 关键字。还是您的意思是分别处理每一行?在那种情况下——如果你想使用这个解决方案——你必须遍历行。或者您可以查看其他答案之一。在这种情况下,也许@Divakar 可以完全矢量化?
  • 第二个,每行都应用了np.unique(..., return_inverse=True)(或相同效果的东西),我会看看他的解决方案,谢谢:)
【解决方案3】:

我是使用 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】:

如果订单不是问题:

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

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

【讨论】:

  • 不是最好的解决方案,但我认为它不值得投反对票。
【解决方案5】:

这是一个基于矢量化 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])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-11
    相关资源
    最近更新 更多