【问题标题】:Any idea to optimise this algorithm?有什么想法可以优化这个算法吗?
【发布时间】:2023-03-18 03:15:01
【问题描述】:

假设我有一个二进制40*40 矩阵。 在这个矩阵中,值可以是 1 也可以是 0。

我需要解析整个矩阵,对于任何值 == 1,应用以下内容:

如果满足以下条件,则保持值 = 1,否则将值修改回 0:

条件:在N*N的正方形中(以当前评估值为中心),我至少可以数M个值== 1。

N 和 M 是可以为算法设置的参数,自然是N<20(在这种情况下)和M<(N*N - 1)

显而易见的算法是迭代整个图像,然后每次一个值 == 1。围绕这个值执行另一个搜索。它会产生一个 O^3 复杂的算法。有什么想法可以提高效率吗?

编辑:一些代码使这更容易理解。

让我们创建一个随机初始化的 40*40 的 1 和 0 矩阵。 5%(任意选择)的值为 1,95% 的值为 0。

import matplotlib.pyplot as plt
import numpy as np

%matplotlib inline

def display_array(image):
    image_display_ready = image * 255

    print(image_display_ready)

    plt.imshow(image_display_ready, cmap='gray')
    plt.show()

image = np.zeros([40,40])

for _ in range(80):  # 5% of the pixels are == 1
    i, j = np.random.randint(40, size=2)
    image[i, j] = 1

# Image displayed on left below before preprocessing    
display_array(image)   

def cleaning_algorithm_v1(src_image, FAT, LR, FLAG, verbose=False):
    """
    FAT  = 4 # False Alarm Threshold (number of surrounding 1s pixel values)
    LR   = 8 # Lookup Range +/- i/j value
    FLAG = 2 # 1s pixels kept as 1s after processing are flag with this value.
    """

    rslt_img = np.copy(src_image)

    for i in range(rslt_img.shape[0]):
        for j in  range(rslt_img.shape[1]):

            if rslt_img[i, j] >= 1:

                surrounding_abnormal_pixels = list()

                lower_i = max(i - LR, 0)
                upper_i = min(i + LR + 1, rslt_img.shape[0])

                lower_j = max(j - LR, 0)
                upper_j = min(j + LR + 1, rslt_img.shape[1])

                abnormal_pixel_count = 0

                for i_k in range(lower_i, upper_i):
                    for j_k in range(lower_j, upper_j):

                        if i_k == i and j_k == j:
                            continue

                        pixel_value = rslt_img[i_k, j_k]

                        if pixel_value >= 1:
                            abnormal_pixel_count += 1

                if abnormal_pixel_count >= FAT:
                    rslt_img[i, j] = FLAG

    rslt_img[rslt_img != FLAG] = 0
    rslt_img[rslt_img == FLAG] = 1

    return rslt_img

# Image displayed on right below after preprocessing  
display_array(cleaning_algorithm_v1(image, FAT=10, LR=6, FLAG=2))

这给出了以下内容:

【问题讨论】:

  • 其实你建议的算法复杂度是O((M^2)*(N^2))。您解析 M^2 个位置的矩阵,并且每当找到值 1 时,您就解析另一个 N^2 个位置的矩阵。最坏的情况,你可以找到 M^2 个(MxM 矩阵都是 1)。
  • 矩阵是 40x40 吗?时间复杂度只有在渐近极限的情况下才有意义......
  • 被评估的位置靠近边缘是什么情况? (正方形是否被缠绕或截断或......?)
  • 好吧,我不知道如何降低复杂性,但鉴于您在运行时知道 N 和 M,您可以为每个大小为 N^ 的点(即 40^2)生成一个矩阵2 并计算每个矩阵的值。 但是,就像@unutbu 指出的那样,您没有提到极端情况。此外,如果您切换其中一个值,未来点会发生什么?你用旧的还是新的切换的?如果是旧的,我的建议是让它尴尬地并行工作,否则它会中断。所以你可能想在你的问题中说明这一点。
  • @haris-nadeem 我只使用原始矩阵作为源而不是修改后的版本

标签: python algorithm matrix binary time-complexity


【解决方案1】:

使用卷积怎么样?

您的内核将是一个 1 的 NxN 窗口。在这种情况下,内核是可分离的,因此您可以将卷积处理为 2 个一维卷积。你可以这样做:

import numpy as np
from scipy.ndimage.filters import convolve1d
from time import time

mat = np.random.random_integers(0, 1, (40, 40))

N = 5
M = 15

window = np.ones((N, ), dtype=np.int)

start = time()

interm = convolve1d(mat, window, axis=0)
result = convolve1d(interm, window, axis=1)

[rows, cols] = np.where(result >= M)
result[:, :] = 0
result[(rows, cols)] = 1

end = time()
print "{} seconds".format(end - start)
0.00155591964722 seconds

不确定复杂度如何比较,但卷积在各种 python 深度学习库中得到了很好的优化。

【讨论】:

  • 由于你的一维卷积核都是[1, 1, 1, 1, ..., 1] 的形式,你可以在 O(N) 时间内递增地计算它们(当应用于长度为 N 的行或列时)。我猜 numpy 不能自动执行这个优化。
  • 我绝对没有想过使用卷积,这是一个了不起的想法!让我们看看它是如何比较的!
  • 该死的,有关信息@william-yolland,你的提议快了 10 倍:D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多