使用NumPy按元素长度排序字符串数组

4
我想使用numpy按元素长度对字符串数组进行排序。
>>> arr = ["year","month","eye","i","stream","key","house"]
>>> x = np.sort(arr, axis=-1, kind='mergesort')
>>> print(x)
['eye' 'house' 'i' 'key' 'month' 'stream' 'year']

但是它按字母数字顺序进行排序。我应该如何使用numpy按长度对它们进行排序?

1
如果你这样做是因为你认为它可能会更快,那么你并没有理解numpy的工作方式。它是为占用相同字节数的元素设计的。不等长字符串不满足这一点,因此在numpy中它们只会被包装成对象,这可能会更加低效。 - Oliver W.
1
虽然使用numpy有很多好处,但我必须同意Oliver的评论。这个代码示例自然地调用了Python内置的排序方法,它允许更美观/紧凑的语法。(但也许你有其他使用numpy的理由,而这只是一个例子)。 - sascha
谢谢。目前我对numpy还很陌生,正在尝试理解。@sascha 当我有许多字符串元素要按长度排序时,我应该使用哪种方法?只用Python自带的sort方法吗? - GGG
谢谢 @OliverW。 - GGG
根据你的使用情况选择适合的工具。我认为性能上不会有太大差异。如果代码的其他部分使用了numpy,请继续使用它。如果没有,那么仅仅为了排序而使用numpy是很奇怪的,因为内置的排序函数也可以做到。不知道你在做什么情况下很难给出建议(上面的用例实际上并不需要numpy)。 - sascha
我理解了,谢谢 @sascha - GGG
2个回答

3

添加一个辅助数组,包含字符串的长度,然后使用numpy的argsort函数,该函数会根据这些长度给出排序后的索引。使用这些索引来索引原始数据:

import numpy as np
arr = np.array(["year","month","eye","i","stream","key","house"])  # np-array needed for later indexing
arr_ = map(lambda x: len(x), arr)  # remark: py3 would work different here
x = arr[np.argsort(arr_)]
print(x)

2
还有numpy.char.str_len(但它只是稍微快一点)。 - user2379410
因为您正在使用Python3并忽略了我的评论,请使用arr_ = list(map...)而不是仅仅使用map(...)。Py3的map返回一个迭代器,而不是一个列表/数组,所以我们需要这个额外的步骤。 - sascha

1
如果我将您的列表扩展到arr1=arr*1000,则使用len作为key函数的Python列表排序最快。
In [77]: len(arr1)
Out[77]: 7000

In [78]: timeit sarr=sorted(arr1,key=len)
100 loops, best of 3: 3.03 ms per loop

In [79]: %%timeit
arrA=np.array(arr1)
larr=[len(i) for i in arrA]  # list comprehension works same as map
sarr=arrA[np.argsort(larr)]
   ....: 
100 loops, best of 3: 7.77 ms per loop

将列表转换为数组大约需要1毫秒(这种转换会增加显著的开销,特别是对于小型列表而言)。使用已创建的数组和np.char.str_len,时间仍然比Python的sort慢。
In [83]: timeit sarr=arrA[np.argsort(np.char.str_len(arrA))]
100 loops, best of 3: 6.51 ms per loop
< p > 尽管 np.char 函数很方便,但它们仍然基本上迭代列表,应用相应的 str 方法。

通常情况下,argsort 给您提供了与 key 函数相同的大部分功能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接