首页 文章

计算2D NumPy数组中每行和每列内的非零元素

提问于
浏览
18

我有一个 NumPy 矩阵,主要包含非零值,但有时会包含零值 . 我需要能够:

  • 计算每行中的非零值,并将该计数放入我可以在后续操作中使用的变量中,可能通过迭代行索引并在迭代过程中执行计算 .

  • 计算每列中的非零值,并将该计数放入我可以在后续操作中使用的变量中,可能通过迭代列索引并在迭代过程中执行计算 .

例如,我需要做的一件事是对每一行求和,然后将每行和除以每行中的非零值的数量,为每个行索引报告单独的结果 . 然后我需要对每列进行求和,然后将列总和除以列中非零值的数量,同时为每个列索引报告单独的结果 . 我还需要做其他事情,但在我弄清楚如何处理我在这里列出的内容后,它们应该很容易 .

我正在使用的代码如下 . 您可以看到我正在创建一个零数组,然后从 csv 文件中填充它 . 某些行将包含所有列的值,但其他行仍会在某些最后一列中保留一些零,从而产生上述问题 .

以下代码的最后五行来自此论坛上的另一个帖子 . 最后五行代码返回零的行/列索引的打印列表 . 但是,我不知道如何使用该结果信息来创建上述的非零行计数和非零列计数 .

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))

谁能帮我这个?

4 回答

  • 14
    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 元素的数量 .

    变量 columnsrows 包含原始数组的每列/每行中的非零(元素!= 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)
    

    EDIT 2

    要获取所有列/行的平均值,请使用以下命令:

    colMean = a.sum(0) / (a != 0).sum(0)
    rowMean = a.sum(1) / (a != 0).sum(1)
    

    如果列/行中没有非零元素,您想要做什么?然后我们可以调整代码来解决这个问题 .

  • 29

    在scipy稀疏矩阵 m 中计算每行非零元素的快速方法是:

    np.diff(m.tocsr().indptr)
    

    CSR矩阵的 indptr 属性指示数据内与行之间的边界对应的索引 . 因此,计算每个条目之间的差异将提供每行中非零元素的数量 .

    同样,对于每列中的非零元素数,请使用:

    np.diff(m.tocsc().indptr)
    

    如果数据已经是适当的形式,它们将分别在O( m.shape[0] )和O( m.shape[1] )中运行,而不是在Marat和Finn的解决方案中运行O( m.getnnz() ) .

    如果您需要行和列nozero计数,并且,例如 m 已经是CSR,您可以使用:

    row_nonzeros = np.diff(m.indptr)
    col_nonzeros = np.bincount(m.indices)
    

    这并不比第一次转换到CSC(即O( m.getnnz() ))得到 col_nonzeros 的速度快,但由于实现细节而更快 .

  • 0

    更快的方法是使用1而不是实际值来克隆矩阵 . 然后只按行或列总结:

    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倍(1秒对53)

    编辑:也许您需要将NumNonZeroElementsByColumn转换为1维数组

    np.array(NumNonZeroElementsByColumn)[0]
    
  • 2

    (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.
    

    我想知道是否有更优雅的方式 .

相关问题