【问题标题】:Python: Select subset from list based on index setPython:根据索引集从列表中选择子集
【发布时间】:2011-03-11 21:10:48
【问题描述】:

我有几个列表具有相同数量的条目(每个都指定一个对象属性):

property_a = [545., 656., 5.4, 33.]
property_b = [ 1.2,  1.3, 2.3, 0.3]
...

并列出具有相同长度的标志

good_objects = [True, False, False, True]

(可以很容易地用等效的索引列表代替:

good_indices = [0, 3]

生成新列表property_aselproperty_bsel……的最简单方法是什么?这些列表仅包含True 条目或索引指示的值?

property_asel = [545., 33.]
property_bsel = [ 1.2, 0.3]

【问题讨论】:

    标签: python list


    【解决方案1】:

    你可以使用list comprehension:

    property_asel = [val for is_good, val in zip(good_objects, property_a) if is_good]
    

    property_asel = [property_a[i] for i in good_indices]
    

    后者更快,因为good_indices 的长度少于property_a 的长度,假设good_indices 是预先计算的而不是动态生成的。


    编辑:第一个选项等效于itertools.compress,自 Python 2.7/3.1 起可用。请参阅@Gary Kerr 的回答。

    property_asel = list(itertools.compress(property_a, good_objects))
    

    【讨论】:

    • @fuen:是的。在 Python 2 上导致很多(使用 itertools.izip 代替),而不是在 Python 3 上。这是因为 Python 2 中的 zip 将创建一个新列表,但在 Python 3 上它只会返回一个(惰性)生成器.
    • 好的,那么我应该坚持你的第二个建议,因为这是我代码的核心部分。
    • @85:你为什么担心性能?写下你要做什么,如果慢,那就测试一下,找出瓶颈。
    • @PreludeAndFugue:如果有两个等效选项,最好知道哪个更快,然后立即使用那个。
    • 您可以只使用from itertools import izip 并在第一个示例中使用它而不是zip。这将创建一个迭代器,与 Python 3 相同。
    【解决方案2】:

    Matlab 和 Scilab 语言为您提出的问题提供了比 Python 更简单、更优雅的语法,因此我认为您能做的最好的事情就是使用 Python 中的 Numpy 包来模仿 Matlab/Scilab。通过这样做,您的问题的解决方案非常简洁和优雅:

    from numpy import *
    property_a = array([545., 656., 5.4, 33.])
    property_b = array([ 1.2,  1.3, 2.3, 0.3])
    good_objects = [True, False, False, True]
    good_indices = [0, 3]
    property_asel = property_a[good_objects]
    property_bsel = property_b[good_indices]
    

    Numpy 试图模仿 Matlab/Scilab,但这是有代价的:您需要使用关键字“array”声明每个列表,这会使您的脚本超载(Matlab/Scilab 不存在此问题)。请注意,此解决方案仅限于数字数组,您的示例就是这种情况。

    【讨论】:

    • 他在问题中没有提到 NumPy——没有必要就 NumPy 与 Matlab 表达你的意见。 Python 列表与 NumPy 数组相同,即使它们都大致对应于向量。 (Python 列表就像 Matlab 元胞数组——每个元素可以有不同的数据类型。NumPy 数组受到更多限制,以实现某些优化)。您可以通过 Python 的内置 filter 或外部库 pandas 获得与您的示例类似的语法。如果你要交换语言,你也可以试试 R,但 这不是问题要问的
    【解决方案3】:

    假设您只有项目列表和真实/必需索引列表,这应该是最快的:

    property_asel = [ property_a[index] for index in good_indices ]
    

    这意味着属性选择只会执行与真实/必需索引一样多的轮次。如果您有许多遵循单个标签(真/假)列表规则的属性列表,您可以使用相同的列表理解原则创建索引列表:

    good_indices = [ index for index, item in enumerate(good_objects) if item ]
    

    这会遍历 good_objects 中的每个项目(同时通过 enumerate 记住其索引)并仅返回该项目为 true 的索引。


    对于没有理解列表的人,这里是英文散文版本,代码以粗体突出显示:

    列出索引每组索引,项目存在一个枚举 good objectsif(其中)item 为 True

    【讨论】:

      【解决方案4】:

      使用内置函数zip

      property_asel = [a for (a, truth) in zip(property_a, good_objects) if truth]
      

      编辑

      只看 2.7 的新功能。 itertools 模块中现在有一个函数,类似于上面的代码。

      http://docs.python.org/library/itertools.html#itertools.compress

      itertools.compress('ABCDEF', [1,0,1,0,1,1]) =>
        A, C, E, F
      

      【讨论】:

      • 在这里使用itertools.compress 让我不知所措。列表理解更具可读性,无需深入了解压缩在做什么。
      • 嗯,我发现使用 compress 的代码更具可读性:) 也许我有偏见,因为它正是我想要的。
      • 为什么不提供itertools.compress 的示例而不是复制粘贴文档示例?
      【解决方案5】:

      我看到了 2 个选项。

      1. 使用 numpy:

        property_a = numpy.array([545., 656., 5.4, 33.])
        property_b = numpy.array([ 1.2,  1.3, 2.3, 0.3])
        good_objects = [True, False, False, True]
        good_indices = [0, 3]
        property_asel = property_a[good_objects]
        property_bsel = property_b[good_indices]
        
      2. 使用列表推导并压缩它:

        property_a = [545., 656., 5.4, 33.]
        property_b = [ 1.2,  1.3, 2.3, 0.3]
        good_objects = [True, False, False, True]
        good_indices = [0, 3]
        property_asel = [x for x, y in zip(property_a, good_objects) if y]
        property_bsel = [property_b[i] for i in good_indices]
        

      【讨论】:

      • 使用 Numpy 是一个很好的建议,因为 OP 似乎想要将数字存储在列表中。二维数组会更好。
      • 这也是一个很好的建议,因为这对于 R 的用户来说是非常熟悉的语法,这种选择非常强大,尤其是在嵌套和/或多维时。
      • [property_b[i] for i in good_indices] 在没有numpy 的情况下使用是一个不错的选择
      猜你喜欢
      • 2020-01-12
      • 1970-01-01
      • 2020-09-05
      • 1970-01-01
      • 2016-01-14
      • 1970-01-01
      • 2014-02-03
      • 2018-06-04
      • 1970-01-01
      相关资源
      最近更新 更多