Ввод-вывод: 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 — колоночный бинарный формат, который хранит типы, сжимает данные и читает только нужные столбцы.
| Критерий | CSV | Parquet |
| Типы данных | теряются (всё текст) | сохраняются |
| Размер на диске | большой | в разы меньше (сжатие) |
| Скорость чтения | медленно | быстро |
| Чтение части столбцов | нет | да (колоночный) |
| Читается человеком | да | нет |
df.to_parquet("data.parquet") # запись
df = pd.read_parquet("data.parquet", columns=["id", "сумма"]) # читаем 2 столбца
Правило: CSV — для обмена с людьми и внешними системами; parquet — для промежуточного хранения и больших данных внутри пайплайна. Сохранили почищенные данные в parquet один раз — и дальше читаете их быстро и с правильными типами.
Почему CSV в принципе ненадёжен? Это просто текст без схемы. Распознавание типов CSV делает на лету и по выборке строк, поэтому одни и те же данные могут прочитаться по-разному в разных запусках или окружениях: ведущие нули в кодах теряются (007 → 7), длинные числовые 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.