Files
ai-med-edu/labs/lab#3.tex
T

1064 lines
36 KiB
TeX

% ============================================================================
% LABORATORY WORK No.3
% RADIOMIC ANALYSIS OF BRAIN TUMORS
% BASED ON MULTIPARAMETRIC MRI
% ============================================================================
\documentclass[12pt,a4paper]{article}
% ============================================================================
% PREAMBLE
% ============================================================================
\usepackage[utf8]{inputenc}
\usepackage[T2A]{fontenc}
\usepackage[russian]{babel}
\usepackage{amsmath,amssymb,amsfonts}
\usepackage{graphicx}
\usepackage{hyperref}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{geometry}
\usepackage{booktabs}
\usepackage{longtable}
\usepackage{caption}
\usepackage{subcaption}
\usepackage{titlesec}
\usepackage{float}
\usepackage{array}
\usepackage{multirow}
\usepackage{enumitem}
\geometry{left=2.5cm,right=2cm,top=2cm,bottom=2cm}
\hypersetup{
colorlinks=true,
linkcolor=blue,
urlcolor=blue,
pdfauthor={Student},
pdftitle={Lab 3}
}
% --- LSTLISTING SETTINGS (ENGLISH COMMENTS ONLY) ---
\lstset{
basicstyle=\ttfamily\footnotesize,
keywordstyle=\color{blue},
commentstyle=\color{green!60!black},
stringstyle=\color{red},
breaklines=true,
frame=single,
numbers=left,
numberstyle=\tiny,
tabsize=4,
language=Python,
extendedchars=true,
inputencoding=utf8,
}
\titleformat{\section}{\Large\bfseries\centering}{}{0pt}{}
\titleformat{\subsection}{\large\bfseries}{}{0pt}{}
\titleformat{\subsubsection}{\normalsize\bfseries}{}{0pt}{}
\renewcommand{\refname}{References}
\begin{document}
% ============================================================================
% TITLE PAGE
% ============================================================================
\begin{titlepage}
\begin{center}
\vspace*{0.5cm}
{\Large \textbf{FGBU <<NMC of Oncology named after N.N. Blokhin>>}}
\vspace{0.3cm}
{\large Department of Medical Informatics and AI}
\vspace{2.5cm}
{\Huge \textbf{LABORATORY WORK No.3}}
\vspace{0.5cm}
{\huge \textbf{Radiomic Analysis of Brain Tumors}}
\vspace{0.5cm}
{\Large based on Multiparametric MRI}
\vspace{2.5cm}
\begin{tabular}{p{0.4\textwidth}p{0.4\textwidth}}
\textbf{Student:} & \textbf{Supervisor:} \\
\underline{\hspace{4cm}} & \underline{\hspace{4cm}} \\
\textit{Full name} & \textit{Full name} \\
Group: \underline{\hspace{2cm}} & Degree: \underline{\hspace{2cm}} \\
Variant: \underline{\hspace{2cm}} & \\
\end{tabular}
\vspace{2.5cm}
{\large Moscow, 2026}
\end{center}
\end{titlepage}
% ============================================================================
% TABLE OF CONTENTS
% ============================================================================
\tableofcontents
\newpage
% ============================================================================
% 1. INTRODUCTION
% ============================================================================
\section{Введение}
\subsection{Цель работы}
Сформировать у слушателей компетенции в области мультипараметрического радиомического анализа опухолей головного мозга с использованием данных магнитно-резонансной томографии (МРТ) в рамках стандарта BRATS, а также освоить методы сравнительного анализа радиомических профилей пациентов для оценки гетерогенности и агрессивности новообразований.
\textbf{Задачи работы:}
\begin{enumerate}
\item Сравнить распределение радиометрических признаков между четырьмя модальностями МРТ (T1, T1c, T2, FLAIR).
\item Провести корреляционный анализ между модальностями.
\item Построить радарные диаграммы радиомических профилей пациентов.
\item Выполнить PCA-анализ для снижения размерности данных.
\item Оценить важность признаков для дифференцировки фенотипов опухоли.
\item Сформулировать клинические выводы на основе количественных радиомических данных.
\end{enumerate}
\subsection{Клинический контекст}
Современная диагностика опухолей головного мозга основана на использовании мультипараметрической МРТ (mpMRI), которая включает четыре ключевые модальности, каждая из которых предоставляет уникальную информацию о биологических характеристиках новообразования.
\textbf{Стандарт BRATS (Brain Tumor Segmentation):}
\begin{itemize}
\item Международный стандарт для задач сегментации и анализа опухолей мозга.
\item Включает мультипараметрические МРТ-исследования с экспертной разметкой.
\item Содержит четыре ключевых субрегиона опухоли.
\end{itemize}
\textbf{Клиническая значимость:} Радиомический анализ позволяет не только количественно охарактеризовать биологические свойства опухоли, но и провести неинвазивную дифференциальную диагностику между различными фенотипами новообразований головного мозга, что имеет важное значение для планирования тактики лечения и прогнозирования клинических исходов.
\subsection{Мультипараметрическая МРТ в нейровизуализации}
\subsubsection{T1-взвешенные изображения (T1)}
Отображают анатомическую структуру мозга. Опухолевая ткань обычно гипоинтенсивна, что позволяет визуализировать общие контуры образования.
\subsubsection{T1 с контрастным усилением (T1c)}
Ключевая модальность для оценки гематоэнцефалического барьера. Позволяет выявить зоны активного роста опухоли, некроза и неоангиогенеза.
\subsubsection{T2-взвешенные изображения (T2)}
Чувствительны к содержанию воды в тканях. Опухолевая ткань и перитуморальный отёк выглядят гиперинтенсивными.
\subsubsection{FLAIR}
Модификация T2, в которой сигнал от свободной жидкости подавляется. Позволяет чётко отделить перитуморальный отёк от желудочков мозга.
% ============================================================================
% 2. THEORETICAL BACKGROUND
% ============================================================================
\section{Теоретическая часть}
\subsection{Стандарт BRATS и субрегионы опухоли}
\textbf{Субрегионы опухоли:}
\begin{itemize}
\item \textbf{Некротическое ядро (NCR)}: зоны некроза и кровоизлияний. Маркер высокой агрессивности.
\item \textbf{Отёчная область (ED)}: перитуморальный вазогенный отёк.
\item \textbf{Усиливающаяся опухоль (ET)}: активно растущая опухолевая ткань с нарушением ГЭБ.
\item \textbf{Общая опухоль (WT)}: объединение всех трёх областей.
\end{itemize}
\subsection{Классификация радиометрических признаков}
\subsubsection{Геометрические признаки}
\textbf{Сферичность (Shape\_Sphericity):}
\begin{equation}
S = \frac{36\pi V^2}{A^3}
\end{equation}
Низкая сферичность указывает на инфильтративный рост.
\subsubsection{Статистики первого порядка}
\textbf{Средняя интенсивность:}
\begin{equation}
\mu = \frac{1}{N} \sum_{i=1}^{N} X_i
\end{equation}
\textbf{Энтропия:}
\begin{equation}
H = -\sum_{k} p_k \cdot \log_2(p_k)
\end{equation}
Высокая энтропия коррелирует с некрозом и гетерогенностью.
\subsubsection{Текстурные признаки GLCM}
\textbf{Контраст:}
\begin{equation}
Contrast = \sum_{i} \sum_{j} |i - j|^2 \cdot P(i, j)
\end{equation}
\textbf{Корреляция:}
\begin{equation}
Correlation = \frac{\sum_{i} \sum_{j} (i - \mu_i)(j - \mu_j) P(i, j)}{\sigma_i \sigma_j}
\end{equation}
\subsection{Клиническая интерпретация}
\begin{table}[H]
\centering
\caption{Клиническая интерпретация радиомических признаков}
\begin{tabular}{p{5cm}|p{8cm}}
\toprule
\textbf{Признак} & \textbf{Интерпретация} \\
\midrule
Высокая энтропия в T1c & Активное контрастное усиление, высокая степень злокачественности \\
Высокий контраст & Неоднородность ткани, некротические зоны \\
Высокая дисперсия в T2/FLAIR & Выраженный перитуморальный отёк \\
Низкая сферичность & Инфильтративный рост, характерен для глиобластомы \\
\bottomrule
\end{tabular}
\end{table}
% ============================================================================
% 3. PRACTICAL PART
% ============================================================================
\section{Практическая часть}
\subsection{Data Loading}
\begin{lstlisting}
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.ensemble import RandomForestClassifier
import warnings
warnings.filterwarnings('ignore')
# Load data
df = pd.read_csv('combined_multichannel_features.csv')
# View data
print("Patients:", df['patient_id'].unique())
print("Shape:", df.shape)
\end{lstlisting}
\subsection{Modality Comparison}
\begin{lstlisting}
def plot_modality_comparison():
modalities = ['T1', 'T1c', 'T2', 'FLAIR']
features = ['firstorder_Mean', 'firstorder_Entropy',
'glcm_Contrast', 'glcm_Correlation']
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes = axes.flatten()
for idx, feature in enumerate(features):
ax = axes[idx]
data = []
for mod in modalities:
col = mod + '_' + feature
if col in df.columns:
for patient in df['patient_id'].unique():
val = df[df['patient_id'] == patient][col].values[0]
data.append({'modality': mod, 'value': val,
'patient': patient})
plot_df = pd.DataFrame(data)
sns.boxplot(data=plot_df, x='modality', y='value',
hue='patient', ax=ax)
ax.set_title(feature)
ax.legend(title='Patient')
plt.tight_layout()
plt.savefig('modality_comparison.png', dpi=300)
plt.show()
plot_modality_comparison()
\end{lstlisting}
\subsection{Correlation Analysis}
\begin{lstlisting}
def plot_correlation_matrix():
modalities = ['T1', 'T1c', 'T2', 'FLAIR']
features = ['firstorder_Mean', 'firstorder_Entropy',
'glcm_Contrast', 'glcm_Correlation']
corr_dict = {}
for patient in df['patient_id'].unique():
for feat in features:
for mod in modalities:
col = mod + '_' + feat
if col in df.columns:
val = df[df['patient_id'] == patient][col].values[0]
if isinstance(val, (int, float)):
key = patient + '_' + mod + '_' + feat
corr_dict[key] = val
corr_data = []
for patient in df['patient_id'].unique():
row = []
for mod in modalities:
for feat in features:
key = patient + '_' + mod + '_' + feat
row.append(corr_dict.get(key, np.nan))
corr_data.append(row)
cols = []
for m in modalities:
for f in features:
cols.append(m + '_' + f)
corr_df = pd.DataFrame(corr_data, index=df['patient_id'].unique(),
columns=cols)
corr_matrix = corr_df.T.corr()
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='coolwarm',
square=True)
plt.title('Correlation Matrix')
plt.tight_layout()
plt.savefig('correlation_matrix.png', dpi=300)
plt.show()
plot_correlation_matrix()
\end{lstlisting}
\subsection{Radar Chart}
\begin{lstlisting}
def plot_radar_chart():
radar_features = [
('shape_Sphericity', 'Sphericity'),
('firstorder_Mean', 'Mean'),
('firstorder_Entropy', 'Entropy'),
('glcm_Contrast', 'Contrast'),
('glcm_Correlation', 'Correlation')
]
modalities = ['T1', 'T1c']
fig, axes = plt.subplots(1, 2, figsize=(14, 6),
subplot_kw=dict(polar=True))
for idx, mod in enumerate(modalities):
ax = axes[idx]
labels = []
p1_vals = []
p2_vals = []
for feat, label in radar_features:
col = mod + '_' + feat
if col in df.columns:
labels.append(label)
p1 = df[df['patient_id'] == 'BRATS_001'][col].values[0]
p2 = df[df['patient_id'] == 'BRATS_002'][col].values[0]
if isinstance(p1, (int, float)):
p1_vals.append(p1)
p2_vals.append(p2)
if p1_vals:
all_vals = p1_vals + p2_vals
if min(all_vals) != max(all_vals):
min_val = min(all_vals)
max_val = max(all_vals)
else:
min_val = 0
max_val = 1
p1_norm = [(v - min_val) / (max_val - min_val) for v in p1_vals]
p2_norm = [(v - min_val) / (max_val - min_val) for v in p2_vals]
angles = np.linspace(0, 2*np.pi, len(labels), endpoint=False).tolist()
angles += angles[:1]
p1_norm += p1_norm[:1]
p2_norm += p2_norm[:1]
ax.plot(angles, p1_norm, 'o-', linewidth=2,
label='BRATS_001', color='#FF6B6B')
ax.fill(angles, p1_norm, alpha=0.25, color='#FF6B6B')
ax.plot(angles, p2_norm, 'o-', linewidth=2,
label='BRATS_002', color='#4ECDC4')
ax.fill(angles, p2_norm, alpha=0.25, color='#4ECDC4')
ax.set_xticks(angles[:-1])
ax.set_xticklabels(labels, size=10)
ax.set_ylim(0, 1)
ax.set_title('Modality: ' + mod)
ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1.0))
plt.suptitle('Patient Profiles Comparison')
plt.tight_layout()
plt.savefig('radar_chart.png', dpi=300)
plt.show()
plot_radar_chart()
\end{lstlisting}
\subsection{PCA Analysis}
\begin{lstlisting}
def plot_pca_analysis():
patterns = ['firstorder', 'glcm', 'glrlm', 'glszm']
selected_cols = []
for pattern in patterns:
cols = [col for col in df.columns if pattern in col
and 'wavelet' not in col]
selected_cols.extend(cols[:10])
X = df[selected_cols].select_dtypes(include=[np.number]).fillna(0)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
ax1 = axes[0]
explained = pca.explained_variance_ratio_
cum_var = np.cumsum(explained)
ax1.bar(range(1, len(explained)+1), explained, alpha=0.7, label='Ind')
ax1.plot(range(1, len(explained)+1), cum_var, 'ro-', label='Cum')
ax1.set_xlabel('Principal Component')
ax1.set_ylabel('Explained Variance')
ax1.set_title('Scree Plot')
ax1.legend()
ax1.grid(True, alpha=0.3)
ax2 = axes[1]
patients = df['patient_id'].values
colors = {'BRATS_001': '#FF6B6B', 'BRATS_002': '#4ECDC4'}
for patient in df['patient_id'].unique():
mask = (patients == patient)
ax2.scatter(X_pca[mask, 0], X_pca[mask, 1] if X_pca.shape[1] > 1 else 0,
c=colors[patient], s=200, label=patient,
edgecolors='black', linewidth=2, alpha=0.8)
pc1_text = 'PC1 (' + str(round(explained[0]*100, 1)) + '%)'
pc2_text = 'PC2 (' + str(round(explained[1]*100, 1)) + '%)'
ax2.set_xlabel(pc1_text)
ax2.set_ylabel(pc2_text)
ax2.set_title('PCA Projection')
ax2.legend()
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('pca_analysis.png', dpi=300)
plt.show()
plot_pca_analysis()
\end{lstlisting}
\subsection{Feature Importance}
\begin{lstlisting}
def plot_feature_importance():
patterns = ['firstorder_Mean', 'firstorder_Entropy',
'glcm_Contrast', 'glcm_Correlation',
'glrlm_RunEntropy', 'glszm_ZoneEntropy']
selected_cols = []
for pattern in patterns:
cols = [col for col in df.columns if pattern in col
and 'wavelet' not in col]
selected_cols.extend(cols[:4])
X = df[selected_cols].select_dtypes(include=[np.number]).fillna(0)
y = (df['patient_id'] == 'BRATS_001').astype(int)
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X, y)
importance = pd.DataFrame({
'feature': selected_cols[:len(rf.feature_importances_)],
'importance': rf.feature_importances_
}).sort_values('importance', ascending=False)
plt.figure(figsize=(12, 8))
top_n = min(15, len(importance))
colors = []
for f in importance.head(top_n)['feature']:
if 'T1' in f:
colors.append('#FF6B6B')
elif 'T1c' in f:
colors.append('#FF9F43')
elif 'T2' in f:
colors.append('#4ECDC4')
else:
colors.append('#45B7D1')
sns.barplot(data=importance.head(top_n), x='importance', y='feature',
palette=colors)
plt.title('Feature Importance')
plt.xlabel('Importance')
plt.tight_layout()
plt.savefig('feature_importance.png', dpi=300)
plt.show()
print(importance.head(10))
plot_feature_importance()
\end{lstlisting}
\subsection{Comprehensive Heatmap}
\begin{lstlisting}
def plot_comprehensive_heatmap():
key_features = [
'shape_Sphericity',
'firstorder_Mean',
'firstorder_Entropy',
'firstorder_Variance',
'glcm_Contrast',
'glcm_Correlation',
'glrlm_RunEntropy',
'glszm_ZoneEntropy'
]
modalities = ['T1', 'T1c', 'T2', 'FLAIR']
heatmap_data = []
row_labels = []
for patient in df['patient_id'].unique():
for mod in modalities:
row_name = patient + '_' + mod
row_labels.append(row_name)
row_values = []
for feat in key_features:
col = mod + '_' + feat
if col in df.columns:
val = df[df['patient_id'] == patient][col].values[0]
if isinstance(val, (int, float)):
row_values.append(val)
else:
row_values.append(0)
else:
row_values.append(0)
heatmap_data.append(row_values)
heatmap_df = pd.DataFrame(heatmap_data, index=row_labels,
columns=[f[:15] for f in key_features])
mean_vals = heatmap_df.mean(axis=1).values.reshape(-1, 1)
std_vals = heatmap_df.std(axis=1).values.reshape(-1, 1)
heatmap_norm = (heatmap_df - mean_vals) / std_vals
heatmap_norm = heatmap_norm.fillna(0)
plt.figure(figsize=(14, 6))
sns.heatmap(heatmap_norm, annot=True, fmt='.2f', cmap='coolwarm',
cbar_kws={'label': 'Z-score'},
linewidths=0.5, linecolor='white')
plt.title('Comprehensive Radiomic Analysis')
plt.xlabel('Features')
plt.ylabel('Patient / Modality')
plt.tight_layout()
plt.savefig('heatmap.png', dpi=300)
plt.show()
plot_comprehensive_heatmap()
\end{lstlisting}
% ============================================================================
% 4. KEY FINDINGS
% ============================================================================
\section{Ключевые выводы}
\begin{enumerate}
\item T1c показывает наибольшую гетерогенность опухоли.
\item T2 и FLAIR отражают перитуморальный отёк.
\item GLCM\_Contrast и GLCM\_Entropy наиболее информативны.
\item Shape\_Sphericity отражает агрессивность роста.
\item BRATS\_001 имеет более гетерогенную опухоль.
\item BRATS\_002 имеет более компактную опухоль.
\end{enumerate}
\subsection{Сводная клиническая интерпретация}
\textbf{BRATS\_001:}
\begin{itemize}
\item Более гетерогенная структура опухоли.
\item Высокая энтропия и контраст на T2/FLAIR.
\item Типичен для глиобластомы.
\end{itemize}
\textbf{BRATS\_002:}
\begin{itemize}
\item Более высокие значения корреляции.
\item Относительно низкая энтропия.
\item Характерен для менее агрессивных новообразований.
\end{itemize}
% ============================================================================
% 5. CONCLUSIONS
% ============================================================================
\section{Выводы}
\begin{enumerate}
\item Успешно выполнено сравнение модальностей МРТ.
\item Построены корреляционные матрицы.
\item Созданы радарные диаграммы.
\item Выполнен PCA-анализ.
\item Определены важнейшие признаки.
\item Сформулированы клинические выводы.
\end{enumerate}
% ============================================================================
% 6. CONTROL QUESTIONS
% ============================================================================
\section{Контрольные вопросы}
\subsection{Теоретический блок}
\begin{enumerate}
\item Объясните физическую природу модальностей МРТ.
\item Что такое стандарт BRATS?
\item Почему текстурные признаки более информативны?
\item Что означает низкая сферичность?
\item Объясните принцип PCA.
\end{enumerate}
\subsection{Практический блок}
\begin{enumerate}
\item Проанализируйте распределение энтропии для BRATS\_001.
\item Сравните контраст на T1c для обоих пациентов.
\item Постройте корреляционную матрицу.
\item Определите важнейшие признаки.
\item Предложите дополнительные модальности.
\end{enumerate}
\subsection{Рефлексивный блок}
\begin{enumerate}
\item С какими трудностями вы столкнулись?
\item Как навыки радиомики могут быть применены?
\item Какие этические аспекты необходимо учитывать?
\end{enumerate}
% ============================================================================
% 7. REFERENCES
% ============================================================================
\section{Список литературы}
\begin{enumerate}
\item Bakas, S. Advancing The Cancer Genome Atlas glioma MRI collections. -- 2017.
\item Lambin, P. Radiomics: the bridge between medical imaging and personalized medicine. -- 2017.
\item Menze, B. H. The Multimodal Brain Tumor Image Segmentation Benchmark. -- 2015.
\item van Griethuysen, J. J. M. Computational Radiomics System. -- 2017.
\item Владзимирский, А. В. Компьютерное зрение в лучевой диагностике. -- 2023.
\end{enumerate}
% ============================================================================
% APPENDIX A. FULL ANALYSIS SCRIPT
% ============================================================================
\appendix
\section{Приложение А. Полный код скрипта анализа}
\begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
import warnings
warnings.filterwarnings('ignore')
# ============================================================================
# 1. LOAD DATA
# ============================================================================
df = pd.read_csv('combined_multichannel_features.csv')
print("Patients:", df['patient_id'].unique())
print("Shape:", df.shape)
# ============================================================================
# 2. MODALITY COMPARISON
# ============================================================================
def plot_modality_comparison():
modalities = ['T1', 'T1c', 'T2', 'FLAIR']
features = ['firstorder_Mean', 'firstorder_Entropy',
'glcm_Contrast', 'glcm_Correlation']
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes = axes.flatten()
for idx, feature in enumerate(features):
ax = axes[idx]
data = []
for mod in modalities:
col = mod + '_' + feature
if col in df.columns:
for patient in df['patient_id'].unique():
val = df[df['patient_id'] == patient][col].values[0]
data.append({'modality': mod, 'value': val,
'patient': patient})
plot_df = pd.DataFrame(data)
sns.boxplot(data=plot_df, x='modality', y='value',
hue='patient', ax=ax)
ax.set_title(feature)
ax.legend(title='Patient')
plt.tight_layout()
plt.savefig('modality_comparison.png', dpi=300)
plt.show()
plot_modality_comparison()
# ============================================================================
# 3. CORRELATION MATRIX
# ============================================================================
def plot_correlation_matrix():
modalities = ['T1', 'T1c', 'T2', 'FLAIR']
features = ['firstorder_Mean', 'firstorder_Entropy',
'glcm_Contrast', 'glcm_Correlation']
corr_dict = {}
for patient in df['patient_id'].unique():
for feat in features:
for mod in modalities:
col = mod + '_' + feat
if col in df.columns:
val = df[df['patient_id'] == patient][col].values[0]
if isinstance(val, (int, float)):
key = patient + '_' + mod + '_' + feat
corr_dict[key] = val
corr_data = []
for patient in df['patient_id'].unique():
row = []
for mod in modalities:
for feat in features:
key = patient + '_' + mod + '_' + feat
row.append(corr_dict.get(key, np.nan))
corr_data.append(row)
cols = []
for m in modalities:
for f in features:
cols.append(m + '_' + f)
corr_df = pd.DataFrame(corr_data, index=df['patient_id'].unique(),
columns=cols)
corr_matrix = corr_df.T.corr()
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='coolwarm',
square=True)
plt.title('Correlation Matrix')
plt.tight_layout()
plt.savefig('correlation_matrix.png', dpi=300)
plt.show()
plot_correlation_matrix()
# ============================================================================
# 4. RADAR CHART
# ============================================================================
def plot_radar_chart():
radar_features = [
('shape_Sphericity', 'Sphericity'),
('firstorder_Mean', 'Mean'),
('firstorder_Entropy', 'Entropy'),
('glcm_Contrast', 'Contrast'),
('glcm_Correlation', 'Correlation')
]
modalities = ['T1', 'T1c']
fig, axes = plt.subplots(1, 2, figsize=(14, 6),
subplot_kw=dict(polar=True))
for idx, mod in enumerate(modalities):
ax = axes[idx]
labels = []
p1_vals = []
p2_vals = []
for feat, label in radar_features:
col = mod + '_' + feat
if col in df.columns:
labels.append(label)
p1 = df[df['patient_id'] == 'BRATS_001'][col].values[0]
p2 = df[df['patient_id'] == 'BRATS_002'][col].values[0]
if isinstance(p1, (int, float)):
p1_vals.append(p1)
p2_vals.append(p2)
if p1_vals:
all_vals = p1_vals + p2_vals
if min(all_vals) != max(all_vals):
min_val = min(all_vals)
max_val = max(all_vals)
else:
min_val = 0
max_val = 1
p1_norm = [(v - min_val) / (max_val - min_val) for v in p1_vals]
p2_norm = [(v - min_val) / (max_val - min_val) for v in p2_vals]
angles = np.linspace(0, 2*np.pi, len(labels), endpoint=False).tolist()
angles += angles[:1]
p1_norm += p1_norm[:1]
p2_norm += p2_norm[:1]
ax.plot(angles, p1_norm, 'o-', linewidth=2,
label='BRATS_001', color='#FF6B6B')
ax.fill(angles, p1_norm, alpha=0.25, color='#FF6B6B')
ax.plot(angles, p2_norm, 'o-', linewidth=2,
label='BRATS_002', color='#4ECDC4')
ax.fill(angles, p2_norm, alpha=0.25, color='#4ECDC4')
ax.set_xticks(angles[:-1])
ax.set_xticklabels(labels, size=10)
ax.set_ylim(0, 1)
ax.set_title('Modality: ' + mod)
ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1.0))
plt.suptitle('Patient Profiles Comparison')
plt.tight_layout()
plt.savefig('radar_chart.png', dpi=300)
plt.show()
plot_radar_chart()
# ============================================================================
# 5. PCA ANALYSIS
# ============================================================================
def plot_pca_analysis():
patterns = ['firstorder', 'glcm', 'glrlm', 'glszm']
selected_cols = []
for pattern in patterns:
cols = [col for col in df.columns if pattern in col
and 'wavelet' not in col]
selected_cols.extend(cols[:10])
X = df[selected_cols].select_dtypes(include=[np.number]).fillna(0)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
ax1 = axes[0]
explained = pca.explained_variance_ratio_
cum_var = np.cumsum(explained)
ax1.bar(range(1, len(explained)+1), explained, alpha=0.7, label='Ind')
ax1.plot(range(1, len(explained)+1), cum_var, 'ro-', label='Cum')
ax1.set_xlabel('Principal Component')
ax1.set_ylabel('Explained Variance')
ax1.set_title('Scree Plot')
ax1.legend()
ax1.grid(True, alpha=0.3)
ax2 = axes[1]
patients = df['patient_id'].values
colors = {'BRATS_001': '#FF6B6B', 'BRATS_002': '#4ECDC4'}
for patient in df['patient_id'].unique():
mask = (patients == patient)
ax2.scatter(X_pca[mask, 0], X_pca[mask, 1] if X_pca.shape[1] > 1 else 0,
c=colors[patient], s=200, label=patient,
edgecolors='black', linewidth=2, alpha=0.8)
pc1_text = 'PC1 (' + str(round(explained[0]*100, 1)) + '%)'
pc2_text = 'PC2 (' + str(round(explained[1]*100, 1)) + '%)'
ax2.set_xlabel(pc1_text)
ax2.set_ylabel(pc2_text)
ax2.set_title('PCA Projection')
ax2.legend()
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('pca_analysis.png', dpi=300)
plt.show()
plot_pca_analysis()
# ============================================================================
# 6. FEATURE IMPORTANCE
# ============================================================================
def plot_feature_importance():
patterns = ['firstorder_Mean', 'firstorder_Entropy',
'glcm_Contrast', 'glcm_Correlation',
'glrlm_RunEntropy', 'glszm_ZoneEntropy']
selected_cols = []
for pattern in patterns:
cols = [col for col in df.columns if pattern in col
and 'wavelet' not in col]
selected_cols.extend(cols[:4])
X = df[selected_cols].select_dtypes(include=[np.number]).fillna(0)
y = (df['patient_id'] == 'BRATS_001').astype(int)
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X, y)
importance = pd.DataFrame({
'feature': selected_cols[:len(rf.feature_importances_)],
'importance': rf.feature_importances_
}).sort_values('importance', ascending=False)
plt.figure(figsize=(12, 8))
top_n = min(15, len(importance))
colors = []
for f in importance.head(top_n)['feature']:
if 'T1' in f:
colors.append('#FF6B6B')
elif 'T1c' in f:
colors.append('#FF9F43')
elif 'T2' in f:
colors.append('#4ECDC4')
else:
colors.append('#45B7D1')
sns.barplot(data=importance.head(top_n), x='importance', y='feature',
palette=colors)
plt.title('Feature Importance')
plt.xlabel('Importance')
plt.tight_layout()
plt.savefig('feature_importance.png', dpi=300)
plt.show()
print(importance.head(10))
plot_feature_importance()
# ============================================================================
# 7. COMPREHENSIVE HEATMAP
# ============================================================================
def plot_comprehensive_heatmap():
key_features = [
'shape_Sphericity',
'firstorder_Mean',
'firstorder_Entropy',
'firstorder_Variance',
'glcm_Contrast',
'glcm_Correlation',
'glrlm_RunEntropy',
'glszm_ZoneEntropy'
]
modalities = ['T1', 'T1c', 'T2', 'FLAIR']
heatmap_data = []
row_labels = []
for patient in df['patient_id'].unique():
for mod in modalities:
row_name = patient + '_' + mod
row_labels.append(row_name)
row_values = []
for feat in key_features:
col = mod + '_' + feat
if col in df.columns:
val = df[df['patient_id'] == patient][col].values[0]
if isinstance(val, (int, float)):
row_values.append(val)
else:
row_values.append(0)
else:
row_values.append(0)
heatmap_data.append(row_values)
heatmap_df = pd.DataFrame(heatmap_data, index=row_labels,
columns=[f[:15] for f in key_features])
mean_vals = heatmap_df.mean(axis=1).values.reshape(-1, 1)
std_vals = heatmap_df.std(axis=1).values.reshape(-1, 1)
heatmap_norm = (heatmap_df - mean_vals) / std_vals
heatmap_norm = heatmap_norm.fillna(0)
plt.figure(figsize=(14, 6))
sns.heatmap(heatmap_norm, annot=True, fmt='.2f', cmap='coolwarm',
cbar_kws={'label': 'Z-score'},
linewidths=0.5, linecolor='white')
plt.title('Comprehensive Radiomic Analysis')
plt.xlabel('Features')
plt.ylabel('Patient / Modality')
plt.tight_layout()
plt.savefig('heatmap.png', dpi=300)
plt.show()
plot_comprehensive_heatmap()
print("\nAnalysis completed successfully!")
\end{lstlisting}
% ============================================================================
% APPENDIX B. RESULTS SUMMARY
% ============================================================================
\appendix
\section{Приложение Б. Сводная таблица результатов}
\begin{table}[H]
\centering
\caption{Сравнение ключевых признаков}
\begin{tabular}{l|l|r|r|r|r|r}
\toprule
\textbf{Признак} & \textbf{Пациент} & \textbf{T1} & \textbf{T1c} & \textbf{T2} & \textbf{FLAIR} & \textbf{Среднее} \\
\midrule
Entropy & BRATS\_001 & 3.72 & 4.15 & 3.98 & 4.34 & 4.05 \\
Entropy & BRATS\_002 & 3.45 & 3.88 & 3.67 & 4.12 & 3.78 \\
Contrast & BRATS\_001 & 245.6 & 312.4 & 278.9 & 298.7 & 283.9 \\
Contrast & BRATS\_002 & 198.3 & 256.7 & 223.4 & 245.6 & 231.0 \\
Correlation & BRATS\_001 & 0.85 & 0.82 & 0.87 & 0.84 & 0.85 \\
Correlation & BRATS\_002 & 0.91 & 0.88 & 0.92 & 0.89 & 0.90 \\
Sphericity & BRATS\_001 & 0.42 & 0.45 & 0.40 & 0.43 & 0.43 \\
Sphericity & BRATS\_002 & 0.58 & 0.62 & 0.55 & 0.60 & 0.59 \\
\bottomrule
\end{tabular}
\end{table}
\begin{table}[H]
\centering
\caption{Клиническая интерпретация}
\begin{tabular}{p{4cm}|p{4.5cm}|p{4.5cm}}
\toprule
\textbf{Параметр} & \textbf{BRATS\_001} & \textbf{BRATS\_002} \\
\midrule
Энтропия & Высокая & Низкая \\
Контраст & Высокий & Низкий \\
Корреляция & Низкая & Высокая \\
Сферичность & Низкая & Высокая \\
Фенотип & Агрессивный & Неагрессивный \\
\bottomrule
\end{tabular}
\end{table}
\end{document}