【问题标题】:List elements’ counter列表元素的计数器
【发布时间】:2019-07-11 23:07:35
【问题描述】:

这里是 Python 新手。

我正在寻找一种创建列表(输出)的简单方法,它返回另一个目标列表(MyList)的元素计数,同时保留索引(?)。

这是我想要的:

MyList = ["a", "b", "c", "c", "a", "c"]
Output = [ 2 ,  1 ,  3 ,  3 ,  2 ,  3 ]

我找到了类似问题的解决方案。计算列表中每个元素的出现次数。

In  : Counter(MyList)
Out : Counter({'a': 2, 'b': 1, 'c': 3})

然而,这会返回一个不保留索引的 Counter 对象。

我假设给定 Counter 中的键,我可以构建我想要的输出,但是我不确定如何继续。

额外信息,我在脚本中导入了熊猫,而 MyList 实际上是熊猫数据框中的一列。

【问题讨论】:

    标签: python python-3.x pandas list counter


    【解决方案1】:

    您可以使用函数itemgetter,而不是其他解决方案中的listcomp:

    from collections import Counter
    from operator import itemgetter
    
    lst = ["a", "b", "c", "c", "a", "c"]
    
    c = Counter(lst)
    itemgetter(*lst)(c)
    # (2, 1, 3, 3, 2, 3)
    

    更新:正如@ALollz 在 cmets 中提到的,这个解决方案似乎是最快的解决方案。如果 OP 需要列表而不是元组,则必须使用 list 转换结果。

    【讨论】:

    • 也许list(itemgetter(*MyList)(c)) 来匹配输出,但我很惊讶这没有更多的选票。似乎是最快的解决方案
    • @ALollz 不错!你说得对。我认为这很容易,OP 可能知道该怎么做。也许他只需要一个数组。
    • 绝对是最快的,我有一个后续问题。导入额外的模块是否会对代码性能产生负面影响?我之前实现过 @ALollz 的解决方案,因为它看起来最快并且不需要任何模块,而且(很可能)我会为此操作导入 itemgetter 和 Counter
    • 我认为不是删除答案,而是为我服务;)
    【解决方案2】:

    您可以使用list.count 方法,该方法将计算每个字符串在MyList 中出现的次数。您可以使用list comprehension 生成包含计数的新列表:

    MyList = ["a", "b", "c", "c", "a", "c"]
    
    [MyList.count(i) for i in MyList]
    # [2, 1, 3, 3, 2, 3]
    

    【讨论】:

    • 适用于该示例,但不在我的列表中。它返回以下内容:KeyError: 'Level 1111111111ABC11111 not found'。 (这是我计算的第一个元素)
    • 你能分享你的实际名单吗? @Gio
    • 不,很遗憾我不能。我能做的最好的就是给你一个蒙面的例子,不确定它是否有任何帮助。我可以确认元素是字符串你:In : type(df.iloc[1]["MyList"])Out: str
    • 嗯,这应该可以正常工作,确保您是 MyList 实际上是一个列表。而且您正在使用它来迭代列表理解和计算值。
    • 嗯,熊猫系列不是@Gio 列表。这是一个列表方法。您可以使用 Series.tolist() 将您的系列转换为列表
    【解决方案3】:

    使用np.unique 创建值计数字典并映射值。这会很快,虽然不如 Counter 方法快:

    import numpy as np
    
    list(map(dict(zip(*np.unique(MyList, return_counts=True))).get, MyList))
    #[2, 1, 3, 3, 2, 3]
    

    中等规模列表的一些时间安排:

    MyList = np.random.randint(1, 2000, 5000).tolist()
    
    %timeit [MyList.count(i) for i in MyList]
    #413 ms ± 165 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    %timeit list(map(dict(zip(*np.unique(MyList, return_counts=True))).get, MyList))
    #1.89 ms ± 1.73 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    %timeit pd.DataFrame(MyList).groupby(MyList).transform(len)[0].tolist()
    #2.18 s ± 12.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    c=Counter(MyList)
    %timeit lout=[c[i] for i in MyList]
    #679 µs ± 2.33 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
    c = Counter(MyList)
    %timeit list(itemgetter(*MyList)(c))
    #503 µs ± 162 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    

    更多列表:

    MyList = np.random.randint(1, 2000, 50000).tolist()
    
    %timeit [MyList.count(i) for i in MyList]
    #41.2 s ± 5.27 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    %timeit list(map(dict(zip(*np.unique(MyList, return_counts=True))).get, MyList))
    #18 ms ± 56.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    %timeit pd.DataFrame(MyList).groupby(MyList).transform(len)[0].tolist()
    #2.44 s ± 12.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    c=Counter(MyList)
    %timeit lout=[c[i] for i in MyList]
    #6.89 ms ± 22.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    c = Counter(MyList)
    %timeit list(itemgetter(*MyList)(c))
    #5.27 ms ± 10.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    

    【讨论】:

    • 有兴趣看看 Counter 对这项任务的优化程度
    • 是的,我真的很惊讶。这几天我会安装perfplot 让它更容易看到。
    • 希望我能看到剧情。会很有趣。 :)
    【解决方案4】:

    你只需要实现下面的代码

        c=Counter(MyList)
        lout=[c[i] for i in MyList]
    

    现在列表 lout 是您想要的输出

    【讨论】:

    • 您可能希望在列表理解之外初始化 Counter,然后简单地访问其值,而不是创建 len(MyList) Counters
    • @yatu 是的,你是对的。由于它是一个小列表,我只是在一行中给出了它。我现在已经编辑了答案。 :)
    【解决方案5】:

    pandas 解决方案如下所示:

    df = pd.DataFrame(data=["a", "b", "c", "c", "a", "c"], columns=['MyList'])
    df['Count'] = df.groupby('MyList')['MyList'].transform(len)
    

    编辑:如果这是您唯一想做的事情,则不应使用 pandas。因为pandas标签,我才回答了这个问题。

    性能取决于组数:

    MyList = np.random.randint(1, 10, 10000).tolist()
    df = pd.DataFrame(MyList)
    
    %timeit [MyList.count(i) for i in MyList]
    # 1.32 s ± 15.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    %timeit df.groupby(0)[0].transform(len)
    # 3.89 ms ± 112 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    MyList = np.random.randint(1, 9000, 10000).tolist()
    df = pd.DataFrame(MyList)
    
    %timeit [MyList.count(i) for i in MyList]
    # 1.36 s ± 11.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    %timeit df.groupby(0)[0].transform(len)
    # 1.33 s ± 19.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    

    【讨论】:

    • 完美运行,但速度变慢很快(刚刚在具有 15k 观察的样本数据集上尝试过)
    【解决方案6】:

    请注意,@Gio 表明该列表是 pandas Series 对象。在这种情况下,您可以将 Series 对象转换为列表:

    import pandas as pd
    
    l = ["a", "b", "c", "c", "a", "c"]
    ds = pd.Series(l) 
    l=ds.tolist()
    [l.count(i) for i in ds] 
    # [2, 1, 3, 3, 2, 3]
    

    但是,一旦有了系列,就可以通过value_counts 计算元素。

    l = ["a", "b", "c", "c", "a", "c"]
    s = pd.Series(l) #Series object
    c=s.value_counts() #c is Series again
    [c[i] for i in s] 
    # [2, 1, 3, 3, 2, 3]
    

    【讨论】:

      【解决方案7】:

      这是 hettinger 的经典 sn-ps 中的一个 :)

      from collections import Counter, OrderedDict
      
      class OrderedCounter(Counter, OrderedDict):
           'Counter that remembers the order elements are first seen'
           def __repr__(self):
               return '%s(%r)' % (self.__class__.__name__,
                                  OrderedDict(self))
           def __reduce__(self):
               return self.__class__, (OrderedDict(self),)
      
      x = ["a", "b", "c", "c", "a", "c"]
      oc = OrderedCounter(x)
      >>> oc
      OrderedCounter(OrderedDict([('a', 2), ('b', 1), ('c', 3)]))
      >>> oc['a']
      2
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-12-18
        • 1970-01-01
        • 2021-03-09
        • 2014-04-19
        • 2010-10-10
        • 1970-01-01
        • 1970-01-01
        • 2020-06-02
        相关资源
        最近更新 更多