【问题标题】:Numpy: checking if an element in a multidimensional array is in a tupleNumpy:检查多维数组中的元素是否在元组中
【发布时间】:2011-11-06 00:15:04
【问题描述】:

看来我还在为the "in" operator in numpy 挣扎。情况如下:

>>> a = np.random.randint(1, 10, (2, 2, 3))
>>> a
array([[[9, 8, 8],
        [4, 9, 1]],

       [[6, 6, 3],
        [9, 3, 5]]])

我想获取第二个元素在(6, 8) 中的那些三元组的索引。我凭直觉尝试的方式是:

>>> a[:, :, 1] in (6, 8)
ValueError: The truth value of an array with more than one element...

我的最终目标是在这些位置插入前面的数字乘以 2。 使用上面的示例,a 应该变为:

array([[[9, 18, 8],   #8 @ pos #2 --> replaced by 9 @ pos #1 by 2
        [4, 9, 1]],

       [[6, 12, 3],   #6 @ pos #2 --> replaced by 6 @ pos #1 by 2
        [9, 3, 5]]])

提前感谢您的建议和时间!

【问题讨论】:

    标签: python numpy python-2.7


    【解决方案1】:

    这是一种适用于任意长度元组的方法。它使用numpy.in1d 函数。

    import numpy as np
    np.random.seed(1)
    
    a = np.random.randint(1, 10, (2, 2, 3))
    print(a)
    
    check_tuple = (6, 9, 1)
    
    bool_array = np.in1d(a[:,:,1], check_tuple)
    ind = np.where(bool_array)[0]
    a0 = a[:,:,0].reshape((len(bool_array), ))
    a1 = a[:,:,1].reshape((len(bool_array), ))
    a1[ind] = a0[ind] * 2
    
    print(a)
    

    还有输出:

    [[[6 9 6]
      [1 1 2]]
    
     [[8 7 3]
      [5 6 3]]]
    
    [[[ 6 12  6]
      [ 1  2  2]]
    
     [[ 8  7  3]
      [ 5 10  3]]]
    

    【讨论】:

    • 有趣的是发现in1d的用法。它有点冗长(就转换的操作数量而言)但值得尝试! +1
    【解决方案2】:
    import numpy as np
    a = np.array([[[9, 8, 8],
                   [4, 9, 1]],
    
                  [[6, 6, 3],
                   [9, 3, 5]]])
    
    ind=(a[:,:,1]<=8) & (a[:,:,1]>=6)
    a[ind,1]=a[ind,0]*2
    print(a)
    

    产量

    [[[ 9 18  8]
      [ 4  9  1]]
    
     [[ 6 12  3]
      [ 9  3  5]]]
    

    如果您希望检查不是简单范围的集合中的成员资格,那么我喜欢使用 Python 循环的mac's idea 和使用 np.in1d 的bellamyj's idea。哪个更快取决于check_tuple的大小:

    test.py:

    import numpy as np
    np.random.seed(1)
    
    N = 10
    a = np.random.randint(1, 1000, (2, 2, 3))
    check_tuple = np.random.randint(1, 1000, N)
    
    def using_in1d(a):
        idx = np.in1d(a[:,:,1], check_tuple)
        idx=idx.reshape(a[:,:,1].shape)
        a[idx,1] = a[idx,0] * 2
        return a
    
    def using_in(a):
        idx = np.zeros(a[:,:,0].shape,dtype=bool)
        for n in check_tuple:
            idx |= a[:,:,1]==n
        a[idx,1] = a[idx,0]*2
        return a
    
    assert np.allclose(using_in1d(a),using_in(a))    
    

    当 N = 10 时,using_in 稍快:

    % python -m timeit -s'import test' 'test.using_in1d(test.a)'
    10000 loops, best of 3: 156 usec per loop
    % python -m timeit -s'import test' 'test.using_in(test.a)'
    10000 loops, best of 3: 143 usec per loop
    

    当 N = 100 时,using_in1d 更快:

    % python -m timeit -s'import test' 'test.using_in1d(test.a)'
    10000 loops, best of 3: 171 usec per loop
    % python -m timeit -s'import test' 'test.using_in(test.a)'
    1000 loops, best of 3: 1.15 msec per loop
    

    【讨论】:

    • 官方 numpy 辅导有徽章吗?如果是你就会得到它。 :) 你对 numpy 有什么好的学习资料吗?官方 [暂定] 教程和参考资料的结构使我很难找到我需要的信息...:-/
    • 顺便说一句:这是一个巧妙的解决方法,但如果可以使用 in 运算符会更可取,因为在我的“真实案例”中,我有一个大约 10 个值的池,不仅(6, 8).
    • 诀窍不在于阅读内容,而在于阅读方式。对于每个函数,花几分钟时间询问,什么是一个简单的例子来演示这个函数的行为?我什么时候可以使用这个?开始构建一个练习/演示每个功能/概念的示例文件。学习是构建示例文件的副作用。暂定教程和官方文档是很好的资源。您也可以尝试使用numpy bookuser guide 来度过一个周末。祝你好运!
    【解决方案3】:

    我从 Cellprofiler 的一位开发人员那里学到了另一种基于使用查找表的方法。 首先,您需要创建一个查找表 (LUT),它的大小与数组中的最大数相同。对于每个可能的数组值,LUT 具有 True 或 false 值。 示例:

    # create a large volume image with random numbers
    a = np.random.randint(1, 1000, (50, 1000 , 1000))
    labels_to_find=np.unique(np.random.randint(1,1000,500))
    
    # create filter mask LUT 
    def find_mask_LUT(inputarr, obs):
        keep = np.zeros(np.max(inputarr)+1, bool)
        keep[np.array(obs)] = True
        return keep[inputarr]
    
    # This will return a mask that is the 
    # same shape as a, with True is a is one of the 
    # labels we look for, False otherwise
    find_mask_LUT(a, labels_to_find)
    

    这确实很快(比 np.in1d 快得多,而且速度不取决于对象的数量。)

    【讨论】:

      【解决方案4】:

      受到unutbu's answer 的启发,我发现了这个可能的解决方案:

      >>> l = (8, 6)
      >>> idx = np.zeros((2, 2), dtype=bool)
      >>> for n in l:
      ...     idx |= a[:,:,1] == n
      >>> idx
      array([[ True, False],
             [ True, False]], dtype=bool)
      >>> a[idx]
      array([[9, 8, 8],
             [6, 6, 3]])
      

      不过,它需要知道数组的维度才能事先调查。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-22
        • 1970-01-01
        • 2013-03-16
        • 1970-01-01
        • 2018-02-23
        相关资源
        最近更新 更多