【问题标题】:Frequency count per sub array or slice in a 3D NumPy array3D NumPy 数组中每个子数组或切片的频率计数
【发布时间】:2016-08-24 10:43:01
【问题描述】:

我正在尝试获取 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 数组中的子集编号。

我也对其他输出/解决方案持开放态度!

提前致谢!

【问题讨论】:

  • 您能描述一下您要解决的更高层次的问题吗?

标签: python arrays numpy scipy frequency


【解决方案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 的索引进行后处理

【讨论】:

  • 我认为 OP 正在寻找每个子数组或切片的计数。这样flatten 就会与期望的输出相矛盾。
  • 这个例子是做什么的;计算的是 'array_3d.flatten()' 和 'index' 的唯一组合
  • 啊,我明白了!好的。避免零点怎么样?避免输出的第一个元素?
  • 我认为最优雅的处理方式是使用 count[value>0] 进行后处理
【解决方案2】:

方法#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]

【讨论】:

  • 感谢您的评论。这种方法效果很好 wen array_3d 比较小。但是,我的 array_3d 有 89528 个子数组。很可能,这就是掩码不起作用的原因,因为掩码数组变大了。
  • @WilmarvanOmmeren 是的,这肯定是资源匮乏的方法。
  • @WilmarvanOmmeren 你能看看刚刚添加的第二种方法吗?谢谢!
  • @WilmarvanOmmeren 很高兴听到这个消息! :)
【解决方案3】:

Pandas 也为这个结果提供了直观的方法:

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]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-05
    • 2015-09-12
    • 2018-05-27
    相关资源
    最近更新 更多