我试图在一个numpy 3d数组中获得每个子数组的频率计数(没有零)。但是,scipy.stats.itemfreq工具返回二维数组中的频率计数。
我得到的是:
array_3d= array([[[1, 0, 0],
[1, 0, 0],
[0, 2, 0]],
[[0, 0, 0],
[0, 0, 3],
[3, 3, 3]],
[[0, 0, 4],
[0, 0, 4],
[0, 0, 4]]])
>>> itemfreq(array_3d)[1:,]
# outputs
array([ 1, 2],
[ 2, 1],
[ 3, 4],
[ 4, 3]], dtype=int64)
虽然我想要输出:
array([[ 1, 2, 2, 1],
[ 3, 4],
[ 4, 3]], dtype=object)
这个想法是,不均匀的数字始终是唯一值,偶数是频率。
另一个输出可能是:
array([ 1, 2, 0],
[ 2, 1, 0],
[ 3, 4, 1],
[ 4, 3, 2]], dtype=int64)
第三列表示3d数组中的子集编号。
我也对其他输出/解决方案持开放态度!
提前致谢!
答案 0 :(得分:1)
方法#1
这是使用NumPy broadcasting
-
# Get unique non-zero elements
unq = np.unique(array_3d[array_3d!=0])
# Get matches mask corresponding to all array_3d elements against all unq elements
mask = array_3d == unq[:,None,None,None]
# Get the counts
sums = mask.sum(axis=(2,3)).T
# Indices of non-zero(valid) counts
Rvalid,Cvalid = np.where(sums!=0)
# Finally, pressent the output in the desired format
out = np.column_stack((unq[Cvalid],sums[sums!=0],Rvalid))
请注意,这将是一种资源匮乏的方法。
方法#2
这是另一种资源匮乏的方法,因此可能更受欢迎 -
a2d = np.sort(array_3d.reshape(array_3d.shape[0],-1),axis=1)
start_mask = np.column_stack((a2d[:,0] !=0,np.diff(a2d,axis=1)>0))
unqID = a2d + ((np.arange(a2d.shape[0])*a2d.max())[:,None])
count = np.unique(unqID[a2d!=0],return_counts=True)[1]
out = np.column_stack((a2d[start_mask],count,np.where(start_mask)[0]))
请注意,count
可以使用np.bincount
计算,也可能更快,就像这样 -
C = np.bincount(unqID[a2d!=0])
count = C[C!=0]
答案 1 :(得分:1)
numpy_indexed包(免责声明:我是它的作者)可用于以优雅和矢量化的方式解决这个问题:
import numpy_indexed as npi
index = np.arange(array_3d.size) // array_3d[0].size
(value, index), count = npi.count((array_3d.flatten(), index))
然后给出:
index = [0 0 0 1 1 2 2]
value = [0 1 2 0 3 0 4]
count = [6 2 1 5 4 6 3]
可以通过索引值>进行后处理;如果需要,则为0
答案 2 :(得分:0)
熊猫也给出了这个结果的直观方式:
df = pd.DataFrame(array_3d.reshape(3,9))
stats = df.apply(lambda x : unique(x,return_counts=True),axis=1)
result = stats.apply(lambda x : vstack(x)[:,1:].ravel())
对于
#stats
0 ([0, 1, 2], [6, 2, 1])
1 ([0, 3], [5, 4])
2 ([0, 4], [6, 3])
#result
0 [1, 2, 2, 1]
1 [3, 4]
2 [4, 3]