вступление

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

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

Я считаю, что тестирование (вместе с мониторингом) — одна из фундаментальных и наиболее ценных областей современной разработки программного обеспечения. В то время как программирование и анализ данных становятся все более и более автоматизированными и требуют меньше внимания со стороны человека, тестирование, в конце концов, — это всего лишь способ объявить, что мы хотим получить на выходе. Если мы не можем описать, чего мы хотим (или проверить, что было сделано) — значит, наша значимость в этом цикле быстро падает.

В работе я в основном использую Golang и Python, поэтому почти все примеры относятся к этим языкам программирования.

Название навеяно этим прекрасным видео от Rational Animation.

Шаг 1: Проверка схем и качество кода

Статический анализ кода

Это определенно огромная территория, с которой я не очень знаком, но не могу не упомянуть о голангчи-линте. В основном это агрегатор, который помогает организовать другие инструменты и неплохо справляется с этой задачей. Однако иногда это могло вызвать некоторые неудобства, например, gosec мог создавать отчеты для SonarQube, но результаты, завернутые в golangci-lint, выглядят хуже, чем прямая интеграция. В любом случае такая проблема решаема с помощью разных конфигураций для CI/CD и IDE.

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

Валидация данных

У нас есть широкий спектр инструментов для проверки данных в мгновенных коммуникационных протоколах (средние RPC) и отложенный подход к коммуникациям (средние очереди). Спецификации OpenAPI часто используются с YAML. JSONSchema также по-прежнему играет важную роль, как правило, в различных типах REST API. Если вы готовы к бинарным протоколам — выбирайте с умом Avro/Protobuf/Thrift. Говоря конкретно о решениях Golang — go-playground/validator — хороший и популярный вариант.

Кроме того, структуры со статическими типами сами по себе являются валидаторами. Интересно, что некоторые из этих инструментов можно было найти в связи с БД или Queue и вышеперечисленными опциями, доступными у них. БД обычно имеют комбинации схема при записи и схема при чтении — это еще один абстрактно описанный уровень проверки. Не знаю об очередях вообще, но у Kafka есть Реестр схем, который не только помогает проверять данные, но и значительно упрощает разработку этих схем.

Этот вид техники, вероятно, является подтипом или потомком проектирования по контракту. Если по какой-либо причине вам нужен этот стиль проверки, вы можете легко найти библиотеки на упомянутой странице вики.

Проверка кода ИИ

Я не знаю ни одного доступного бесплатного инструмента для Golang, но, вероятно, он существует. Примером коммерчески доступных инструментов может быть deepsource.io. Эти ребята утверждают, что их продукт может заменить огромное количество бесплатных и коммерческих инструментов.

Конечно, у нас есть примеры общедоступных работ для других языков: это про Javascript [1] и более свежее про Python [2]. Оба они были упомянуты на презентации движка глубокого кода Snyk. По рекламе Сник из ролика видно, что для применения (или покупки) любого инструментария для этой цели — организация обязана иметь хотя бы одного реального специалиста в этой области, если не хотят быть обманутыми. Также интересным наблюдением является то, что этот инструмент предназначен для жалоб на отсутствие слоев, упомянутых в предыдущем абзаце о проверке данных.

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

Помощники по дизайну

Схемы или графики

Удивительно (шучу), но качество проектной документации напрямую влияет на качество кода. По моему личному опыту, схемы работают лучше, чем текстовые описания. Между тем, многие разработчики программного обеспечения стараются игнорировать инструменты. UML, BPMN, ERD и C4 — эти четыре кажутся наиболее популярными. Кроме того, простая интеллект-карта также работает довольно хорошо, но имеет немного другое направление — для объяснения идей самому автору. И что интересно — можно было бы сделать и наоборот — например, генерировать диаграммы классов из существующего кода. Это может быть использовано в рабочем процессе фактического и желаемого состояний. Визуализация определенно помогает создавать более качественные программы, даже если реальная программа едва ли соотносится с диаграммой проекта в конце.

Такие принципы проектирования, как SOLID и KISS, кажутся слишком тривиальными, чтобы упоминать их здесь. Тем более, что последний точно провалился в глобальном представлении. Но, к сожалению, процент работоспособных приложений на практике, по крайней мере, первого, настолько мал — похоже, лишь небольшой процент инженеров знает что-то сверх определений. Очень рекомендую курс всем, кто пишет на Go. Это дает хорошую связь между базовой теорией и реальной функциональностью языка. К сожалению, курс не был обновлен, чтобы включить последние изменения в синтаксис.

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

Поскольку мы подошли к FSM, я хочу добавить еще пару моментов. Во-первых, мы, вероятно, снова подойдем к проверке данных. Состояние также представлено в виде данных, а переходы между состояниями такие же, но с маркерами последовательности. Во-вторых, тип диаграммы UML имеет специфический подтип — конечный автомат UML. (О нем часто забывают даже на страницах, посвященных FSM, поэтому я стараюсь его рекламировать.)

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

Формальные методы

Говоря о валидации без встраивания в код, я также хочу упомянуть языки, которые позволяют выполнять валидацию алгоритма — или языки формальных спецификаций. У нас есть три основные категории, но я упомяну только две. Первый — проверка модели — разновидность перебора всех возможных состояний (да, отличается от нечеткого тестирования тем, что требует моделирования системы на специализированном языке). Кажется, TLA+ — хороший пример этого класса. Это инструмент для проверки архитектуры программирования с ранее упомянутой концепцией конечных автоматов. Второй класс — это автоматические средства доказательства теорем, и я думаю, что наиболее популярным примером является средство доказательства теорем Z3. Очень интересный аспект Z3 — его можно применять для поиска решений, а не только для их проверки. И что еще более впечатляет — связь между Z3 и TLA+ — апалач. Вы можете сказать — как весь этот научный коллектив относится к программированию на Golang? Посмотрите поближе на этот проект под названием GCatch [3]. К сожалению, в настоящее время проект практически не развивается. Изучив исходный код, я пришел к выводу, что сам проект страдает от низкого качества кода.

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

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

Модульное тестирование

Только начало

Я думаю, что пакет testify — это почти стандартный способ написания тестов в Golang. Однако я часто вижу странные конструкции вместо того, чтобы просто использовать свидетельство, даже в популярных проектах с открытым исходным кодом. Более продвинутым пользователям нравятся табличные тесты — ок, я могу согласиться, что это может быть полезно для проверки блока с минимальными параметрами и не большим количеством возможных результатов. Но что я часто вижу — тестовые строки, содержащие флаги черной магии, которые проходят внутри бесконечно длинного блока t.Run(…). И сюрприз — большинство IDE плохо поддерживают такой тип построения и когда вы хотите отладить конкретный случай, то без ухищрений просто не обойтись. Ситуация становится еще хуже, когда таблица содержит десятки или сотни строк. Может я просто не знаю как бороться с такими проблемами, буду благодарен если кто подскажет решение.

Но даже если вышеописанная проблема решаема, на мой взгляд, сама конструкция недействительна. Вместо того, чтобы делать эти несуразно выглядящие таблицы, я предпочитаю использовать Suite из пакета testify. Если вам нужна повторяющаяся логика, которая не соответствует дизайну SetupTest/TearDownTest — всегда можно определить функцию частного получателя в унаследованном типе Suite. И конструкция дает логически необходимое место для описания в функции имени теста, когда для «табличных» тестов требуется столбец «имя» — что для меня немного странное решение.

Моки, BDD и многое другое

Также в testify присутствует пакет Mock, но в основном по историческим причинам более распространен gomock. И на рынке есть больше решений для mock-темы golang.

Кстати, весь этот персонал как-то закрывает только базовые потребности в тестировании, когда по каким-то причинам не хочется усложнять проект. Если вы более-менее серьезно относитесь к тестированию, обязательно знание фреймворков в стиле BDD — godog или менее привязанных к оригиналу, но с удобным флюоресцентным интерфейсомginkgo.

Я не уверен в правильной концепции библиотеки с открытым исходным кодом для фикстур, примененной к golang (много информации в Интернете, но она не полностью соответствует моему пониманию фикстур), в прошлый раз, когда мне нужно было что-то в этом стиле, я написал мой собственный загрузчик фикстур строго привязан к конкретной задаче. Мое понимание фикстур вдохновлено pytest.

Еще одна интересная история — Проект Allure. У него много библиотек на Golang — просто гуглите и выбирайте, что вам нравится, или, может быть, вы хотите написать еще одну?

Другие методологии

Честно говоря, тестирование не является моей основной областью интересов. Мог бы только порекомендовать страницу википедии и максимально использовать их все.

Тестирование схем баз данных и различного персонала также медленно растет. Просто пример.

Производительность

Одно место, где я хочу точно указать, — это тестирование производительности. Думаю, более-менее понятно, как писать бенчмарки с помощью встроенного функционала golang или выполнять профилирование с помощью go pprof. Сложнее определить критерии преждевременной оптимизации. И здесь может помочь концепция под названием каузальное профилирование [4]. Он также имеет поддержку golang.

Я вернусь к проблеме «причинности» ближе к концу.

Помимо этого, я также хочу упомянуть еще один проект того же автора для python — Scalene [5]. Впрочем, вы, скорее всего, уже знаете об этом.

Шаг 2: используйте машинное обучение

Проверка данных обучения

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

Мы могли бы использовать один из двух или комбинацию следующих методов. Фильтрация самих данных или наличие логики отклонения результатов обучения на «плохих» данных. Я имею в виду использование самой модели для характеристики входного потока. Второй вариант сам по себе может быть плохой идеей, но с ним можно легко справиться, откатившись к предыдущей версии. Сама обученная модель в любом случае должна иметь как минимум резервную копию (или лучший контроль версий).

Поскольку я специализировался на временных рядах (сокращенно до TS ниже), почти все мои примеры относятся к этой области. Существует почти бесконечный набор инструментов для проверки входного потока TS. Я имею в виду признаки, которые можно извлечь из входных данных и, следовательно, проверить. Начнем с самих характеристик.

Извлечение признаков

Набор интересных методов предоставляет библиотека pyts, но значительная их часть предполагает наличие конкретных входных данных — я имею в виду предварительные знания о значении ТС.

Более общий и классический набор методов представлен в библиотеке tsfresh. Другой набор методов о корреляции между временными рядами можно найти на tslearn. Их больше — набор статистических методов, реализованных в проекте цезий-мл. Собственно, методов получения новых данных из существующих так много, что существует «исследование важности [6] из них.

Отказ от неправильных моделей

Процесс выбрасывания не очень удачных моделей стал отдельной дисциплиной в ML.

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

Затем мы выбираем, с помощью какой функции мы оцениваем разницу с фактическими результатами. Посмотрите на несколько популярных модельных KPI. Дальнейший разговор о регрессионных метриках — а они мне интересны из-за их прямой связи с временными рядами, вторая группа — метрики классификации тоже может быть интересна в контексте — но через поддержку специфичных для TS методов классификационными методами ML ). Общий обзор концепций можно найти в этом сообщении в блоге.

Еще один источник безумия — попытки на лету сообразить, в каком направлении развиваются модели, и бесперспективное рубление веток. Набор из них хорошего качества представлен в упаковке mle-hyperopt. Начиная с простейшего поиска по сетке и заканчивая относительно новыми подходами, например Hyperband (новый подход, основанный на Bandit). В сообществе Оптуна, похоже, приобрела большую популярность. При этом методы между библиотеками полностью не пересекаются. Итак, серебряной пули нет — и их нужно выбирать с умом. Здесь мы существенно отошли от первоначальной темы, так как затронули область автомл, но необходимо упомянуть еще несколько моментов.

Описанные выше методы можно комбинировать с модельным ансамблем и индивидуальной настройкой гиперпараметров модели — пример с эволюционными алгоритмами для организации процесса — ФЕДОТ [7].

Другой подход к поиску оптимальных гиперпараметров заключается в обучении нейронной сети (или любой другой модели) для выбора специализированной оптимальной модели с оптимальными гиперпараметрами (или их набора для дальнейшей обработки одним из указанных выше методов или ансамбля) без дополнительного обучения (он же нулевой -выстрел или вывод из нескольких выстрелов) — эта методология часто выступает как метаобучение. Хорошо известным примером в мире ТС является Кац [8].

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

Нормализация данных

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

Если после предварительного анализа, приведенного выше, мы пришли к мысли, что имеем дело с совершенно нерегулярными временными рядами, то, вероятно, целесообразно использовать специализированные методы: метод Кростона [9], периодограммы Ломба-Скаргла [10]. ], и т. д.

Еще один простой, но часто забываемый шаг — проверка границ меток времени — никаких точек данных из будущего (обычно вызванных программными ошибками и попытками использовать результаты, уже обработанные другой моделью) и никаких сверхдревних данных (типичный источник — проблемы с преобразованием даты и поврежденные данные в БД).

В дополнение к проверке регулярности, приведенной выше, полезно провести более значимый частотный анализ. Если автокорреляционные функции и анализ Фурье не помогли, можно использовать вейвлет-преобразования. Не забудьте проверить стационарность, если вы старомодны и ваша модель (или система моделей) чувствительна к ней.

Также довольно часто возникает необходимость нормализовать метаданные для временных рядов (одномерное извлечение или многомерное — в данном случае не имеет значения). Приемов может быть много, но я хочу выделить один конкретный инструмент — PClean [11]. Интригует то, что на конференции 2019 года у него есть интеграция с моделью GPT, но в репозитории я не могу найти упоминания об этом. Непонятно — я плохо ищу, или эта ссылка устарела как неэффективная, или наоборот — слишком эффективна, чтобы быть в свободном доступе.

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

TheDeepChecker [11] — определенно перспективный проект, целью которого является выявление различных проблем с программированием глубоких нейронных сетей, в том числе проблем с входными данными. Кроме того, этот инструмент очень похож на инструменты из раздела Проверка кода AI выше, но на этот раз нацелен на код ML.

Короткое замечание об объяснении модели

Кроме возможностей контролируемого обучения, важного для понимания того, как модель интерпретирует потребляемые данные. Много статей написано про SHAP — это скорее промышленный стандарт.

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

План B

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

Шаг 3: Последняя миля

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

Поверхностный обзор тестирования после развертывания можно найти здесь.

Даже если нам каким-то образом не удалось подготовить качественный продукт на предыдущих шагах, у нас есть шанс предотвратить репутационный ущерб (или хотя бы уменьшить его) с помощью умного выкатывания в производство. У нас есть куча классических способов перехода на новую версию: синий/зеленый, канареечный, и т.д.. К этому моменту стало ясно, что без современной экосистемы маршрутизации использовать эти приемы будет сложно или невозможно.

Кроме того, если у вас есть постоянное хранилище с требованиями к миграции схемы, важно подумать не только об обратной совместимости, но и о протестированном откате миграции. Сценарий миграции (как и сценарий миграции с откатом) обязан соответствовать требованиям производительности в продакшене в том редком случае, когда он блокирует все остальное.

Конечно, сложно поддерживать все эти процедуры без соответствующего фреймворка для CI/CD. Фламинго выглядит довольно интригующе, однако, я думаю, любые инструменты из этого района при правильном использовании колоссально упрощают жизнь. Подход Gitops, несмотря на критику, отводит решающую роль в организации последовательности переходов состояний (да, он распространился повсеместно). Когда нам приходится иметь дело с регулярным развертыванием, рекомендуется проверить бюджет ошибок.

Существует также другой метод, который используется, если мы неизбежно не можем что-то протестировать, не развернув его для небольшой части клиентов. A/B-тестирование — это отдельное направление науки, но следует сказать несколько слов. Сегодня результаты почти всегда анализируются с помощью машинного обучения. Лечения, воздействующие на ковариантные группы, также существуют как последовательности переходов состояний (звучит знакомо?). Мы могли бы делать прогнозы с оптимизацией локального вида KPI (CATE, ITE).

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

Заключение

Весь этот набор мыслей мог выглядеть фрагментарно. Но у меня есть пара причин — почему все они объединены в одну статью. Во-первых: golang хорошо подходит в качестве первой линии защиты в системе, которая содержит ML или сложный код внутри и написана на python. Написать его на питоне тоже можно, но по моему опыту, Golang значительно упрощает эту задачу. Он хорошо работает для простой и понятной задачи проверки схемы. Второе: время от времени появляются полезные взаимосвязи. DTW (или метод из этого семейства, например, CTW [12]) выглядит весьма полезным для тестирования задач, связанных с временными рядами (где возможны временные сдвиги).

Мне не удалось попробовать это на практике, но у меня есть несколько идей: преобразование запросов к базам данных временных рядов (сравнение результатов разных движков запросов с небольшими сдвигами из-за исправления алгоритмов), поиск похожих элементов с несинхронизированными временными метками. , все, что связано с данными человека и т. д. Заполнение пробелов от FEDOT [7] может помочь скрыть проблемы на других уровнях защиты в крайних случаях. Причинность Грейнджера можно было бы использовать не только при подготовке ковариантов для моделей прогнозирования. И, возможно, вы хотите узнать о комбинации DTW и причинности по Грейнджеру — Variable Lag Time Causality [13]. Если идея вас цепляет — для этого доступен широкий набор методов [14].

[1] М. Прадел и К. Сен, «DeepBugs: обучающий подход к обнаружению ошибок на основе имен», Proc. Программа АКМ. яз., том. 2, нет. OOPSLA, стр. 1–25, октябрь 2018 г., doi: 10.1145/3276517.

[2] М. Алламанис, Х. Джексон-Флакс и М. Брокшмидт, «Обнаружение и устранение ошибок с самоконтролем». arXiv, 16 ноября 2021 г. doi: 10.48550/arXiv.2105.12787.

[3] T. Tu, X. Liu, L. Song и Y. Zhang, «Понимание реальных ошибок параллелизма в Go», Proceedings of the Twenty-Fourth International Conference on Architectural Support for Programming Languages ​​and Операционные системы, в ASPLOS '19. Нью-Йорк, штат Нью-Йорк, США: Ассоциация вычислительной техники, апрель 2019 г., стр. 865–878. дои: 10.1145/3297858.3304069.

[4] К. Куртсингер и Э. Д. Бергер, «C oz: поиск кода, который учитывается с помощью причинного профилирования», в Proceedings of the 25th Symposium on Operating Systems Principles, Монтерей, Калифорния: ACM, октябрь 2015 г., стр. 184–197. дои: 10.1145/2815400.2815409.

[5] Э. Д. Бергер, С. Стерн и Дж. А. Пиццорно, Триангуляция проблем производительности Python с помощью Scalene. arXiv, 14 декабря 2022 г. По состоянию на 27 мая 2023 г. [Онлайн]. Доступно: http://arxiv.org/abs/2212.07597

[6] CH Lubba, S.S. Sethi, P. Knaute, S.R. Schultz, B.D. Fulcher и N.S. Jones, «catch22: CAnonical Time-series Characteristics», Data Min. Знай. Дисков., vol. 33, нет. 6, стр. 1821–1852, ноябрь 2019 г., doi: 10.1007/s10618–019–00647-x.

[7] Н. О. Никитин и др., «Автоматизированный эволюционный подход к проектированию составных конвейеров машинного обучения», Future Gener. вычисл. Сист., том. 127, стр. 109–125, февраль 2022 г., doi: 10.1016/j.future.2021.08.022.

[8] П. Чжан и др., «Обучение с самоконтролем для быстрой и масштабируемой настройки гиперпараметров временных рядов», ArXiv Prepr. ArXiv210205740, 2021 г.

[9] А. Сегерстедт и Э. Левен, Исследование различных методов прогнозирования типа Кростона. 2020. По состоянию на 24 апреля 2023 г. [Онлайн]. Доступно: https://urn.kb.se/resolve?urn=urn:nbn:se:ltu:diva-78088

[10] Дж. Т. ВандерПлас, «Понимание периодограммы Ломба-Скаргла», Astrophys. Дж. Доп. Сер., том. 236, нет. 1, с. 16 мая 2018 г., doi: 10.3847/1538–4365/aab766.

[11] А. К. Лью, М. Агравал, Д. Зонтаг и В. К. Мансингка, «PClean: байесовская очистка данных в масштабе с вероятностным программированием для предметной области». arXiv, 18 ноября 2022 г. doi: 10.48550/arXiv.2007.11838.

[12] Ф. Чжоу, «Каноническое искажение времени для выравнивания человеческого поведения».

[13] К. Аморнбунчорнвей, Е. Желева и Т. Бергер-Вольф, «Причинно-следственная связь по Грейнджеру с переменным запаздыванием и передаточная энтропия для анализа временных рядов», ACM Trans. Знай. Дисков. Данные, том. 15, нет. 4, с. 67:1–67:30, май 2021 г., doi: 10.1145/3441452.

[14] Р. Мораффах et al., «Причинно-следственный вывод для анализа временных рядов: проблемы, методы и оценка». arXiv, 10 февраля 2021 г. doi: 10.48550/arXiv.2102.05829.