Python 使用for循环查找两个数据集中最接近的值

Python 使用for循环查找两个数据集中最接近的值,python,matlab,numpy,Python,Matlab,Numpy,在MATLAB中,我能够通过以下代码识别数据_b中与数据_a中的值最接近的值,以及指示它们出现在矩阵中哪个位置的索引: clear all; close all; clc; data_a = [0; 15; 30; 45; 60; 75; 90]; data_b = randi([0, 90], [180, 101]); [rows_a,cols_a] = size(data_a); [rows_b,cols_b] = size(data_b); val1 = zeros(rows_a

在MATLAB中,我能够通过以下代码识别数据_b中与数据_a中的值最接近的值,以及指示它们出现在矩阵中哪个位置的索引:

clear all; close all; clc;

data_a = [0; 15; 30; 45; 60; 75; 90];
data_b = randi([0, 90], [180, 101]);

[rows_a,cols_a] = size(data_a);  
[rows_b,cols_b] = size(data_b);

val1 = zeros(rows_a,cols_b);
ind1 = zeros(rows_a,cols_b);

for i = 1:cols_b
    for j = 1:rows_a
        [val1(j,i),ind1(j,i)] = min(abs(data_b(:,i) - data_a(j)));
    end
end
由于我想逐步淘汰MATLAB(最终我将失去许可证),我决定在python中尝试同样的方法,但没有任何运气:

import numpy as np

data_a = np.array([[0],[15],[30],[45],[60],[75],[90]])
data_b = np.random.randint(91, size=(180, 101))

[rows_a,cols_a] = data_a.shape
[rows_b,cols_b] = data_b.shape

val1 = np.zeros((rows_a,cols_b))
ind1 = np.zeros((rows_a,cols_b))

for i in range(cols_b):
    for j in range(rows_a):
        [val1[j][i],ind1[j][i]] = np.amin(np.abs(data_b[:][i] - data_a[j]))
代码还产生了一个错误,使我一点也不明白:

TypeError: cannot unpack non-iterable numpy.int32 object
如果有人能抽出时间来解释为什么我是一个无知的傻瓜,指出我做错了什么,以及我能做些什么来纠正它,我将不胜感激,因为这已经证明是我进步的主要障碍

谢谢。

您的错误与“[val1[j][i],ind1[j][i]=(单个数字)”有关。您试图为它分配一个在python中不起作用的值。这个怎么样

import numpy as np

data_a = np.array([[0],[15],[30],[45],[60],[75],[90]])
data_b = np.random.randint(91, size=(180,101))

[rows_a,cols_a] = data_a.shape
[rows_b,cols_b] = data_b.shape

val1 = np.zeros((rows_a,cols_b))
ind1 = np.zeros((rows_a,cols_b))

for i in range(cols_b):
    for j in range(rows_a):
        array = np.abs(data_b[:][i] - data_a[j])
        val = np.amin(array)
        val1[j][i] = val
        ind1[j][i] = np.where(val == array)[0][0]
Numpy amin不返回索引,因此需要使用np.where返回它。本例不存储完整索引,只存储行中第一次出现的索引。然后可以将其拉出,因为行顺序与ind1和data_b中的列顺序相匹配。例如,在第一次迭代中

In [2]: np.abs(data_b[:][0] - data_a[j0])
Out[2]: 
array([ 3, 31, 19, 53, 28, 81, 10, 11, 89, 15, 50, 22, 40, 81, 43, 29, 63,
       72, 22, 37, 54, 12, 19, 78, 85, 78, 37, 81, 41, 24, 29, 56, 37, 86,
       67,  7, 38, 27, 83, 81, 66, 32, 68, 29, 71, 26, 12, 27, 45, 58, 17,
       57, 54, 55, 23, 21, 46, 58, 75, 10, 25, 85, 70, 76,  0, 11, 19, 83,
       81, 68,  8, 63, 72, 48, 18, 29,  0, 47, 85, 79, 72, 85, 28, 28,  7,
       41, 80, 56, 59, 44, 82, 33, 42, 23, 42, 89, 58, 52, 44, 65, 65])

In [3]: np.amin(array)
Out[3]: 0

In [4]: val
Out[4]: 0

In [5]: np.where(val == array)[0][0]
Out[5]: 69

In [6]: data_b[0,69]
Out[6]: 0

我认为你们面临两个问题:

  • 多维数组的切片使用不正确:使用
    [i,j]
    而不是
    [i][j]
  • min()
    从MATLAB不正确地翻译为NumPy:您必须同时使用
    argmin()
    min()
  • 您的固定代码如下所示:

    import numpy as np
    
    # just to make it reproducible in testing, can be commented for production
    np.random.seed(0)
    
    data_a = np.array([[0],[15],[30],[45],[60],[75],[90]])
    data_b = np.random.randint(91, size=(180, 101))
    
    [rows_a,cols_a] = data_a.shape
    [rows_b,cols_b] = data_b.shape
    
    val1 = np.zeros((rows_a,cols_b), dtype=int)
    ind1 = np.zeros((rows_a,cols_b), dtype=int)
    
    for i in range(cols_b):
        for j in range(rows_a):
            ind1[j, i] = np.argmin(np.abs(data_b[:, i] - data_a[j]))
            val1[j, i] = np.min(np.abs(data_b[:, i] - data_a[j])[ind1[j, i]])
    
    不过,我会避免在这里直接循环,并充分利用广播:

    import numpy as np
    
    # just to make it reproducible in testing, can be commented for production
    np.random.seed(0)
    
    data_a = np.arange(0, 90 + 1, 15).reshape((-1, 1, 1))
    data_b = np.random.randint(90 + 1, size=(1, 180, 101))
    
    tmp_arr = np.abs(data_a.reshape(-1, 1, 1) - data_b.reshape(1, 180, -1), dtype=int)
    min_idxs = np.argmin(tmp_arr, axis=1)
    min_vals = np.min(tmp_arr, axis=1)
    del tmp_arr  # you can delete this if you no longer need it
    
    其中现在
    ind1==min_idxs
    val1==min_vals
    ,即:

    print(np.all(min_idxs == ind1))
    # True
    print(np.all(min_vals == val1))
    # True
    

    我想知道你的MATLAB代码是如何工作的。
    val1
    ind1
    的维度是不同的,您仍然能够在同一for循环中使用i和j索引?您不必在MATLAB中将所有内容都分组到方括号中,您知道。仅当您有多个元素(如在
    数据中),但不在单个元素周围…Bazingaa时,它们似乎是相同的7x101矩阵(尽管我的知识有限,可能误解了您的评论)。我知道,阿德里安,由于懒惰,我把它从python复制到了MATLAB。如果您发现它有误导性,我很抱歉。您是否有理由希望
    数据\u a
    具有这种形状(例如
    (7,1)
    )?您是否可以提供一个较小尺寸的输入/输出示例?(我假设
    data_a
    只能有两点,而且
    data_b
    可以减少到较少的元素,以便进行测试)谢谢您的帮助。不幸的是(这很可能是由于我的无能和普遍的愚蠢),我无法使它像我想象的那样工作(以及它在MATLAB中的工作方式)。最后我想得到一个7x101矩阵,其中包含最接近参考值(data_a)的数据_b值。非常感谢,norok2!杰出的这正是我一直尝试(但失败)去做的!如果你不介意我问(有点离题),但是有没有办法列出所有出现数字(
    data\u a
    )的
    data\u b
    位置,而不仅仅是第一次出现?你的解决方案正是我所追求的,而另一个只是一种好奇心,以备将来参考。@顽皮的波浪我不知道有一个函数可以找到所有的全局最大值/最小值,我想这与你可能想要得到一致维度的结果这一事实有关(如果一个序列中有2个最小值,另一个序列中有3个最小值,那么结果的形状应该是什么?)无论如何,如果你有一个数组
    arr
    ,你知道它的最小值
    min\u arr
    ,你可以得到一个掩码,通过
    arr==min\u arr
    选择所有这些值来获得你将使用的索引(arr==min\u-arr)
    。我理解——我对这一切都很陌生,所以当有经验的用户让我明白过来时,这会有很大帮助。再次感谢,@norok2.:)