【问题标题】:How to sort a NumPy array by frequency?如何按频率对 NumPy 数组进行排序?
【发布时间】:2023-07-17 14:02:02
【问题描述】:

我正在尝试按元素的频率对 NumPy 数组进行排序。例如,如果有一个数组 [3,4,5,1,2,4,1,1,2,4],输出将是另一个 NumPy,从最常见到最不常见的元素(无重复)排序。所以解决方案是[4,1,2,3,5]。如果两个元素的出现次数相同,则最先出现的元素在输出中最先出现。我试过这样做,但我似乎无法得到一个实用的答案。到目前为止,这是我的代码:

temp1 = problems[j]
indexes = np.unique(temp1, return_index = True)[1]
temp2 = temp1[np.sort(indexes)]
temp3 = np.unique(temp1, return_counts = True)[1]
temp4 = np.argsort(temp3)[::-1] + 1

其中问题[j] 是一个 NumPy 数组,如 [3,4,5,1,2,4,1,1,2,4]。 temp4 到目前为止返回 [4,1,2,5,3] 但它不正确,因为当两个元素具有相同的出现次数时它无法处理。

【问题讨论】:

  • Python argsort 不稳定,除非您选择其他排序方法。

标签: python arrays sorting numpy


【解决方案1】:

您可以对每个元素的频率使用 argsort 来查找排序位置并将索引应用于唯一元素数组

unique_elements, frequency = np.unique(array, return_counts=True)
sorted_indexes = np.argsort(frequency)[::-1]
sorted_by_freq = unique_elements[sorted_indexes]

【讨论】:

    【解决方案2】:

    如果值是整数且很小,或者您只关心大小为 1 的 bin:

    def sort_by_frequency(arr):
        return np.flip(np.argsort(np.bincount(arr))[-(np.unique(arr).size):])
    
    v = [1,1,1,1,1,2,2,9,3,3,3,3,7,8,8]
    sort_by_frequency(v)
    

    这应该会产生

    array([1, 3, 8, 2, 9, 7]
    

    【讨论】:

      【解决方案3】:

      你可以把数组中每个元素的个数统计一下,然后把它作为内置sorted函数的key

      def sortbyfreq(arr):
          s = set(arr)
          keys = {n: (-arr.count(n), arr.index(n)) for n in s}
          return sorted(list(s), key=lambda n: keys[n])
      

      【讨论】:

      • 一旦您执行set(arr),订购就会丢失。您如何确保输入数组的顺序保持为具有相同计数的 2 个值?
      【解决方案4】:

      使用 zip 和 itemgetter 应该会有所帮助

      from operator import itemgetter
      import numpy as np
      temp1 = problems[j]
      temp, idx, cnt = np.unique(temp1, return_index = True, return_counts=True)
      cnt = 1 / cnt
      k = sorted(zip(temp, cnt, idx), key=itemgetter(1, 2))
      print(next(zip(*k)))
      

      【讨论】:

        【解决方案5】:

        仍然适用于 NumPy 数组的非 NumPy 解决方案是使用 OrderedCounter 后跟 sorted 和自定义函数:

        from collections import OrderedDict, Counter
        
        class OrderedCounter(Counter, OrderedDict):
            pass
        
        L = [3,4,5,1,2,4,1,1,2,4]
        
        c = OrderedCounter(L)
        keys = list(c)
        
        res = sorted(c, key=lambda x: (-c[x], keys.index(x)))
        
        print(res)
        
        [4, 1, 2, 3, 5]
        

        【讨论】: