ТранскрибаторТранскрибатор
Практическая инструкция

Разделение CSV-расшифровки по интервью через Python: файлы и реестр групп

Как разделить таблицу реплик по interview_id, сохранить все колонки и составить manifest.csv. Проверка количества строк и безопасные имена файлов.

Транскрибатор
ЗАПИСЬПЛАН РАБОТЫПроверьте идентификаторыСоздайте отдельные группыСверьте реестр и строкиПроверить результатОТ СЛОВ К РЕЗУЛЬТАТУ
Работа с реальной записьюНаглядный учебный примерШаблон для копирования
1Проверьтеидентификаторы2Создайте отдельныегруппы3Сверьте реестр и строки
Один исходный CSV превращается в несколько проверяемых файлов с общим реестром.

Когда требуется разделение по источнику

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

Подтвердите, что каждая строка имеет правильный идентификатор записи. Значения I-12 и I-13 в примере вымышленные. Метка должна обозначать источник целиком, а не номер говорящего или дату без уточнения. Если два файла получили один ID, код объединит их строки и не обнаружит ошибку назначения.

Проверьте схему и точное совпадение значений

Учебный CSV содержит колонки interview_id, speaker, timecode, text. Другие поля сохраняются. До запуска проверьте структуру CSV и пустые реплики. Разделитель примера — запятая, кодировка — UTF-8 с допустимой начальной меткой BOM.

Группировка точная: I-12 и I-12 с пробелом в конце попадут в разные группы. Код не исправляет значения молча. Пустой ID останавливает обработку. Сначала установите правила названий, сверьте спорные значения с источником и сохраните отдельную исправленную копию с описанием изменения.

Создайте файлы и реестр соответствий

Положите transcript.csv рядом с split_interviews.py. Сохраните приведённый код и выполните python split_interviews.py. Папка interviews-split должна отсутствовать: mkdir без exist_ok препятствует смешению нового выпуска с прежним. Если создание прервалось, проверьте состав получившейся папки до следующего запуска; используйте новое имя для повторного комплекта.

defaultdict(list) создаёт список для впервые встреченного ключа. Порядок строк внутри группы соответствует исходному CSV. На диск пишутся group-001.csv и следующие имена. Значения ID не становятся путями, поэтому символы / в идентификаторе не создадут вложенные каталоги. manifest.csv связывает имя с исходным ID и количеством записей.

import csv
from pathlib import Path
from collections import defaultdict

groups = defaultdict(list)
with Path("transcript.csv").open(encoding="utf-8-sig", newline="") as source:
    reader = csv.DictReader(source)
    headers = reader.fieldnames or []
    if "interview_id" not in headers or len(headers) != len(set(headers)):
        raise ValueError("Проверьте заголовки")
    for row in reader:
        if None in row or any(v is None for v in row.values()):
            raise ValueError("Неполная строка или лишние поля")
        key = row["interview_id"]
        if not key.strip(): raise ValueError("Пустой interview_id")
        groups[key].append(row)
folder = Path("interviews-split")
folder.mkdir()
manifest = []
for n, (key, rows) in enumerate(groups.items(), 1):
    name = f"group-{n:03d}.csv"
    with (folder / name).open("x", encoding="utf-8-sig", newline="") as target:
        writer = csv.DictWriter(target, fieldnames=headers)
        writer.writeheader()
        writer.writerows(rows)
    manifest.append({"file": name, "interview_id": key, "rows": len(rows)})
with (folder / "manifest.csv").open("x", encoding="utf-8-sig", newline="") as target:
    writer = csv.DictWriter(target, fieldnames=["file", "interview_id", "rows"])
    writer.writeheader()
    writer.writerows(manifest)
print("Групп:", len(groups), "Строк:", sum(map(len, groups.values())))

Проверьте комплект перед передачей

Сложите rows из реестра, сравните с входным числом записей и откройте первый и последний фрагменты каждой группы. Не считайте физические строки текстового файла: внутри CSV-поля могут быть переносы. Проверьте, что в файле нет чужого interview_id, а таймкоды относятся к нужной записи.

Для передачи полного комплекта поможет проверка состава ZIP. Исходную текстовую основу можно подготовить через расшифровку аудио; ID интервью и схему таблицы назначает ваш рабочий процесс.

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

Учебный пример

Учебный пример: три реплики и два интервью

Вымышленные записи I-12, I-13, I-12 дают две группы, сохраняя порядок внутри каждой.

ФайлИнтервьюЗаписей
group-001.csvI-122
group-002.csvI-131
ИтогоДва источника3
ВходID у каждой репликиПроверить источникРазбиениеТочное совпадениеСохранить все поляКонтрольРеестр и суммаСверить комплект
Реестр удерживает связь нейтрального имени файла с конкретной записью.

Если итоговая сумма отличается, не передавайте комплект как полный. Проверьте прерывание записи, заголовки и исключённые вручную строки.

Акт проверки разбиения

Рабочая заготовкаВыделите и скопируйте
Исходный CSV: [имя и версия]
Колонка группировки: interview_id
Правила ID: [описание]
Записей во входе: [число]
Групп: [число]
Сумма rows: [число]
Спорные ID: [решения]
Начало и конец групп: [проверка]
Папка и реестр: [пути]

Частые вопросы

Это разделение по говорящим?

Нет. Здесь ключ — идентификатор интервью. Смысл ключа нужно подтвердить до запуска.

Можно назвать файл самим ID?

В примере используются нейтральные имена и реестр, чтобы не превращать произвольные значения в пути.

Почему группа с пробелом отдельная?

Сравнение точное. Нормализацию ID нужно согласовать и проверить отдельно.

Скрипт подходит для огромного CSV?

Он хранит строки в памяти. Оцените объём и используйте другой подход при ограничении памяти.