用于获取大于引用的元素计数的向量化窗体

2024-09-26 04:43:30 发布

您现在位置:Python中文网/ 问答频道 /正文

…这个参考来自一个单独的矩阵。你知道吗

这个问题是前面回答的一个问题的扩展,其中引用元素直接来自与之比较的同一列。一些聪明的排序和引用排序的索引似乎解决了这个问题。你知道吗

广播在原问题和新问题中都有提出。我的内存在n ~ 3000左右用完,需要再大一个数量级。你知道吗


目标(生产等级)缩放定义:

为了使所提出的解决方案在[SPACE]-和[TIME]-域中公平且相互可比,
假设n = 50000; m = 20; k = 50; a = np.random.rand( n, m ); ...


我现在对一个更一般的形式感兴趣,其中参考值来自另一个参考值矩阵。你知道吗

原始问题:

Vectorized pythonic way to get count of elements greater than current element

新问题:我们能否编写一个矢量化的表单来执行以下角色。你知道吗

函数接收2个二维数组作为输入。你知道吗

A = n x m
B = k x m

返回

C = k x m.

C[i,j]A[:,j]中大于B[i,j]的观测值的比例

这是我令人尴尬的慢双循环实现。你知道吗

import numpy as np

n = 100
m = 20
k = 50
a = np.random.rand(n,m)
b = np.random.rand(k,m)
c = np.zeros((k,m))

for j in range(0,m): #cols
   for i in range(0,k):  # rows
     r = b[i,j]  
     c[i,j] = ( ( a[:,j] > r).sum() ) / (n) 

Tags: in元素目标for定义排序nprange
2条回答

我认为你可以使用广播:

c = (a[:,None,:] > b).mean(axis=0)

演示:

In [207]: n = 5

In [208]: m = 3

In [209]: a = np.random.randint(10, size=(n,m))

In [210]: b = np.random.randint(10, size=(n,m))

In [211]: c = np.zeros((n,m))

In [212]: a
Out[212]:
array([[2, 2, 8],
       [5, 0, 8],
       [2, 5, 7],
       [4, 4, 4],
       [2, 6, 7]])

In [213]: b
Out[213]:
array([[3, 6, 8],
       [2, 7, 5],
       [8, 9, 2],
       [9, 8, 7],
       [2, 7, 2]])

In [214]: for j in range(0,m): #cols
     ...:    for i in range(0,n):  # rows
     ...:      r = b[i,j]
     ...:      c[i,j] = ( ( a[:,j] > r).sum() ) / (n)
     ...:
     ...:

In [215]: c
Out[215]:
array([[0.4, 0. , 0. ],
       [0.4, 0. , 0.8],
       [0. , 0. , 1. ],
       [0. , 0. , 0.4],
       [0.4, 0. , 1. ]])

In [216]: (a[:,None,:] > b).mean(axis=0)
Out[216]:
array([[0.4, 0. , 0. ],
       [0.4, 0. , 0.8],
       [0. , 0. , 1. ],
       [0. , 0. , 0.4],
       [0.4, 0. , 1. ]])

支票:

In [217]: ((a[:,None,:] > b).mean(axis=0) == c).all()
Out[217]: True

进近#1

我们可以再次使用argsort技巧,正如在^{}中讨论的那样,但是有点扭曲。我们将第二个数组连接到第一个数组中,然后执行argsort-ing。我们需要对级联数组和第二个数组使用argsort,并获得所需的输出。这个实现看起来像这样-

ab = np.vstack((a,b))
len_a, len_b = len(a), len(b)
b_argoffset = b.argsort(0).argsort(0)
total_args = ab.argsort(0).argsort(0)[-len_b:]
out = len_a - total_args + b_argoffset

解释

  1. 将要计算其值的第二个数组连接到第一个数组中。你知道吗
  2. 现在,由于我们正在追加,我们将稍后在第一个数组长度结束后获得它们的索引位置。你知道吗
  3. 我们使用一个argsort来获得第二个数组w.r.t到整个级联数组的相对位置,并使用另一个argsort来追溯这些索引w.r.t的原始顺序。你知道吗
  4. 我们需要对自身上的第二个数组重复doubleargsort-ing,以便补偿串联。你知道吗
  5. 这些索引针对b中的每个元素,比较:a[:,j] > b[i,j]。现在,这些索引顺序是基于0的,即接近0的索引表示a[:,j]中的元素数大于当前元素b[i,j],因此计数更大,反之亦然。因此,我们需要从a[:,j]的长度中减去这些索引,得到最终的输出。你知道吗

方法#1-改善

我们将通过使用array-assignment来进一步优化它,同样是受到来自同一解决方案的Approach #2的启发。因此,这些arg输出:b_argoffsettotal_args可以交替计算,就像这样-

def unqargsort(a):
    n,m = a.shape     
    idx = a.argsort(0)
    out = np.zeros((n,m),dtype=int)
    out[idx, np.arange(m)] = np.arange(n)[:,None]
    return out

b_argoffset = unqargsort(b)

total_args = unqargsort(ab)[-len_b:]

进近#2

我们还可以利用^{}实现一种完全不同的方法-

k,m = b.shape
sidx = a.argsort(0)
out = np.empty((k,m), dtype=int)
for i in range(m): #cols
    out[:,i] = np.searchsorted(a[:,i], b[:,i],sorter=sidx[:,i])
out = len(a) - out  

解释

  1. 我们得到a的每一列的排序顺序索引。你知道吗
  2. 然后,使用这些索引来获得如何将值从b放入排序后的a中,使用searcshorted。这与{}中步骤#3,4的输出相同。你知道吗

请注意,这些方法为我们提供了计数。因此,对于最终的输出,将得到的输出除以n。你知道吗

相关问题 更多 >