Урок курса

Загрузка CSV с явными типами и датами через read_csv

NumPy и pandas: практический тренажёр

В прошлом уроке DataFrame создавался вручную — из словаря или списка словарей. В реальной работе данные почти всегда приходят из файла, и самый распространённый формат — CSV. Здесь разберём, как pd.read_csv превращает текстовый файл в DataFrame за один вызов.

pd.read_csv: чтение CSV по пути и файловому объекту

Базовый вызов выглядит так:

import pandas as pd

df = pd.read_csv('data/orders.csv')

Первый аргумент filepath_or_buffer — это либо строка с путём к файлу, либо файловый объект. Pandas принимает оба варианта одинаково.

Путь может быть относительным или абсолютным:

# относительный путь
df = pd.read_csv('data/orders.csv')

# абсолютный путь
df = pd.read_csv('/home/user/projects/data/orders.csv')

Вместо пути можно передать любой файловый объект — например, открытый через open() или созданный через io.StringIO (полезно в тестах и при работе с данными из памяти):

import io

csv_text = """id,date,amount,category
1,2024-01-15,99.5,food
2,2024-02-20,150.0,tech
"""

buf = io.StringIO(csv_text)
df = pd.read_csv(buf)
print(df)

В обоих случаях pandas делает одно и то же: читает первую строку файла как заголовок столбцов, а дальше — строки данных.

Типы pandas выводит автоматически, просматривая значения каждого столбца. Числа без дробной части становятся int64, числа с точкой — float64, всё остальное — object (строки). Посмотреть, что получилось:

print(df.dtypes)
# id          int64
# date        object
# amount      float64
# category    object

Здесь date — это строка (object), потому что pandas по умолчанию не пытается распознавать даты. Автовывод типов работает хорошо для числовых столбцов, но для дат и столбцов с особыми требованиями к типу нужны явные параметры — они будут следующим шагом.

Выбор нужных столбцов через usecols

Когда CSV-файл содержит десятки столбцов, а нужны только три — нет смысла загружать всё. Параметр usecols позволяет указать именно те столбцы, которые должны попасть в DataFrame.

Передавать можно список имён:

import pandas as pd

df = pd.read_csv('data/orders.csv', usecols=['id', 'date', 'amount'])
print(df.columns.tolist())
# ['id', 'date', 'amount']

Если имена столбцов в файле заранее неизвестны или нужно обратиться к ним по позиции, usecols принимает и список целых чисел:

# Взять первый, второй и третий столбцы (0-based)
df = pd.read_csv('data/orders.csv', usecols=[0, 1, 2])

Оба варианта дают одинаковый результат, если позиции соответствуют тем же столбцам.

Один момент, который сбивает с толку: порядок столбцов в результирующем DataFrame определяется не списком usecols, а порядком в самом файле. То есть если написать usecols=['amount', 'id', 'date'], в DataFrame они всё равно окажутся в том порядке, в котором идут в CSV — id, date, amount.

Практический смысл usecols не только в удобстве, но и в экономии памяти: pandas не читает и не хранит данные из пропущенных столбцов вообще. Для больших файлов с широкими таблицами это ощутимо.

Явные типы и разбор дат: параметры dtype и parse_dates

Автоматический вывод типов, который pandas делает при чтении CSV, работает предсказуемо для чисел, но часто ошибается в деталях: столбец с целыми числами получает int64, хотя для экономии памяти лучше подошёл бы int32; столбец с ценами может стать object, если в нём встречается запятая вместо точки. Чтобы не исправлять это постфактум через astype, нужные типы задаются прямо при чтении через параметр dtype.

Параметр dtype

dtype принимает словарь, где ключ — имя столбца, значение — нужный тип:

import pandas as pd

df = pd.read_csv(
    'data/orders.csv',
    dtype={
        'id': 'int32',
        'amount': 'float64',
        'category': 'str'
    }
)

В качестве типов работают строки NumPy/pandas ('int32', 'float64', 'Int64' с заглавной I для nullable-целых) и Python-типы (str, float). Pandas применяет преобразование во время чтения, поэтому никаких отдельных вызовов astype после загрузки не нужно.

Если в файле окажется значение, которое нельзя привести к указанному типу, pandas бросит ValueError — и это хорошо: ошибка сразу сигнализирует о грязных данных, а не прячется в неожиданном NaN где-то внутри DataFrame.

Один нюанс: столбцы, которые не указаны в словаре dtype, получают тип автоматически, как обычно. Словарь не обязан покрывать все столбцы.

Параметр parse_dates

Даты — отдельная история. Даже если в файле написано 2024-01-15, pandas по умолчанию читает это как строку (object). Чтобы столбец стал datetime64[ns] прямо при загрузке, используется parse_dates:

df = pd.read_csv(
    'data/orders.csv',
    parse_dates=['date']
)

parse_dates принимает список имён столбцов (или позиций). Pandas пытается распознать формат автоматически — ISO-8601 (YYYY-MM-DD) он обрабатывает без проблем. Для нестандартных форматов вроде 15/01/2024 автораспознавание может не сработать, и тогда потребуется дополнительный шаг уже после загрузки. Но для большинства реальных датасетов, где дата записана в стандартном виде, parse_dates закрывает задачу полностью.

Оба параметра прекрасно работают вместе:

df = pd.read_csv(
    'data/orders.csv',
    dtype={'id': 'int32', 'amount': 'float64'},
    parse_dates=['date']
)

Такой вызов даёт id типа int32, amount типа float64, date типа datetime64[ns] — всё в один шаг, без постобработки. Как убедиться, что типы действительно применились корректно, разберём в следующей секции.

Проверка типов через df.dtypes и сквозной пример

После того как read_csv отработал с нужными параметрами, остаётся один вопрос: применились ли они так, как ожидалось? Ответ даёт df.dtypes.

df.dtypes возвращает Series, где индекс — имена столбцов, а значения — их типы. Смотреть его нужно сразу после загрузки, до любой дальнейшей обработки — именно тогда он подтверждает, что параметры dtype и parse_dates сработали корректно.

Разберём на конкретном примере. Возьмём CSV с четырьмя столбцами: id, date, amount, category. Нужны только первые три, id должен быть int32, amount — float64, а date — datetime64:

import pandas as pd
import io

csv_text = '''id,date,amount,category
1,2024-01-15,99.5,food
2,2024-02-20,150.0,tech
3,2024-03-10,45.25,food
'''

buf = io.StringIO(csv_text)
df = pd.read_csv(
    buf,
    usecols=['id', 'date', 'amount'],
    dtype={'id': 'int32', 'amount': 'float64'},
    parse_dates=['date']
)

print(df.dtypes)

Вывод:

id               int32
date    datetime64[ns]
amount         float64
dtype: object

Это именно то, что задавалось при вызове. category в DataFrame вообще нет — usecols его исключил. id получил int32, а не дефолтный int64. date стал datetime64[ns], а не строкой. amount — float64.

Если какой-то тип не совпал с ожидаемым, чаще всего причина в одном из двух:

  • Неизвестный ключ в dtype — pandas молча игнорирует его, столбец получает автоматический тип. Например, если написать dtype={'amout': 'float64'} (опечатка), ошибки не будет, но amount окажется float64 лишь случайно (по автовыводу), а намерение останется незамеченным. Проверяйте df.dtypes именно поэтому.
  • Несуществующий столбец в parse_dates — поведение противоположное: pandas бросит ValueError.

Это значит, что имя столбца в parse_dates не совпадает ни с одним столбцом в файле (или он был исключён через usecols). Здесь ошибка видна сразу.

Во всех случаях df.dtypes помогает локализовать проблему: если тип столбца не тот, что ожидался, — ищите опечатку в ключе dtype или проверьте, не исключён ли нужный столбец через usecols.

df.dtypes — тот же атрибут, что уже использовался при ручном создании DataFrame в предыдущем уроке. Разница только в контексте: там он описывал структуру, которую задавали явно через словарь; здесь — подтверждает, что read_csv правильно интерпретировал CSV-файл. Этот же datetime64[ns]-столбец позже станет базой для работы с компонентами дат через .dt — но это уже отдельная тема.

Закрепите тему на задачах

После загрузки проверьте число строк, dtype и значение ключа с ведущими нулями. Разделитель и кодировка могут создать правдоподобную, но неверную таблицу.

Загрузка CSV с явными типами и датами через read_csv — задача по NumPy и pandas

pandas read_csv: usecols, dtype и parse_dates в задаче

pandas read_csv: конфликт usecols и parse_dates

Откройте условие и решите задачу перед чтением следующей темы. В задачах на код проверяется программа, в тестовых заданиях — выбранный ответ. Для последовательного обучения вернитесь в программу бесплатного курса.

Задача 1

DataFrame загружен командой:
df = pd.read_csv(buf, usecols=['a', 'b'], dtype={'a': 'int32'}, parse_dates=['b'])

Какой dtype будет у столбца 'b' в выводе df.dtypes, если 'b' содержит значения вида '2024-01-15'?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 2

CSV-файл содержит столбцы: id, name, price, date. Выполняется вызов:

df = pd.read_csv(path, usecols=['id', 'price'])

Сколько столбцов будет в df и какие именно?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 3

Вы хотите загрузить CSV из переменной path, выбрать только столбцы 'user_id' и 'created_at', задать для 'user_id' тип int32 и распарсить 'created_at' как datetime — всё в одном вызове. Какой вызов pd.read_csv правильно решает эту задачу?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 4

Найди и исправь: три ошибки в вызове pd.read_csv с usecols, dtype и parse_dates

Что уже дано

Проверяющая система выполняет скрытый start_code, который создаёт файл transactions.csv в рабочей директории. Содержимое файла:

txn_id,user_id,amount,currency,txn_date
1,42,100.0,RUB,2024-01-05
2,17,250.5,USD,2024-01-12
3,42,75.0,RUB,2024-02-01
4,99,500.0,EUR,2024-02-14

В редакторе уже есть сломанный код. В нём ровно три ошибки в трёх независимых строках:

  1. В usecols указан столбец 'currency', хотя по условию он должен быть исключён — нужны только 'txn_id', 'user_id', 'amount', 'txn_date'.
  2. В словаре dtype ключ для идентификатора транзакции написан как 'txn_id', но тип указан 'float64' — хотя это целочисленный идентификатор и должен быть 'int32'.
  3. В parse_dates указан столбец 'amount' — хотя разбирать как дату нужно столбец 'txn_date'.

Каждая ошибка находится в отдельной строке. Исправьте все три.

Что нужно сделать

Отредактируйте код так, чтобы после исправления переменная df содержала DataFrame со следующими свойствами:

  • df.shape равен (4, 4);
  • столбцы — ['txn_id', 'user_id', 'amount', 'txn_date'] (без 'currency');
  • df['txn_id'].dtype — int32;
  • df['user_id'].dtype — int32;
  • df['amount'].dtype — float64;
  • df['txn_date'].dtype — datetime64[ns].

Ввод и вывод

stdin не используется. Печатать через print в stdout ничего не нужно.

Проверяющая система читает верхнеуровневую переменную df после выполнения вашего кода и проверяет её shape, столбцы и dtypes.

РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задача 5

pd.read_csv с usecols, dtype и parse_dates: загрузка и проверка dtypes

Что уже дано

Проверяющая система выполняет скрытый start_code, который создаёт файл employees.csv в рабочей директории. Содержимое файла:

emp_id,name,salary,department,hired_on
1,Алина,75000.0,Разработка,2021-03-15
2,Борис,92000.0,Аналитика,2019-11-01
3,Вера,64000.0,Разработка,2022-06-30
4,Глеб,110000.0,Управление,2018-04-12
5,Дина,81000.0,Аналитика,2020-09-07

Файл создаётся до выполнения вашего кода. Никаких заранее созданных переменных нет — вы читаете файл сами.

Что нужно сделать

Напишите верхнеуровневый код (без функций), который:

  1. Загружает файл employees.csv через pd.read_csv с тремя параметрами:
  • usecols=['emp_id', 'salary', 'hired_on'] — загрузить только эти три столбца;
  • dtype={'emp_id': 'int32', 'salary': 'float64'} — задать типы явно;
  • parse_dates=['hired_on'] — разобрать столбец hired_on как дату.
  1. Сохраняет результат в переменную df.
  2. Создаёт переменную col_names — список имён столбцов: list(df.columns).
  3. Создаёт переменную emp_id_dtype — строковое представление dtype столбца emp_id: str(df['emp_id'].dtype).
  4. Создаёт переменную hired_on_kind — первый символ dtype столбца hired_on: df['hired_on'].dtype.kind. Для datetime64[ns] это 'M'.

Проверяющая система читает переменные df, col_names, emp_id_dtype и hired_on_kind после выполнения вашего кода.

Ввод и вывод

stdin не используется. Печатать через print в stdout ничего не нужно.

Проверяющая система читает верхнеуровневые переменные df, col_names, emp_id_dtype и hired_on_kind после выполнения вашего кода и проверяет:

  • df.shape равен (5, 3);
  • col_names содержит ровно ['emp_id', 'salary', 'hired_on'];
  • emp_id_dtype равен 'int32';
  • hired_on_kind равен 'M' (datetime);
  • столбец name и столбец department в df отсутствуют.
РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задача 6

pd.read_csv через файловый объект: usecols, dtype, parse_dates и вывод dtypes

Что уже дано

Скрытый start_code создаёт файл orders.csv в рабочей директории. Содержимое файла:

order_id,customer,amount,status,order_date
101,Алина,1500.0,shipped,2024-02-10
102,Борис,320.5,pending,2024-03-22
103,Вера,870.0,shipped,2024-04-05
104,Глеб,45.0,cancelled,2024-04-18

Файл создаётся до выполнения вашего кода. Никаких заранее созданных переменных нет — вы открываете файл и читаете его сами.

Что нужно сделать

Напишите верхнеуровневый код (без функций), который:

  1. Открывает файл orders.csv через open('orders.csv', encoding='utf-8') и передаёт файловый объект в pd.read_csv вместо строки-пути.
  2. Вызывает pd.read_csv с тремя параметрами:
  • usecols=['order_id', 'amount', 'order_date'] — загрузить только эти три столбца;
  • dtype={'order_id': 'int32', 'amount': 'float64'} — задать типы явно;
  • parse_dates=['order_date'] — разобрать столбец order_date как дату.
  1. Сохраняет результат в переменную df.
  2. Создаёт переменную dtypes_dict — словарь вида {имя_столбца: str(dtype)} для всех столбцов df. Пример построения: {col: str(df[col].dtype) for col in df.columns}.
  3. Создаёт переменную row_count — целое число строк в df (df.shape[0]).

Проверяющая система читает переменные df, dtypes_dict и row_count после выполнения вашего кода.

Ввод и вывод

stdin не используется. Печатать через print в stdout ничего не нужно.

Проверяющая система читает верхнеуровневые переменные df, dtypes_dict и row_count после выполнения вашего кода и проверяет:

  • df.shape равен (4, 3);
  • столбцы df — ровно ['order_id', 'amount', 'order_date'] (без customer и status);
  • dtypes_dict['order_id'] равен 'int32';
  • dtypes_dict['amount'] равен 'float64';
  • dtypes_dict['order_date'] начинается с 'datetime64';
  • row_count равен 4.
РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задача 7

pd.read_csv через io.StringIO: конфликт usecols и parse_dates

Что уже дано

Проверяющая система выполняет скрытый start_code, который не создаёт никаких переменных. Все данные вы формируете сами.

Что нужно сделать

Напишите верхнеуровневый код (без функций), который:

  1. Создаёт CSV-источник в памяти через io.StringIO со следующим содержимым:
visit_id,page,duration,visit_date
1,home,30,2024-04-01
2,catalog,120,2024-04-03
3,home,15,2024-04-07
4,checkout,200,2024-04-10
  1. Загружает данные через pd.read_csv с тремя параметрами:
  • usecols=['visit_id', 'duration', 'visit_date'] — загрузить только эти три столбца (без page);
  • dtype={'visit_id': 'int32', 'duration': 'int32'} — задать типы явно;
  • parse_dates=['visit_date'] — разобрать столбец visit_date как дату.
  1. Сохраняет результат в переменную df.
  2. Создаёт переменную shape — кортеж df.shape.
  3. Создаёт переменную cols — список имён столбцов: list(df.columns).
  4. Создаёт переменную dtypes_dict — словарь {имя_столбца: str(df[имя_столбца].dtype) for имя_столбца in df.columns}.

Проверяющая система читает переменные df, shape, cols и dtypes_dict после выполнения вашего кода.

Ввод и вывод

stdin не используется. Печатать через print в stdout ничего не нужно.

Проверяющая система читает верхнеуровневые переменные df, shape, cols и dtypes_dict после выполнения вашего кода и проверяет:

  • shape равен (4, 3);
  • cols содержит ровно ['visit_id', 'duration', 'visit_date'] (без page);
  • dtypes_dict['visit_id'] равен 'int32';
  • dtypes_dict['duration'] равен 'int32';
  • dtypes_dict['visit_date'] начинается с 'datetime64';
  • столбец page в df отсутствует.
РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задачи к уроку

Все задачи курса →

Продолжить с сохранением прогресса

Перейдите к уроку в учебном кабинете.

Перейти к интерактивному уроку