2016-04-29 71 views
2

我試圖獲得numpy 3d數組中每個子陣列的頻率計數(無零)。但是,scipy.stats.itemfreq工具會返回2d數組中的頻率計數。3D NumPy數組中每個子陣列或切片的頻率計數

我得到的是:

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

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如果需要的話

+0

我認爲OP正在尋找每個子陣列或切片的計數。因此,「扁平化」會與期望的輸出相矛盾。 – Divakar

+0

這是什麼樣的例子;什麼是計數'array_3d.flatten()'和'索引' –

+0

啊我看到的獨特組合!尼斯。怎麼樣避免零?避免輸出的第一個元素? – Divakar

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] 
+0

感謝您的評論。這個方法工作完美,array_3d相對較小。不過,我的array_3d有89528個子陣列。最有可能的是,這是掩碼不工作的原因,因爲掩碼數組變得很大。 –

+0

@WilmarvanOmmeren是的,這肯定會是資源飢餓的方法。 – Divakar

+1

@WilmarvanOmmeren你可以看看剛添加的第二種方法嗎?謝謝! – Divakar

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]