Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在大型数组中识别按最大距离分隔的Python数组单元格对?_Python_Arrays_Numpy_Scipy_Distance - Fatal编程技术网

在大型数组中识别按最大距离分隔的Python数组单元格对?

在大型数组中识别按最大距离分隔的Python数组单元格对?,python,arrays,numpy,scipy,distance,Python,Arrays,Numpy,Scipy,Distance,我有包含空间生态栖息地数据的光栅,我已经将其转换为二维numpy数组。在此数组中,值1=数据,0=无数据。 根据这些数据,我想生成一个包含所有数据单元对的数组,其中每个单元之间的距离小于最大欧几里德截止距离(即相隔2个单元) 我发现这很有用,但答案似乎是首先测量所有成对距离,然后通过一个最大截止值对结果设置阈值。我的数据集很大(13500*12000数组中超过100万个数据单元),因此任何试图计算所有单元对之间距离的两两距离度量都将失败:我需要一个解决方案,该解决方案以某种方式停止寻找某个搜索半

我有包含空间生态栖息地数据的光栅,我已经将其转换为二维numpy数组。在此数组中,值1=数据,0=无数据。 根据这些数据,我想生成一个包含所有数据单元对的数组,其中每个单元之间的距离小于最大欧几里德截止距离(即相隔2个单元)

我发现这很有用,但答案似乎是首先测量所有成对距离,然后通过一个最大截止值对结果设置阈值。我的数据集很大(13500*12000数组中超过100万个数据单元),因此任何试图计算所有单元对之间距离的两两距离度量都将失败:我需要一个解决方案,该解决方案以某种方式停止寻找某个搜索半径(或类似半径)之外的可能邻居

我已经尝试了
scipy.space.distance.pdist
,但到目前为止,我还没有成功地将它应用到二维数据中,或者找到一种方法来阻止
pdist
计算甚至更远的细胞对之间的距离。我附加了一个示例数组和一个最大欧几里德截止距离=2个单元格的所需输出数组:


我不得不承认,我的臀部很虚弱——也许有一种方法可以直接做到这一点。尽管如此,这个问题在纯Python中并不困难。以下代码将输出匹配数据的x/y坐标对。有很多潜在的优化可能会使代码变得模糊,并使其运行得更快,但是考虑到数据集的大小和示例radius的大小(2.0),我怀疑这些优化是否值得(可能会有例外,在数组中而不是子列表中创建numpy视图)

更新了——该代码修复了几个错误——(1)在低于起始点的行上看得太远了,(2)在靠近左边缘的地方没有做正确的事情。该函数的调用现在使用2.5的半径来显示如何拾取其他对

example_array = [[0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
                [0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1],
                [0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
                [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
                [1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1],
                [1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1],
                [1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0],
                [1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0],
                [1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
                [1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

def findpairs(mylist, radius = 2.0):
    """
    Find pairs with data within a given radius.
    If we work from the top of the array down, we never
    need to look up (because we already would have found
    those, and we never need to look left on the same line.
    """

    # Create the parameters of a half circle, which is
    # the relative beginning and ending X coordinates to
    # search for each Y line starting at this one and
    # working down.  To avoid duplicates and extra work,
    # not only do we not look up, we never look left on
    # the same line as what we are matching, but we do
    # on subsequent lines.

    semicircle = []
    x = 1
    while x:
        y = len(semicircle)
        x = int(max(0, (radius ** 2 - y ** 2)) ** 0.5)
        # Don't look back on same line...
        semicircle.append((-x if y else 1, x + 1))

    # The maximum number of y lines we will search
    # at a time.
    max_y = len(semicircle)

    for y_start in range(len(mylist)):
        sublists = enumerate(mylist[y_start:y_start + max_y], y_start)
        sublists = zip(semicircle, sublists)
        check = (x for (x, value) in enumerate(mylist[y_start]) if value)
        for x_start in check:
            for (x_lo, x_hi), (y, ylist) in sublists:
                # Deal with left edge problem
                x_lo = max(0, x_lo + x_start)
                xlist = ylist[x_lo: x_start + x_hi]
                for x, value in enumerate(xlist, x_lo):
                    if value:
                        yield (x_start, y_start), (x, y)

print(list(findpairs(example_array, 2.5)))
执行时间将高度依赖于数据。对于GRIN,我创建了您指定大小(13500 x 12000)的数组来测试计时。我使用了更大的半径(3.0而不是2.0),并尝试了两种情况:没有匹配,每次匹配。为了避免一次又一次地重新分配列表,我只需运行迭代器并抛出结果。下面是实现这一点的代码。对于一个最佳情况(空)数组,它在我的机器上运行了7秒钟;最坏情况(全部为1)阵列的时间约为12分钟

def dummy(val):
    onelist = 13500 * [val]
    listolists = 12000 * [onelist]

    for i in findpairs(listolists, 3.0):
      pass

dummy(0)
dummy(1)

一个简单的算法是:迭代每个数据点(r,c);取一个切片数组[r-D:r+D,c-D:c+D];将该切片中任何数据点的索引附加到结果中。但是,对于您的数据集来说,这可能太慢了。该算法使用点之间的“曼哈顿”距离。如果你需要欧几里德公式,你可以预先计算一个应用于切片的蒙版。对于每个单元格,你可以搜索感兴趣半径内的相邻单元格。如果数组被索引(i,j)且最大_半径为2,则对i和j从单元索引迭代到单元索引[+2,+1,0,-1,-2],i=j时除外。如果你需要最接近的一对,当你到达最大半径时,使用一个带截止线的BFS。嗨,帕特里克,这看起来很棒,谢谢!有一个问题:我已经将上面代码生成的列表转换为一个igraph网络进行可视化,但似乎缺少了几个边。我在下面附上了一张图片:蓝色高光是阵列左边界上完全缺失的短链接,黄色和绿色高光是仅在特定方向上识别的较长链接(在本例中,SSE和ESE链接缺失,而SSW和WSW链接被拾取):(上面的输出示例;最大距离=2)(1)左侧边缘是一个缺陷,我理解,但必须找到修复方法。(3)“缺失”的绿色和黄色链接实际上是(a)SSW/WSW方向的缺陷(修复很容易),以及(b)我对您的问题的理解。它们比“2.0”长从一点到另一点。如何计算距离?修复所有已知错误(答案已更新)但我认为你需要弄清楚如何指定半径。嗨,帕特里克,谢谢你的更新。现在它运行得非常好。你在上面的例子中对较长的链接也很正确:SSW/WSW链接确实不应该包含在2半径限制中。它们现在只显示在半径大于~2.5的情况下,这是完美的。
def dummy(val):
    onelist = 13500 * [val]
    listolists = 12000 * [onelist]

    for i in findpairs(listolists, 3.0):
      pass

dummy(0)
dummy(1)