Violin Plot в Python: мощный инструмент визуализации данных
Пройдите тест, узнайте какой профессии подходите
Для кого эта статья:
- профессионалы в области аналитики данных
- студенты и начинающие аналитики, изучающие визуализацию данных
- специалисты, работающие с Python и библиотеками для анализа данных
Визуализация данных — ключевой компонент аналитики, позволяющий превращать числовые массивы в интуитивно понятные образы. Среди множества инструментов Python особое место занимает Violin Plot — элегантное решение для детального анализа распределения данных. Этот график объединяет преимущества box plot и kernel density plot, позволяя одновременно оценить медиану, квартили, плотность распределения и выбросы. В 2025 году, когда объемы анализируемых данных продолжают расти экспоненциально, Violin Plot становится незаменимым инструментом для тех, кто стремится извлечь максимум информации из своих датасетов. 📊🎻
Хотите освоить передовые методы визуализации данных, включая Violin Plot и другие мощные инструменты? Курс «Аналитик данных» с нуля от Skypro — это ваш путь к профессиональному владению Python для анализа данных. Курс включает практические проекты с реальными данными, где вы научитесь создавать информативные визуализации, которые помогают принимать обоснованные решения. Инвестируйте в свои навыки сейчас, чтобы стать востребованным специалистом на рынке аналитики!
Что такое Violin Plot и его роль в анализе данных
Violin Plot (скрипичная диаграмма) представляет собой гибридный инструмент визуализации, сочетающий в себе элементы box plot (ящик с усами) и kernel density plot (график плотности вероятности). Название происходит от характерной формы графика, напоминающей скрипку или виолончель. 🎻
Основная ценность Violin Plot заключается в его способности одновременно отображать:
- Полное распределение данных (через кривые плотности вероятности)
- Медиану и квартили (через внутренние элементы "ящика")
- Минимумы и максимумы (через "усы")
- Выбросы (через отдельные точки)
- Сравнительную плотность вероятности на разных участках распределения (через ширину "скрипки")
Алексей Петров, старший аналитик данных
Я столкнулся с необходимостью проанализировать время отклика API в различных географических регионах. Традиционные графики показывали только среднее значение и стандартное отклонение, что скрывало критические аномалии в данных. Внедрив Violin Plot в наш аналитический дашборд, мы обнаружили бимодальное распределение в некоторых регионах — это указывало на периодические проблемы с сетевой инфраструктурой. Благодаря этой находке мы оптимизировали маршрутизацию трафика и снизили время отклика на 37%. Скрипичные диаграммы позволили увидеть то, что оставалось невидимым на стандартных графиках, и это кардинально изменило наш подход к мониторингу производительности.
Преимущества Violin Plot по сравнению с другими методами визуализации:
Тип графика | Отображение распределения | Показ статистических метрик | Сравнение групп | Визуализация бимодальности |
---|---|---|---|---|
Violin Plot | Полное + плотность | Медиана, квартили, диапазон | Отличное | Явное |
Box Plot | Ограниченное | Медиана, квартили, диапазон | Хорошее | Отсутствует |
Histogram | Дискретное | Только визуально | Ограниченное | Видимое, но неточное |
Density Plot | Непрерывное | Отсутствуют | Среднее | Видимое |
Violin Plot становится особенно ценным в следующих ситуациях:
- При анализе асимметричных распределений, где среднее значение не является репрезентативным
- При выявлении мультимодальных распределений (имеющих несколько "пиков")
- При сравнении нескольких групп данных с различной структурой распределения
- При необходимости детального анализа выбросов в контексте всего распределения

Создание базовых Violin Plot в Python с помощью Seaborn
Библиотека Seaborn делает создание Violin Plot в Python исключительно простым и гибким процессом. Рассмотрим основные способы построения скрипичных диаграмм с использованием различных наборов данных. 🐍
Для начала необходимо импортировать все необходимые библиотеки:
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# Установка стиля Seaborn
sns.set(style="whitegrid")
Базовый Violin Plot можно создать буквально одной строкой кода:
# Загрузка демонстрационного набора данных
tips = sns.load_dataset("tips")
# Создание базового Violin Plot
plt.figure(figsize=(10, 6))
sns.violinplot(x="day", y="total_bill", data=tips)
plt.title("Распределение счетов по дням недели")
plt.show()
Для сравнения нескольких категорий с дополнительной группировкой:
# Violin Plot с группировкой по полу
plt.figure(figsize=(12, 7))
sns.violinplot(x="day", y="total_bill", hue="sex", data=tips, split=True, palette="Set2")
plt.title("Распределение счетов по дням недели и полу клиентов")
plt.show()
Ключевые параметры функции violinplot
в Seaborn:
Параметр | Описание | Возможные значения |
---|---|---|
data | DataFrame с данными | pandas.DataFrame |
x, y | Переменные для осей X и Y | Имена столбцов в DataFrame |
hue | Группировка по категориям | Имя категориального столбца |
split | Разделение "скрипок" для hue | True/False |
inner | Представление внутри "скрипки" | "box", "quartile", "point", "stick", None |
scale | Метод масштабирования ширины | "area", "count", "width" |
bw | Сглаживание кривой плотности | float или {"scott", "silverman"} |
Для работы с собственными данными вы можете использовать DataFrame из любого источника:
# Пример с загрузкой данных из CSV
# df = pd.read_csv("path_to_your_data.csv")
# sns.violinplot(x="category_column", y="numeric_column", data=df)
# Пример с созданием синтетических данных
np.random.seed(42)
categories = ['A', 'B', 'C', 'D']
data = pd.DataFrame({
'category': np.random.choice(categories, 1000),
'value': np.concatenate([
np.random.normal(0, 1, 250), # Нормальное распределение для A
np.random.gamma(2, 2, 250), # Гамма-распределение для B
np.random.exponential(2, 250), # Экспоненциальное для C
np.concatenate([np.random.normal(-3, 1, 125), np.random.normal(3, 1, 125)]) # Бимодальное для D
])
})
plt.figure(figsize=(12, 7))
sns.violinplot(x="category", y="value", data=data, inner="quartile", palette="viridis")
plt.title("Violin Plot различных распределений")
plt.show()
Для сравнения с другими типами визуализаций можно совместить несколько графиков:
# Сравнение Violin Plot с Box Plot
plt.figure(figsize=(15, 6))
plt.subplot(1, 2, 1)
sns.violinplot(x="category", y="value", data=data, inner="quartile")
plt.title("Violin Plot")
plt.subplot(1, 2, 2)
sns.boxplot(x="category", y="value", data=data)
plt.title("Box Plot")
plt.tight_layout()
plt.show()
Настройка и стилизация Violin Plot для презентаций
Профессиональная визуализация данных требует не только информативности, но и эстетического оформления, особенно для презентаций и публикаций. Seaborn предоставляет обширные возможности для настройки внешнего вида Violin Plot. 🎨
Начнем с базовой настройки стилей Seaborn:
# Установка стилей для презентационного качества
sns.set(style="whitegrid", context="talk", palette="pastel")
plt.figure(figsize=(12, 8))
# Создание основного графика с улучшенным стилем
vp = sns.violinplot(x="day", y="total_bill", data=tips, inner="quartile",
palette="Set2", linewidth=1.5, saturation=0.8)
# Настройка осей и заголовков
plt.title("Распределение счетов по дням недели", fontsize=18, pad=20)
plt.xlabel("День недели", fontsize=14, labelpad=15)
plt.ylabel("Сумма счета ($)", fontsize=14, labelpad=15)
# Улучшение сетки для читаемости
plt.grid(axis='y', alpha=0.3, linestyle='--')
# Настройка тиков осей
plt.xticks(fontsize=12)
plt.yticks(fontsize=12)
# Добавление аннотаций
medians = tips.groupby('day')['total_bill'].median().values
positions = range(len(medians))
for pos, median in zip(positions, medians):
plt.text(pos, median+1, f"${median:.2f}", horizontalalignment='center',
size='medium', color='darkblue', weight='semibold')
plt.tight_layout()
plt.show()
Для создания многоуровневых Violin Plot с дополнительной информацией:
# Создание более сложного Violin Plot с подгруппами
plt.figure(figsize=(14, 8))
# Основной график с разделением по двум категориям
vp = sns.violinplot(x="day", y="total_bill", hue="time", data=tips,
split=True, inner="quartile", palette={"Lunch": "#9b59b6", "Dinner": "#3498db"},
linewidth=1.2, cut=0)
# Добавление swarmplot для отображения фактических точек данных
sns.swarmplot(x="day", y="total_bill", hue="time", data=tips,
size=4, edgecolor="gray", linewidth=0.5,
palette={"Lunch": "#d2b4de", "Dinner": "#aed6f1"},
dodge=True, alpha=0.7)
# Улучшение легенды
handles, labels = vp.get_legend_handles_labels()
plt.legend(handles[:2], labels[:2], title="Время приема пищи",
loc="upper right", frameon=True, fontsize=12)
# Настройка осей и заголовков
plt.title("Распределение счетов по дням недели и времени приема пищи",
fontsize=18, pad=20)
plt.xlabel("День недели", fontsize=14, labelpad=15)
plt.ylabel("Сумма счета ($)", fontsize=14, labelpad=15)
# Персонализация стиля графика
plt.grid(axis='y', alpha=0.3, linestyle='-.')
sns.despine(left=False, bottom=False)
plt.tight_layout()
plt.show()
Для создания высокоинформативных и стилизованных Violin Plot с добавлением статистической информации:
# Создание Violin Plot со статистическими элементами
plt.figure(figsize=(14, 10))
# Измененный формат основного графика
vp = sns.violinplot(x="day", y="total_bill", data=tips, inner=None,
palette="YlGnBu", cut=0, width=0.8)
# Наложение boxplot для отображения статистических параметров
sns.boxplot(x="day", y="total_bill", data=tips, width=0.15,
color="white", boxprops={"zorder": 2}, showfliers=False)
# Добавление фактических точек данных с jitter
sns.stripplot(x="day", y="total_bill", data=tips, size=3,
color=".3", linewidth=0, alpha=0.4, jitter=True)
# Расчет и отображение статистик
for i, day in enumerate(tips['day'].unique()):
day_data = tips[tips['day'] == day]['total_bill']
# Среднее значение
plt.text(i, day_data.mean()+1, f"μ={day_data.mean():.2f}",
horizontalalignment='center', size=11, color='darkgreen')
# Медиана уже показана в boxplot
# Стандартное отклонение
plt.text(i, day_data.max()+2, f"σ={day_data.std():.2f}",
horizontalalignment='center', size=11, color='darkred')
# Улучшение внешнего вида
plt.title("Расширенный анализ распределения счетов по дням недели",
fontsize=18, pad=20)
plt.xlabel("День недели", fontsize=14, labelpad=15)
plt.ylabel("Сумма счета ($)", fontsize=14, labelpad=15)
# Добавление подписи и пояснительного текста
plt.figtext(0.15, 0.01, "Примечание: μ – среднее значение, σ – стандартное отклонение",
fontsize=10, style='italic')
plt.tight_layout(pad=2)
plt.show()
Дополнительные советы по стилизации для профессиональных презентаций:
- Используйте согласованные цветовые схемы, соответствующие вашему бренду или теме презентации
- Для научных публикаций выбирайте цветовые палитры, которые хорошо воспроизводятся при печати в оттенках серого
- Добавляйте информативные подписи, пояснения и аннотации прямо на графике
- Для сравнения нескольких категорий используйте цветовые градиенты вместо ярко контрастирующих цветов
- Сохраняйте графики в векторных форматах (SVG, PDF) для презентаций высокого качества
Мария Соколова, руководитель отдела аналитики
Подготовка отчета для руководства о влиянии нового образовательного продукта на результаты студентов поставила перед нами серьезный вызов. У нас были данные по тестовым баллам, но стандартные столбчатые диаграммы средних значений не передавали полной картины. Решение пришло с Violin Plot — я создала сравнительную визуализацию, где контрольная и экспериментальная группы были представлены рядом. График наглядно показывал не только улучшение средних показателей, но и важнейший факт: новая методика особенно помогала отстающим студентам. Руководство, увидев эту визуализацию, моментально поняло ценность продукта и утвердило масштабное внедрение методики. Violin Plot превратил сложные статистические данные в четкую историю успеха, понятную даже нетехническим специалистам.
Сравнительный анализ распределений с Violin Plot
Одно из главных преимуществ Violin Plot — возможность наглядного сравнения распределений между различными группами данных. Это особенно полезно при проведении А/Б-тестирования, сравнении демографических групп или анализе изменений во времени. 📈
Рассмотрим методы эффективного построения сравнительных Violin Plot для выявления различий в распределениях:
# Загрузка датасета для демонстрации
diamonds = sns.load_dataset("diamonds")
# Подготовка данных для сравнения (выборка для ускорения визуализации)
diamonds_sample = diamonds.sample(n=3000, random_state=42)
# Сравнение распределения цен бриллиантов по качеству огранки
plt.figure(figsize=(14, 8))
# Основной Violin Plot
sns.violinplot(x="cut", y="price", data=diamonds_sample,
palette="viridis", inner="quartile",
order=["Fair", "Good", "Very Good", "Premium", "Ideal"])
# Настройка графика
plt.title("Распределение цен бриллиантов по качеству огранки", fontsize=16)
plt.xlabel("Качество огранки", fontsize=14)
plt.ylabel("Цена (USD)", fontsize=14)
plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.show()
Для более детального сравнения можно добавить статистические тесты:
from scipy import stats
import numpy as np
# Функция для расчета и отображения результатов статистических тестов
def add_statistical_comparison(ax, data, x_var, y_var, pairs):
# Получение уникальных категорий и их позиций
categories = data[x_var].unique()
positions = dict(zip(categories, range(len(categories))))
# Высота для размещения скобок сравнения
y_max = data[y_var].max()
for i, (group1, group2) in enumerate(pairs):
# Получение данных для каждой группы
data1 = data[data[x_var] == group1][y_var]
data2 = data[data[x_var] == group2][y_var]
# Выполнение t-теста
t_stat, p_value = stats.ttest_ind(data1, data2, equal_var=False)
# Определение высоты для текущего сравнения
height = y_max + (i + 1) * (y_max * 0.05)
# Добавление скобки и p-value
x1, x2 = positions[group1], positions[group2]
plt.plot([x1, x1, x2, x2], [height-y_max*0.02, height, height, height-y_max*0.02],
lw=1.5, c='black')
# Форматирование p-value для отображения
if p_value < 0.001:
p_text = "p < 0.001 ***"
elif p_value < 0.01:
p_text = f"p = {p_value:.3f} **"
elif p_value < 0.05:
p_text = f"p = {p_value:.3f} *"
else:
p_text = f"p = {p_value:.3f} (ns)"
plt.text((x1+x2)/2, height+y_max*0.01, p_text, ha='center', va='bottom', fontsize=12)
# Создание основного графика
plt.figure(figsize=(16, 10))
ax = sns.violinplot(x="cut", y="price", data=diamonds_sample,
palette="viridis", inner="quartile",
order=["Fair", "Good", "Very Good", "Premium", "Ideal"])
# Добавление статистических сравнений
pairs_to_compare = [("Fair", "Good"), ("Good", "Very Good"),
("Very Good", "Premium"), ("Premium", "Ideal")]
add_statistical_comparison(ax, diamonds_sample, "cut", "price", pairs_to_compare)
# Настройка графика
plt.title("Статистическое сравнение цен бриллиантов по качеству огранки", fontsize=16)
plt.xlabel("Качество огранки", fontsize=14)
plt.ylabel("Цена (USD)", fontsize=14)
plt.ylim(0, diamonds_sample["price"].max() * 1.3) # Расширение для аннотаций
plt.grid(axis='y', linestyle='--', alpha=0.7)
# Пояснение к уровням значимости
plt.figtext(0.15, 0.01, "Уровни значимости: *** p<0.001, ** p<0.01, * p<0.05, ns – не значимо",
fontsize=10, style='italic')
plt.tight_layout()
plt.show()
Для двумерного сравнения с дополнительной группировкой:
# Сравнение распределения цен по огранке и прозрачности
plt.figure(figsize=(18, 10))
# Фильтрация датасета для четкой визуализации
clarity_order = ["I1", "SI2", "SI1", "VS2", "VS1", "VVS2", "VVS1", "IF"]
cut_order = ["Fair", "Good", "Very Good", "Premium", "Ideal"]
# Создание основного графика с двумя факторами
sns.violinplot(x="clarity", y="price", hue="cut", data=diamonds_sample,
palette="YlOrBr", split=False, inner="quartile",
order=clarity_order, hue_order=cut_order,
scale="width", gridsize=100)
# Улучшение читаемости визуализации
plt.title("Сравнительный анализ цен бриллиантов по прозрачности и качеству огранки", fontsize=16)
plt.xlabel("Прозрачность", fontsize=14)
plt.ylabel("Цена (USD)", fontsize=14)
plt.legend(title="Качество огранки", fontsize=12, title_fontsize=13)
plt.grid(axis='y', linestyle='--', alpha=0.4)
# Поворот подписей x-оси для лучшей читаемости
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
Ключевые методики для эффективного сравнительного анализа с помощью Violin Plot:
Тип сравнения | Методика | Когда использовать |
---|---|---|
Простое сравнение групп | Базовый violinplot с упорядоченными категориями | При сравнении до 7-8 групп с одномерными данными |
Попарное сравнение со статистикой | Violinplot + статистические тесты с аннотациями | Для научных публикаций, требующих строгих статистических доказательств |
Многофакторное сравнение | Violinplot с параметром hue для группировки | При анализе взаимодействия двух категориальных переменных |
До/После сравнение | Парные violinplot с разделенной осью | При анализе изменений в эксперименте, А/Б-тестировании |
Многомерное сравнение | Матрица violinplot (FacetGrid) | При необходимости сравнения по трем и более измерениям |
Для создания матрицы сравнительных Violin Plot:
# Создание матрицы Violin Plot для многомерного сравнения
g = sns.FacetGrid(diamonds_sample, col="color", row="cut",
margin_titles=True, height=3, aspect=1.2,
col_order=["D", "E", "F", "G", "H", "I", "J"],
row_order=["Ideal", "Premium", "Very Good", "Good", "Fair"])
# Определение функции построения для каждой ячейки
g.map(sns.violinplot, "clarity", "price", inner=None, order=clarity_order,
palette="mako", cut=0, linewidth=1)
# Добавление индивидуальных точек для малых выборок
g.map(sns.stripplot, "clarity", "price", size=2, color=".3",
linewidth=0, alpha=0.5, jitter=True)
# Настройка общих заголовков и подписей
g.set_axis_labels("Прозрачность", "Цена (USD)")
g.set_titles(col_template="Цвет: {col_name}", row_template="Огранка: {row_name}")
g.fig.suptitle("Многомерный анализ цен бриллиантов", fontsize=18)
g.fig.subplots_adjust(top=0.93)
# Поворот подписей оси x
for ax in g.axes.flat:
ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
plt.tight_layout()
plt.show()
Хотите определить, какое направление в аналитике лучше всего подходит для ваших навыков и интересов? Тест на профориентацию от Skypro поможет вам понять, стоит ли развиваться в области визуальной аналитики данных или ваши таланты лежат в другой сфере. Пройдите короткий онлайн-тест и получите персональные рекомендации по карьерному развитию, включая оценку ваших способностей к работе с такими инструментами как Violin Plot и другими методами визуализации данных.
Практические кейсы применения Violin Plot в исследованиях
Violin Plot находит широкое применение в различных областях исследований, от научных экспериментов до бизнес-аналитики. Рассмотрим несколько практических кейсов с реализацией в Python. 🔬
- Фармацевтические исследования: анализ эффективности препаратов
# Синтетические данные для демонстрации
np.random.seed(42)
drug_data = pd.DataFrame({
'Drug': np.repeat(['A', 'B', 'C', 'Placebo'], 50),
'Response': np.concatenate([
np.random.normal(30, 5, 50), # Препарат A
np.random.normal(25, 7, 50), # Препарат B
np.random.normal(40, 4, 50), # Препарат C
np.random.normal(20, 6, 50) # Плацебо
]),
'Age_Group': np.random.choice(['18-30', '31-45', '46-60', '60+'], 200)
})
# Создание расширенного Violin Plot
plt.figure(figsize=(14, 8))
# Основной график с цветовым кодированием по возрастным группам
ax = sns.violinplot(x="Drug", y="Response", hue="Age_Group", data=drug_data,
palette="rocket", inner="quartile", split=False)
# Наложение точек данных для детального рассмотрения
sns.stripplot(x="Drug", y="Response", hue="Age_Group", data=drug_data,
dodge=True, alpha=0.3, jitter=True, size=4, linewidth=1,
palette="rocket")
# Устранение дублирования в легенде
handles, labels = ax.get_legend_handles_labels()
plt.legend(handles[:4], labels[:4], title="Возрастная группа",
bbox_to_anchor=(1.05, 1), loc='upper left')
# Добавление статистической информации о средних значениях
for i, drug in enumerate(drug_data['Drug'].unique()):
mean_val = drug_data[drug_data['Drug'] == drug]['Response'].mean()
plt.text(i, mean_val + 2, f"μ = {mean_val:.1f}",
ha='center', va='bottom', fontsize=12, weight='bold')
# Настройка внешнего вида
plt.title("Сравнение эффективности препаратов по возрастным группам", fontsize=16)
plt.xlabel("Препарат", fontsize=14)
plt.ylabel("Клинический ответ (единицы измерения)", fontsize=14)
plt.grid(axis='y', linestyle='--', alpha=0.5)
plt.tight_layout()
plt.show()
- Финансовый анализ: распределение доходности различных инвестиционных инструментов
# Синтетические данные о доходности инвестиций
np.random.seed(42)
investments = pd.DataFrame({
'Type': np.repeat(['Stocks', 'Bonds', 'Real_Estate', 'Crypto', 'Commodities'], 100),
'Return': np.concatenate([
np.random.normal(8, 15, 100), # Акции
np.random.normal(4, 3, 100), # Облигации
np.random.normal(6, 5, 100), # Недвижимость
np.concatenate([ # Криптовалюта (бимодальное распределение)
np.random.normal(20, 10, 50),
np.random.normal(-10, 15, 50)
]),
np.random.normal(5, 8, 100) # Сырьевые товары
]),
'Year': np.random.choice(['2021', '2022', '2023', '2024', '2025'], 500)
})
# Расчет статистики рисков
risk_stats = investments.groupby('Type')['Return'].agg(['std', 'mean', 'median',
lambda x: np.percentile(x, 10),
lambda x: np.percentile(x, 90)])
risk_stats.columns = ['Волатильность', 'Средняя доходность', 'Медиана', 'P10', 'P90']
risk_stats['Коэф. Шарпа'] = risk_stats['Средняя доходность'] / risk_stats['Волатильность']
risk_stats = risk_stats.sort_values('Коэф. Шарпа', ascending=False)
# Создание визуализации
plt.figure(figsize=(15, 10))
# Основной график
order = risk_stats.index
sns.violinplot(x="Type", y="Return", data=investments, inner="quartile",
palette="Blues", order=order, cut=0)
# Добавление горизонтальной линии на уровне нулевой доходности
plt.axhline(y=0, color='red', linestyle='--', alpha=0.7)
# Аннотации с ключевыми рисковыми метриками
for i, typ in enumerate(order):
stats = risk_stats.loc[typ]
plt.annotate(f"Волат: {stats['Волатильность']:.1f}\nШарп: {stats['Коэф. Шарпа']:.2f}",
xy=(i, stats['P90'] + 2), xytext=(i, stats['P90'] + 5),
ha='center', va='bottom', fontsize=10,
bbox=dict(boxstyle="round,pad=0.3", fc='white', ec="gray", alpha=0.8))
# Настройка внешнего вида
plt.title("Распределение доходности по типам инвестиций (2021-2025)", fontsize=16)
plt.xlabel("Тип инвестиций", fontsize=14)
plt.ylabel("Годовая доходность (%)", fontsize=14)
plt.grid(axis='y', linestyle='--', alpha=0.5)
# Улучшение читаемости оси x
plt.xticks([0, 1, 2, 3, 4], ['Акции', 'Облигации', 'Недвижимость',
'Криптовалюта', 'Сырьевые товары'], rotation=0)
plt.tight_layout()
plt.show()
- Образовательная аналитика: анализ результатов студентов до и после внедрения новых методик обучения
# Синтетические данные об успеваемости
np.random.seed(42)
n_students = 200
student_data = pd.DataFrame({
'Student_ID': range(1, n_students + 1),
'Group': np.repeat(['Control', 'Experimental'], n_students // 2),
'Score_Before': np.concatenate([
np.random.normal(65, 15, n_students // 2), # Контрольная группа
np.random.normal(63, 14, n_students // 2) # Экспериментальная группа
]),
})
# Создание результатов после эксперимента с различным эффектом
control_after = student_data[student_data['Group'] == 'Control']['Score_Before'] + np.random.normal(5, 5, n_students // 2)
experimental_after = student_data[student_data['Group'] == 'Experimental']['Score_Before'] + np.random.normal(15, 8, n_students // 2)
student_data['Score_After'] = np.concatenate([control_after, experimental_after])
# Преобразование в "длинный" формат для визуализации
student_long = pd.melt(student_data,
id_vars=['Student_ID', 'Group'],
value_vars=['Score_Before', 'Score_After'],
var_name='Time', value_name='Score')
student_long['Time'] = student_long['Time'].str.replace('Score_', '')
# Создание визуализации
plt.figure(figsize=(14, 9))
# Основной график
sns.violinplot(x="Group", y="Score", hue="Time", data=student_long,
split=True, inner="quart", palette={"Before": "#3498db", "After": "#2ecc71"},
cut=0)
# Добавление линий, соединяющих средние значения
for group in ['Control', 'Experimental']:
group_data = student_long[student_long['Group'] == group]
mean_before = group_data[group_data['Time'] == 'Before']['Score'].mean()
mean_after = group_data[group_data['Time'] == 'After']['Score'].mean()
idx = 0 if group == 'Control' else 1
plt.plot([idx-0.2, idx+0.2], [mean_before, mean_after], color='black',
linestyle='-', linewidth=2, marker='o', markersize=8)
# Добавление аннотации об улучшении
improvement = mean_after – mean_before
plt.annotate(f"+{improvement:.1f}", xy=(idx, (mean_before + mean_after)/2 + 2),
xytext=(idx + 0.35, (mean_before + mean_after)/2 + 2),
arrowprops=dict(arrowstyle='->'), fontsize=12, fontweight='bold',
color='darkgreen' if improvement > 10 else 'black')
# Настройка внешнего вида
plt.title("Влияние новой методики обучения на результаты студентов", fontsize=16)
plt.xlabel("Группа", fontsize=14)
plt.ylabel("Тестовый балл", fontsize=14)
plt.grid(axis='y', linestyle='--', alpha=0.5)
plt.ylim(20, 110)
# Добавление аннотации с описанием результатов
plt.figtext(0.15, 0.01,
"Экспериментальная группа показала значительно более высокое улучшение показателей\n" +
"по сравнению с контрольной группой, что подтверждает эффективность новой методики.",
fontsize=12)
plt.tight_layout()
plt.show()
Другие области практического применения Violin Plot:
- Биомедицинские исследования: анализ экспрессии генов, сравнение биомаркеров между группами пациентов
- Социологические исследования: визуализация распределения мнений по разным демографическим группам
- Инженерный анализ: сравнение производительности различных систем или конфигураций
- Экологические исследования: анализ распределения биологических показателей в разных экосистемах
- Маркетинговые исследования: сравнение потребительских предпочтений между сегментами рынка
- Спортивная аналитика: сравнение распределения показателей производительности спортсменов
- Психологические исследования: анализ распределения результатов психологических тестов
Violin Plot — это не просто визуальный инструмент, а мощный способ глубокого понимания данных, который превосходит традиционные методы визуализации. Объединяя в себе лучшие качества box plot и плотностного распределения, скрипичные диаграммы позволяют аналитикам одновременно видеть центральные тенденции, вариативность, форму распределения и выбросы. Эта многогранность делает их незаменимыми при сравнительном анализе групп, выявлении неоднородностей в данных и поиске скрытых закономерностей. Владение этим инструментом — признак профессионального аналитика, способного извлечь максимум информации из своих данных.