如何将矩阵从Matlab转换为Python?

时间:2017-06-20 15:43:39

标签: python matlab pandas numpy matrix

我在Matlab中有以下代码,我不熟悉:

function segments = segmentEnergy(data, th)
    mag = sqrt(sum(data(:, 1:3) .^ 2, 2));
    mag = mag - mean(mag);

    above = find(mag>=th*std(mag));
    indicator = zeros(size(mag));
    indicator(above) = 1;
    plot(mag); hold on; plot(indicator*1000, 'r')
end

我在Python中编写了以下函数:

def segment_energy(data, th):
    mag = np.linalg.norm((data['x'], data['y'], data['z']))
    print "This is the mag: " + str(mag)
    mag -= np.mean(mag)

    above = np.where(mag >= th * np.std(mag))
    indicator = np.zeros(mag.shape)
    indicator[above] = 1
    plt.plot(mag)
    plt.plot(indicator * 1000, 'r')
    plt.show()

我收到错误:

line 23, in segment_energy
indicator[above] = 1
IndexError: too many indices for array

data是从包含三轴加速度计数据的CSV文件中读取的pandas DataFrame。加速度计数据的轴为xyz。数据框的列按此顺序为timestamptime skippedxyzlabel

错误是因为Python代码中的mag是标量,我将其视为矩阵。但是,我不确定他们如何将mag转换为MATLAB函数中的矩阵。

1 个答案:

答案 0 :(得分:3)

默认情况下,numpy.linalg.norm的输出会给出一个标量值,给出您当前调用该函数的方式。因为mag的输出现在是标量,所以其余代码将无法按预期运行,原因如下:

  1. 使用单个标量执行平均减法将得到值0(即mag <- mag - np.mean(mag) --> 0)。

  2. above语句将始终返回单个元素的元组。该元素包含一个长度为1的NumPy数组,其中包含索引0,表示“array”的第一个元素(在这种情况下是标量)满足约束条件。通过使用np.std的默认定义,单个常量的标准偏差也为0,这一点始终得到满足。

  3. 调用shape单个标量值是未定义的,它实际上会为您提供一个空的形状:()。请注意,如果您没有使用numpy.mean减去,那么执行mag.shape实际上会给您一个错误,因为它不是NumPy数组。用np.mean减法将标量合并为NumPy数组。

    观察:

    In [56]: mag = 10
    
    In [57]: type(mag)
    Out[57]: int
    
    In [58]: mag -= np.mean(mag)
    
    In [59]: type(mag)
    Out[59]: numpy.float64
    
  4. 最后,调用indicator创建代码将生成一个空维度数组,因为您尝试索引到没有大小的数组,它会给您一个错误。

  5. 假设mag被计算为某个值,请注意这个可重现的错误...比如...... 10和th = 1

    In [60]: mag = 10
    
    In [61]: mag -= np.mean(mag)
    
    In [62]: mag.shape
    Out[62]: ()
    
    In [63]: th = 1
    
    In [64]: above = np.where(mag >= th * np.std(mag))
    
    In [65]: indicator = np.zeros(mag.shape)
    
    In [66]: indicator
    Out[66]: array(0.0)
    
    In [67]: mag
    Out[67]: 0.0
    
    In [68]: indicator[above] = 1
    ---------------------------------------------------------------------------
    IndexError                                Traceback (most recent call last)
    <ipython-input-67-adf9cff7610a> in <module>()
    ----> 1 indicator[above] = 1
    
    IndexError: too many indices for array
    

    因此,您的解决方案是重新考虑如何编写此功能。 MATLAB代码假定data已经是一个2D矩阵,因此他们独立地计算每行的范数或长度。因为我们现在知道输入是一个pandas DataFrame,所以我们可以很容易地在它上面应用numpy操作,就像在MATLAB中做的那样。假设您的列在代码中标记为xyz,并且每列都是numpy值数组,只需更改第一行代码。

    def segment_energy(data, th):
        mag = np.sqrt(np.sum(data.loc[:, ['x','y','z']]** 2.0, axis=1)) # Change
        mag = np.array(mag) # Convert to NumPy array
        mag -= np.mean(mag)
    
        above = np.where(mag >= th * np.std(mag))
        indicator = np.zeros(mag.shape)
        indicator[above] = 1
        plt.plot(mag)
        plt.plot(indicator * 1000, 'r')
        plt.show()
    

    代码中的第一个语句是MATLAB中代码的实际NumPy转换。我们使用pandas loc的一部分DataFrame方法来索引您要查找的三个列。我们还需要转换为NumPy数组,以便其余的计算工作。

    您也可以使用numpy.linalg.norm,但指定要操作的。由于数据是2D,请指定axis=1以计算矩阵的行方式:

    mag = np.linalg.norm(data.loc[:, ['x', 'y', 'z']], axis=1)
    

    以上内容会将数据合并为NumPy数组。