最善の方法は、データが大きい場所に依存すると思います。
- ほとんどのカウントが小さい巨大なマトリックスがありますか? また
- 膨大な数のカウントを含む適度なサイズのマトリックスがありますか?
これは 2 番目のケースに適した解決策ですが、最初のケースでも問題なく機能します。
基本的に、カウントがたまたま 2D マトリックスにあるという事実はそれほど重要ではありません。これは基本的に、ビニングされた母集団からのサンプリングの問題です。したがって、できることはビンを直接抽出することであり、マトリックスについては少し忘れてください。
import numpy as np
import random
# Input counts matrix
mat = np.array([
[5, 5, 2],
[1, 1, 3],
[6, 0, 4]
], dtype=np.int64)
# Build a list of (row,col) pairs, and a list of counts
keys, counts = zip(*[
((i,j), mat[i,j])
for i in range(mat.shape[0])
for j in range(mat.shape[1])
if mat[i,j] > 0
])
そして、カウントの累積配列を使用して、これらのビンからサンプリングします。
# Make the cumulative counts array
counts = np.array(counts, dtype=np.int64)
sum_counts = np.cumsum(counts)
# Decide how many counts to include in the sample
frac_select = 0.30
count_select = int(sum_counts[-1] * frac_select)
# Choose unique counts
ind_select = sorted(random.sample(xrange(sum_counts[-1]), count_select))
# A vector to hold the new counts
out_counts = np.zeros(counts.shape, dtype=np.int64)
# Perform basically the merge step of merge-sort, finding where
# the counts land in the cumulative array
i = 0
j = 0
while i<len(sum_counts) and j<len(ind_select):
if ind_select[j] < sum_counts[i]:
j += 1
out_counts[i] += 1
else:
i += 1
# Rebuild the matrix using the `keys` list from before
out_mat = np.zeros(mat.shape, dtype=np.int64)
for i in range(len(out_counts)):
out_mat[keys[i]] = out_counts[i]
これで、サンプリングされたマトリックスが に作成されout_mat
ます。