Разделение CSV-расшифровки по интервью через Python: файлы и реестр групп
Как разделить таблицу реплик по interview_id, сохранить все колонки и составить manifest.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.csv | I-12 | 2 |
| group-002.csv | I-13 | 1 |
| Итого | Два источника | 3 |
Если итоговая сумма отличается, не передавайте комплект как полный. Проверьте прерывание записи, заголовки и исключённые вручную строки.
Акт проверки разбиения
Исходный CSV: [имя и версия] Колонка группировки: interview_id Правила ID: [описание] Записей во входе: [число] Групп: [число] Сумма rows: [число] Спорные ID: [решения] Начало и конец групп: [проверка] Папка и реестр: [пути]
Частые вопросы
Это разделение по говорящим?
Нет. Здесь ключ — идентификатор интервью. Смысл ключа нужно подтвердить до запуска.
Можно назвать файл самим ID?
В примере используются нейтральные имена и реестр, чтобы не превращать произвольные значения в пути.
Почему группа с пробелом отдельная?
Сравнение точное. Нормализацию ID нужно согласовать и проверить отдельно.
Скрипт подходит для огромного CSV?
Он хранит строки в памяти. Оцените объём и используйте другой подход при ограничении памяти.