Работа с данными в формате CSV средствами Python

Раздел: Работа с данными -> Обработка табличных данных

Основы работы с CSV в Python

CSV (Comma-Separated Values) - распространённый формат для табличных данных. В Python для работы с ним существует встроенный модуль csv, а также сторонние библиотеки, такие как pandas и numpy. Выбор подхода зависит от размера файла, требуемой производительности и сложности операций.

Основное решение - модуль csv (DictReader / DictWriter)

Модуль csv - встроенный и не требует установки. Он оптимален для большинства задач: чтение, запись, преобразование типов, работа с разными разделителями и кавычками.

Чтение CSV с заголовками

import csv

with open('data.csv', 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row['Имя'], row['Возраст'])

Python удалить столбцы (удаление столбцов из таблицы в python)

Иван 25
Мария 30

Python csv (работа с csv в python)

Пояснение: csv.DictReader автоматически использует первую строку как имена полей. Каждая строка возвращается в виде словаря. Параметр encoding задаёт кодировку файла.

Запись CSV с заголовками

import csv

data = [
    {'Имя': 'Иван', 'Возраст': 25},
    {'Имя': 'Мария', 'Возраст': 30}
]
with open('output.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.DictWriter(f, fieldnames=['Имя', 'Возраст'])
    writer.writeheader()
    writer.writerows(data)

Пояснение: newline='' предотвращает появление лишних пустых строк в Windows. Метод writeheader записывает заголовок.

Типичные ошибки и их решения:

  • Проблема: Не совпадают имена полей в словаре и fieldnames. Решение - убедиться, что ключи словаря соответствуют переданному списку fieldnames.
  • Проблема: Ошибка кодировки при чтении. Решение - указать параметр encoding (например, 'utf-8', 'cp1251').
  • Проблема: В CSV используются точки с запятой вместо запятых. Решение - передать delimiter=';' в конструктор reader/writer.

Вариант 1: Pandas для анализа данных

Как прочитать CSV в DataFrame и выполнить базовую статистику?

Цель: Когда требуется фильтрация, группировка, объединение таблиц, визуализация. Pandas предоставляет высокоуровневый интерфейс.

import pandas as pd

df = pd.read_csv('data.csv')
print(df.head())           # первые 5 строк
print(df.describe())       # статистика по числовым колонкам
   Имя  Возраст  Зарплата
0  Иван      25     50000
1 Мария      30     60000
          Возраст     Зарплата
count   2.000000     2.000000
mean   27.500000  55000.000000
std     3.535534   7071.067812

Пояснение: Pandas автоматически определяет типы данных, обрабатывает пропуски (NaN). Для больших файлов можно читать по кускам: chunksize.

Распространённые проблемы:

  • Неверное определение разделителя. Решение - указать sep=';' или sep='\t'.
  • Пропущенные значения обрабатываются как NaN, что может повлиять на расчёты. Для замены используется fillna().

Вариант 2: NumPy для числовых данных

Как загрузить только числовые столбцы из CSV в массив NumPy?

Цель: Эффективная обработка больших числовых массивов (линейная алгебра, машинное обучение без pandas).

import numpy as np

data = np.loadtxt('numbers.csv', delimiter=',', skiprows=1)
print(data[:3])
[[25. 50000.]
 [30. 60000.]
 [22. 45000.]]

Пояснение: skiprows=1 пропускает заголовок. Все данные должны быть числовыми - иначе возникнет ошибка. Для смешанных типов лучше использовать genfromtxt.

Если в файле есть текстовые колонки, loadtxt вызовет ошибку. Решение - использовать np.genfromtxt с параметром dtype=None.

Вариант 3: Ручной split (для простых файлов без кавычек)

Как самый быстрый способ прочитать CSV без зависимостей?

Цель: Минимальная обработка, если файл гарантированно не содержит кавычек и сложных экранирований.

with open('simple.csv', 'r', encoding='utf-8') as f:
    lines = f.readlines()
    header = lines[0].strip().split(',')
    for line in lines[1:]:
        row = line.strip().split(',')
        print(dict(zip(header, row)))
{'Имя': 'Иван', 'Возраст': '25'}
{'Имя': 'Мария', 'Возраст': '30'}

Пояснение: Метод split не учитывает кавычки, поэтому если значение содержит запятую, возникнет ошибка. Применим только для простых случаев.

Главная проблема - некорректное разбиение при наличии кавычек. Для надёжности лучше использовать модуль csv.

Вариант 4: Генератор для чтения больших файлов

Как обработать CSV размером несколько гигабайт, не загружая его целиком в память?

Цель: Поточная обработка строк (фильтрация, сумма, запись результатов). Экономия памяти.

import csv

def read_large_csv(file_path):
    with open(file_path, 'r', encoding='utf-8') as f:
        reader = csv.reader(f)
        header = next(reader)
        yield header
        for row in reader:
            yield row

for row in read_large_csv('huge.csv'):
    # обработка строки
    pass

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

Ошибка при работе с памятью возникает, если накапливать много данных в списке. Нужно сразу обрабатывать каждую строку.

Вариант 5: Определение формата с помощью Sniffer

Как автоматически определить разделитель, символ кавычек и диалект CSV?

Цель: Если структура CSV неизвестна или может варьироваться (разные разделители, кодировки).

import csv

with open('unknown.csv', newline='', encoding='utf-8') as f:
    sample = f.read(1024)  # читаем первые байты для анализа
    dialect = csv.Sniffer().sniff(sample)
    f.seek(0)
    reader = csv.reader(f, dialect)
    for row in reader:
        print(row)

Пояснение: Sniffer анализирует образец и возвращает объект диалекта с параметрами delimiter, quotechar и др. Полезно для универсальных загрузчиков.

Если образец слишком мал (менее 100 байт), Sniffer может ошибиться. Рекомендуется увеличить размер образца.

Вариант 6: Работа с кодировками и ошибками

Как обработать CSV, где встречаются разные кодировки (например, Windows-1251) или повреждённые байты?

Цель: Извлечение данных из файлов с неизвестной кодировкой или бинарными включениями.

import csv

with open('mixed_encoding.csv', 'r', encoding='utf-8', errors='replace') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

Пояснение: Параметр errors='replace' заменяет нечитаемые символы на , что позволяет продолжить обработку. Для точного преобразования можно использовать модуль chardet для автоматического определения кодировки.

Замена символов может исказить данные. Если важно сохранить точность, лучше определить правильную кодировку и перекодировать файл.

Расширенные примеры работы с CSV

1. Чтение CSV из строки (StringIO)

Иногда данные CSV приходят в виде текстовой строки (например, из HTTP-запроса). Для имитации файлового объекта используется io.StringIO.

Пример
import csv
from io import StringIO

csv_text = "Имя,Возраст\nИван,25\nМария,30"
f = StringIO(csv_text)
reader = csv.DictReader(f)
for row in reader:
    print(row)
{'Имя': 'Иван', 'Возраст': '25'}
{'Имя': 'Мария', 'Возраст': '30'}

2. Запись CSV с указанием порядка столбцов через DictWriter

Порядок столбцов определяется списком fieldnames. Если словарь содержит лишние ключи, они будут проигнорированы (если не задан extrasaction).

Пример
import csv

data = [{'Имя': 'Анна', 'Возраст': 28, 'Город': 'Москва'}]
with open('ordered.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.DictWriter(f, fieldnames=['Возраст', 'Имя'], extrasaction='ignore')
    writer.writeheader()
    writer.writerows(data)
Содержимое файла ordered.csv:
Возраст,Имя
28,Анна

3. Фильтрация строк с помощью генератора

Можно построчно отфильтровать данные, не загружая весь файл.

Пример
import csv

with open('data.csv', 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    filtered = (row for row in reader if int(row['Возраст']) > 25)
    for person in filtered:
        print(person['Имя'])
Мария

4. Пропуск строк с комментариями

Если CSV содержит строки, начинающиеся с символа комментария (например, '#'), их можно проигнорировать.

Пример
import csv

with open('comments.csv', 'r', encoding='utf-8') as f:
    reader = csv.reader(line for line in f if not line.startswith('#'))
    for row in reader:
        print(row)

Файл comments.csv:

# Это комментарий
Имя,Возраст
Иван,25

5. Чтение CSV с разными разделителями и автоматическим определением

Пример с использованием csv.Sniffer для файла с разделителем табуляции.

Пример
import csv

with open('tab_sep.csv', newline='', encoding='utf-8') as f:
    sample = f.read(2048)
    dialect = csv.Sniffer().sniff(sample)
    f.seek(0)
    reader = csv.reader(f, dialect)
    for row in reader:
        print(row)
['Имя', 'Возраст', 'Зарплата']
['Иван', '25', '50000']

6. Обработка больших файлов по кускам (chunks) с pandas

Pandas позволяет читать CSV частями и агрегировать результат.

Пример
import pandas as pd

chunksize = 1000
results = []
for chunk in pd.read_csv('huge.csv', chunksize=chunksize):
    # пример: средний возраст по каждому куску
    mean_age = chunk['Возраст'].mean()
    results.append(mean_age)
overall_mean = sum(results) / len(results)
print(f"Средний возраст: {overall_mean:.2f}")
Средний возраст: 34.78

7. Обработка ошибок кодировки с errors='replace'

Когда файл содержит символы не в UTF-8, можно заменить их на знак замены.

Пример
import csv

with open('broken_encoding.csv', 'r', encoding='utf-8', errors='replace') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

8. Преобразование строк в даты при чтении

Использование параметра parse_dates в pandas или ручной конвертации с datetime.strptime.

Пример
import csv
from datetime import datetime

with open('dates.csv', 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
        date = datetime.strptime(row['Дата'], '%Y-%m-%d')
        print(date.year)

9. Объединение нескольких CSV-файлов в один

Построчная запись всех данных из нескольких файлов в один результирующий.

Пример
import csv

input_files = ['part1.csv', 'part2.csv']
with open('merged.csv', 'w', newline='', encoding='utf-8') as out:
    writer = csv.writer(out)
    for i, fname in enumerate(input_files):
        with open(fname, 'r', encoding='utf-8') as f:
            reader = csv.reader(f)
            if i == 0:
                writer.writerow(next(reader))  # заголовок только из первого
            else:
                next(reader)  # пропустить заголовки остальных
            for row in reader:
                writer.writerow(row)

10. Сортировка CSV по столбцу без pandas

Загрузка всех строк, сортировка и запись обратно. Подходит для файлов, помещающихся в память.

Пример
import csv

with open('data.csv', 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    rows = list(reader)

rows.sort(key=lambda x: int(x['Возраст']))

with open('sorted.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.DictWriter(f, fieldnames=reader.fieldnames)
    writer.writeheader()
    writer.writerows(rows)

11. Агрегация данных (сумма, среднее) по группам

Группировка по одному столбцу и вычисление агрегатов для другого с помощью словарей.

Пример
import csv
from collections import defaultdict

with open('sales.csv', 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    totals = defaultdict(float)
    counts = defaultdict(int)
    for row in reader:
        product = row['Продукт']
        price = float(row['Цена'])
        totals[product] += price
        counts[product] += 1

for product, total in totals.items():
    avg = total / counts[product]
    print(f"{product}: средняя цена {avg:.2f}")

12. Создание собственного диалекта с помощью csv.Dialect

Можно определить кастомный формат, если файл использует нестандартные параметры (например, двойные кавычки и обратную косую черту для экранирования).

Пример
import csv

class CustomDialect(csv.Dialect):
    delimiter = '|'
    quotechar = '"'
    doublequote = True
    skipinitialspace = True
    lineterminator = '\n'
    quoting = csv.QUOTE_ALL

with open('custom.csv', 'r', newline='', encoding='utf-8') as f:
    reader = csv.reader(f, dialect=CustomDialect)
    for row in reader:
        print(row)

13. Работа с вложенными кавычками и экранированием

Модуль csv корректно обрабатывает поля, содержащие символы-разделители внутри кавычек, а также удвоенные кавычки для экранирования.

Пример
import csv

csv_text = '"Иван","25","город Москва, Россия"'
f = StringIO(csv_text)
reader = csv.reader(f)
for row in reader:
    print(row)
['Иван', '25', 'город Москва, Россия']

14. Потоковая обработка с записью результата в другой CSV

Чтение из одного файла, преобразование данных и запись в другой, не накапливая строки.

Пример
import csv

with open('source.csv', 'r', encoding='utf-8') as src, \
     open('result.csv', 'w', newline='', encoding='utf-8') as dst:
    reader = csv.DictReader(src)
    writer = csv.DictWriter(dst, fieldnames=reader.fieldnames)
    writer.writeheader()
    for row in reader:
        row['Возраст'] = int(row['Возраст']) + 1  # увеличим возраст на 1
        writer.writerow(row)

Работа с CSV в Python - comments

En
Python csv (python)