В современных задачах анализа данных, от биоинформатики и нейробиологии до социальных и поведенческих исследований, обычно используется традиционный пайплайн обработки данных. Он почти всегда включает агрессивную предварительную фильтрацию признаков, снижение размерности (PCA и аналоги), а затем кластеризацию или обучение нейросетевых моделей.
На практике эти шаги считаются технически необходимыми и редко подвергаются сомнению. В этой статье я хочу обсудить, почему в исследовательском анализе такая практика может приводить к систематически некорректным выводам — и даже к созданию искусственных сущностей, отсутствующих в реальности. Связано ли это с тем, что почти две трети научных исследований невозможно воспроизвести. Код, эксперимент и комментарий кандидата биологических наук, сотрудника РАН Дарьи Романовой ниже.
С точки зрения ML-инженерии различие между обучением и анализом довольно простое. Если цель обучить модель находить заранее заданные паттерны, то фильтрация сырых данных оправдана:
заранее известно, что ищется;
можно отбросить заведомо нерелевантные признаки;
фактически задаются границы класса, который необходимо распознать.
Инженеры во время обучения помогают нейросети быстрее определить границы классов. Но если цель анализ данных и выявление неизвестных структур, ситуация принципиально иная. Здесь неизвестно заранее:
какие признаки окажутся важными;
какие различия окажутся устойчивыми;
какие структуры действительно существуют в данных.
В этом режиме агрессивная фильтрация перестаёт быть нейтральной технической операцией и превращается в априорную гипотезу о структуре данных. При очищении данных от шума корректируется тот реальный мир, который проверяет гипотезы на прочность.
В предыдущей статье я приводил примеры, когда синтетические датасеты приводили к деградации моделей уже в первой итерации. Снижение качества ответов я объяснял тем, что из обучающих данных исчезали граничные примеры (hard negatives). В результате модель оперировала усредненными данными и давала усредненные ответы, ломаясь на границах задачи. Удаление hard negatives вело к галлюцинированию структуры.
Фактически, в ряде областей ученые, фильтруя данные, формируют тот же самый синтетический датасет. Из него убраны граничные случаи, выбросы, и, что печально, возникает соблазн убрать данные, которые не соответствуют рассматриваемой гипотезе.
Сразу выделю, фильтрация — снижение энтропии признаков, t-SNE/UMAP — усиление локальных признаков, кластеризация — онтологизация этих контрастов.
Фильтрация признаков обычно мотивируется борьбой с шумом, вычислительными ограничениями или улучшением визуализаций. Однако с точки зрения информации она в первую очередь снижает энтропию представления данных.
Проще говоря:
уменьшается число степеней свободы;
отбрасываются слабые, редкие и контекстные сигналы;
пространство данных становится более «жёстким» и бедным.
После этого в обеднённом пространстве:
границы становятся резкими;
кластеры — хорошо разделимыми;
модели — уверенными.
Проблема в том, что эта уверенность часто относится не к реальности, а к выбранному способу смотреть на данные. Когда сначала резко снижается энтропия представления, а затем применяется кластеризация или нейросеть, происходит важная подмена: модель анализирует не исходные данные, а структуру, уже созданную фильтрацией.
В результате возникают кластеры, состояния, типы или сущности, которые:
хорошо воспроизводятся внутри данного пайплайна;
выглядят убедительно на визуализациях;
но могут не соответствовать реальным объектам или процессам.
Так могут появиться новые виды генов, клеток, научные статьи и гранты.
Это особенно хорошо видно в высокоразмерных данных (например, single-cell секвенирование), где уменьшение фильтрации бывает приводит не к росту числа сущностей, а наоборот — к их схлопыванию и исчезновению резких границ.
Чтобы уйти от философских споров, можно ввести простой операциональный критерий:
Практически это означает, что обнаруженная структура должна сохраняться при:
ослаблении фильтрации признаков;
добавлении низковариабельных и редких сигналов;
уменьшении степени снижения размерности;
возвращении части шума.
Если при этом границы размываются, кластеры сливаются или исчезают — скорее всего, это не реальная сущность, а артефакт метода.
Алгоритмы кластеризации ищут различия на основе контрастов. Но в реальном мире любой объект существует не в вакууме, а в окружении шума: погрешности измерений, естественная изменчивость, случайные отклонения. Настоящий сигнал — тот, который виден несмотря на этот шум. Он достаточно сильный, чтобы не утонуть в нём.
Фильтрация убирает шум — и вместе с ним убирает проверку на прочность. Можно привести пример:
Из тысяч звёзд на небе вы оставляете только самые яркие — скажем, сотню. Среди них глаз тут же находит фигуры: линии, треугольники, ковши. Собственно, именно так и появились созвездия — люди отфильтровали шум из тусклых звёзд и нашли паттерны в оставшихся. Паттерны выглядят убедительно, у них есть имена и исследующая их «наука». Но звёзды одного созвездия могут находиться в сотнях световых лет друг от друга и не иметь между собой ничего общего. Верните на небо все тусклые звёзды, выровняйте яркость — и фигуры растворятся в общем поле. Созвездия реальны как проекция, но не как объекты. Фильтрация высоковариабельных генов работает по тому же принципу: отбираем самые яркие признаки, убираем тусклый фон — и в оставшихся неизбежно проступают паттерны. Вопрос в том, созвездия это или реальные скопления.
Алгоритмы кластеризации (как и нейросети) — это способы поиска различий, работающие на контрастах. В реальном мире любая сущность (например, биологическая клетка) постоянно подвергается давлению энтропии — шуму измерений, биологической вариативности. Реальная сущность — это то, что сопротивляется этому шуму, сохраняя свою структуру. Когда данные фильтруются, это сопротивление исчезает. В отсутствие сопротивления малейшая случайная флуктуация интерпретируется математикой как значимый сигнал.
Очень удачно у меня появилась возможность обсудить эту проблему с кандидатом биологических наук, научным сотрудником лаборатории клеточной нейробиологии обучения Института высшей нервной деятельности и нейрофизиологии РАН Дарьей Романовой. Она немного рассказала о том, что происходит в области single-cell транскриптомики (анализ экспрессии генов в единичных клетках):
Как обычно выглядит стандартный пайплайн обработки данных в вашей области?
Что происходит, если нарушить этот стандарт и убрать фильтрацию?
Получается, фильтрация создает иллюзию сложности?
Я решил попробовать воспроизвести стандартный индустриальный пайплайн анализа single-cell данных (аналогичный используемым в Seurat или Scanpy), но применить его к заведомо структурно пустым данным и с целью найти структуру.
Была сгенерирована матрица из случайных чисел (нормальное распределение), имитирующая 300 клеток и 10 000 генов. В этих данных по определению отсутствуют типы клеток, кластеры или биологический сигнал — это чистый белый шум. И применил стандартный пайплайн.
Важно сразу оговориться: ниже описан не специально подобранный трюк, а последовательность вполне легитимных шагов, каждый из которых регулярно встречается в практических пайплайнах анализа данных.
Шаг 1. Фильтрация по дисперсии и PCA.
Отобрал топ-500 наиболее вариабельных генов и применил PCA. Результат оказался ожидаемым: линейное сжатие честно показало бесформенное облако без каких-либо разделимых групп.
Шаг 2. Нелинейная визуализация (t-SNE) со стандартными параметрами.
Далее я применил t-SNE с типичными настройками (perplexity=30). Однако и в этом случае алгоритм не выявил никакой структуры: данные по-прежнему выглядели как единое стохастическое облако.
Шаг 3. Изменение масштаба анализа.
Снижение параметра perplexity до 5 — допустимое и нередко используемое значение — радикально изменило картину. Алгоритм перестал учитывать глобальную структуру данных и сфокусировался на локальных совпадениях. В результате на экране появились признаки устойчивых кластеров — несмотря на то, что исходные данные по-прежнему оставались чистым шумом.
Шаг 4. Кластеризация.
Для кластеризации применил K-Means к 2D-координатам t-SNE-embedding. Это может показаться методологическим упрощением, однако подобная практика документирована в академической литературе и учебных материалах. В частности:
В официальном воркшопе Chan Zuckerberg Initiative по scRNA-seq анализу (scRNA-python-workshop) KMeans применяется непосредственно к UMAP-координатам: «Scanpy doesn't include a method for k-means clustering, so we'll extract the UMAP coordinates... and use scikit-learn for this task instead» (CZI Single Cell Workshop).
Документация UMAP прямо обсуждает кластеризацию на embedding-координатах как распространённую, хотя и спорную практику: «UMAP can be used as an effective preprocessing step to boost the performance of density based clustering. This is somewhat controversial... The most notable [concern] is that UMAP, like t-SNE, does not completely preserve density. UMAP, like t-SNE, can also create false tears in clusters, resulting in a finer clustering than is necessarily present in the data» (UMAP documentation).
В статье Bioconductor OSCA (Orchestrating Single-Cell Analysis) кластеризация (включая k-means и graph-based подходы) в целом рассматривается как способ упростить высокоразмерные данные до дискретных групп, удобных для последующей интерпретации, при этом подчёркивается зависимость результата от выбранного метода и параметров.(Bioconductor OSCA).
Более того, даже когда формально применяется graph-based кластеризация (Leiden/Louvain), исследователь де-факто оценивает и интерпретирует результаты по визуализации — по t-SNE или UMAP. Визуальная группировка точек фактически играет роль финальной кластеризации в голове исследователя. Я лишь формализовал этот процесс.
Впрочем, как видно на графике ниже, K-Means здесь — просто красивая раскраска. Ему без разницы, что красить: он всегда нарежет плоскость на k аккуратных зон и каждую покрасит в свой цвет. Верхний ряд графика это наглядно показывает — кластеры «найдены» во всех четырёх случаях, включая однородные облака. Выглядит убедительно, но не значит ничего. Реальная информация — в геометрии точек, то есть в нижнем ряду.
Код экспериментаimport numpy as np import matplotlib.pyplot as plt from sklearn.decomposition import PCA from sklearn.manifold import TSNE from sklearn.cluster import KMeans from matplotlib.colors import ListedColormap import os n_cells = 300 n_genes = 10000 n_hvg = 500 random_seed = 42 n_clusters = 6 print("Генерация шума...") np.random.seed(random_seed) X_raw = np.random.normal(loc=0, scale=1, size=(n_cells, n_genes)) # --- Подготовка --- gene_vars = np.var(X_raw, axis=0) hvg_indices = np.argsort(gene_vars)[-n_hvg:] X_hvg = X_raw[:, hvg_indices] X_pca_filtered = PCA(n_components=15).fit_transform(X_hvg) X_pca_full = PCA(n_components=30).fit_transform(X_raw) # --- Вычисляем все 4 t-SNE --- print(" t-SNE: фильтрация + perp=5...") X_tsne_f5 = TSNE(n_components=2, perplexity=5, random_state=random_seed, init='pca', learning_rate='auto').fit_transform(X_pca_filtered) print(" t-SNE: фильтрация + perp=30...") X_tsne_f30 = TSNE(n_components=2, perplexity=30, random_state=random_seed, init='pca', learning_rate='auto').fit_transform(X_pca_filtered) print(" t-SNE: полные + perp=5...") X_tsne_n5 = TSNE(n_components=2, perplexity=5, random_state=random_seed, init='pca', learning_rate='auto').fit_transform(X_pca_full) print(" t-SNE: полные + perp=30...") X_tsne_n30 = TSNE(n_components=2, perplexity=30, random_state=random_seed, init='pca', learning_rate='auto').fit_transform(X_pca_full) # KMeans на каждом t-SNE embedding labels_f5 = KMeans(n_clusters=n_clusters, random_state=random_seed, n_init=10).fit_predict(X_tsne_f5) labels_f30 = KMeans(n_clusters=n_clusters, random_state=random_seed, n_init=10).fit_predict(X_tsne_f30) labels_n5 = KMeans(n_clusters=n_clusters, random_state=random_seed, n_init=10).fit_predict(X_tsne_n5) labels_n30 = KMeans(n_clusters=n_clusters, random_state=random_seed, n_init=10).fit_predict(X_tsne_n30) cluster_colors = ['#e41a1c', '#377eb8', '#4daf4a', '#984ea3', '#ff7f00', '#a65628'] cmap_discrete = ListedColormap(cluster_colors) neutral = '#6c8ebf' # === РИСУЕМ: 2 строки × 4 столбца === # Верхний ряд: с KMeans раскраской # Нижний ряд: те же данные без раскраски (один цвет) fig, axes = plt.subplots(2, 4, figsize=(22, 11)) tsne_data = [ (X_tsne_f5, labels_f5, "Фильтрация\nperplexity=5"), (X_tsne_f30, labels_f30, "Фильтрация\nperplexity=30"), (X_tsne_n5, labels_n5, "Без фильтрации\nperplexity=5"), (X_tsne_n30, labels_n30, "Без фильтрации\nperplexity=30"), ] for col, (X_tsne, labels, title) in enumerate(tsne_data): # Верхний: с раскраской ax_top = axes[0, col] ax_top.scatter(X_tsne[:, 0], X_tsne[:, 1], c=labels, cmap=cmap_discrete, s=50, edgecolors='k', linewidth=0.4, alpha=0.85) color = '#c0392b' if col == 0 else '#2c3e50' ax_top.set_title(title, fontsize=12, fontweight='bold', color=color) ax_top.axis('off') # Нижний: без раскраски ax_bot = axes[1, col] ax_bot.scatter(X_tsne[:, 0], X_tsne[:, 1], c=neutral, s=50, edgecolors='k', linewidth=0.3, alpha=0.5) ax_bot.axis('off') # Подписи строк fig.text(0.01, 0.73, 'С раскраской\n(KMeans на t-SNE)', ha='left', fontsize=12, rotation=90, color='#2c3e50', fontweight='bold', va='center') fig.text(0.01, 0.30, 'Без раскраски\n(только геометрия)', ha='left', fontsize=12, rotation=90, color='#7f8c8d', fontweight='bold', va='center') fig.suptitle('KMeans всегда найдёт кластеры — но совпадают ли они с геометрией?', fontsize=15, fontweight='bold', y=0.98) plt.tight_layout(rect=[0.04, 0.01, 1, 0.95]) plt.savefig(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'result_2x2.png'), dpi=150, bbox_inches='tight', facecolor='white') plt.show() print("Готово.")
Результат
На итоговой визуализации представлены восемь графиков: четыре комбинации параметров (фильтрация/без × perplexity 5/30), каждая в двух вариантах — с раскраской KMeans (верхний ряд) и без неё (нижний ряд). Нижний ряд показывает реальность. Те же самые точки, та же геометрия — но без цветовой маскировки. И здесь разница очевидна:
Первый столбец (фильтрация + perplexity=5): точки разбиты на обособленные островки с пустым пространством между ними. Именно эту геометрию KMeans превращает в «типы клеток».
Второй столбец (фильтрация + perplexity=30): единое облако без разрывов. Фильтрация одна, без помощи низкой perplexity, не создаёт иллюзии.
Третий столбец (без фильтрации + perplexity=5): островки есть, но они мельче и менее выражены. Low perplexity одна, без фильтрации, создаёт лишь слабый намёк на структуру.
Четвёртый столбец (без фильтрации + perplexity=30): однородное облако — так выглядит шум, когда его не трогают.
Вывод
Этот эксперимент наглядно показывает: галлюцинация структуры возникает не сама по себе. Чтобы увидеть в шуме типы клеток, часто недостаточно просто отфильтровать данные. Нужно еще и подобрать параметры отображения так, чтобы они разорвали непрерывный шум на удобные части. То есть композиция шагов, формально соответствующая устоявшемуся пайплайну, приводит к искажению результатов. Возникает риск, что исследователь, подбирающий, например, параметры визуализации неосознанно начнет ориентироваться на красоту и интерпретируемость картинки, а не на устойчивость структуры.
Многие скажут, что визуализация не доказательство, но на практике, особенно в презентациях, часто воспринимается за таковое.
И отмечу, я взял чисто случайные данные. Но если среди них будет хоть какая-то минимальная связь, а она в реальных экспериментах есть всегда, фильтрация приведет к их резкому и не всегда обоснованному усилению, возможно за счёт отброса реальных зависимостей, и для этого даже не понадобятся манипуляции с коэффициентами.
Всё это выглядит достаточно забавно, но если, например, вы узнаете что из 53 знаковых исследований в области онкологии удалось воспроизвести только 6 (11%), то поймете насколько, на самом деле, трагична сложившаяся ситуация.
Важно подчеркнуть: речь не идёт о том, что фильтрация однозначно ведёт к неправильным выводам. Она вполне оправдана:
в supervised-задачах;
при проверке конкретных гипотез;
для контроля технических артефактов;
когда структура данных заранее известна.
Если природа устраняемого шума чисто техническая (ошибки секвенирования, наводки электросети, проезд трамвая), то фильтрация нужна обязательно. Но фильтрация должна быть обоснованной, с пониманием что и почему фильтруем.
Отдельно стоит остановиться на «проклятии размерности», которое часто приводят как аргумент в пользу агрессивной предварительной фильтрации данных. Действительно, в пространствах высокой размерности расстояния между точками имеют тенденцию к концентрации, что затрудняет работу многих алгоритмов кластеризации.
Однако в этом аргументе обычно смешиваются два разных аспекта.
Во-первых, вычислительная сложность.
Работа с десятками тысяч признаков требует значительных ресурсов по памяти и времени. Это реальная инженерная проблема, но она не является методологическим аргументом сама по себе: оптимизация вычислений и ограничение ресурсов — задача реализации, а не основание для изменения онтологии данных в научном анализе.
Во-вторых, геометрия данных.
Если точки в высокоразмерном пространстве распределены не случайно, а в соответствии с некоторой внутренней структурой, алгоритмы manifold learning в принципе способны её выделить, однако на практике предварительное снижение размерности с помощью PCA обычно используется для стабилизации численных свойств и подавления шума (хотя для нелинейных структур опасна и PCA). Критическая ошибка возникает не при использовании PCA, а при агрессивной фильтрации признаков до этапа анализа, когда структура данных изменяется ещё до того, как она была выявлена.
Широко распространённая практика агрессивной предварительной фильтрации признаков (например, удаления генов до этапа PCA) часто мотивируется не строгой математической необходимостью, а стремлением получить более визуально чистую и интерпретируемую картинку. Такая фильтрация меняет пространство представления ещё до анализа и может приводить к искусственному формированию границ и сущностей, которых не существует в исходных данных.
То есть в целом, проблема возникает тогда, когда фильтрация становится обязательным шагом по умолчанию в исследовательском анализе без проверки того, как она влияет на онтологию результатов.
Несмотря на описанные проблемы, агрессивная фильтрация стала стандартом по нескольким причинам:
исторически помогала справляться с шумными и малыми датасетами;
улучшает визуализации и story-telling, создавая иллюзию точности;
встроена в популярные библиотеки и туториалы;
повышает воспроизводимость пайплайнов, но не обязательно корректность интерпретации.
рецензирование в научных журналах часто ориентировано на выводы и интерпретацию, аудит же сырых данных и методов их подготовки крайне трудозатратен.
В результате фильтрация стала даже не хорошим тоном, а обязательным к использованию инструментом.
Предварительная фильтрация признаков — сильное методологическое допущение, требующее такой же строгой валидации и обоснования, как например выбор статистического теста. В исследовательском анализе данных фильтрация может создавать искусственные границы и порождать сущности, существующие лишь в рамках выбранного пайплайна. Минимальный шаг к более корректному анализу — рассматривать фильтрацию как гипотезу и проверять устойчивость результатов при увеличении энтропии представления.
Учитывая, что перепроверить выводы для сложных экспериментов крайне дорого вплоть до десятков миллионов долларов, множество исследований фактически никогда не перепроверяется. И количество таких исследований растет с каждым годом.
Такой подход во-первых, снижает доверие к результатам глубоких исследований, во-вторых, высок шанс, что ученые пропустят что-то действительно важное.
Источник


