【问题标题】:Count instances in numpy array within a certain value of each row在每行的某个值内计算 numpy 数组中的实例
【发布时间】:2018-09-05 17:01:30
【问题描述】:

我有一个像这样的 numpy 数组

[[ 0, 57],
 [ 7, 72],
 [ 2, 51],
 [ 8, 67],
 [ 4, 42]]

我想为每一行找出第二列中有多少元素在该行的第二列值的一定距离内(例如,10)。所以在这个例子中,这里的解决方案是

[[ 0, 57, 3],
 [ 7, 72, 2],
 [ 2, 51, 3],
 [ 8, 67, 3],
 [ 4, 42, 2]]

所以 [第一行,第三列] 是 3,因为在第二列 (57,51,67) 中有 3 个元素在距离 57 的 10 范围内。对于每一行也是如此

任何帮助将不胜感激!

【问题讨论】:

  • 你的阵列有多大?
  • 大约 100 万行
  • 您希望每个点有多少个邻居?

标签: python numpy


【解决方案1】:

这是一种利用 broadcastingouter-subtraction 的方法 -

(np.abs(a[:,1,None] - a[:,1]) <= 10).sum(1)

使用outer subtract builtincount_nonzero 进行计数-

np.count_nonzero(np.abs(np.subtract.outer(a[:,1],a[:,1]))<=10,axis=1)

示例运行 -

# Input array
In [23]: a
Out[23]: 
array([[ 0, 57],
       [ 7, 72],
       [ 2, 51],
       [ 8, 67],
       [ 4, 42]])

# Get count
In [24]: count = (np.abs(a[:,1,None] - a[:,1]) <= 10).sum(1)

In [25]: count
Out[25]: array([3, 2, 3, 3, 2])

# Stack with input
In [26]: np.c_[a,count]
Out[26]: 
array([[ 0, 57,  3],
       [ 7, 72,  2],
       [ 2, 51,  3],
       [ 8, 67,  3],
       [ 4, 42,  2]])

或者SciPy's cdist -

In [53]: from scipy.spatial.distance import cdist

In [54]: (cdist(a[:,None,1],a[:,1,None], 'minkowski', p=2)<=10).sum(1)
Out[54]: array([3, 2, 3, 3, 2])

对于输入中的百万行,我们可能希望使用一个循环的 -

n = len(a)
count = np.empty(n, dtype=int)
for i in range(n):
    count[i] = np.count_nonzero(np.abs(a[:,1]-a[i,1])<=10)

【讨论】:

  • 感谢您的解决方案 - 我试过了,但收到“MemoryError”。我的数组大约有 100 万行
  • 谢谢!现在工作,虽然真的很慢!另外,如果我想让简单的差异小于 10(而不是绝对),我该怎么做?
  • @alphaomega83 “简单的区别”是什么意思?
【解决方案2】:

这是一种非广播方法,它利用了这样一个事实,即要知道有多少数字在 10 之 3 之内,您可以从严格小于 7 的数字中减去

import numpy as np

def broadcast(x, width):
    # for comparison
    return (np.abs(x[:,None] - x) <= width).sum(1)


def largest_leq(arr, x, allow_equal=True):
    maybe = np.searchsorted(arr, x)
    maybe = maybe.clip(0, len(arr) - 1)
    above = arr[maybe] > x if allow_equal else arr[maybe] >= x
    maybe[above] -= 1
    return maybe

def faster(x, width):
    uniq, inv, counts = np.unique(x, return_counts=True, return_inverse=True)
    counts = counts.cumsum()

    low_bounds = uniq - width
    low_ix = largest_leq(uniq, low_bounds, allow_equal=False)
    low_counts = counts[low_ix]
    low_counts[low_ix < 0] = 0

    high_bounds = uniq + width
    high_counts = counts[largest_leq(uniq, high_bounds)]

    delta = high_counts - low_counts
    out = delta[inv]
    return out

这通过了我的测试:

for width in range(1, 10):
    for window in range(5):
        for trial in range(10):
            x = np.random.randint(0, 10, width)
            b = broadcast(x, window).tolist()
            f = faster(x, window).tolist()
            assert b == f

即使在更大的尺寸下也表现得很好:

In [171]: x = np.random.random(10**6)

In [172]: %time faster(x, 0)
Wall time: 386 ms
Out[172]: array([1, 1, 1, ..., 1, 1, 1], dtype=int64)

In [173]: %time faster(x, 1)
Wall time: 372 ms
Out[173]: array([1000000, 1000000, 1000000, ..., 1000000, 1000000, 1000000], dtype=int64)

In [174]: x = np.random.randint(0, 10, 10**6)

In [175]: %timeit faster(x, 3)
10 loops, best of 3: 83 ms per loop

【讨论】:

    猜你喜欢
    • 2012-03-22
    • 1970-01-01
    • 2020-12-09
    • 2015-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-15
    • 2016-02-09
    相关资源
    最近更新 更多