【问题标题】:Access 1D array with array of lists or arrays使用列表或数组的数组访问一维数组
【发布时间】:2015-02-21 14:57:47
【问题描述】:

我有标签的一维数组。索引为 i 的对象具有标签 label[i]。我还有一个数组或列表数组,其中有我想访问的标签索引。 例如:

labels = np.array([2, 0, 3, 3, 0, 0, 0, 0, 0, 0])
duplicates = np.array(np.array([0,3]), np.array([3,0]), np.array([6,7,8]))

我想访问标签的元素,所以输出看起来像这样:

labels_duplicates = np.array(np.array([2,3]), np.array([3,2]), np.array([0,0,0]))

实现这一目标的最佳方法是什么(最好不使用 for 循环)?

我想要实现的目标:我有一组中心索引(重复)。我必须检查这些中心的标签是否匹配。如果他们这样做,中心将合并为一个中心。如果有比上述更好的解决方案,我会很高兴听到。

【问题讨论】:

    标签: python arrays numpy


    【解决方案1】:

    首先让我们专注于做(不要担心“循环”):

    In [82]: duplicates = [np.array([0,3]), np.array([3,0]), np.array([6,7,8])]
    
    In [83]: [labels[x] for x in duplicates]
    Out[83]: [array([2, 3]), array([3, 2]), array([0, 0, 0])]
    

    我将duplicates 设为列表,而不是数组。 dtype 对象的一维数组只不过是一个列表。 (但两者都适用)

    (np.concatenate(duplicates) 解决方案移至末尾)

    只要您的 duplicates 元素的长度不同,就没有办法(我能想到的)避免“循环”,即对这些元素进行迭代。这就是numpy 索引的本质。二维操作本质上是“矩形的”。如果有一个函数直接执行它,它可能隐藏了一个循环。


    如果只有少数duplicates 更长,并且您不介意丢失“额外”值,则可以剪掉它们:

    labels[np.array([x[:2] for x in duplicates])]
    
    array([[2, 3],
           [3, 2],
           [0, 0]])
    

    同样,您可以将每个 duplicate 扩展为相同的长度。有一个通用的np.pad 函数,但它可能提供比您需要的更多的选项。

    对于填充,目标长度需要理解,就像填充本身一样。 np.pad 可用于复制最后一个值。另一种选择是一些默认或虚拟索引(例如0)。

    mlen = max([len(x) for x in duplicates])
    padded_dups = [np.pad(x,(0,mlen-len(x)),'edge') for x in duplicates]
    labels[np.array(padded_dup)]
    
    array([[2, 3, 3],
           [3, 2, 2],
           [0, 0, 0]])
    

    duplicates 应该是列表还是对象数组?可能没多大关系。

    [labels[x] for x in np.array(duplicates)]
    

    有效。正如您所注意到的,np.array(duplicates)-1 有效,而列表需要[x-1 for x in duplicates]

    在初步计时中,两个减法大约花费相同的时间,这意味着对象数组减法正在执行等效的列表推导。

    这样的数组有时表现得像一个列表,而在其他情况下又像一个二维数组。这是一个正在发展的领域,因此您必须逐个尝试。

    array([array([0, 3]), array([3, 0]), array([6, 7, 8])], dtype=object)
    

    之前我展示了您可以轻松获得标签的平面列表:

    flat_labels = labels[np.concatenate(duplicates)]
    # array([2, 3, 3, 2, 0, 0, 0])
    

    我刚刚意识到np.split 很容易将这样的数组拆分为您想要的子数组:

    split_indices = np.cumsum([len(x) for x in duplicates])[:-1]
    np.split(flat_labels,split_indices)
    
    # [array([2, 3]), array([3, 2]), array([0, 0, 0])]
    

    【讨论】:

    • 我正在考虑使用列表理解来执行此操作,但只是想知道是否还有其他选择。通常重复元素的长度没有差异,但我想制定一个通用解决方案来涵盖它们所在的边缘情况。重复是在循环中生成的,我想知道是否可以在没有循环的情况下访问标签。起初重复是一个列表(附加元素),然后转换为数组,所以我可以减去-1(如果我没记错的话,不可能从列表中减去)。这是否意味着我必须将重复项转换回列表?谢谢。
    • 我还有一个问题。输出标签后,我必须检查任何数组的元素是否具有相同的标签。因为只有可能的标签 (0 - 3),所以我使用 for 循环:merge_centers_idx = duplicates[np.where(np.sum(label_duplicates == i, 1) > 1)]。然后我继续合并带有标签 i 的中心。
    • 我在回答您的第一个问题时添加了一些注释。我不关注第二个。
    • 我不能使用剪辑,因为这意味着信息丢失。什么是最快的填充方式(正如你所说的 np.pad 提供的比我需要的更多)。我怎么知道我应该填充什么大小(我的数组中列表/数组的最大长度是多少)?
    • 我扩展了填充。但我认为我找到了更好的答案 - 连接重复项、索引,然后将结果拆分为子数组。
    猜你喜欢
    • 2021-08-19
    • 1970-01-01
    • 2014-03-08
    • 2014-06-16
    • 1970-01-01
    • 1970-01-01
    • 2017-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多