【问题标题】:Using np.where with OOP将 np.where 与 OOP 一起使用
【发布时间】:2021-02-15 04:38:00
【问题描述】:

我创建了一个 numpy 数组,其中所有单元格的值都是对象。我想使用 np.where 条件,但它不起作用,因为我想检查对象属性的等效条件。对象类如下所示:

class Cell():
     def __init__(self):
         self.value = 'ABC'
     def __repr__(self):
         return self.value

现在我有 2D numpy 数组,其中所有单元格都与这个单元格类等效,我想检查 cell.value == 'ABC'。 numpy 数组看起来像,

array([[M, M, M, M],
       [M, 'ABC', M, M],
       [M, M, M, M],
       [M, M, M, 'ABC'],
       [M, M, M, M]], dtype=object)

如果我尝试运行 np.where(temp == 'ABC'),我会得到以下输出:

(array([], dtype=int64), array([], dtype=int64))

如果我运行命令 np.where(temp.value == 'ABC'),我会收到以下错误:

AttributeError                            Traceback (most recent call last)
<ipython-input-70-073cbaaed538> in <module>
----> 1 np.where(temp.value =='ABC')

AttributeError: 'numpy.ndarray' object has no attribute 'value'

如何将 np.where 与 OOP 结合使用?

【问题讨论】:

  • 请提供minimal reproducible example 以显示哪些代码的行为不符合您的预期,以及具体出了什么问题。
  • np.where(cond) 只是在cond 中查找True/False(技术上非零)值。所以它的作用完全取决于arg==value 表达式产生的结果。在您有一组 Cell 对象时,arr.value 不起作用。这样的对象数组与列表相比几乎没有(如果有的话)优势。
  • 只是为了让您知道,numpy 实际上并不是针对处理对象 dtypes 的情况而设计的。如果可能,您应该避免在代码中使用对象 dtype,即使只是切换到使用内置类型进行处理。现在,您可以使用结构化 dtypes 而不是对象,这取决于您想从类中获得什么
  • 您正在将str 类型与&lt;class '__main__.Cell'&gt; 类型进行比较。只需使用arr.astype(str) 更改类型并与np.where 进行比较。详情请查看我的回答。

标签: python numpy oop


【解决方案1】:

您正在将来自str 类的对象('ABC')与来自'__main__.Cell' 类的对象进行比较。 (尝试检查type(Cell())

解决方法是使用 np.array.astype() 更改类型

arr = np.array([['M', Cell(),'M'], 
                ['M', Cell(),'M'], 
                [Cell(),'M' ,'M']])

np.where(arr.astype(str)=='ABC')
(array([0, 1, 2]), array([1, 1, 0]))

另外,

您可以通过 -

单独检查数组中每个元素的类型
np.vectorize(type)(arr)
array([[<class 'str'>, <class '__main__.Cell'>, <class 'str'>],
       [<class 'str'>, <class '__main__.Cell'>, <class 'str'>],
       [<class '__main__.Cell'>, <class 'str'>, <class 'str'>]],
      dtype=object)

请注意,其中一些是 str 类的对象,您想将其用于比较,而另一些是 Cell 类对象。

【讨论】:

    【解决方案2】:

    我认为你需要遍历整个数组来检查是否有东西等于'ABC'。相同的代码如下:

    m =[]
    for i in range(temp.shape[0]):
        m.append([])
        for j in range(temp.shape[1]):
            m[i].append(temp[i,j].value == 'ABC')
    np.where(m)
    

    在这种情况下,您将不具备使用 np.where 的计算优势,因为您需要使用 for 循环遍历整个数组。

    【讨论】:

    • 您已经放弃了使用object dtype 在速度方面的许多优势。在 CPython 中,一切都是指向其他事物的指针。 Numpy 适用于固定大小的缓冲区,object dtype 基本上只是表示任意(包括大小)对象。基本上它是作为一个指针数组处理的。
    【解决方案3】:
    In [38]: class Cell():
        ...:      def __init__(self):
        ...:          self.value = 'ABC'
        ...:      def __repr__(self):
        ...:          return self.value
        ...: 
    

    这些对象的列表:

    In [39]: alist = [Cell(),Cell(),Cell()]
    In [40]: [c.value for c in alist]
    Out[40]: ['ABC', 'ABC', 'ABC']
    In [41]: alist.value
    Traceback (most recent call last):
      File "<ipython-input-41-e136813b0fd2>", line 1, in <module>
        alist.value
    AttributeError: 'list' object has no attribute 'value'
    

    一个相同的数组:

    In [42]: arr = np.array(alist)
    In [43]: arr
    Out[43]: array([ABC, ABC, ABC], dtype=object)
    In [44]: arr.value
    Traceback (most recent call last):
      File "<ipython-input-44-bfedc572e969>", line 1, in <module>
        arr.value
    AttributeError: 'numpy.ndarray' object has no attribute 'value'
    

    与此列表相同的问题。仅仅因为元素具有某些属性,并不意味着列表或数组具有该属性。这不是 Python 的 OOP 的工作方式。

    In [45]: [c.value for c in arr]
    Out[45]: ['ABC', 'ABC', 'ABC']
    

    列表推导的替代方案:

    In [46]: np.frompyfunc(lambda x: x.value, 1,1)(arr)
    Out[46]: array(['ABC', 'ABC', 'ABC'], dtype=object)
    

    这在某些情况下可能很方便,但并不快。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-20
      • 1970-01-01
      • 2019-10-03
      • 1970-01-01
      • 1970-01-01
      • 2019-03-10
      相关资源
      最近更新 更多