如何用numpy/pandas计算"子矩阵"条目的总和?

Sha*_*ang 4 python numpy matrix pandas

我在Python中有以下8x8矩阵,我将其表示为8×8 numpy数组或pandas DataFrame:

import numpy as np
import pandas as pd

x = range(64)

x = np.reshape(x,(8,8)) 

print(x)

# [[ 0  1  2  3  4  5  6  7]
#  [ 8  9 10 11 12 13 14 15]
#  [16 17 18 19 20 21 22 23]
#  [24 25 26 27 28 29 30 31]
#  [32 33 34 35 36 37 38 39]
#  [40 41 42 43 44 45 46 47]
#  [48 49 50 51 52 53 54 55]
#  [56 57 58 59 60 61 62 63]]

df = pd.DataFrame(x)

print(df)

#      0   1   2   3   4   5   6   7
#  0   0   1   2   3   4   5   6   7
#  1   8   9  10  11  12  13  14  15
#  2  16  17  18  19  20  21  22  23
#  3  24  25  26  27  28  29  30  31
#  4  32  33  34  35  36  37  38  39
#  5  40  41  42  43  44  45  46  47
#  6  48  49  50  51  52  53  54  55
#  7  56  57  58  59  60  61  62  63
Run Code Online (Sandbox Code Playgroud)

我试图计算值的总和,如果它是一个2乘2的矩阵,并用这个和替换上面的值.我的最终结果是

#      0   1   2   3   4   5   6   7
#  0  216  216  216  216  280  280  280  280
#  1  216  216  216  216  280  280  280  280
#  2  216  216  216  216  280  280  280  280
#  3  216  216  216  216  280  280  280  280
#  4  728  728  728  728  792  792  792  792
#  5  728  728  728  728  792  792  792  792
#  6  728  728  728  728  792  792  792  792
#  7  728  728  728  728  792  792  792  792
Run Code Online (Sandbox Code Playgroud)

因此,顶角矩阵的计数为216

0+1+2+3+8+9+10+11+16+17+18+19+24+25+26+27=216
Run Code Online (Sandbox Code Playgroud)

同样的,

32+33+34+35+40+41+42+43+48+49+50+51+56+57+58+59=728
4+5+6+7+12+13+14+15+20+21+22+23+28+29+30+31=280
36+37+38+39+44+45+46+47+52+53+54+55+60+61+62+63=792
Run Code Online (Sandbox Code Playgroud)

是否有numpy/pandas功能使这个计算更容易?特别是对于更大的矩阵,手动设置"和矩阵"的坐标可能非常麻烦.

jde*_*esa 5

使用NumPy的一种方法是:

import numpy as np

def as_submatrices(x, rows, cols=None, writeable=False):
    from numpy.lib.stride_tricks import as_strided
    if cols is None: cols = rows
    x = np.asarray(x)
    x_rows, x_cols = x.shape
    s1, s2 = x.strides
    if x_rows % rows != 0 or x_cols % cols != 0:
        raise ValueError('Invalid dimensions.')
    out_shape = (x_rows // rows, x_cols // cols, rows, cols)
    out_strides = (s1 * rows, s2 * cols, s1, s2)
    return as_strided(x, out_shape, out_strides, writeable=writeable)

def sum_submatrices(x, rows, cols=None):
    if cols is None: cols = rows
    x = np.asarray(x)
    x_sub = as_submatrices(x, rows, cols)
    x_sum = np.sum(x_sub, axis=(2, 3))
    x_rows, x_cols = x.shape
    return np.repeat(np.repeat(x_sum, rows, axis=0), cols, axis=1)

x = np.arange(64).reshape((8, 8))

print(sum_submatrices(x, 4))
# [[216 216 216 216 280 280 280 280]
#  [216 216 216 216 280 280 280 280]
#  [216 216 216 216 280 280 280 280]
#  [216 216 216 216 280 280 280 280]
#  [728 728 728 728 792 792 792 792]
#  [728 728 728 728 792 792 792 792]
#  [728 728 728 728 792 792 792 792]
#  [728 728 728 728 792 792 792 792]]

print(sum_submatrices(x, 2))
# [[ 18  18  26  26  34  34  42  42]
#  [ 18  18  26  26  34  34  42  42]
#  [ 82  82  90  90  98  98 106 106]
#  [ 82  82  90  90  98  98 106 106]
#  [146 146 154 154 162 162 170 170]
#  [146 146 154 154 162 162 170 170]
#  [210 210 218 218 226 226 234 234]
#  [210 210 218 218 226 226 234 234]]

print(sum_submatrices(x, 2, 8))
# [[120 120 120 120 120 120 120 120]
#  [120 120 120 120 120 120 120 120]
#  [376 376 376 376 376 376 376 376]
#  [376 376 376 376 376 376 376 376]
#  [632 632 632 632 632 632 632 632]
#  [632 632 632 632 632 632 632 632]
#  [888 888 888 888 888 888 888 888]
#  [888 888 888 888 888 888 888 888]]
Run Code Online (Sandbox Code Playgroud)

编辑: 正如Divakar指出,np.broadcast_to更快的是np.repeat在这里,所以该功能的改进版本上面会:

def sum_submatrices(x, rows, cols=None):
    if cols is None: cols = rows
    x = np.asarray(x)
    x_sub = as_submatrices(x, rows, cols)
    x_sum = np.sum(x_sub, axis=(2, 3), keepdims=True)
    x_sum = np.broadcast_to(x_sum, x_sub.shape)
    return x_sum.transpose((0, 2, 1, 3)).reshape(x.shape)
Run Code Online (Sandbox Code Playgroud)

这与Divakar的答案基本相同,只有一个更好,因为它不使用步幅技巧和转置.