有效地查找 2D numpy 数组中正值的索引范围



我有一个大的numpy数组(通常为500,000x1024,但可以更大),我正在尝试执行几个取决于数组中正值位置的过程。一个非常小的示例数组可能是

  [[ 0., 0., 0., 0., 0.,-1.,-1., 0., 0.],
   [ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
   [ 0., 1., 1., 0., 0., 1., 5., 0., 0.],
   [ 0., 1., 1., 0., 0., 0., 1., 0., 0.],
   [ 0., 3., 1., 0., 0., 2., 1., 0., 0.],
   [ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
   [ 0., 1., 0., 0., 0., 1., 1., 0., 0.],
   [ 0., 0., 0., 0., 0., 0., 0., 0., 0.]]

第一种是替换每行中相距小于三列的正值之间的任何零。 因此,如果我将这些数字替换为 50,我的示例输出将是

 [[ 0., 0., 0., 0., 0.,-1.,-1., 0., 0.],
  [ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
  [ 0., 1., 1.,50.,50., 1., 5., 0., 0.],
  [ 0., 1., 1., 0., 0., 0., 1., 0., 0.],
  [ 0., 3., 1.,50.,50., 2., 1., 0., 0.],
  [ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
  [ 0., 1., 0., 0., 0., 1., 1., 0., 0.],
  [ 0., 0., 0., 0., 0., 0., 0., 0., 0.]]

我需要做的第二件事是根据正值的范围写出每行的一些信息。例如,使用我修改后的数组,我需要能够为第三行写出一个语句,为 col[1:7] 声明正整数,为第四行写出两个语句,声明 col[1:3] 和 col[6] 中的正整数。

我已经设法利用 numpy 矢量化方法来解决第一个任务,但最终仍然诉诸于遍历列和行(尽管在整个数组的子集上)。否则,我最终会替换给定行中的所有零,而不仅仅是正值之间的零。

但是第二个任务我似乎找不到一种方法来不

循环整个数组
for col in arr:
  for row in arr:

我想我的总体问题是,有没有办法利用 numpy 中的矢量化方法来定义每行不同的列索引范围,并取决于下一列中的值?

任何帮助将不胜感激。

不幸的是,

Numpy 在不生成更多数组的情况下无法进行太多处理,因此我担心任何解决方案都需要像您一直在使用的那样进行某种形式的手动循环,或者创建一个或多个额外的大数组。 您可以使用 numexpr 提出一个非常快速且节省内存的解决方案。

这里有一个尝试,以一种

不一定是内存效率的方式做到这一点,但至少所有的循环都将由 Numpy 完成,所以应该比你一直在做的事情快得多,只要它适合你的内存。 (通过将其中一些重写为就地操作可能会提高内存效率,但我不会担心这一点。

这是您的第 1 步:

positive = x>0 # a boolean array marking the positive values in x
positive0 = positive[:,0:-3] # all but last 3 columns 
positive1 = positive[:,1:-2] # all but 1st and last 2 columns; not actually used
positive2 = positive[:,2:-1] # all but first 2 and last 1 columns
positive3 = positive[:,3:  ] # all but first 3 columns
# In the following, the suffix 1 indicates that we're viewing things from the perspective
# of entries in positive1 above.  So, e.g., has_pos_1_to_left1 will be True at
# any position where an entry in positive1 would be preceded by a positive entry in x
has_pos_1_to_left1 = positive0
has_pos_1_or_2_to_right1 = positive2 | positive3
flanked_by_positives1 = has_pos_1_to_left1 & has_pos_1_or_2_to_right1
zeros = (x == 0)       # indicates everywhere x is 0
zeros1 = zeros[:,1:-2] # all but 1st and last 2 columns
x1 = x[:,1:-2]         # all but 1st and last 2 columns
x1[zeros1 & flanked_by_positives1] = 50 # fill in zeros that were flanked - overwrites x!
# The preceding didn't address the next to last column, b/c we couldn't
# look two slots to the right of it without causing error.  Needs special treatment:
x[:,-2][ zeros[:,-2] & positive[:,-1] & (positive[:,-4] or positive[:,-3])] = 50

这是您的第 2 步:

filled_positives = x>0 # assuming we just filled in x
diffs = numpy.diff(filled_positives) # will be 1 at first positive in any sequence,
                                     # -1 after last positive, zero elsewhere
endings = numpy.where(diffs==-1) # tuple specifying coords where positive sequences end 
                                 # omits final column!!!
beginnings = numpy.where(diffs==1) # tuple specifying coords where pos seqs about to start
                                   # omits column #0!!!

使用这些开始和结束坐标来提取有关您所说的所需每一行的信息应该很简单,但请记住,这种差异检测方法仅捕获从非正到正的转换,反之亦然,因此它不会提及从第 0 列开始或从最后一列结束的正序列,因此如果需要,您需要单独查找这些非转换。

您可以使用高效的 numpy 迭代器,如 flatiter 或 nditer

例如,对于您的第二个任务

In [1]: x = array([[ 0., 0., 0., 0., 0.,-1.,-1., 0., 0.],
   ...:            [ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
   ...:            [ 0., 1., 1.,50.,50., 1., 5., 0., 0.],
   ...:            [ 0., 1., 1., 0., 0., 0., 1., 0., 0.],
   ...:            [ 0., 3., 1.,50.,50., 2., 1., 0., 0.],
   ...:            [ 0., 0., 0., 0., 0., 0., 0., 0., 0.],
   ...:            [ 0., 1., 0., 0., 0., 1., 1., 0., 0.],
   ...:            [ 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
In [2]: islands = []
   ...: fl = x.flat
   ...: while fl.index < x.size:
   ...:     coord = fl.coords
   ...:     if fl.next() > 0:
   ...:         length = 1
   ...:         while fl.next() > 0:
   ...:             length +=1
   ...:         islands.append([coord, length])
In [3]: for (row, col), length in islands:
   ...:     print 'row:%d ; col[%d:%d]' %(row, col, col+length)
row:2 ; col[1:7]
row:3 ; col[1:3]
row:3 ; col[6:7]
row:4 ; col[1:7]
row:6 ; col[1:2]
row:6 ; col[5:7]

对于你的第一个问题:创建一个变量来保存你遇到的第一个正数的索引,并有一个 if 语句,如果下一个值为正数并且计数(从第一个正数计算位置的变量)小于 3,则重置位置。

对于第二个问题:创建一个数组并添加正值位置的索引。

 String[] indices = new String[];
 int pos = 0;
 for col in arr:
     for row in arr:
        if(index is positive){
             indices[pos] = "[" + col + ":" + row + "]";
             pos++;
         }

第二种方法是让数据创建对象,假设你有一个类:

public class Matrix{
   int indicex;
   int indicey;
   double val;
   boolean positiveInt;
   //default constructor
   public Matrix(int indicex, int indicey, double val, boolean positiveInt){
   this.indicex = indicex;
   this.indicey = indicey;
   this.val = val;
   this.positiveInt = positiveInt;
   }    
   //getter
   public boolean isPositive(){
        if(positiveInt == true){
              return true;
        }else{
            return false;
        }

然后在驱动程序类中,您将读取数据并创建一个对象新矩阵(indexx,indexy,val,true/false)....这将被放入一个数组列表中,您可以在该数组列表中搜索正数。

List<Matrix> storeObjects = new ArrayList<Matrix>();
some method(){
   Matrix matrixObject = new Matrix(indexx, indexy, val, trueOrFalse);
   storeObjects.add(matrixObject)
 }
 for every object in store objects 
    if(object.isPositive()){
         put object in a separate array of positive objects
     }
  }

相关内容

  • 没有找到相关文章

最新更新