簡體   English   中英

如何從 numpy 數組列表中“刪除”一個 numpy 數組?

[英]How do you 'remove' a numpy array from a list of numpy arrays?

如果我有一個 numpy 數組列表,那么使用 remove 方法會返回一個值錯誤。

例如:

import numpy as np

l = [np.array([1,1,1]),np.array([2,2,2]),np.array([3,3,3])]

l.remove(np.array([2,2,2]))

會給我

ValueError:包含多個元素的數組的真值不明確。 使用 a.any() 或 a.all()

我似乎無法讓 all() 工作,這是不可能的嗎?

這里的問題是,當兩個 numpy 數組與 == 進行比較時,如在 remove() 和 index() 方法中,返回一個布爾值的 numpy 數組(逐元素比較),這被解釋為不明確。 比較兩個 numpy 數組是否相等的一個好方法是使用 numpy 的 array_equal() 函數。

由於列表的 remove() 方法沒有關鍵參數(就像 sort() 一樣),我認為您需要創建自己的函數來執行此操作。 這是我做的一個:

def removearray(L,arr):
    ind = 0
    size = len(L)
    while ind != size and not np.array_equal(L[ind],arr):
        ind += 1
    if ind != size:
        L.pop(ind)
    else:
        raise ValueError('array not found in list.')

如果您需要它更快,那么您可以對它進行 Cython 化。

干得好:

list.pop(1)

更新:

list.pop(list.index(element))

我不認為你可以繞過遍歷列表來找到元素的位置。 別擔心。 默認情況下,Python 會使用一種好的搜索算法來為您找到最少的成本。

使用 Python 基本功能

以下解決方案使用數組列表中的list.index(element)方法。

搜索numpy.ndarray需要能夠散列 numpy.ndarray 實例。 因此,我們需要實現一個哈希算法。 這相當簡單,雖然呈現的代碼看起來有點長,但大部分行用於檢查邊緣情況或添加注釋。

您可以將代碼復制粘貼到文件中,然后從命令行或 SDK 作為 PyCharm 運行它。

你需要知道

  • [].index(元素)
  • hash(散列和散列沖突)
  • 如何散列一個numpy數組

筆記:

  • 哈希沖突會導致錯誤的決定,你需要自己決定概率和影響
  • 如果有多個具有相同數據的數組,則僅刪除數組的第一次出現。

import numpy as np


def remove(array, arrays):
    """
    Remove the `array` from the `list` of `arrays`
    Operates inplace on the `list` of `arrays` given

    :param array: `np.ndarray`
    :param arrays: `list:np.ndarray`
    :return: None
    """

    assert isinstance(arrays, list), f'Expected a list, got {type(arrays)} instead'
    assert isinstance(array, np.ndarray), f'Expected a numpy.ndarray, got {type(array)} instead'
    for a in arrays:
        assert isinstance(a, np.ndarray), f'Expected a numpy.ndarray instances in arrays, found {type(a)} instead'

    # Numpy ndarrays are not hashable by default, so we create
    # our own hashing algorithm. The following will do the job ...
    def _hash(a):
        return hash(a.tobytes())

    try:
        # We create a list of hashes and search for the index
        # of the hash of the array we want to remove.
        index = [_hash(a) for a in arrays].index(_hash(array))
    except ValueError as e:
        # It might be, that the array is not in the list at all.
        print(f'Array not in list. Leaving input unchanged.')
    else:
        # Only in the case of no exception we pop the array
        # with the same index/position from the original
        # arrays list
        arrays.pop(index)


if __name__ == '__main__':

    # Let's start with the following arrays as given in the question
    arrays = [np.array([1, 1, 1]), np.array([2, 2, 2]), np.array([3, 3, 3])]
    print(arrays)

    # And remove this array instance from it.
    # Note, this is a new instance, so the object id is
    # different. Structure and values coincide.
    remove(np.array([2, 2, 2]), arrays)

    # Let's check the result
    print(arrays)

    # Let's check, whether our edge case handling works.
    remove(np.array([1, 2, 3]), arrays)

使用 Python 和 Numpy 的基本功能

您可以運行以下單行代碼以獲得結果...

import numpy as np

# Your inputs ...
l = [np.array([1, 1, 1]), np.array([2, 2, 2]), np.array([3, 3, 3])]
array_to_remove = np.array([2, 2, 2])

# My result ...
result = [a for a, skip in zip(l, [np.allclose(a, array_to_remove) for a in l]) if not skip]

print(result)

...或將以下內容復制粘貼到腳本中並進行一些實驗。

你需要

  • numpy.allclose 將 numpy 數組與浮點表示錯誤進行比較
  • 壓縮
  • 列表理解
  • 面具的概念

筆記, ...

  • 此解決方案返回一個列表,其中沒有我們搜索的數組的所有出現
  • 返回的列表包含對 np.ndarray 實例的引用,也從初始列表引用。 沒有副本!

import numpy as np


def remove(array, arrays):
    """
    Remove the `array` from the `list` of `arrays`
    Returns list with remaining arrays by keeping the order.

    :param array: `np.ndarray`
    :param arrays: `list:np.ndarray`
    :return: `list:np.ndarray`
    """

    assert isinstance(arrays, list), f'Expected a list, got {type(arrays)} instead'
    assert isinstance(array, np.ndarray), f'Expected a numpy.ndarray, got {type(array)} instead'
    for a in arrays:
        assert isinstance(a, np.ndarray), f'Expected a numpy.ndarray instances in arrays, found {type(a)} instead'

    # We use np.allclose for comparing arrays, this will work even if there are
    # floating point representation differences.
    # The idea is to create a boolean mask of the same lenght as the input arrays.
    # Then we loop over the arrays-elements and the mask-elements and skip the
    # flagged elements
    mask = [np.allclose(a, array) for a in arrays]
    return [a for a, skip in zip(arrays, mask) if not skip]


if __name__ == '__main__':

    # Let's start with the following arrays as given in the question
    arrays = [np.array([1, 1, 1]), np.array([2, 2, 2]), np.array([3, 3, 3])]
    print(arrays)

    # And remove this array instance from it.
    # Note, this is a new instance, so the object id is
    # different. Structure and values coincide.
    _arrays = remove(np.array([2, 2, 2]), arrays)

    # Let's check the result
    print(_arrays)

    # Let's check, whether our edge case handling works.
    print(arrays)
    _arrays = remove(np.array([1, 2, 3]), arrays)
    print(_arrays)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM