Ввод-вывод: read_csv, parquet и Excel

Большинство проектов начинается с чтения файла — и правильно настроенный read_csv экономит часы последующей очистки.

read_csv — самая используемая функция ввода в pandas. Её параметры позволяют сразу задать типы, распарсить даты и читать только нужное.

read_csv: больше, чем имя файла

Наивный вызов pd.read_csv("data.csv") работает, но оставляет проблемы на потом: даты как строки, числа с запятой как object, лишние столбцы в памяти. Гораздо лучше настроить чтение сразу:

df = pd.read_csv(
    "sales.csv",
    dtype={"id": "Int64", "город": "category"},  # типы сразу
    parse_dates=["дата"],                          # даты сразу
    usecols=["id", "дата", "город", "сумма"],      # только нужные столбцы
    sep=";",                                        # разделитель
    decimal=",",                                    # запятая как дробная точка
    na_values=["-", "н/д", ""],                     # что считать пропуском
    encoding="utf-8",
)

Разберём ключевые параметры:

ПараметрЗачем
dtypeзадать типы при чтении — без последующего astype
parse_datesсразу распарсить столбцы-даты в datetime
usecolsчитать только нужные столбцы — меньше памяти и быстрее
sep / decimalнестандартные разделитель и дробная точка
na_valuesдополнительные маркеры пропуска
nrowsпрочитать только первые N строк (для разведки)
encodingкодировка (частая беда — windows-1251 в русских CSV)

usecols и dtype — главные рычаги памяти: если из 50 столбцов нужны 5, не тащите остальные. А nrows=1000 позволяет быстро «подсмотреть» структуру большого файла, не загружая его целиком.

chunksize: чтение по частям

Когда файл не помещается в память, его читают порциями. chunksize возвращает итератор по кускам DataFrame — каждый можно обработать и агрегировать, не держа всё сразу:

# имитация поточной обработки CSV по частям без загрузки целиком
rows = [("Москва", 100), ("Сочи", 80), ("Москва", 120),
        ("Сочи", 90), ("Москва", 60), ("Тверь", 40)]
chunk_size = 2

totals = {}
# читаем порциями по 2 строки и накапливаем суммы
for start in range(0, len(rows), chunk_size):
    chunk = rows[start:start + chunk_size]
    for city, amount in chunk:
        totals[city] = totals.get(city, 0) + amount
    print("обработан кусок:", chunk)

print("итоги:", dict(sorted(totals.items())))

Вывод:

обработан кусок: [('Москва', 100), ('Сочи', 80)]
обработан кусок: [('Москва', 120), ('Сочи', 90)]
обработан кусок: [('Москва', 60), ('Тверь', 40)]
итоги: {'Москва': 280, 'Сочи': 170, 'Тверь': 40}

Мы посчитали суммы по городам, ни разу не держа в памяти весь датасет — только куски по две строки. С pd.read_csv(..., chunksize=10000) вы так же итерируетесь по кускам DataFrame и агрегируете результат по частям.

Parquet против CSV

CSV — универсальный текстовый формат, но для серьёзной работы он плох: нет типов (всё перечитывается и угадывается), большой размер, медленное чтение. Parquet — колоночный бинарный формат, который хранит типы, сжимает данные и читает только нужные столбцы.

КритерийCSVParquet
Типы данныхтеряются (всё текст)сохраняются
Размер на дискебольшойв разы меньше (сжатие)
Скорость чтениямедленнобыстро
Чтение части столбцовнетда (колоночный)
Читается человекомданет
df.to_parquet("data.parquet")          # запись
df = pd.read_parquet("data.parquet", columns=["id", "сумма"])  # читаем 2 столбца

Правило: CSV — для обмена с людьми и внешними системами; parquet — для промежуточного хранения и больших данных внутри пайплайна. Сохранили почищенные данные в parquet один раз — и дальше читаете их быстро и с правильными типами.

Почему CSV в принципе ненадёжен? Это просто текст без схемы. Распознавание типов CSV делает на лету и по выборке строк, поэтому одни и те же данные могут прочитаться по-разному в разных запусках или окружениях: ведущие нули в кодах теряются (0077), длинные числовые id переполняются и съезжают в float, булевы значения вида "Да"/"Нет" остаются строками. Parquet хранит схему вместе с данными, поэтому что записали — то и прочитали, без угадывания. Если данные живут только внутри вашего пайплайна и не предназначены для человека, parquet почти всегда лучший выбор: он надёжнее, компактнее и быстрее.

Excel

Excel удобен для бизнес-отчётов, но как формат данных тяжёлый и медленный. read_excel/to_excel требуют дополнительных пакетов (openpyxl) и поддерживают листы:

df = pd.read_excel("report.xlsx", sheet_name="Продажи")
df.to_excel("output.xlsx", sheet_name="Итоги", index=False)
sheets = pd.read_excel("report.xlsx", sheet_name=None)  # все листы → dict

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

Подводные камни

  • Кодировка русских CSV. Файлы из 1С/Excel часто в windows-1251; без правильного encoding получите «кракозябры» или ошибку.
  • Числа с запятой. «1 234,56» прочитается как строка; нужны decimal="," и иногда thousands=" ".
  • Угадывание типов на больших файлах. Без dtype= pandas угадывает типы по выборке и может ошибиться (id как float). Задавайте типы явно.
  • to_excel без index=False добавит лишний столбец с индексом в файл.
  • parse_dates без format на больших файлах медленный — лучше указать формат через date_format/постобработку.

Лучшие практики

  • Настраивайте чтение сразу: dtype, parse_dates, usecols, na_values — это убирает половину последующей очистки.
  • Большие файлы читайте через chunksize или сразу переходите на parquet.
  • Для хранения внутри пайплайна предпочитайте parquet: типы, сжатие, скорость.
  • Для разведки структуры используйте nrows, а не загрузку всего файла.

Итог

  • read_csv с dtype/parse_dates/usecols экономит память и время на очистке.
  • chunksize позволяет обрабатывать файлы крупнее памяти по частям.
  • Parquet хранит типы, сжимает и читает столбцы выборочно — лучше CSV для пайплайнов.
  • Excel — для отчётов людям; при записи указывайте index=False.
Проверьте себя
1. Зачем при чтении большого CSV использовать параметр usecols?
AЧтобы отсортировать столбцы
BЧтобы читать только нужные столбцы — меньше памяти и быстрее
CЧтобы удалить дубликаты
DЧтобы распарсить даты
2. В чём главное преимущество parquet перед CSV для пайплайна данных?
AParquet читается человеком в блокноте
BParquet сохраняет типы данных, сжимает файл и позволяет читать столбцы выборочно
CParquet всегда меньше по числу строк
DCSV не поддерживает числа
3. Файл крупнее доступной оперативной памяти. Как его обработать в pandas?
AЭто невозможно
BЧитать через chunksize порциями и агрегировать результат по частям
CУдалить половину строк
DИспользовать только read_excel
Поддержать проект