从.m Matlab文件中声明的矩阵创建numpy数组

2 投票
2 回答
1086 浏览
提问于 2025-04-17 05:08

一个同事留下了一些我想用Numpy分析的数据文件。

每个文件都是一个matlab文件,比如说 data.m,里面的格式是这样的(当然实际内容会有很多列和行):

values = [-24.92 -23.66 -22.55 ;
-24.77 -23.56 -22.45 ;
-24.54 -23.64 -22.56 ;
];

这就是matlab中常用的显式矩阵创建语法。

我想问的是:从这些文件创建一个numpy数组的最实用方法是什么?

我可以考虑用一种“粗暴”或者“快速且简单”的方法,但如果有更直接的办法,我当然更愿意使用,比如说numpy的标准函数或者其他模块的函数。

补充说明:我注意到我的文件可能包含 NaN 值,所以我很可能会调整答案,使用 numpy.genfromtxt 而不是 numpy.loadtxt。我计划在有了最终代码后尽快分享出来。

谢谢大家的帮助!

补充说明:我最后写出了以下代码,我用正则表达式提取了 [] 之间的内容,并使用 genfromtxt 创建了一个numpy数组,以便处理NaN。一个更简短的解决方案是使用 fromstring 方法,这个方法不需要StringIO,但它无法处理NaN,而我的数据中有NaN :oP

#!/usr/bin/env python
# coding: utf-8

import numpy, re, StringIO

with open('data.m') as f:
    s = re.search('\[(.*)\]', f.read(), re.DOTALL).group(1)
    buf = StringIO.StringIO(s)
    a = numpy.genfromtxt(buf, missing_values='NaN', filling_values=numpy.nan)

2 个回答

1

你可以把一个迭代器传给 np.genfromtxt

import numpy as np
import re

with open(filename, 'r') as f:
    lines = (re.sub(r'[^-+.0-9 ]+', '', line) for line in f)
    arr = np.genfromtxt(lines)

print(arr)

这样会得到

[[-24.92 -23.66 -22.55]
 [-24.77 -23.56 -22.45]
 [-24.54 -23.64 -22.56]]

感谢 Bitwise 提供的这个线索。

2

这里有几个选项,虽然都不是内置的。

你可能觉得不可接受的解决方案

这个解决方案可能属于你所说的“快速且粗糙”的类型,但它可以为下一个解决方案铺路。

values = [ 去掉,最后一行的 ]; 也去掉,然后把所有的 ; 替换成空白,这样就得到了:

-24.92 -23.66 -22.55 
-24.77 -23.56 -22.45 
-24.54 -23.64 -22.56 

然后你可以像下面这样使用 numpy 的 loadtxt

>>> import numpy as np
>>> A = np.loadtxt('data.m')

>>> A
array([[-24.92, -23.66, -22.55],
       [-24.77, -23.56, -22.45],
       [-24.54, -23.64, -22.56]])

你可能觉得可以接受的解决方案

在这个解决方案中,我们创建一个方法,把输入的数据转换成 numpy loadtxt 能接受的格式(实际上和上面的一样)。

import StringIO
import numpy as np

def convert_m(fname):
    with open(fname, 'r') as fin:
        arrstr = fin.read()
    arrstr = arrstr.split('[', 1)[-1] # remove the content up to the first '['
    arrstr = arrstr.rsplit(']', 1)[0] # remove the content after ']'
    arrstr = arrstr.replace(';', '\n') # replace ';' with newline
    return StringIO.StringIO(arrstr)

现在我们有了这个,接下来做以下操作。

>>> np.loadtxt(convert_m('data.m'))
array([[-24.92, -23.66, -22.55],
       [-24.77, -23.56, -22.45],
       [-24.54, -23.64, -22.56]])

撰写回答