web-dev-qa-db-ja.com

2D NumPy配列の各行および各列内のゼロ以外の要素をカウントする

ほとんどが非ゼロの値を含むNumPyマトリックスがありますが、時々ゼロの値が含まれます。次のことができる必要があります。

  1. 各行のゼロ以外の値を数え、その数を変数に入れます。これは、おそらく行のインデックスを繰り返し処理し、反復処理中に計算を実行することによって、後続の操作で使用できます。

  2. 各列のゼロ以外の値をカウントし、そのカウントを変数に入れます。おそらく、列のインデックスを反復処理し、反復処理中に計算を実行することによって、その後の操作で使用できます。

たとえば、私がする必要がある1つのことは、各行を合計し、各行の合計を各行のゼロ以外の値の数で除算して、各行インデックスの個別の結果を報告することです。次に、各列を合計し、列の合計を列内のゼロ以外の値の数で除算する必要があります。また、各列インデックスの個別の結果を報告します。他のことも行う必要がありますが、ここに記載していることを実行する方法を理解した後は、簡単にできるはずです。

私が使用しているコードは以下のとおりです。ゼロの配列を作成してcsvファイルから入力していることがわかります。一部の行にはすべての列の値が含まれますが、他の行には最後の列の一部にゼロが残っているため、上記の問題が発生します。

以下のコードの最後の5行は、このフォーラムの別の投稿からのものです。これらの最後の5行のコードは、ゼロの行/列インデックスの印刷リストを返します。ただし、その結果の情報を使用して、上記のゼロ以外の行カウントとゼロ以外の列カウントを作成する方法がわかりません。

ANOVAInputMatrixValuesArray=zeros([len(TestIDs),9],float)
j=0
for j in range(0,len(TestIDs)):
    TestID=str(TestIDs[j])
    ReadOrWrite='Read'
    fileName=inputFileName
    directory=GetCurrentDirectory(arguments that return correct directory)
    inputfile=open(directory,'r')
    reader=csv.reader(inputfile)
    m=0
    for row in reader:
        if m<9:
            if row[0]!='TestID':
                ANOVAInputMatrixValuesArray[(j-1),m]=row[2]
                m+=1
    inputfile.close()

IndicesOfZeros = indices(ANOVAInputMatrixValuesArray.shape) 
locs = IndicesOfZeros[:,ANOVAInputMatrixValuesArray == 0]
pts = hsplit(locs, len(locs[0]))
for pt in pts:
    print(', '.join(str(p[0]) for p in pt))

誰かがこれを手伝ってくれる?

26
MedicalMath
_import numpy as np

a = np.array([[1, 0, 1],
              [2, 3, 4],
              [0, 0, 7]])

columns = (a != 0).sum(0)
rows    = (a != 0).sum(1)
_

変数_(a != 0)_は、元のaと同じ形状の配列であり、ゼロ以外のすべての要素のTrueが含まれています。

.sum(x)関数は、軸xの要素を合計します。 _True/False_要素の合計は、True要素の数です。

変数columnsおよびrowsには、元の配列の各列/行の非ゼロ(要素!= 0)値の数が含まれています。

_columns = np.array([2, 1, 3])
rows    = np.array([2, 3, 1])
_

[〜#〜] edit [〜#〜]:コード全体は次のようになります(元のコードをいくつか簡略化すると):

_ANOVAInputMatrixValuesArray = zeros([len(TestIDs), 9], float)
for j, TestID in enumerate(TestIDs):
    ReadOrWrite = 'Read'
    fileName = inputFileName
    directory = GetCurrentDirectory(arguments that return correct directory)
    # use directory or filename to get the CSV file?
    with open(directory, 'r') as csvfile:
        ANOVAInputMatrixValuesArray[j,:] = loadtxt(csvfile, comments='TestId', delimiter=';', usecols=(2,))[:9]

nonZeroCols = (ANOVAInputMatrixValuesArray != 0).sum(0)
nonZeroRows = (ANOVAInputMatrixValuesArray != 0).sum(1)
_

編集2

すべての列/行の平均値を取得するには、以下を使用します。

_colMean = a.sum(0) / (a != 0).sum(0)
rowMean = a.sum(1) / (a != 0).sum(1)
_

列/行にゼロ以外の要素がない場合はどうしますか?次に、そのような問題を解決するためにコードを適応させることができます。

34
eumiro

Scipyスパース行列mの行ごとにゼロ以外の要素を数える高速な方法は次のとおりです。

_np.diff(m.tocsr().indptr)
_

CSRマトリックスのindptr属性は、行間の境界に対応するデータ内のインデックスを示します。したがって、各エントリ間の差を計算すると、各行のゼロ以外の要素の数がわかります。

同様に、各列の非ゼロ要素の数については、以下を使用します。

_np.diff(m.tocsc().indptr)
_

データが既に適切な形式である場合、これらは-ではなく、それぞれO(_m.shape[0]_)およびO(_m.shape[1]_)で実行されます- O(m.getnnz() MaratおよびFinnの解法では。

行と列の両方のnozeroカウントが必要で、たとえば、mがすでにCSRである場合、次のように使用できます。

_row_nonzeros = np.diff(m.indptr)
col_nonzeros = np.bincount(m.indices)
_

これは、最初にCSCに変換する(つまりO(m.getnnz())よりも漸近的に高速ではありませんが、_col_nonzeros_を取得するには高速ですが、実装の詳細により高速です。

20
joeln

より速い方法は、実際の値ではなく行列を使って行列を複製することです。次に、行または列ごとに合計します。

X_clone = X.tocsc()
X_clone.data = np.ones( X_clone.data.shape )
NumNonZeroElementsByColumn = X_clone.sum(0)
NumNonZeroElementsByRow = X_clone.sum(1)

FinnÅrupNielsenのソリューションよりも50倍速くなりました(53に対して1秒)。

編集:おそらく、NumNonZeroElementsByColumnを1次元配列に変換する必要があります

np.array(NumNonZeroElementsByColumn)[0]
2

スパース行列の場合、CSR/CSC行列でサポートされているgetnnz()関数を使用します。

例えば。

a = scipy.sparse.csr_matrix([[0, 1, 1], [0, 1, 0]])
a.getnnz(axis=0)

array([0, 2, 1])
0
sandyp

(a!= 0)は、私の現在のバージョンのscipyのスパース行列(scipy.sparse.lil_matrix)では機能しません。

スパースマトリックスの場合:

    (i,j) = X.nonzero()
    column_sums = np.zeros(X.shape[1])
    for n in np.asarray(j).ravel():
        column_sums[n] += 1.

もっと上品な方法があるのか​​な。

0