1

たとえば、ペアをリストするテキストファイルがあります

10,1
2,7
3,1
10,1

これは対称行列に変換されているため、(1,10) エントリはペア (1,10) がリストに表示された回数です。このマトリックスをサブサンプリングしたいと思います。サブサンプルとは、元のテキスト ファイルの行のランダムな 30% のみを使用した結果のマトリックスを作成したいと考えています。したがって、この例では、テキスト ファイルの 70% を消去した場合、(1,10) ペアは 2 回ではなく 1 回しか表示されないため、行列の (1,10) エントリは 2 ではなく 1 になります。

元のテキスト ファイルが実際にある場合、random.sample を使用してファイル内の行の 30% を選択するだけで、これは簡単に実行できます。しかし、行列しかない場合、データの 70% をランダムに間引くにはどうすればよいでしょうか?

4

3 に答える 3

1

残念ながら、例 2 と 3 では、元のファイルの行数に応じた正しい分布が観察されません。

元のデータからタプルを削除する代わりに、マトリックスからカウントをランダムに削除できます。したがって、ランダムなインデックスを生成し、対応するカウントを減らす必要があります。ゼロ カウントを減らさないようにして、代わりに新しいインデックスを生成してください。カウントされたタプルの全体量が 30% に減少するまで、これを行います。基本的に、これは次のようになります。

amount_to_decrease = 0.7 * overall_amount

decreased = 0

while decreased < amount_to_decrease:
    x = random.randint(0, n)
    y = random.randint(0, n)
    if matrix[x][y] > 0:
        matrix[x][y]-=1
        decreased+=1
        if x != y:
            matrix[y][x]-=1

これは、マトリックスが十分に取り込まれている場合にうまく機能するはずです。そうでない場合 マトリックスからタプルのリストを再作成し、そこからランダムなサブセットを選択することができます。この後、残りのタプルからマトリックスを再作成します。

tuples = []
for y in range(n):
    for x in range(y+1):
        for _ in range(matrix[x][y])
            tuples.append((x,y))
remaining = random.sample(tuples, int(overall_amount*0.7) )

または、ゼロではないすべてのインデックスを見つけるために最初のパスを実行し、次にこれらをサンプリングしてカウントを減らす組み合わせを実行できます。

valid_indices = []
for y in range(n):
    for x in range(y+1):
        valid_indices.append((x,y))

amount_to_decrease = 0.7 * overall_amount
decreased = 0
while decreased < amount_to_decrease:
    x,y = random.choice(valid_indices)
    matrix[x][y]-=1
    if x != y:
        matrix[y][x]-=1
    if matrix[y][x] == 0:
        valid_indices.remove((x,y))

適切な可能性を使用する別のアプローチがありますが、正確な削減が得られない場合があります。アイデアは、ライン/カウントを維持する確率を設定することです。30% までの削減を目指している場合、これは 0.3 になる可能性があります。次に、マトリックスを調べて、すべてのカウントを保持する必要があるかどうかを確認できます。

keep_chance = 0.3
for y in range(n):
    for x in range(y+1):
        for _ in range(matrix[x][y])
            if random.random() > keep_chance:
                matrix[x][y] -= 1
                if x != y:
                    matrix[y][x]-=1
于 2012-08-05T17:01:19.400 に答える
1

最善の方法は、データが大きい場所に依存すると思います。

  • ほとんどのカウントが小さい巨大なマトリックスがありますか? また
  • 膨大な数のカウントを含む適度なサイズのマトリックスがありますか?

これは 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ます。

于 2012-08-05T17:15:33.910 に答える
0

対 1,10 と 10,1 が異なると仮定すると、mat[1][10] は必ずしも mat[10][1] と同じではありません (そうでない場合は、行の下を読んでください)。

最初に、行列内のすべての値の合計を計算します。

この合計をSとします。これにより、ファイル内の行数がカウントされます。

xとyを行列の次元とします

次に、 nを 0 から [S の 70%] までループします。

  • 1 から x までのランダムな整数を選択します。これをjとする
  • 1 から y までのランダムな整数を選択します。これをkとする
  • mat[j][k] > 0 の場合、mat[j][k] を減らして n++ を実行

ファイルの行ごとに行列の単一の値を増やすため、行列の正の値をランダムに減らすことは、ファイルの行を間引くことと同じです。


10,1 が 1,10 と同じ場合、行列の半分は必要ないため、次のようにアルゴリズムを変更できます。

0 から [S の 70%] までのnのループ:

  • 1 から x までのランダムな整数を選択します。これをjとする
  • 1 から k の間のランダムな整数を選択します。これをkとする
  • mat[j][k] > 0 の場合、mat[j][k] を減らして n++ を実行
于 2012-08-05T16:59:36.097 に答える