Алгоритм извлечения данных из справочника 1912 года, серия промтов для этапа «Даты», по которой код написала модель Claude Sonnet, проверка кода на всём томе и план доработки.
Саитов В. И. Петербургский некрополь. Т. 1 (А–Г). СПб.: Тип. М. М. Стасюлевича, 1912. Словарь лиц, погребённых на петербургских кладбищах в XVIII – начале XX в., составлен по поручению вел. кн. Николая Михайловича. Использован OCR-текст с Internet Archive: archive.org/details/peterburgskijnekropolt1ag60 — 61 623 строки, около 3 МБ.
Типичная статья:
| Абаза, Аггей Васильевичъ, р. 16 декабря 1782 { 21 марта 1852 (Александро-Невская лавра…) |
Почему этот источник. Он близок к актовым книгам, которые разбирались на семинаре. Это массовый серийный источник с устойчивой формулой записи: фамилия, имя, чин, р. дата † дата, возраст, родственники, (кладбище). Формула позволяет описать правила деления. При этом текст «грязный»: дореформенная орфография, OCR-ошибки, разорванные страницы. На таком тексте видно, зачем нужны механизмы контроля. Из дат рождения и смерти получаются возраст смерти, сезонность и динамика по десятилетиям, то есть основа для исследовательского вопроса.
Схема со слайда «Автоматизированная разметка текста» применена к источнику:
| Этап | Что делает | Правило | Контроль |
|---|---|---|---|
| 0. Подготовка | Скачивает источник, отсекает предисловие, удаляет мусорные строки, склеивает переносы | Начало словаря — «Абаза, Аггей»; мусор — строки из цифр и обрывков | Проверка содержимого скачанного файла; число и примеры удалённых строк |
| 1. Статьи | Делит текст на статьи | «Фамилия,» с начала абзаца на букву своего раздела; режет склеенные статьи после «).» | Число статей по буквам; нарушения алфавитного порядка |
| 2. Имя | Фамилия, имя, отчество, пол | Текст до второй запятой; пол — по окончанию отчества или фамилии | Доля статей без отчества, словарь имён |
| 3. Даты | Даты рождения и смерти | Знаки «р.» / «†» с учётом OCR-вариантов; только «своя» часть статьи | Самопроверка на примерах из промтов, пометки, эталон |
| 4. Статус | Чин, титул, сословие, профессия | Словарь: «колл. сов.», «купецъ», «графиня», «младенецъ»… | Частотный список нераспознанных слов |
| 5. Кладбище | Место погребения и его нормализация | Последняя скобка; словарь вариантов («Волково лютер.» = «Волково лютеранское») | Все варианты сводятся к списку кладбищ из предисловия (около 40) |
| 6. Таблица | Сборка базы: человек — даты — статус — кладбище | Связь по id статьи | Выборочная ручная сверка 50 строк |
Код этапа написала модель Claude Sonnet: пять промтов подавались по очереди в одном диалоге. Промты написаны обычным языком, как задание коллеге-программисту:
Задача: что за источник, как устроена статья, что значат «р.» и крест, куда сохранить результат и в каком формате. «Начни с простой версии».
Контроль: 3 примера в самопроверке (полная дата, только смерть, отсылка без дат); доля статей с датой смерти.
Я историк, работаю со справочником «Петербургский некрополь» (1912). Это словарь людей,
похороненных на кладбищах Петербурга. Текст получен распознаванием скана (OCR),
поэтому в нём много опечаток, а орфография дореформенная (ъ, ѣ, і).
Статьи уже разделены: файл output/entries.csv, столбцы id, surname, is_reference, text.
Типичная статья:
Абаза, Аггей Васильевичъ, р. 16 декабря 1782 { 21 марта 1852 (Александро-Невская лавра).
Здесь «р.» — дата рождения, а дата после креста † — дата смерти (в OCR крест часто
превратился в «{», «+», «|», «1» или «Т»). В скобках в конце — кладбище.
Нужна программа на Python (без сторонних библиотек), которая для каждой статьи находит
дату рождения и дату смерти самого человека и сохраняет их в output/dates_sonnet.csv
(столбцы id, birth, death). Формат даты: 1852-03-21; если известен только год — 1852;
если год и месяц — 1852-03; если даты нет — пусто.
Назови файл code/dates_sonnet.py. Начни с простой версии.
Сделай так, чтобы программа при каждом запуске сначала проверяла себя на примерах
и останавливалась, если какой-то пример не прошёл:
- «Баженовъ, Иванъ Прокофьевичъ, р. 8 ноября 1791 + 8 января 1872 (Смоленское кладбище).»
→ рождение 1791-11-08, смерть 1872-01-08
- «Боголюбовъ, Павелъ Николаевичъ + 28 декабря 1904 (Новодѣвичій монастырь).»
→ рождения нет, смерть 1904-12-28
- «Аксенова, Елизавета Ивановна—см. Анцъ.» → это отсылка, дат нет
Запусти программу и скажи, у какой доли статей нашлась дата смерти.Задача: сначала посчитать по данным, как OCR записал крест и названия месяцев, показать частые варианты, потом научить программу их понимать. Подсказки словами: «1336» = 1836, крест бывает цифрой 1, месяц с заглавной, бывают только годы.
Контроль: +7 примеров («поня», «апрфля», «1 5 марта», «р. 1852 Т 1892», «1336», «Февраля»).
Дата смерти находится далеко не у всех статей: OCR исказил текст. Прежде чем исправлять
программу, посмотри на сами данные. Посчитай, какими символами на самом деле записан
крест перед датой смерти и как выглядят названия месяцев (например, «іюля» часто
превратилось в «юля», «поля» или «1юля»). Покажи мне самые частые варианты.
Потом научи программу понимать эти варианты. Несколько вещей, которые я заметила сама:
- в годах OCR путает цифры: «1336» на самом деле 1836, а «т852» — 1852;
- крест иногда выглядит как цифра 1: «р. 15 ноября 1852 1 5 марта 1856» значит,
что человек умер 5 марта 1856;
- месяц может быть с заглавной буквы: «2 Февраля 1894»;
- иногда указаны только годы: «р. 1852 Т 1892».
Добавь эти примеры к проверкам:
- «Годенъ, Викторія + 28 поня 1905 (Католическое кладбище).» → смерть 1905-06-28
- «Брезинская, Юстина + 16 апрфля 1889 (Смоленское кладбище).» → смерть 1889-04-16
- «Гребне, Софія-Доротея, р. 12 марта 1816 1 26 января 1877 (Волково кладбище).»
→ рождение 1816-03-12, смерть 1877-01-26
- «Гюне, баронъ Эдуардъ, р. 15 ноября 1852 1 5 марта 1856 (Волково кладбище).»
→ рождение 1852-11-15, смерть 1856-03-05
- «Гельмгольцъ, Ѳедоръ, капитанъ, р. 1852 Т 1892 (Гатчинское кладбище).» → 1852 и 1892
- «Гамельманъ, Амалія, р. 9 февраля 1800 + 23 января 1336 (Волково кладбище).» → смерть 1836-01-23
- «Волкова, Марія Филипповна + 2 Февраля 1894 (Новодѣвичій монастырь).» → смерть 1894-02-02
Запусти и покажи, насколько выросла доля статей с датой смерти.Задача: брать только даты самого человека, до родственников и скобки с кладбищем; не всякая скобка — кладбище; слова между «р.» и датой; «рожд.» = урождённая; дату без креста помечать.
Контроль: +5 примеров (дата жены не берётся, «(Бивоча)», «рожд. Вердье», «р. въ Митавѣ»).
Теперь важно не перепутать людей. После основного человека в статье часто упомянуты
родственники со своими датами: «Жена: Вѣра Петровна + 23 октября 1909» или
«Съ М. И. Аксеновой». Нам нужны только даты самого человека — те, что идут до упоминания
родственников и до скобки с названием кладбища. Но не всякая скобка — кладбище:
в «рожд. Дюлу (Бивоча)» в скобках просто другое написание фамилии.
Ещё три тонкости:
- между «р.» или крестом и датой бывают слова: «р. въ Ригѣ 9 апрѣля 1829», «+ убитъ 12 октября 1877»;
- «рожд. Вердье» значит «урождённая Вердье» — это девичья фамилия, а не дата рождения;
- если в статье пропущен крест, а дата стоит после даты рождения, это скорее всего тоже дата смерти,
но такие случаи стоит пометить, чтобы потом проверить.
Примеры для проверок:
- «Акорчевъ, Александръ, колл. сов. { 26 марта 1885, на 61 г. Жена: Вѣра Петровна 1 23 октября 1909 (Смоленское кладбище).» → смерть 1885-03-26
- «Банье, Андрей-Фридрихъ, р. въ Мекленбургъ-Шверинѣ 29 сентября 1769 + 27 апрѣля 1840, 70 л. (Волково кладбище).» → рождение 1769-09-29, смерть 1840-04-27
- «Брюнъ-де-Сентъ-Ипполитъ, Елизавета, рожд. Дюлу (Бивоча) 1 5 февраля 1843, 34 л. (Смоленское кладбище).» → смерть 1843-02-05
- «Годенъ, Викторія, рожд. Вердье + 28 поня 1905, 71 г. (Католическое кладбище).» → рождения нет
- «Вальдманъ, Елена, рожд. Шинна, р. въ Митавѣ 30 сентября 1799 т 1 мая 1875 (Гатчинское кладбище).» → рождение 1799-09-30, смерть 1875-05-01
Запусти и покажи результат.Задача: помечать подозрительные статьи (год вне 1700–1912, рождение позже смерти, больше 110 лет, возраст в тексте не совпадает, год есть — смерти нет, смерть без креста), сохранить их в файл на проверку и печатать сводку.
Контроль: +1 пример (пометки у статьи с годом «1992»); сводка на экране.
Мне нужно понимать, где программе можно доверять, а где нужно проверить глазами.
Пусть она помечает подозрительные статьи:
- год рождения или смерти вне 1700–1912 (книга издана в 1912 году);
- рождение позже смерти;
- человек прожил больше 110 лет;
- в тексте указан возраст («на 45 г.», «63 л.»), и он не совпадает с разницей годов больше чем на год;
- в статье есть год, а дату смерти найти не удалось;
- дата смерти взята без креста.
Помеченные статьи вместе с текстом сохрани в output/dates_sonnet_review.csv,
а пометки добавь столбцом flags в dates_sonnet.csv. В конце работы программа должна
печатать короткую сводку: сколько статей обработано, у скольких найдены даты рождения
и смерти, сколько статей с каждой пометкой.
Пример для проверки: у статьи «Аркъ-фанъ, Карлъ, р. 28 августа 1839 + 11 августа 1992 (Волково кладбище).»
должны быть пометки «год вне диапазона» и «больше 110 лет».
Запусти и покажи сводку.Задача: сравнить с 60 вручную проверенными статьями, объяснить каждое расхождение простыми словами, исправить ошибки кода, а ошибки самого источника не подгонять.
Контроль: точность и полнота до и после исправлений.
Я вручную проверила 60 случайных статей (data/gold_dates.csv). Запусти сравнение:
python3 code/evaluate.py output/dates_sonnet.csv
Покажи результат и для каждого расхождения объясни простыми словами, в чём причина.
Если ошибся код — исправь его так, чтобы прежние проверки по-прежнему проходили, и запусти
сравнение ещё раз. Если ошибка в самом тексте источника (OCR) — не подгоняй код, просто скажи об этом.
Файлы с разметкой и evaluate.py не меняй.Код Sonnet запущен на всём томе: 13 620 статей, из них 12 330 без отсылок «см.». Итог на отложенной выборке — 40 случайных статей, размеченных вручную и не показанных модели:
| Шаг | Дата смерти найдена (из 13 620) | Примеров в самопроверке | Что произошло |
|---|---|---|---|
| 1 · первая версия | 11 319 | 3 / 3 | Модель сразу сделала месяцы терпимыми к опечаткам: даже «простая» версия нашла 83 % всех статей |
| 2 · искажения OCR | 11 467 | 10 / 10 | Модель сама посчитала варианты креста («+» 1955, «1» 1012, «|» 826, «Т» 490…) и месяцев («поля» 386, «поня» 321, «апрфля» 133…); починила годы 13xx и «т852» |
| 3 · чьи это даты | 11 577 | 15 / 15 | Даты родственников отрезаны; склеенная со ссылкой «см.» статья читается дальше; дата без креста помечается |
| 4 · контроль | 11 577 | 16 / 16 | Шесть видов пометок, включая сверку с возрастом из текста; 616 статей на проверку |
| 5 · сверка с эталоном | 11 694 | 18 / 18 | Эталон: смерть 96 / 93 % → 100 / 100 %. Модель нашла пять ошибок кода: «р. 2 + 3 апрѣля» (нечитаемое рождение), «5 ня», «азгуста», «19 1юля»; на проверку осталось 516 статей |
| Выборка | Рождение: точн. / полн. | Смерть: точн. / полн. | Замечание |
|---|---|---|---|
| Эталон, 60 статей, до шага 5 | 90 / 96 % | 96 / 93 % | До самопроверки модели |
| Эталон, 60 статей, после шага 5 | 100 / 100 % | 100 / 100 % | Модель исправляла код по этим статьям, оценка завышена |
| Отложенная выборка, 40 статей | 94 / 100 % | 97 / 100 % | Модели не показывалась: честная оценка. До шага 5 было 94 / 100 % и 92 / 92 %: исправления по эталону помогли и на новых статьях |
| Текст статьи (OCR) | Рождение | Смерть | Что сложного |
|---|---|---|---|
| Гребне, Соф!я-Доротея, рожд. //етерсонв, р. 12 марта 1816 1 26 января 1877 | 1816-03-12 | 1877-01-26 | «рожд.» без даты; † распознан как «1» |
| Банье, Андрей-Фридрихъ, р. въ Мекленбургъ-ШверинЪ 29 сентября 1769 + 27 апрЪля 1840 | 1769-09-29 | 1840-04-27 | Место между знаком и датой |
| Алябьевъ, Оедоръ младенецъ, р. 5 ня 1858 + 16 мая 1859 | 1858-06-05 | 1859-05-16 | «ня» = іюня |
| Годенъ, Виктор!я, рожд. Вердье + 28 поня 1905, 71 г. | — | 1905-06-28 | «рожд.» = урождённая; «поня» = іюня |
| Бажановъ, Григорий Алексѣевичъ, д. ст. сов. 1820. Вдова: Устина … т 16 мая 1846 | — | 1820 | Знак † потерян; дата вдовы отрезана по слову «Вдова» |
| Блюмъ, Людвигъ-Фридрихъ, р. 7 октября 1804 | 19 сентября (1 октября) 1864 | 1804-10-07 | 1864-09-19 | Двойная дата по старому и новому стилю |
| Аркъ-фанъ, Карлъ Карловичъ, р. 28 августа 1839 … + 11 августа 1992 | 1839-08-28 | 1992-08-11 | на проверку ошибка OCR в источнике (1892) |
| Пометка | Статей | Что обычно стоит за ней |
|---|---|---|
| смерть без креста | 228 | Знак † съеден OCR; дата взята по положению (сразу после рождения) — её стоит проверить |
| есть год, но нет смерти | 196 | Сильно испорченный OCR («24 : Бля 1888», «19053»), дата только рождения |
| возраст не совпадает | 44 | Возраст «на 45 г.» расходится с разницей годов: ошибка цифр в OCR или возраст с месяцами |
| рождение позже смерти | 32 | Ошибка цифр в OCR: «р. 3 февраля 1849 1 17 марта 1832» |
| больше 110 лет | 23 | «1992», «1534» — ошибки OCR в годах |
| год вне диапазона | 15 | Год вне 1700–1912: «0099», «1002» |
Все статьи с пометками записаны в output/dates_sonnet_review.csv вместе с текстом статьи.
11 154 статьи с известным месяцем смерти и годом в пределах 1700–1912. Больше всего смертей в марте (1 178), меньше всего в августе (705). Это основа для вопроса о сезонности смертности петербургской элиты XIX в. Медианный возраст смерти — 56 лет (5 661 статья с обеими датами и без пометок).
Соответствие задаче. Этап выполняет свою задачу. На отложенной выборке программа нашла все 38 дат смерти и все 17 дат рождения. Единственная ошибка возникла до этапа «Даты»:
Доработка на следующем этапе:
Нужен Python 3.10 или новее, сторонние библиотеки не нужны. Команды выполняются из папки practice (на Windows — python вместо python3):
python3 code/download.py # скачать OCR-текст с archive.org в data/
python3 code/segment.py # этапы 0–1 → output/entries.csv
python3 code/dates_sonnet.py # этап 3 (код Sonnet): самопроверка + даты + пометки
python3 code/evaluate.py # сверка с эталоном (60 статей)
python3 code/evaluate.py output/dates_sonnet.csv data/holdout_dates.csv # отложенная выборка
Или одной командой: python3 necropol_dates.py. Это всё решение в одном файле: скачивание, разбиение, код Sonnet, контроль и проверка по встроенной ручной разметке. Результаты побайтно совпадают с поэтапным запуском.
Источник (data/necropol_t1.txt, 3 МБ) и промежуточный файл статей (output/entries.csv) в архив не входят: их создают download.py и segment.py. Если скачивание не работает, файл можно взять вручную: https://archive.org/download/peterburgskijnekropolt1ag60/peterburgskijnekropolt1ag60_djvu.txt, сохранить как data/necropol_t1.txt. Файлы этапов 0–1 записаны в UTF-8 с BOM и сразу открываются в Excel; файлы этапа 3 — в обычном UTF-8, в Excel их открывают через «Данные → Из текста/CSV».
reports/result.docx | Этот отчёт в формате Word |
prompts/sonnet_prompts.md | Серия из 5 промтов (раздел 02) |
code/dates_sonnet.py | Этап 3: код, написанный Claude Sonnet по промтам, без правок |
code/download.py, code/segment.py | Этапы 0–1: скачивание, очистка, разбиение на статьи |
code/evaluate.py | Сверка с ручной разметкой |
necropol_dates.py | Всё решение одним файлом |
data/gold_dates.csv, holdout_dates.csv | Ручная разметка: 60 + 40 статей |
output/dates_sonnet.csv | Результат: даты и пометки для 13 620 статей |
output/dates_sonnet_review.csv | 516 статей на ручную проверку |
Модели: Claude Sonnet (Anthropic) — написала код этапа 3 по серии промтов; Claude Opus 5.5 (Anthropic), в режиме агента Claude Code — подготовка.
Цели: написание кода; подготовка ручной разметки для проверки; оформление отчёта.
Что вошло в работу: код этапа 3 (Sonnet, без правок); код этапов 0–1 и проверки (Opus); тексты промтов; разметка эталона (100 статей); отчёт.
Собственная доработка после общения с моделью:
Ручная разметка эталона (100 статей) выполнена с помощью Claude Opus; независимая сверка её человеком со сканом пока не проводилась и стоит в плане доработки.