Привет, Хабр!

Сегодня с вами участница профессионального сообщества NTA Яруллина Ляйсян.

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

Но не менее важной в указанном вопросе является статистика. Она позволяет провести качественную обработку данных и сделать выводы на ее основе — без статистической базы графическое представление данных не несет особой ценности. И в наше время океана неподтвержденной информации это куда более серьезная проблема, чем могло бы показаться изначально. Поэтому важно уметь быстро внедрять аннотации статистической значимости в полученную визуализацию и уметь ее расшифровывать.

В последние годы создаются специальные статистические пакеты, которые позволяют реализовать вышеизложенное в жизнь быстро и просто. Например, специально для библиотеки Seaborn, используемой для построения статистических графиков, был создан пакет Statannotations. Он позволяет проводить дополнительные вычисления статистических тестов и добавлять их результаты в виде аннотаций к графикам. Рассмотрю его подробнее и для примера загляну в глубины мозга.

На что способен Statannotations?

О Statannotations

Если в кратко, то Statannotations это open‑source Python‑пакет для вычислений статистических тестов и добавления статистических аннотаций к графикам, созданным с помощью seabor.

GitHab проекта

Документация

При помощи указанного пакета можно вводить статистические комментарии на разных видах визуализации данных, например:

  • Диаграмма размаха (или «ящик с усами»):

  • Столбчатая диаграмма:

  • Strip plots (одномерная диаграмма рассеяния):

  • Swarm plots (одномерная диаграмма рассеяния без перекрывания точек):

  • Скрипичная диаграмма:

При этом в пакете интегрированы такие статистические тесты, как:

  • Критерий Манна‑Уитни;

  • t‑критерий Стьюдента;

  • t‑критерий Уэлча;

  • Тест Левена;

  • Критерий Вилкоксона;

  • Критерий Краскела‑Уоллиса;

  • Тест Бруннера‑Мюнцеля.

Кроме того, Statannotations позволяет вводить поправку на множественное сравнение гипотез, используя такие методы коррекции, как:

  • Поправка Бонферрони («bonf»);

  • Поправка Бенджамини‑Хохберга («BH»);

  • Метод Холма‑Бонферрони («HB»);

  • Поправка Бенджамини‑Екутиэли («BY»).

Данный пакет представляет умную компоновку нескольких аннотаций с правильными смещениями по оси Y. Поддерживаются как вертикальная, так горизонтальная ориентации комментариев. Также аннотации могут располагаться как внутри графика, так и за его пределами, во втором случае не нарушая его размерностей. Формат комментариев можно настроить: он может быть звездчатым либо в виде p‑значения. Кроме того, имеется множество других параметров, с которыми можно ознакомиться в документации.

А теперь попробую

Для полного понимания работы действия пакета Statannotations рассмотрю его применение на графиках, описывающих реализацию астроцитарной сети головного мозга.

О чём это я

Данные по активности были получены путем графового анализа видеозаписи жизнедеятельности клеток головного мозга мышей. Это исследование проводилось для изучения изменения сетевых характеристик астроцитарной культуры головного мозга при моделировании старения. Как думаете, почему именно астроциты, а не всем известные нейроны? Потому что именно астроцитарная сеть отвечает за поддержание работы нейронов, их питание, свойства окружающей среды, проводимость и т. д. Поэтому старение астроцитов — «нянек» — неизменно влияет на старение нейронов и возникновение возрастных заболеваний.

Источник

Итак, у нас есть график, составленный при помощи Seaborn:

fig, axs = plt.subplots(1, figsize=(5, 4), dpi=300)
sns.set_palette(rotate(sns.color_palette("Set1", 12), 0))
bx = sns.boxplot(data=df_ins_outs, x="group", y="insouts", width = 0.5, boxprops=dict(alpha=.5), ax = axs)
sns.swarmplot(x = "group", y = "insouts", data = df_ins_outs, ax = axs, size = 4)

for i, box in enumerate(bx.artists): 
        color = box.get_facecolor()
        color = list(color)
        color[3] = 0.8
        box.set_edgecolor([.3,.4,.5,.6])
        box.set_linewidth(1)
        for j in range(i*6,i*6+6):
            bx.lines[j].set_color(color)
            bx.lines[j].set_mec(color)
            bx.lines[j].set_mfc(color)
            bx.lines[j].set_linewidth(1)

plt.yscale('log')

axs.set_xticklabels(captions, fontsize = 10)
axs.set_ylabel('Среднее число периодически\n-возникающих связей на клетку', fontsize = 10)
axs.set_xlabel('')

Все полученные данные разделяются на четыре основные группы клеток: молодые; молодые, подверженные гипоксии; старые; старые, подверженные гипоксии. При помощи гипоксического повреждения я моделировала условия ишемии для выявления особенностей отклика на нее молодых и старых групп. На полученном графике выведены диаграммы размаха и рассеяния для каждой группы:

Для окончательного штриха не хватает лишь аннотаций статистической значимости при сравнении всех имеющихся групп. Статистическая значимость крайне важна при презентации научных результатов исследований, иначе они могут быть недостаточно серьезно восприняты. Такое отношение возникает из‑за того, что визуально можно наблюдать одну картину, хотя при этом статистика будет показывать другую.

Для начала устанавливаю Statannotations, используя pip:

pip install statannotations

Либо conda:

conda install -c conda-forge statannotations

Импортирую Аннотатор:

from statannotations.Annotator import Annotator

Затем выявляю группы, которые необходимо сравнить, формируя список кортежей. Их можно записать в отдельную переменную:

[("Control", "Hyp"), 
("Control", "Hyp old"), 
("Control", "Int old"), 
("Hyp", "Hyp old"), 
("Hyp", "Int old"),
("Hyp old", "Int old")]

Создаю экземпляр Аннотатора, все параметры которого передаются в Seaborn:

annot = Annotator(axs, [("Control", "Hyp"), 
                        ("Control", "Hyp old"), 
                        ("Control", "Int old"), 
                        ("Hyp", "Hyp old"), 
                        ("Hyp", "Int old"),
                        ("Hyp old", "Int old")], 
                  data=df_ins_outs, x="group", y="insouts", order=group_names)

Для выбора теста («test»), поправки («comparisons_correction»), формата комментариев («text_format»), их расположения («loc») и др. параметров использую.configure:

annot.configure(test='Mann-Whitney', comparisons_correction="Bonferroni", 
                text_format ="star", loc='inside', verbose=2, line_width=0.5, fontsize = 7)
annot.apply_test()

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

В результате всех манипуляций аннотирую и наношу тот самый последний статистический штрих на график:

axs, test_results = annot.annotate()

Готово!

Исходя из легенды аннотаций p‑значений, становится ясно, чем больше звезд располагается между группами, тем выше статистическая значимость их различий. При этом сами p‑значения сильно снижаются. Так же визуально можно наблюдать, что старение сильно ухудшило количество периодически возникающих связей на клетку, что указывает на снижение интенсивности работы каждой активной клетки в культуре. Аннотация показывает, что эти изменения существенны. Если рассмотреть средние значения внутри одной группы — молодых клеток, например, то можно наблюдать снижение, которое с точки зрения статистики не оказалось значимым. Если бы пакет Statannotations не был использован, график был бы интерпретирован неверно, что может привести к серьезным ошибкам в анализе тех или иных изменений значений в последующих исследованиях.

В итоге

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

Надеюсь, что Statannotations поможет оптимизировать и вашу работу.

Возможно, вам было бы интересно ознакомится с исследованием, на которое я ссылаюсь.

Mitroshina E. V. et al. Unravelling the Collective Calcium Dynamics of Physiologically Aged Astrocytes under a Hypoxic State In Vitro //International Journal of Molecular Sciences. – 2023. – Т. 24. – №. 15. – С. 12286. Ссылка

Комментарии (5)


  1. kay_kay
    18.01.2024 08:54

    Спасибо.

    ЗЫ. Вот интересно, плюс статье поставил самым первым, а в закладки поместил шестым.

    С точки зрения статистики, это чрезвычайно невероятное событие)


    1. NewTechAudit Автор
      18.01.2024 08:54

      Добрый день!

      Вам спасибо за интерес с посту и интересное наблюдение)


      1. kay_kay
        18.01.2024 08:54

        А Вы в России работаете?


  1. adeshere
    18.01.2024 08:54

    Аннотация значимости - это, конечно, полезно. Но без легенды она понятна только посвященным. Я вот всю жизнь занимаюсь статистикой, но без легенды мне тут не все очевидно. Одна звездочка - это сколько? Почему "ящики" смещены относительно точек? Почему "усы" не симметричны ящикам? Если переменные визуализированы в логарифмической шкале, и она более естественная для этих данных, то, возможно, и статистические критерии тоже надо считать по логарифмам значений, а не по номинальным величинам,

    как это, по-видимому, сделано сейчас?

    и результатом чего как раз и объясняется та асимметрия, про которую я спросил?

    На самом деле этот вопрос совсем не такой простой - какую шкалу, линейную или логарифмическую, правильнее брать за основу. В биологии очень многие величины более естественно считаются именно в логарифмах. Хотя лично моя позиция - что в подобных случаях надо посчитать и эдак, и так, а потом "сравнить разницу" ;-)

    В общем: идея с визуализацией на рисунках статистических показателей, безусловно, правильная и полезная (мы в своей программе это делаем с 1990 года, но только вместо условных звездочек пишем цифровые значения). Но сама по себе (в отрыве от более глубокого понимания) она имеет ограниченную полезность. Если вы рисуете графики "для себя" (т.е. для профильного специалиста), то я бы все-таки предпочел хорошо отформатированные цифры, а не условные знаки. Если же картинка предназначена для "начальника-дурака", который "вцифры" не понимает (но финансированием распоряжается), тогда да, увы. Гораздо лучше показать (вручить) ему презентацию с такими значками. Чтобы он мог "сойти за умного" перед еще более "фбиговым" боссом...


    1. adeshere
      18.01.2024 08:54

      Вдогонку: речь про последний рисунок в статье, если что