将布尔True计数数组映射到布尔数组的最快方法

时间:2020-09-10 21:20:25

标签: python numpy scipy

我有一个要映射到2D数组的布尔“真”计数的1D数组。

#Array of boolean True counts
b = [1,3,2,5]

#want this 2D array:

[1,1,1,1]
[0,1,1,1]
[0,1,0,1]
[0,0,0,1]
[0,0,0,1]

实现速度越快(NumPy / SciPy)越好。 谢谢

4 个答案:

答案 0 :(得分:2)

使用np.tri和高级索引的纯numpy方法:

b = np.array([1,3,2,5])
k = b.max()
np.tri(k+1,k,-1,dtype=int)[b].T
# array([[1, 1, 1, 1],
#        [0, 1, 1, 1],
#        [0, 1, 0, 1],
#        [0, 0, 0, 1],
#        [0, 0, 0, 1]])

更新:

如果k >> len(b),则两个soln应该更好地工作。基准测试中的m5m6

从第二个条件@Ehsan借来并扩展的基准代码。更改:添加了m5,m6。将最大测试大小从1000减少到200。将输出dtype从int更改为int8。

enter image description here

有趣的观察;我的原始解决方案m2在(低RAM)计算机上的性能比@Ehsan的计算机差得多。

代码(仅适用于新功能):

#@Paul's solution 2
def m5(b):
  k = b.max()
  n = b.size
  return (np.arange(1,2*n+1,dtype=np.int8)&1).repeat(np.ravel([b,k-b],order="F")).reshape(k,n,order="F")

#@Paul's solution 3
def m6(b):
  k = b.max()
  mytri = np.array([1,0],dtype=np.int8).repeat(k)
  mytri = np.lib.stride_tricks.as_strided(mytri[k:],(k,k+1),
                                          (mytri.strides[0],-mytri.strides[0]))
  return mytri[:,b]

答案 1 :(得分:1)

尝试:

pd.DataFrame([[1]*x for x in [1,3,2,5]]).T.fillna(0).values

输出:

array([[1., 1., 1., 1.],
       [0., 1., 1., 1.],
       [0., 1., 0., 1.],
       [0., 0., 0., 1.],
       [0., 0., 0., 1.]])

答案 2 :(得分:1)

您可以创建所需形状的零数组:

arr = np.zeros((np.max(b), len(b)))

然后,您可以创建一个临时数组x = np.indices(arr.shape)[0],即:

array([[0, 0, 0, 0],
       [1, 1, 1, 1],
       [2, 2, 2, 2],
       [3, 3, 3, 3],
       [4, 4, 4, 4]])

然后像这样填充arr

arr[np.where(x<b)] = 1

答案 3 :(得分:1)

tri大的情况下无需创建b.max()的笨拙方法:

b = np.array([1,3,2,5])
r, c = b.size, b.max()
a = np.zeros((c,r), dtype=int)
a[np.arange(c)[:,None]<b] = 1

输出:

[[1 1 1 1]
 [0 1 1 1]
 [0 1 0 1]
 [0 0 0 1]
 [0 0 0 1]]

比较,使用benchit

#@Ehsan's solution
def m1(b):
  r, c = b.size, b.max()
  a = np.zeros((c,r), dtype=int)
  a[np.arange(c)[:,None]<b] = 1
  return a

#@Paul's solution
def m2(b):
  k = b.max()
  return np.tri(k+1,k,-1,dtype=int)[b].T

#@Binyamin's solution  
def m3(b):
  return pd.DataFrame([[1]*x for x in b]).T.fillna(0).values

#@mathfux's solution
def m4(b):
  arr = np.zeros((np.max(b), len(b)), dtype=int)
  x = np.indices(arr.shape)[0]
  arr[np.where(x<b)] = 1
  return arr

对于不同的输入:

in_ = [np.random.randint(100, size=n) for n in [10,100,1000,10000]]

enter image description here

in_ = [np.random.randint(n, size=n) for n in [10,100,1000,10000]]

enter image description here

因此,您选择的内容取决于您的b.max()值与b.size。对于较大的b.max()值(与b.size相比), m1 更快,对于较小的b.max()(与b.size相比), m2 似乎更快。


更新:添加新解决方案并与@Paul的新解决方案进行比较:

#@Ehsan's solution 2  
def m7(b):
  return np.less.outer(np.arange(b.max()),b)+0

或几乎相等:

def m8(b):
  return (np.arange(b.max())<b[:,None]).T+0

比较:

in_ = [np.random.randint(10, size=n) for n in [10,100,1000]]

enter image description here

in_ = [np.random.randint(10000, size=n) for n in [10,100,1000,10000]]

enter image description here

包括 m8

in_ = [np.random.randint(10000, size=n) for n in [10,100,1000]]

enter image description here

相关问题