使用 scipy.io.loadmat 在 python 中加载 matlab 表

Posted

技术标签:

【中文标题】使用 scipy.io.loadmat 在 python 中加载 matlab 表【英文标题】:load matlab tables in python using scipy.io.loadmat 【发布时间】:2014-11-09 07:43:12 【问题描述】:

是否可以?

我在做什么:

在 Matlab 中:

tab = table((1:500)')
save('tab.mat', 'tab')

在 Python 中:

import scipy.io
mat = scipy.io.loadmat('m:/tab.mat')

但我无法使用 mat['tab'] 访问 Python 中的表格选项卡

【问题讨论】:

我可以加载一个matlab数组,所以版本没有问题。我只是无法加载 matlab 表 这里是错误信息:>>> mat['tab'] Traceback(最近一次调用最后):文件“C:\Anaconda\lib\site-packages\IPython\core\interactiveshell. py”,第 2883 行,run_code exec(code_obj, self.user_global_ns, self.user_ns) 文件“”,第 1 行,在 mat['tab'] KeyError: 'tab ' mat 是什么类型的 python 变量 - 是否有任何数据(只是没有分配的字段)?或者loadmat 是否一起失败了表格格式? 你在 python 中得到了什么:scipy.io.whosmat('m:/tab.mat')? (这是我从here 得到的一个想法) 从这个答案到'Read .mat files in Python' 的方法是否适用于table 【参考方案1】:

您的问题的答案是否定的。许多 matlab 对象可以在 python 中加载。除其他外,无法加载表格。见Handle Data Returned from MATLAB to Python

【讨论】:

【参考方案2】:

正如其他人所提到的,这目前是不可能的,因为 Matlab 没有记录这种文件格式。人们正在尝试对文件格式进行逆向工程,但这项工作正在进行中。

一种解决方法是将表格写入 CSV 格式并使用 Python 加载该格式。表中的条目可以是可变长度的数组,它们将被拆分到编号的列中。我编写了一个简短的函数来从这个 CSV 文件中加载标量和数组。

致write the table to CSV in matlab:

writetable(table_name, filename)

在 Python 中读取 CSV 文件:

def load_matlab_csv(filename):
    """Read CSV written by matlab tablewrite into DataFrames

    Each entry in the table can be a scalar or a variable length array.
    If it is a variable length array, then Matlab generates a set of
    columns, long enough to hold the longest array. These columns have
    the variable name with an index appended.

    This function infers which entries are scalars and which are arrays.
    Arrays are grouped together and sorted by their index.

    Returns: scalar_df, array_df
        scalar_df : DataFrame of scalar values from the table
        array_df : DataFrame with MultiIndex on columns
            The first level is the array name
            The second level is the index within that array
    """
    # Read the CSV file
    tdf = pandas.read_table(filename, sep=',')
    cols = list(tdf.columns)

    # Figure out which columns correspond to scalars and which to arrays
    scalar_cols = [] # scalar column names
    arr_cols = [] # array column names, without index
    arrname2idxs =  # dict of array column name to list of integer indices
    arrname2colnames =  # dict of array column name to list of full names

    # Iterate over columns
    for col in cols:
        # If the name ends in "_" plus space plus digits, it's probably
        # from an array
        if col[-1] in '0123456789' and '_' in col:
            # Array col
            # Infer the array name and index
            colsplit = col.split('_')
            arr_idx = int(colsplit[-1])
            arr_name = '_'.join(colsplit[:-1])

            # Store
            if arr_name in arrname2idxs:
                arrname2idxs[arr_name].append(arr_idx)
                arrname2colnames[arr_name].append(col)
            else:
                arrname2idxs[arr_name] = [arr_idx]
                arrname2colnames[arr_name] = [col]
                arr_cols.append(arr_name)

        else:
            # Scalar col
            scalar_cols.append(col)

    # Extract all scalar columns
    scalar_df = tdf[scalar_cols]

    # Extract each set of array columns into its own dataframe
    array_df_d = 
    for arrname in arr_cols:
        adf = tdf[arrname2colnames[arrname]].copy()
        adf.columns = arrname2idxs[arrname]
        array_df_d[arrname] = adf

    # Concatenate array dataframes
    array_df = pandas.concat(array_df_d, axis=1)

    return scalar_df, array_df

scalar_df, array_df = load_matlab_csv(filename)

【讨论】:

【参考方案3】:

我已经针对我正在从事的项目进行了调查,作为一种解决方法,您可以尝试以下方法。

在 MATLAB 中,首先将 @table 对象转换为结构,然后使用以下方法检索列名:

table_struct = struct(table_object);
table_columns = table_struct.varDim.labels;
save table_as_struct table_struct table_columns;

然后你可以在python中尝试以下代码:

import numpy
import pandas as pd
import scipy.io

# function to load table variable from MAT-file
def loadtablefrommat(matfilename, tablevarname, columnnamesvarname):
    """
    read a struct-ified table variable (and column names) from a MAT-file
    and return pandas.DataFrame object.
    """

    # load file
    mat = scipy.io.loadmat(matfilename)

    # get table (struct) variable
    tvar = mat.get(tablevarname)
    data_desc = mat.get(columnnamesvarname)
    types = tvar.dtype
    fieldnames = types.names

    # extract data (from table struct)
    data = None
    for idx in range(len(fieldnames)):
        if fieldnames[idx] == 'data':
            data = tvar[0][0][idx]
            break;

    # get number of columns and rows
    numcols = data.shape[1]
    numrows = data[0, 0].shape[0]

    # and get column headers as a list (array)
    data_cols = []
    for idx in range(numcols):
        data_cols.append(data_desc[0, idx][0])

    # create dict out of original table
    table_dict = 
    for colidx in range(numcols):
        rowvals = []
        for rowidx in range(numrows):
            rowval = data[0,colidx][rowidx][0]
            if type(rowval) == numpy.ndarray and rowval.size > 0:
                rowvals.append(rowval[0])
            else:
                rowvals.append(rowval)
        table_dict[data_cols[colidx]] = rowvals
    return pd.DataFrame(table_dict)

【讨论】:

【参考方案4】:

根据 Jochens 的回答,我提出了一个不同的变体,它对我来说做得很好。 我编写了一个 Matlab 脚本 来自动准备 m 文件(参见我的 GitLab Repositroy 示例)。 它执行以下操作:

在 Matlab 中为类 table

与 Jochens 示例一样,但将数据绑定在一起。所以更容易加载多个变量。下一部分必须使用名称“表”和“列”。

YourVariableName = struct('table', struct(TableYouWantToLoad), 'columns', struct(TableYouWantToLoad).varDim.labels)
save('YourFileName', 'YourVariableName')

在 Matlab 中为类 dataset

替代方案,如果您必须处理旧的数据集类型。

YourVariableName = struct('table', struct(DatasetYouWantToLoad), 'columns', get(DatasetYouWantToLoad,'VarNames'))
save('YourFileName', 'YourVariableName')

在 Python 中

import scipy.io as sio
mdata = sio.loadmat('YourFileName')
mtable = load_table_from_struct(mdata['YourVariableName'])

import pandas as pd

def load_table_from_struct(table_structure) -> pd.DataFrame():

    # get prepared data structure
    data = table_structure[0, 0]['table']['data']
    # get prepared column names
    data_cols = [name[0] for name in table_structure[0, 0]['columns'][0]]

    # create dict out of original table
    table_dict = 
    for colidx in range(len(data_cols)):
        table_dict[data_cols[colidx]] = [val[0] for val in data[0, 0][0, colidx]]

    return pd.DataFrame(table_dict)

它独立于加载文件,但基本上是 Jochens Code 的最小化版本。所以请为他的帖子点赞。

【讨论】:

【参考方案5】:

loadmat 函数不加载 MATLAB 表。相反,可以做一个小的解决方法。表格可以保存为.csv 文件,然后可以使用pandas 读取。

在 MATLAB 中

writetable(table_name, file_name)

在 Python 中

df = pd.read_csv(file_name)

最后,DataFrame df 将有 table_name 的内容

【讨论】:

这是一个很好的解决方法。帮助我找到了我正在寻找的东西。谢谢! 很高兴它有帮助:)

以上是关于使用 scipy.io.loadmat 在 python 中加载 matlab 表的主要内容,如果未能解决你的问题,请参考以下文章

使用 scipy.io.loadmat 从 .mat Matlab 文件中将字典键转换为 Python 中具有相同值的变量名

从使用 Scipy.io.loadmat 加载的 .mat 文件访问数组内容 - python

Scipy IO Loadmat 错误:ValueError:Mat 4 mopt 格式错误

使用 scipy.io loadmat 将 Matlab 结构导入 python 时的值错误

如何使用 Scipy.io.loadmat 将 Matlab mat 文件中的字符串单元格数组加载到 Python 列表或元组中

SciPy中两个模块:io 和misc