Как читать и обрабатывать файлы .mat в Python: полное руководство

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Инженеры и исследователи, работающие с данными в формате .mat из MATLAB и Python
  • Специалисты по обработке данных и разработчики программного обеспечения
  • Студенты и профессионалы в области программирования, желающие повысить свои навыки работы с данными и научными исследованиями

    Интеграция данных между разными средами разработки часто становится головной болью для инженеров и исследователей. Файлы формата .mat, родные для MATLAB, содержат ценные научные данные, которые нередко необходимо обрабатывать в Python-экосистеме. Многие специалисты сталкиваются с трудностями при импорте этих файлов, теряя время на поиск решений вместо работы над проектом. Я подготовил исчерпывающее руководство с примерами кода, которое позволит вам без проблем читать, обрабатывать и интегрировать данные из .mat файлов в ваши Python-проекты. 🐍📊

Изучив принципы работы с .mat файлами в Python, вы сможете существенно расширить свои навыки работы с данными. В курсе Обучение Python-разработке от Skypro мы идем дальше и показываем, как интегрировать эти навыки в полноценные веб-приложения. Вы научитесь не только обрабатывать данные из разных источников, но и создавать на их основе API, веб-интерфейсы и аналитические дашборды. Это перевод ваших технических навыков на новый уровень практического применения.

Формат .mat в Python: базовые методы чтения файлов

Файлы .mat представляют собой бинарный формат, разработанный компанией MathWorks для хранения переменных рабочего пространства MATLAB. Формат эволюционировал со временем, и существуют различные версии: от устаревших (v4, v5) до современных (v7, v7.3). Это важно учитывать при импорте данных в Python, поскольку различные версии требуют разных подходов.

Для чтения .mat файлов в Python существует несколько библиотек:

  • scipy.io — стандартный и наиболее универсальный инструмент для работы с .mat файлами версий до v7.3
  • h5py — библиотека для работы с файлами формата HDF5, подходит для файлов .mat версии v7.3
  • mat73 — специализированная библиотека для работы с файлами .mat версии v7.3
  • PyMatlab — предоставляет интерфейс для взаимодействия с MATLAB из Python

Основной и наиболее простой способ чтения .mat файлов — использование функции loadmat() из модуля scipy.io:

Python
Скопировать код
import scipy.io
# Загрузка данных из .mat файла
mat_data = scipy.io.loadmat('example.mat')
# mat_data теперь представляет собой словарь Python

Результат загрузки — словарь Python, где ключи соответствуют именам переменных в MATLAB, а значения — непосредственно данным. При этом важно помнить, что функция loadmat() по умолчанию добавляет в словарь служебные переменные, такие как __header__, __version__, __globals__, которые можно игнорировать при обработке данных.

Версия .mat Поддерживаемая библиотека Ограничения
v4, v5 scipy.io Нет значительных ограничений
v7 scipy.io Ограничение на размер файла около 2 ГБ
v7.3 h5py, mat73 scipy.io не поддерживает эту версию напрямую

Для файлов версии v7.3, которые хранятся в формате HDF5, необходимо использовать библиотеку h5py:

Python
Скопировать код
import h5py
# Открытие файла в режиме чтения
with h5py.File('example_v73.mat', 'r') as file:
# Доступ к данным по имени переменной
data = file['variable_name'][()]

Михаил Соловьев, инженер-исследователь

На моем проекте по обработке данных МРТ мы столкнулись с проблемой — наши врачи экспортировали данные из проприетарного ПО только в формате .mat. Наш Python-конвейер анализа требовал импорта и обработки около 500 таких файлов ежедневно. Первоначально мы использовали scipy.io.loadmat() и были удовлетворены результатами, пока не столкнулись с новой партией файлов размером более 4 ГБ каждый.

Функция loadmat() выдавала ошибки памяти и просто падала. Оказалось, что лаборатория начала использовать MATLAB R2017b, который по умолчанию сохраняет файлы в формате v7.3. После некоторых исследований мы перешли на h5py:

Python
Скопировать код
import h5py
import numpy as np

def load_mat_v73(filename):
with h5py.File(filename, 'r') as f:
# Создаем словарь для хранения данных
data = {}
for k, v in f.items():
if isinstance(v, h5py.Dataset):
data[k] = np.array(v)
return data

mri_data = load_mat_v73('large_mri_dataset.mat')

Этот подход решил наши проблемы с памятью и значительно ускорил обработку больших .mat файлов. Сейчас наша система обрабатывает терабайты данных МРТ без сбоев.

Пошаговый план для смены профессии

Библиотека scipy.io для импорта MATLAB данных

Модуль scipy.io предоставляет набор функций для работы с форматами ввода-вывода, включая MATLAB. Основные функции для работы с .mat файлами в этой библиотеке:

  • loadmat() — чтение .mat файлов в Python
  • savemat() — сохранение данных Python в формат .mat
  • whosmat() — просмотр содержимого .mat файла без полной загрузки

Рассмотрим подробнее функцию loadmat(), которая является ключевой для импорта данных MATLAB:

Python
Скопировать код
from scipy import io

# Загрузка .mat файла
mat_contents = io.loadmat('sample_data.mat')

# Просмотр ключей (имен переменных)
print(mat_contents.keys())

# Доступ к конкретной переменной
my_variable = mat_contents['variable_name']

Функция loadmat() поддерживает несколько полезных параметров для настройки процесса импорта:

Параметр Описание Пример использования
squeeze_me Устраняет ненужные размерности размером 1 loadmat('file.mat', squeeze_me=True)
structasrecord Загружает структуры MATLAB как вложенные объекты loadmat('file.mat', struct_as_record=False)
variable_names Загружает только указанные переменные loadmat('file.mat', variable_names=['var1', 'var2'])
mat_dtype Определяет тип данных для числовых массивов loadmat('file.mat', mat_dtype=True)

Для просмотра содержимого .mat файла без его полной загрузки используется функция whosmat():

Python
Скопировать код
from scipy import io

# Получение информации о переменных в файле
variables = io.whosmat('sample_data.mat')

# Вывод информации
for name, shape, dtype in variables:
print(f"Переменная: {name}, Размерность: {shape}, Тип данных: {dtype}")

Функция savemat() позволяет сохранять Python-данные в формат .mat для последующего использования в MATLAB:

Python
Скопировать код
import numpy as np
from scipy import io

# Создание данных для сохранения
data = {
'array': np.array([[1, 2, 3], [4, 5, 6]]),
'matrix': np.matrix([[7, 8], [9, 10]]),
'scalar': np.int64(42)
}

# Сохранение данных в .mat файл
io.savemat('output_data.mat', data)

При использовании scipy.io следует помнить о возможных преобразованиях типов данных между Python и MATLAB. Например, строки MATLAB преобразуются в массивы символов в Python, а массивы MATLAB становятся многомерными NumPy-массивами. 🔄

Работа со структурами и массивами из .mat файлов

MATLAB широко использует сложные структуры данных, которые при импорте в Python требуют особого подхода. Понимание этих особенностей критично для корректной обработки данных.

Основные типы данных MATLAB и их соответствие в Python:

  • Матрицы и массивы MATLAB → NumPy массивы в Python
  • Ячеечные массивы (cell arrays) → списки Python или массивы объектов NumPy
  • Структуры MATLAB → вложенные словари или специальные объекты в Python
  • Строки MATLAB → массивы символов или строки Python

Одна из главных особенностей — MATLAB использует индексацию с единицы, тогда как Python — с нуля. Это необходимо учитывать при обработке индексированных данных.

Рассмотрим, как работать со структурами MATLAB в Python:

Python
Скопировать код
import scipy.io
import numpy as np

# Загрузка файла, содержащего структуры
data = scipy.io.loadmat('structures.mat', struct_as_record=False, squeeze_me=True)

# Получение структуры
my_struct = data['struct_name']

# Доступ к полям структуры
field_value = my_struct[0, 0].field_name

При использовании параметра struct_as_record=False структуры MATLAB загружаются как объекты scipy.io.matlab.mio5_params.mat_struct, что позволяет обращаться к полям через точечную нотацию. Параметр squeeze_me=True удаляет избыточные размерности, упрощая работу с данными.

Для работы с ячеечными массивами (cell arrays) MATLAB:

Python
Скопировать код
# Загрузка файла с ячеечным массивом
data = scipy.io.loadmat('cell_arrays.mat', squeeze_me=True)

# Получение ячеечного массива
cell_array = data['cell_var']

# Доступ к элементам ячеечного массива
# Если squeeze_me=True не указан, может потребоваться дополнительная индексация
first_element = cell_array[0] # или cell_array[0, 0] без squeeze_me=True

Для работы с многомерными массивами необходимо учитывать, что MATLAB использует порядок размерностей, отличный от NumPy. В MATLAB первый индекс соответствует строкам, второй — столбцам, что соответствует соглашению (строка, столбец). В NumPy используется (строка, столбец) для 2D массивов, но для N-мерных массивов может потребоваться транспонирование или изменение порядка осей:

Python
Скопировать код
# Загрузка многомерного массива
data = scipy.io.loadmat('arrays.mat')

# Получение массива
array_3d = data['array_3d']

# Транспонирование для соответствия порядку MATLAB
# Для 3D массива меняем порядок осей
array_3d_transposed = np.transpose(array_3d, (2, 1, 0))

Алексей Кузнецов, специалист по обработке данных

В проекте по анализу сигналов с датчиков мы получали файлы .mat с данными, собранными в сложные структуры MATLAB. Каждая структура содержала информацию о различных параметрах эксперимента: временные ряды, метаданные и параметры калибровки.

Поначалу структура данных казалась запутанной. Мы пытались использовать стандартный метод загрузки:

Python
Скопировать код
data = scipy.io.loadmat('experiment_data.mat')
sensor_data = data['sensors']

Но это давало нам сложные вложенные массивы, к которым было трудно обращаться. После нескольких дней мучений я нашел решение:

Python
Скопировать код
data = scipy.io.loadmat('experiment_data.mat', 
struct_as_record=False, 
squeeze_me=True)

# Теперь можно работать через точечную нотацию
for sensor in data['sensors']:
time_series = sensor.time_data
calibration = sensor.calibration_params
# Обработка данных
processed_data = process_signal(time_series, calibration)

Параметр struct_as_record=False был ключевым — он преобразовывал структуры MATLAB в объекты Python с доступом через точечную нотацию вместо сложных словарей. Это сделало код намного более читаемым и сократило время разработки на 40%.

Проблемы совместимости версий и их решение

При работе с .mat файлами возникают проблемы совместимости, связанные с различными версиями формата. Формат .mat эволюционировал вместе с MATLAB, и более новые версии могут содержать структуры данных, несовместимые с библиотеками Python или требующие специальных подходов для обработки.

Основные версии формата .mat и связанные с ними проблемы:

  • v4 и v5 — устаревшие версии, хорошо поддерживаемые scipy.io
  • v7 — поддерживается scipy.io, но с ограничениями на размер файла (около 2 ГБ)
  • v7.3 — использует формат HDF5, требует библиотеки h5py или mat73 для чтения

Как определить версию .mat файла:

Python
Скопировать код
from scipy import io

# Попытка загрузить файл и проверить его версию
try:
data = io.loadmat('example.mat')
print("Файл успешно загружен с помощью scipy.io")
print("Версия файла:", data.get('__version__'))
except NotImplementedError:
print("Файл, вероятно, имеет версию v7.3 или выше (формат HDF5)")

Для работы с файлами v7.3 (HDF5) используйте следующий подход:

Python
Скопировать код
import h5py
import numpy as np

# Функция для загрузки .mat файла версии v7.3
def load_mat_v73(filename):
result = {}
with h5py.File(filename, 'r') as f:
# Рекурсивная функция для обхода всех групп и датасетов
def visit_func(name, node):
if isinstance(node, h5py.Dataset):
result[name] = np.array(node)

f.visititems(visit_func)
return result

# Использование функции
data = load_mat_v73('example_v73.mat')

Альтернативно, можно использовать специализированную библиотеку mat73:

Python
Скопировать код
# Установка: pip install mat73
import mat73

# Чтение файла v7.3
data = mat73.loadmat('example_v73.mat')

Для обеспечения совместимости при сохранении данных из Python в формат .mat:

Python
Скопировать код
from scipy import io

# Для сохранения в формате, совместимом с более старыми версиями MATLAB
io.savemat('output.mat', data, format='5')

# Для более новых версий (но не v7.3)
io.savemat('output.mat', data, format='7')

При работе с большими наборами данных может возникнуть проблема исчерпания памяти. Для решения этой проблемы можно использовать постепенную загрузку данных:

Python
Скопировать код
import h5py

# Открываем файл для чтения
with h5py.File('large_file_v73.mat', 'r') as f:
# Обрабатываем данные частями
dataset = f['large_dataset']
chunk_size = 1000 # Размер части
total_size = dataset.shape[0]

for i in range(0, total_size, chunk_size):
end = min(i + chunk_size, total_size)
chunk = dataset[i:end]
# Обработка части данных
process_chunk(chunk)

Ещё одна распространенная проблема — кодировка строк. В MATLAB строки часто хранятся как массивы символов, и при импорте в Python могут возникнуть проблемы с кодировкой:

Python
Скопировать код
# Преобразование массива символов MATLAB в строку Python
def matlab_str_to_python(matlab_str):
if isinstance(matlab_str, np.ndarray):
# Если это массив символов, объединяем их в строку
return ''.join(chr(c) for c in matlab_str.flat)
return matlab_str

Практические сценарии чтения .mat файлов в проектах

Реальные проекты требуют интеграции чтения .mat файлов в более широкие рабочие процессы. Рассмотрим несколько практических сценариев, которые часто встречаются в проектах обработки данных.

Сценарий 1: Обработка научных данных из экспериментов

Python
Скопировать код
import scipy.io
import numpy as np
import matplotlib.pyplot as plt

# Загрузка экспериментальных данных
data = scipy.io.loadmat('experiment_results.mat', squeeze_me=True)

# Извлечение временного ряда и параметров
time_series = data['time_data']
parameters = data['parameters']

# Анализ данных: расчет статистик
mean_value = np.mean(time_series)
std_dev = np.std(time_series)

# Визуализация результатов
plt.figure(figsize=(10, 6))
plt.plot(time_series)
plt.axhline(mean_value, color='r', linestyle='--')
plt.title(f'Экспериментальные данные (среднее: {mean_value:.2f}, σ: {std_dev:.2f})')
plt.savefig('experiment_analysis.png')
plt.show()

Сценарий 2: Пакетная обработка множества .mat файлов

Python
Скопировать код
import os
import scipy.io
import pandas as pd

# Каталог с файлами .mat
data_dir = 'data_folder/'

# Функция для обработки одного файла
def process_mat_file(filepath):
try:
data = scipy.io.loadmat(filepath, squeeze_me=True)
# Извлечение нужных данных
values = data['measurements']
# Обработка и возврат результатов
return {
'filename': os.path.basename(filepath),
'mean': values.mean(),
'max': values.max(),
'min': values.min()
}
except Exception as e:
print(f"Ошибка при обработке файла {filepath}: {e}")
return None

# Пакетная обработка всех файлов
results = []
for filename in os.listdir(data_dir):
if filename.endswith('.mat'):
filepath = os.path.join(data_dir, filename)
result = process_mat_file(filepath)
if result:
results.append(result)

# Создание DataFrame для анализа и экспорта
results_df = pd.DataFrame(results)
results_df.to_csv('batch_processing_results.csv', index=False)
print(f"Обработано {len(results)} файлов")

Сценарий 3: Интеграция данных из .mat файлов в машинное обучение

Python
Скопировать код
import scipy.io
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# Загрузка данных для машинного обучения
data = scipy.io.loadmat('ml_dataset.mat', squeeze_me=True)

# Подготовка данных
X = data['features']
y = data['labels']

# Разделение на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Обучение модели
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)

# Оценка модели
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Точность модели: {accuracy:.4f}")

Сценарий 4: Сравнительный анализ данных из нескольких экспериментов

Метрика Эксперимент 1 Эксперимент 2 Эксперимент 3 Изменение, %
Средняя амплитуда 2.45 2.67 2.88 +17.55
Пиковая частота (Гц) 128.3 130.1 129.7 +1.09
Время отклика (мс) 42.5 39.8 38.1 -10.35
Энергопотребление (Вт) 1.28 1.15 1.03 -19.53
Python
Скопировать код
import scipy.io
import numpy as np
import pandas as pd

# Загрузка данных из разных экспериментов
exp1 = scipy.io.loadmat('experiment1.mat', squeeze_me=True)
exp2 = scipy.io.loadmat('experiment2.mat', squeeze_me=True)
exp3 = scipy.io.loadmat('experiment3.mat', squeeze_me=True)

# Извлечение метрик для сравнения
metrics = {
'Средняя амплитуда': [
np.mean(exp1['amplitude']),
np.mean(exp2['amplitude']),
np.mean(exp3['amplitude'])
],
'Пиковая частота (Гц)': [
np.max(exp1['frequency']),
np.max(exp2['frequency']),
np.max(exp3['frequency'])
],
'Время отклика (мс)': [
np.mean(exp1['response_time']),
np.mean(exp2['response_time']),
np.mean(exp3['response_time'])
],
'Энергопотребление (Вт)': [
np.mean(exp1['power']),
np.mean(exp2['power']),
np.mean(exp3['power'])
]
}

# Создание DataFrame для сравнительного анализа
df = pd.DataFrame(metrics, index=['Эксперимент 1', 'Эксперимент 2', 'Эксперимент 3'])

# Расчет процентного изменения между первым и последним экспериментом
df['Изменение, %'] = ((df.iloc[2] – df.iloc[0]) / df.iloc[0] * 100).round(2)

# Вывод результатов
print(df.T)

При интеграции данных из .mat файлов в более сложные аналитические конвейеры полезно создать обертки и утилиты, которые скрывают детали работы с форматом и позволяют сосредоточиться на анализе данных. 📊

Например, можно создать универсальную функцию чтения .mat файлов, которая автоматически определяет версию и использует соответствующий метод загрузки:

Python
Скопировать код
def smart_loadmat(filename):
"""Универсальная функция для загрузки .mat файлов любой версии"""
try:
# Сначала пробуем стандартный loadmat
return scipy.io.loadmat(filename, squeeze_me=True)
except NotImplementedError:
# Если не сработало, пробуем h5py для v7.3
try:
import h5py
return load_mat_v73(filename)
except Exception as e:
# Если и это не сработало, пробуем mat73
try:
import mat73
return mat73.loadmat(filename)
except Exception as e:
raise ValueError(f"Не удалось открыть .mat файл: {e}")

Переход с MATLAB на Python становится гораздо проще, когда вы уверенно управляете данными в формате .mat. Мы рассмотрели различные методы чтения этих файлов — от простых сценариев с использованием scipy.io до сложных случаев с HDF5-форматом и многомерными структурами. Помните о различиях в индексации и организации данных между средами. Правильный выбор библиотеки в зависимости от версии файла сэкономит вам часы отладки. Теперь вы готовы эффективно интегрировать данные MATLAB в ваши Python-проекты, сохраняя непрерывность рабочих процессов и целостность информации. 🐍📈

Загрузка...