2025, Oct 31 07:47

Группировка по ID в pandas и запись чистого текста вместо CSV

Как в pandas сгруппировать по ID и записать чистый текст без CSV-артефактов: отказ от to_csv, прямая запись значений OTHER_FIELDS_2 и разделителя без кавычек.

Когда целевой формат — не таблица CSV, а свободный текст, попытка прогнать результат через CSV‑писатель часто оборачивается проблемами. Сгруппированные значения оказываются внутри кавычек в ячейках, появляются лишние запятые, а переносы строк стоят не там, где нужно. Если цель — простой текстовый макет вроде заголовка с ID, далее его строки и разделитель, чище всего записать файл напрямую вместо использования pandas.to_csv.

Постановка задачи

Нужно прочитать CSV с колонками ID и OTHER_FIELDS_2, сгруппировать по ID и сформировать текстовый файл: каждая группа начинается с ID, затем перечисляются непустые значения из OTHER_FIELDS_2 и завершается строкой из звёздочек. Попытка уложить такой макет в формат DataFrame-to-CSV приводит к лишним кавычкам и некорректным переносам строк.

Код, вызывающий проблему с форматированием

Ниже фрагмент, который группирует строки, преобразует сгруппированные данные в строки и затем пишет их через to_csv. Логика понятна, но финальная запись навязывает правила CSV к не-CSV формату, из‑за чего в результате появляются кавычки и артефакты.

import pandas as pd
import csv
tbl = pd.read_csv('idDetails.csv')
row_buffer = []
key_col = 'ID'
value_cols = ['OTHER_FIELDS_2']
clusters = tbl.groupby(key_col)[value_cols]
for k, sub in clusters:
    lines_as_is = sub.to_string(header=False, index=False)
    cleaned = sub.fillna('').dropna(axis=0, how='all')
    flat_text = cleaned.to_string(header=False, index=False)
    sep_line = '**********'
    row_buffer.append([k, '\n', flat_text, '\n', sep_line])
out = pd.DataFrame(row_buffer)
out.to_csv('idDetailsoutput.txt', header=False, index=False)

Почему это не работает для обычного текста

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

Исправление: прямая запись

Для этой задачи откажитесь от DataFrame-to-CSV. Пройдитесь по группам и запишите в текстовый файл ровно то, что нужно. Так вы полностью обойдёте правила экранирования CSV и сохраните контроль над форматированием.

import pandas as pd
# Чтение входных данных
records = pd.read_csv('idDetails.csv')
# Группировка по ID и выбор целевого столбца
by_id = records.groupby('ID')['OTHER_FIELDS_2']
# Запись пользовательского текстового вывода
with open('idDetailsoutput.txt', 'w') as out_f:
    for gid, series in by_id:
        out_f.write(f"{gid}\n")
        for val in series:
            if pd.notna(val) and val.strip() != "":
                out_f.write(f"{val.strip()}\n")
        out_f.write("**********\n")

Получившийся вывод соответствует требуемому формату:

18
20 BA-10  12  06  2  30  S
20 BA-20  12  06  2  30  S
**********
66
20 AD-38  12  06  B
20 AD-38  30  07  B
**********
70
20 OL-45  19  11  B
20 EM-45  19  08  B
**********
77
**********
87
25 R160  22  13  E
25 R165  22  08  E
**********
88
20 TH-42  02  02  5  30  MT
**********

Почему это стоит знать

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

Выводы

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

Статья основана на вопросе с сайта StackOverflow от пользователя learner и ответе пользователя codewithpurpose.