На прошлой неделе, читая Хабр, обратил внимание на обильное и, на мой взгляд, не всегда уместное использование слова «честный». Решил детальней изучить ситуацию, собрал данные и в результате оказалось, что мне не показалось и так было не всегда, а пик, возможно, еще не пройден. В этой статье делюсь полученными результатами, методологией и датасетом для тех, кому может быть интересно попробовать найти какие-нибудь закономерности.
Сразу оговорюсь, что по моему личному мнению наблюдаемый эффект связан исключительно с ростом количества материалов, подготовленных (сгенерированных или отредактированных) при помощи LLM. Более того, использование слов «честный» и «honest» уже обсуждалось на Дзене и зарубежных площадках. При этом я не ставлю цель предложить критерии для определения сгенерированного текста или тем более дать оценку качеству текстов. Исходная задача: проверить, а не показалось ли мне и если нет, то попробовать дать какую-то характеристику наблюдаемому явлению.
Сбор данных
На Хабре я читаю в основном статьи, поэтому для анализа собирал именно их. Дополнительно можно было бы посмотреть посты, новости и комментарии, но это бы сильно увеличило время сбора данных.
Если вы хоть раз обращали внимание на адресную строку, то понимаете, что данные собирались чем-то наподобие
r = requests.get(f'https://habr.com/ru/articles/{id}/')
При оценке количества материалов доступных для сбора необходимо учитывать некоторые особенности идентификаторов, почитать про которые можно, например, здесь: https://habr.com/ru/articles/990586/
Ключевые моменты:
-
id сквозной на все типы материалов (статья, новость, пост и тд)
-
id присваивается при окончании процесса создания черновика
-
на текущий момент выдаются только четные id, до этого могли также выдаваться только нечетные или все вместе
То есть, если сейчас у свежих статей идентификаторы в диапазоне ~ 1 070 000, то это не означает, что на Хабре более 1 миллиона статей. Всего материалов около 600 тысяч включая посты, новости и черновики. Было бы идеально собрать все тексты эпохи ChatGPT (начиная с даты выхода 30 ноября 2022) и немного «до» для референса.
Текст статьи получал парсингом скачанного HTML и удаляя ненужные куски кода
def remove_pre(soup): for soup_pre in soup.select('pre'): soup_pre.decompose() soup = BeautifulSoup(r.content, 'lxml')soup_body = soup.select_one('#post-content-body')remove_pre(soup_body)article_text = soup_body.get_text(separator=' ', strip=True)
Также вытащил дополнительную информацию: автор, дата публикации, список хабов, список меток (“перевод”, “ретроспетива” и др.), количество просмотров, закладок и комментариев, рейтинг поста с детализацией по плюсам и минусам, значение кармы автора (на момент сбора данных, а не на момент публикации соответствующей статьи).
Быстрая проверка
В процессе сбора данных возникло желание побыстрее подтвердить или опровергнуть собственное наблюдение. Решил попробовать сделать это следующим образом
'честн' in article_text.lower()
То есть для каждой собранной статьи проверяю не наличие слова, а наличие подстроки. Затем считаю долю статей, в которых такая подстрока присутствует.
За два месяца особой динамики не увидел, данные при этом продолжали собираться.
Когда собрались данные за 6 месяцев, то тренд стал уже четко виден, но оставалось непонятно, где у него начало и не совпадает ли оно с датой выхода ChatGPT?
Оказалось, что определенное начало есть, но оно сильно позже выхода ChatGPT и уже после начала периода роста количества статей на Хабре. На полных данных визуально выделяются два периода в районе марта и ноября 2025. Детальнее разобраться с происходящим должен помочь собранный датасет.
Описание набора данных
Всего было собрано 135 728 статей с id от 517 864 до 1 073 924 с датой выхода от 4 сентября 2020 по 24 августа 2026. Важно, что это не выборочные статьи, а почти полный набор публикаций за указанный период, то есть статистика по ним будет отражать реальную ситуацию. При этом в набор не включены, например, материалы, которые были убраны в черновики или сняты модератором.
Для анализа употребления конкретного слова тексты статей целиком не нужны, достаточно выписать сами факты, желательно с окружающим текстом, чтобы можно было оценить контекст. На этом этапе весь список интересующих слов еще неизвестен, так как рассматривается не только слово «честный», но и его формы: «честное», «честные», «честной» и др., поэтому продолжаем пользоваться подстрокой честн.
pattern = re.compile(r'честн', re.IGNORECASE)scope_size = 25 # захватываем столько символов вокруг подстрокиword_data = []word_start = [m.start() for m in pattern.finditer(article_text)]for i, start_pos in enumerate(word_start): word_data.append( { 'idx': i, 'start_pos': min(start_pos, scope_size), 'text_around': article_text[max(start_pos-scope_size, 0):min(start_pos+scope_size, len(article_text))] } )
Скрытый текст
Здесь вместе с окружением слова сохраняется его местоположение в итоговой подстроке. Это делается для того, что несмотря на симметричность интервала, само слово может оказаться не посередине, так как в исходном тексте оно может находиться в начале или в конце. Поэтому в ситуациях, когда в один отрезок попало сразу несколько слов содержащих честн, будет непонятно, какое именно из этих слов описывает интервал.
Всего в собранных текстах было зафиксировано 29 202 подстроки честн. На Github размещен список статей с метаданными и перечень вхождений. Дальнейший анализ проводился с помощью этих двух таблиц:
import polars as plimport requests df_articles_raw = pl.read_csv('https://github.com/BogdanPetrov/habr_honest/raw/6166b168dcb4481e569745e1d3c2cbe7a96e4b76/habr_articles.txt.gz', separator='\t')df_words_raw = pl.read_csv('https://github.com/BogdanPetrov/habr_honest/raw/6166b168dcb4481e569745e1d3c2cbe7a96e4b76/habr_word_data.txt.gz', separator='\t')
Уже на этом этапе можно визуально оценить изменение характера употребления слова «честный». Здесь мне помог инструмент, который я назвал «словоскопом».
Словоскоп
Идея простая. Допустим, хочу сравнить использование слова в разные моменты времени. Для этого фильтрую список статей по дате публикации и объединяю с данными по подстрокам:
date_str = '2026-06-15'( df_articles .filter(pl.col('published') >= pendulum.parse(f'{date_str} 00:00:00+00:00')) .filter(pl.col('published') < pendulum.parse(f'{date_str} 00:00:00+00:00').add(days=1)) .join(df_words, how='inner', on='id') .sort('id', 'idx') .with_columns(pl.col('text_around').str.pad_start(pl.col('text_around').str.len_chars() + 50 - pl.col('start_pos'), ' ').alias('text_around')) .with_columns(pl.col('text_around').str.replace_all('\xa0', ' ')) .select(pl.concat_str(pl.col('id'), pl.lit(' '), pl.col('text_around')))['id'])
Для примера сравнение 15 июня 2021 (все 6 вхождений, всего 61 статья опубликована в этот день) и 15 июня 2026 (приведено 16 из 110 вхождений, всего 124 статьи опубликовано в этот день):
...561774 ших клиентов в сторонние банки?» Сотовый оператор честно и открыто отвечает, что есть такая модель б561928 ирался врезаться в айсберг и пойти ко дну со всем честным народом, а я его спас. Ещё что-нибудь? — З562748 тка времени момента появления логотипа компании). Честно говоря, я не совсем понял, зачем рекламодат562770 орошо известного бэкдора Meterpreter. Goagent Мы, честно говоря, обрадовались, увидев использование 562812 ну, возвращался. Оказалось, что он подменил диск. Честно, я не знаю зачем. Его финансовая выгода мин562914 dleware". На первый взгляд это звучит просто, но, честно говоря, промежуточное ПО может быть весьма...1047006 н, стековые заимствования работают в этом случае? Честно говоря, я не знаю! Вот почему всё так сложн1047134 7 против 94 с) — это не «бесплатный xdist», а его честный оверхед: master плюс отдельный процесс-исп1047134 старте), а между тестами — DELETE . База-на-тест честнее, но платит реконнектом, и для типового сью1047134 бы три размера сьюта на двух раннерах. Сравнивать честно можно только like-for-like: один раннер, од1047134 n14), плато с n8 -n 1 vs serial «бесплатно» −3 % (честный оверхед execnet) Oversubscription (n16–20)1047194 токенов за один раз я не возьму». Грубовато, зато честно: вы сразу знаете, что не влезло, и идете ра1047228 жнения и соревнования, что увлекает детей. Теперь честно: ментальная арифметика не заменит школьную 1047358 rplexity и ChatGPT впереди, Алиса набирает. Вывод честный: канал пока небольшой по объему, но теплый1047382 редложить flyway в spring boot сервисе. Признаюсь честно: триггером к детальному разбору Flyway и ег1047394 ак раз все просто). Грабли - почему «дособрать до честной сквозной» заняло потом еще месяцы (этот ра1047428 й ценой сжечь запланированные сторипоинты. Kanban честно визуализирует поток задач, но при малейшем 1047438 вал первую статью про WebScan из Песочницы Хабра. Честно — не ожидал ничего особенного. Думал придут1047438 о была лучшая мотивация чтобы не останавливаться. Честно о трудностях Я подал заявку на Cyber Verifi1047438 айтов. Ограничивает скорость, уважает robots.txt, честный User-Agent. Stealth — для bug bounty. Jitt1047438 can в 4.7x быстрее Nuclei и в 5.8x быстрее Nikto. Честный вывод от Claude который проводил тест: "We1047442 еня на руках спецификация системы. Поэтому дальше честно помечаю, где у меня твёрдый пруф, а где — р...
Все уже придумано до нас
Уже после узнал, что такое отображение называется “KWIC” (Key Word in Context).
Таким образом, с помощью словоскопа удается проиллюстрировать само изменение, но не получается провести более детальный анализ. Также на общую статистику могут влиять посторонние слова и устойчивые выражения «честно говоря», «если честно» и др. Поэтому следующим шагом будет обработка текстовых данных с последующей очисткой.
Обработка текста
Я не лингвист и руки так и не дошли до прохождения курса по NLP, который лежит в закладках уже несколько лет, поэтому выполнил этот этап как смог, возможно упустив какие-то важные детали. Для разбиения на токены и лемматизации, с помощью которой я рассчитывал более точно сгруппировать слова по контексту применения, использовал пакет natasha.
import natashasegmenter = natasha.Segmenter()emb = natasha.NewsEmbedding()morph_tagger = natasha.NewsMorphTagger(emb)morph_vocab = natasha.MorphVocab()doc = natasha.Doc(text_around)doc.segment(segmenter)doc.tag_morph(morph_tagger)for token in doc.tokens: token.lemmatize(morph_vocab) # ищем токен, который относится к целевому словуword_token_idx = -1for i in range(len(doc.tokens)): if doc.tokens[i].start <= start_pos and doc.tokens[i].stop > start_pos: word_token_idx = i break word = doc.tokens[word_token_idx]
После обработки всех вхождений можно посчитать все слова с подстрокой честн. Помимо форм слова «честно» присутствуют слова с приставкой «бес» («бесчестные» и др.), с приставкой «не» («нечестно» и др), а также слова с единичными случаями использования, включая слова с опечатками («честнейший», «честно-асинхронный», «получестно» и др.). Исходное наблюдение было связано со словом «честный», поэтому факты использования других слов необходимо исключить.
|
«честно» |
15528 |
|
«честный» |
2530 |
|
«честность» |
1102 |
|
«честные» |
1039 |
|
«честным» |
978 |
|
… |
|
Также была мысль исключить из рассмотрения устойчивые выражения, так как относительно их использования я не замечал чего-то необычного. Как видно на графике, их употребление выросло, но незначительно.
Итоговый код для пометки фактов, которые исключаются из дальнейшего анализа:
df_words = ( df_words_raw .with_columns( exclude_word = ( pl.col('word').str.contains('^не') | pl.col('word').str.contains('^бес') | (pl.len().over(pl.col('word')) <= 6) ), phrase_before = pl.concat_str(pl.col('word_before'), pl.lit(' '), pl.col('word')), phrase_after = pl.concat_str(pl.col('word'), pl.lit(' '), pl.col('word_after')) ) .with_columns( exclude_phrase = ( (pl.col('word') == 'по-честному') | (pl.coalesce(pl.col('phrase_after'), pl.lit('')) == 'честно говоря') | (pl.coalesce(pl.col('phrase_before'), pl.lit('')) == 'если честно') | (pl.coalesce(pl.col('phrase_before'), pl.lit('')) == 'будем честны') ) ))
Теперь наконец-то можно получить график, отображающий именно использование слова «честный», а не просто подстроки честн. Доли скорректировались, но форма графика осталась прежней. При этом осталось 22428 из 29202 фактов, то есть почти 77%.
Начало тренда
Несмотря на появление ChatGPT и рост числа статей, до 2025 статистика не показывает каких-то изменений в употреблении слова «честный», доля статей колеблется в районе 5% от недели к неделе.
В 2025 ситуация меняется дважды в начале и конце года.
Я провел некоторое время изучая данные в словоскопе и на графиках, но так и не смог поймать точный момент, когда что-то изменилось. Мне стало казаться, что этот процесс похож на рост растения, когда изменения происходят очень медленно и увидеть их можно либо на ускоренной съемке, либо сравнивая более отдаленные друг от друга моменты времени (как в примере выше, где сравнивался 2021 и 2026 год).
Таймлапс
Некоторое подобие таймлапса можно изобразить, отрисовывая анимацию облака слов от периода к периоду.
Анимация с 2021 по 2026 год

Word-O-Scope (улучшенная версия словоскопа)
Скрытый текст
Да-да, словоскоп долго не давал мне покоя. А название — это отсылка к нюхоскопу из Футурамы.
Дальше стало интересно посмотреть на динамику в различных срезах: по хабам, лейблам (может быть всю эту «честность» занесло на Хабр с переводами), корпоративным блогам и др. В Jupyter Notebook делать это не очень удобно, поэтому поручил Cursor разработку Streamlit приложения.
Тот же график, то же KWIC-отображение, но теперь все интерактивное и динамически перестраивается с учетом выбранных фильтров. Доступно по ссылке вместе с исходным кодом: https://habr-honest.streamlit.app/
Здесь уже можно было детальней изучить отдельные срезы. Характерный рост заметен практически в любом срезе, но можно отметить несколько любопытных вещей:
-
в корпоративных блогах доля употребления слова меньше
-
в статьях с лейблом «Из песочницы» доля выше, чем в среднем по Хабру
-
у авторов, которые писали статьи до эпохи ChatGPT употребление слова ниже чем у тех, чья первая статья вышла после ноября 2022
Последний факт навел на мысль, что начало тренда не удалось обнаружить из-за накопительного эффекта. То есть авторы не все сразу начинали употреблять это слово, а постепенно. При этом доля повторного употребления слова «честный» в новой статье в среднем по авторам оказалась всего лишь 14%, что может говорить о том, что наблюдаемое явление временное и скоро привычка пропадет или перейдет на какое-нибудь другое слово. Хотя некоторые авторы однозначно злоупотребляют этим словом, здесь их перечислять не буду, но в датасете все хорошо видно.
А что с другими словами?
Еще при быстрой проверке своего наблюдения параллельно замерил частоту других слов. Результаты оказались ожидаемыми и скорее подтвердили то, что с использованием слова «честный» происходит что-то необычное.
Заключение
Форма и содержание статей на Хабре объективно меняется и изменение частоты использования отдельных слов — наглядное тому подтверждение. Распространенность таких инструментов как LLM оказывает на этот процесс значительное влияние. И хотя мне не очень нравится видеть большое количество сгенерированного, неестественного текста, я воспринимаю это как обратную сторону медали. Сейчас каждому доступен довольно мощный инструмент для решения повседневных и рабочих задач и пока это не может не радовать. А что касается Хабра, то аудитория в любом случае проголосует.
ссылка на оригинал статьи https://habr.com/ru/articles/1075522/