【问题标题】:Sorting a scipy.stats.itemfreq result containing strings对包含字符串的 scipy.stats.itemfreq 结果进行排序
【发布时间】:2015-07-06 19:47:59
【问题描述】:

问题

我正在尝试计算字符串列表的频率并按降序对其进行排序。 scipy.stats.itemfreq 生成频率结果,这些结果作为字符串元素的 numpy 数组输出。这就是我难过的地方。如何排序?

到目前为止,我已经尝试过operator.itemgetter,它似乎适用于一个小列表,直到我意识到它是按第一个字符串字符排序而不是将字符串转换为整数,所以'5' > '11' 因为它正在比较51 不是511

我正在使用 python 2.7、numpy 1.8.1、scipy 0.14.0。

示例代码:

from scipy.stats import itemfreq
import operator as op

items = ['platypus duck','platypus duck','platypus duck','platypus duck','cat','dog','platypus duck','elephant','cat','cat','dog','bird','','','cat','dog','bird','cat','cat','cat','cat','cat','cat','cat']
items = itemfreq(items)
items = sorted(items, key=op.itemgetter(1), reverse=True)
print items
print items[0]

输出:

[array(['platypus duck', '5'], 
      dtype='|S13'), array(['dog', '3'], 
      dtype='|S13'), array(['', '2'], 
      dtype='|S13'), array(['bird', '2'], 
      dtype='|S13'), array(['cat', '11'], 
      dtype='|S13'), array(['elephant', '1'], 
      dtype='|S13')]
['platypus duck' '5']

预期输出:

我正在订购这样的东西:

[array(['cat', '11'], 
      dtype='|S13'), array(['platypus duck', '5'], 
      dtype='|S13'), array(['dog', '3'], 
      dtype='|S13'), array(['', '2'], 
      dtype='|S13'), array(['bird', '2'], 
      dtype='|S13'), array(['elephant', '1'], 
      dtype='|S13')]
['cat', '11']

总结

我的问题是:如何按计数的降序对数组(在本例中为字符串数组)进行排序?请随时为我上面的代码示例建议替代和更快/改进的方法。

【问题讨论】:

    标签: python arrays sorting numpy scipy


    【解决方案1】:

    不幸的是,itemfreq 在同一数组中返回唯一项它们的计数。对于您的情况,这意味着将计数转换为字符串,这很愚蠢。

    如果您可以将 numpy 升级到 1.9 版,那么您可以使用 numpy.uniquereturn_counts=True 参数来代替使用 itemfreq(有关如何在旧版 numpy 中完成此操作,请参见下文):

    In [29]: items = ['platypus duck','platypus duck','platypus duck','platypus duck','cat','dog','platypus duck','elephant','cat','cat','dog','bird','','','cat','dog','bird','cat','cat','cat','cat','cat','cat','cat']
    
    In [30]: values, counts = np.unique(items, return_counts=True)
    
    In [31]: values
    Out[31]: 
    array(['', 'bird', 'cat', 'dog', 'elephant', 'platypus duck'], 
          dtype='|S13')
    
    In [32]: counts
    Out[32]: array([ 2,  2, 11,  3,  1,  5])
    

    获取将counts 降序排列的索引:

    In [38]: idx = np.argsort(counts)[::-1]
    
    In [39]: values[idx]
    Out[39]: 
    array(['cat', 'platypus duck', 'dog', 'bird', '', 'elephant'], 
          dtype='|S13')
    
    In [40]: counts[idx]
    Out[40]: array([11,  5,  3,  2,  2,  1])
    

    对于旧版本的numpy,可以结合np.uniquenp.bincount,如下:

    In [46]: values, inv = np.unique(items, return_inverse=True)
    
    In [47]: counts = np.bincount(inv)
    
    In [48]: values
    Out[48]: 
    array(['', 'bird', 'cat', 'dog', 'elephant', 'platypus duck'], 
          dtype='|S13')
    
    In [49]: counts
    Out[49]: array([ 2,  2, 11,  3,  1,  5])
    
    In [50]: idx = np.argsort(counts)[::-1]
    
    In [51]: values[idx]
    Out[51]: 
    array(['cat', 'platypus duck', 'dog', 'bird', '', 'elephant'], 
          dtype='|S13')
    
    In [52]: counts[idx]
    Out[52]: array([11,  5,  3,  2,  2,  1])
    

    事实上,上面的内容正是itemfreq 所做的。这是 scipy 源代码中itemfreq 的定义(没有文档字符串):

    def itemfreq(a):
        items, inv = np.unique(a, return_inverse=True)
        freq = np.bincount(inv)
        return np.array([items, freq]).T
    

    【讨论】:

    • @HappyLeapSecond 这是一个很好的观点——感谢关于版本的提醒。
    【解决方案2】:

    实现任务的更简单的方法 - 获取项目的频率并按频率对项目进行排序 - 是使用 pandas 函数value_counts(有关原始帖子和更多建议,请参阅here):

    import pandas as pd
    import numpy as np
    x = np.array(["bird","cat","dog","dog","cat","cat"])
    pd.value_counts(x)
    
    cat     3
    dog     2
    bird    1
    dtype: int64
    

    只获取出现次数,排序:

    y = pd.value_counts(x).values
    
    array([3, 2, 1])
    

    仅获取要计数的项目的唯一名称,排序:

    z = pd.value_counts(x).index
    
    Index(['cat', 'dog', 'bird'], dtype='object')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-09
      • 2016-11-10
      • 1970-01-01
      • 2020-02-18
      • 1970-01-01
      • 2021-08-12
      • 2016-10-28
      相关资源
      最近更新 更多