Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/307.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 每行的Bin元素-NumPy的矢量化二维Bincount_Python_Performance_Numpy_Matrix_Vectorization - Fatal编程技术网

Python 每行的Bin元素-NumPy的矢量化二维Bincount

Python 每行的Bin元素-NumPy的矢量化二维Bincount,python,performance,numpy,matrix,vectorization,Python,Performance,Numpy,Matrix,Vectorization,我有一个整数数组。矩阵值的范围是从0到矩阵中的最大元素(换句话说,从0到最大数据元素的所有数字都显示在矩阵中)。我需要建立有效的(有效意味着快速完全矢量化的解决方案)来搜索每行中的元素数量,并根据矩阵值对它们进行编码 我找不到一个类似的问题,或者一个不知何故有助于解决这个问题的问题 因此,如果我在输入中有这个数据: # shape is (N0=4, m0=4) 1 1 0 4 2 4 2 1 1 2 3 5 4 4 4 1 期望输出为: #

我有一个整数数组。矩阵值的范围是从0到矩阵中的最大元素(换句话说,从0到最大数据元素的所有数字都显示在矩阵中)。我需要建立有效的(有效意味着快速完全矢量化的解决方案)来搜索每行中的元素数量,并根据矩阵值对它们进行编码

我找不到一个类似的问题,或者一个不知何故有助于解决这个问题的问题

因此,如果我在输入中有这个
数据

# shape is (N0=4, m0=4) 
1   1   0   4
2   4   2   1
1   2   3   5
4   4   4   1
期望输出为:

# shape(N=N0, m=data.max()+1):
1   2   0   0   1   0
0   1   2   0   1   0
0   1   1   1   0   1
0   1   0   0   3   0
我知道如何解决这个问题,只需计算
数据
每行中的唯一值,逐个迭代,然后结合结果,考虑
数据
数组中所有可能的值

当使用NumPy进行矢量化时,关键问题是逐个搜索每个数字的速度很慢,并且假设存在许多唯一的数字,这不是有效的解决方案。通常,
N
和唯一数计数都相当大(顺便说一下,
N
似乎比唯一数计数大)


有人有好主意吗?

这就是
1D
数组的基本功能。但是,我们需要在每一行上迭代地使用它(简单地考虑它)。为了使其矢量化,我们可以将每一行偏移该最大值。其思想是为每一行设置不同的存储箱,这样它们就不会受到具有相同编号的其他行元素的影响

因此,实施将是必要的-

# Vectorized solution
def bincount2D_vectorized(a):    
    N = a.max()+1
    a_offs = a + np.arange(a.shape[0])[:,None]*N
    return np.bincount(a_offs.ravel(), minlength=a.shape[0]*N).reshape(-1,N)
# Loopy solution
def bincount2D_loopy(a):
    N = a.max()+1
    m,n = a.shape
    out = np.zeros((m,N),dtype=int)
    for i in range(m):
        out[i] = np.bincount(a[i], minlength=N)
    return out 
样本运行-

In [189]: a
Out[189]: 
array([[1, 1, 0, 4],
       [2, 4, 2, 1],
       [1, 2, 3, 5],
       [4, 4, 4, 1]])

In [190]: bincount2D_vectorized(a)
Out[190]: 
array([[1, 2, 0, 0, 1, 0],
       [0, 1, 2, 0, 1, 0],
       [0, 1, 1, 1, 0, 1],
       [0, 1, 0, 0, 3, 0]])
麻木调整

我们可以进一步加速。现在,
numba
允许进行一些调整

  • 首先,它允许JIT编译

  • 此外,最近他们引入了一种实验性的方法,可以自动并行化具有并行语义的函数中的操作

  • 最后一个调整是用作
    范围的替代品。文档中指出,它并行运行循环,类似于OpenMP并行for loops和Cython的prange
    prange
    在处理较大的数据集时表现良好,这可能是因为设置并行工作所需的开销

所以,有了这两个新的调整以及for no-Python模式,我们将有三个变体-

# Numba solutions
def bincount2D_numba(a, use_parallel=False, use_prange=False):
    N = a.max()+1
    m,n = a.shape
    out = np.zeros((m,N),dtype=int)

    # Choose fucntion based on args
    func = bincount2D_numba_func0
    if use_parallel:
        if use_prange:
            func = bincount2D_numba_func2
        else:
            func = bincount2D_numba_func1
    # Run chosen function on input data and output
    func(a, out, m, n)
    return out

@njit
def bincount2D_numba_func0(a, out, m, n):
    for i in range(m):
        for j in range(n):
            out[i,a[i,j]] += 1

@njit(parallel=True)
def bincount2D_numba_func1(a, out, m, n):
    for i in range(m):
        for j in range(n):
            out[i,a[i,j]] += 1

@njit(parallel=True)
def bincount2D_numba_func2(a, out, m, n):
    for i in prange(m):
        for j in prange(n):
            out[i,a[i,j]] += 1
为了完整性和以后的测试,循环版本将是-

# Vectorized solution
def bincount2D_vectorized(a):    
    N = a.max()+1
    a_offs = a + np.arange(a.shape[0])[:,None]*N
    return np.bincount(a_offs.ravel(), minlength=a.shape[0]*N).reshape(-1,N)
# Loopy solution
def bincount2D_loopy(a):
    N = a.max()+1
    m,n = a.shape
    out = np.zeros((m,N),dtype=int)
    for i in range(m):
        out[i] = np.bincount(a[i], minlength=N)
    return out 
运行时测试

案例1:

案例2:

案例3:


似乎
numba
变体的性能非常好。从三种变体中选择一种将取决于输入阵列形状参数,并在某种程度上取决于其中唯一元素的数量。

基本上这就是
1D
阵列的作用。但是,我们需要在每一行上迭代地使用它(简单地考虑它)。为了使其矢量化,我们可以将每一行偏移该最大值。其思想是为每一行设置不同的存储箱,这样它们就不会受到具有相同编号的其他行元素的影响

因此,实施将是必要的-

# Vectorized solution
def bincount2D_vectorized(a):    
    N = a.max()+1
    a_offs = a + np.arange(a.shape[0])[:,None]*N
    return np.bincount(a_offs.ravel(), minlength=a.shape[0]*N).reshape(-1,N)
# Loopy solution
def bincount2D_loopy(a):
    N = a.max()+1
    m,n = a.shape
    out = np.zeros((m,N),dtype=int)
    for i in range(m):
        out[i] = np.bincount(a[i], minlength=N)
    return out 
样本运行-

In [189]: a
Out[189]: 
array([[1, 1, 0, 4],
       [2, 4, 2, 1],
       [1, 2, 3, 5],
       [4, 4, 4, 1]])

In [190]: bincount2D_vectorized(a)
Out[190]: 
array([[1, 2, 0, 0, 1, 0],
       [0, 1, 2, 0, 1, 0],
       [0, 1, 1, 1, 0, 1],
       [0, 1, 0, 0, 3, 0]])
麻木调整

我们可以进一步加速。现在,
numba
允许进行一些调整

  • 首先,它允许JIT编译

  • 此外,最近他们引入了一种实验性的方法,可以自动并行化具有并行语义的函数中的操作

  • 最后一个调整是用作
    范围的替代品。文档中指出,它并行运行循环,类似于OpenMP并行for loops和Cython的prange
    prange
    在处理较大的数据集时表现良好,这可能是因为设置并行工作所需的开销

所以,有了这两个新的调整以及for no-Python模式,我们将有三个变体-

# Numba solutions
def bincount2D_numba(a, use_parallel=False, use_prange=False):
    N = a.max()+1
    m,n = a.shape
    out = np.zeros((m,N),dtype=int)

    # Choose fucntion based on args
    func = bincount2D_numba_func0
    if use_parallel:
        if use_prange:
            func = bincount2D_numba_func2
        else:
            func = bincount2D_numba_func1
    # Run chosen function on input data and output
    func(a, out, m, n)
    return out

@njit
def bincount2D_numba_func0(a, out, m, n):
    for i in range(m):
        for j in range(n):
            out[i,a[i,j]] += 1

@njit(parallel=True)
def bincount2D_numba_func1(a, out, m, n):
    for i in range(m):
        for j in range(n):
            out[i,a[i,j]] += 1

@njit(parallel=True)
def bincount2D_numba_func2(a, out, m, n):
    for i in prange(m):
        for j in prange(n):
            out[i,a[i,j]] += 1
为了完整性和以后的测试,循环版本将是-

# Vectorized solution
def bincount2D_vectorized(a):    
    N = a.max()+1
    a_offs = a + np.arange(a.shape[0])[:,None]*N
    return np.bincount(a_offs.ravel(), minlength=a.shape[0]*N).reshape(-1,N)
# Loopy solution
def bincount2D_loopy(a):
    N = a.max()+1
    m,n = a.shape
    out = np.zeros((m,N),dtype=int)
    for i in range(m):
        out[i] = np.bincount(a[i], minlength=N)
    return out 
运行时测试

案例1:

案例2:

案例3:


似乎
numba
变体的性能非常好。从三种变体中选择一种将取决于输入阵列形状参数,并在某种程度上取决于其中唯一元素的数量。

太好了。它完全按照需要工作。非常感谢。
a+np.arange(a.shape[0])[:,None]*N
现在看起来很神奇。请您解释一下“偏移”值的概念好吗?哦,我明白了:您偏移每行中的值以使其唯一。@Grigoriy完全正确,因为相同的数字在馈送到
bincount
时会累积到展平版本中的相同位置。因此,通过这种偏移,我们在不同的行中保留相同的数字,作为单独的数字,以便bincount使用。这就是整个想法,真的,太好了。它完全按照需要工作。非常感谢。
a+np.arange(a.shape[0])[:,None]*N
现在看起来很神奇。请您解释一下“偏移”值的概念好吗?哦,我明白了:您偏移每行中的值以使其唯一。@Grigoriy完全正确,因为相同的数字在馈送到
bincount
时会累积到展平版本中的相同位置。因此,通过这种偏移,我们在不同的行中保留相同的数字,作为单独的数字,以便bincount使用。这就是全部的想法。