我有一个要映射到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)越好。 谢谢
答案 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应该更好地工作。基准测试中的m5
和m6
。
从第二个条件@Ehsan借来并扩展的基准代码。更改:添加了m5,m6。将最大测试大小从1000减少到200。将输出dtype从int更改为int8。
有趣的观察;我的原始解决方案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]]
in_ = [np.random.randint(n, size=n) for n in [10,100,1000,10000]]
因此,您选择的内容取决于您的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]]
in_ = [np.random.randint(10000, size=n) for n in [10,100,1000,10000]]
包括 m8 :
in_ = [np.random.randint(10000, size=n) for n in [10,100,1000]]