繁体   English   中英

仅使用纯 python 将矩阵中的每一行与每一列进行比较

[英]compare each row with each column in matrix using only pure python

我有一个我制作的 function,我想在矩阵的每一列和每一行上运行它,以检查是否有行和列产生相同的 output。

例如:

matrix = [[1,2,3],
          [7,8,9]]

我想运行 function,我们称之为myfun ,在每一列[1,7][2,8][3,9]上分别运行,并且在每一行[1,2,3][7,8,9] 如果有一行和一列产生相同的结果,计数器ct将 go 增加 1。所有这些都可以在另一个 function 中找到,称为count_good ,它基本上计算产生相同结果的行和列。

这是到目前为止的代码:

def count_good(mat):
    ct = 0
    for i in mat:
        for j in mat:
            if myfun(i) == myfun(j):
                ct += 1
    return ct
            

但是,当我使用 print 检查我的代码时,我得到了这个:

mat = [[1,2,3],[7,8,9]]
​
for i in mat:
    for j in mat:
        print(i,j)
​
[1, 2, 3] [1, 2, 3]
[1, 2, 3] [7, 8, 9]
[7, 8, 9] [1, 2, 3]
[7, 8, 9] [7, 8, 9]

我看到代码没有返回我需要的'这意味着count_good function 将不起作用。 如何在每一行和每一列上运行 function? 我需要在没有任何外部库帮助的情况下做到这一点,没有mapzip或类似的东西,只有非常纯的 python。

让我们从使用itertoolscollections开始,然后将其转换回“纯” python。

from itertools import product, starmap, chain # combinations?
from collections import Counter

要有效地迭代嵌套循环,您可以使用itertools.product 您也可以使用starmap扩展 function 的 arguments。 这是myfun在行上的值的生成器:

starmap(myfun, product(matrix, repeat=2))

要转置矩阵并遍历列,请使用zip(*习惯用法:

starmap(myfun, product(zip(*matrix), repeat=2))

您可以使用collections.Counter to map 每个可能的返回值的所有重复:

Counter(starmap(myfun, chain(product(matrix, repeat=2), product(zip(*matrix), repeat=2))))

如果您想避免在相同元素上运行myfun ,请将product(..., repeat=2)替换为combinations(..., 2)

现在您已经了解了如何执行此操作,请将所有外部库的内容替换为等效的内置函数:

counter = {}
for i in range(len(matrix)):
    for j in range(len(matrix)):
        result = myfun(matrix[i], matrix[j])
        counter[result] = counter.get(result, 0) + 1
for i in range(len(matrix[0])):
    for j in range(len(matrix[0])):
        c1 = [matrix[row][i] for row in range(len(matrix))]
        c2 = [matrix[row][j] for row in range(len(matrix))]
        result = myfun(c1, c2)
        counter[result] = counter.get(result, 0) + 1

如果您想要组合,请将循环对替换为

for i in range(len(...) - 1):
    for j in range(i + 1, len(...)):

使用本机 python:

def count_good(mat):
    ct = 0
    for row in mat:
        for col_idx in range(len(mat[0])):
            column = [x[col_idx] for x in mat]
            if myfun(row) == myfun(column):
                ct += 1
    return ct

但是,这是非常低效的,因为它是一个三重嵌套的 for 循环。 我建议改用 numpy。

例如

def count_good(mat):
    ct = 0
    mat = np.array(mat)
    for row in mat:
        for column in mat.T:
            if myfun(row) == myfun(column):
                ct += 1
    return ct

TL;博士
要从 N 个 M 元素列表的 2D 列表中获取一列,首先将列表展平为 N×M 元素的 1D 列表,然后从 1D 列表中选择步幅等于 M(列数)的元素,为您提供原始二维列表的一列。


首先,我创建一个随机整数矩阵,作为等长列表的列表——这里我从“纯”Python 的目标中获得一些自由,OP 可能会手动输入一些分配的矩阵。

from random import randrange, seed
seed(20220914)
dim = 5
matrix = [[randrange(dim) for column in range(dim)] for row in range(dim)]
print(*matrix, sep='\n')

我们需要将 function 应用于矩阵的每一行和每一列,我打算将其作为列表提供。 在这里,我选择了一个简单的元素总和。

def myfun(l_st):
    the_sum = 0
    for value in l_st: the_sum = the_sum+value
    return the_sum

为了继续,我们将做一些意想不到的事情,即我们展开矩阵,从一个空列表开始,我们对行进行循环并将当前行“求和”为unwrapped ,请注意,将两个列表相加会给您一个列表包含两个列表的所有元素。

unwrapped = []
for row in matrix: unwrapped = unwrapped+row

下面我们将需要矩阵中的列数,这个数字可以通过计算矩阵最后一行中的元素来计算。

ncols = 0
for value in row: ncols = ncols+1

现在,我们可以计算将myfunc应用于每一列产生的值,计算我们有多少次相同的值。

我们使用一个辅助变量start ,它初始化为零并在以下循环的每次迭代中递增,它使用一个虚拟变量扫描当前行的所有元素,因此start的值为0, 1, ..., ncols-1 ,因此unwrapped[start::ncols]是一个列表,正好包含矩阵的一列。

count_of_column_values = {}
start = 0
for dummy in row:
    column_value = myfun(unwrapped[start::ncols])
    if column_value not in count_of_column_values:
        count_of_column_values[column_value] = 1
    else:
        count_of_column_values[column_value] = count_of_column_values[column_value] + 1
    start = start+1

此时,我们已准备好将myfun应用于行

count = 0
for row in matrix:
    row_value = myfun(row)
    if row_value in count_of_column_values: count = count+count_of_column_values[row_value]
print(count)

执行上面的代码打印

[1, 4, 4, 1, 0]
[1, 2, 4, 1, 4]
[1, 4, 4, 0, 1]
[4, 0, 3, 1, 2]
[0, 0, 4, 2, 2]
3

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM