簡體   English   中英

3D NumPy 數組中每個子數組或切片的頻率計數

[英]Frequency count per sub array or slice in a 3D NumPy array

我正在嘗試獲取 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 數組中的子集數。

我也對其他輸出/解決方案持開放態度!

提前致謝!

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

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 對其進行后處理

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]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM