Нашли ошибку?
Скачать чистый
урок 2 из 7≈ 20 минупражнения: 0 из 3

Типы

Почему числа читаются как текст и как это заметить; astype и pd.to_numeric с errors="coerce"; целые числа с пропусками — тип Int64; что теряется при переводе дробных в целые.

Python запустится при первом выполнении

Поставщик прислал «Кофейной лавке» прайс-лист на 2026 год. Файл набирали вручную — и это видно.

[ ]Прайс поставщика
import pandas as pd

supplier = pd.read_csv("data/supplier_prices.csv")
supplier.head(6)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
product_id name category price cost stock updated
0 P01 эспрессо-смесь 1 кг Кофе 1 560 ₽ 920 120.0 15.01.2026
1 P02 Колумбия 250 г Кофе 760 ₽ 400 64.0 13.01.2026
2 P03 эфиопия 250 г Кофе 830 ₽ 460 NaN 12.01.2026
3 P04 БРАЗИЛИЯ 1 КГ Кофе 1 370 ₽ 850 64.0 16.01.2026
4 P05 Кофе без кофеина 250 г Кофе 760 ₽ нет данных 59.0 13.01.2026
5 P06 Чёрный чай 100 г Чай 370 ₽ 160 104.0 14.01.2026

Названия написаны как попало, в цене стоит знак рубля, в себестоимости вместо числа встречается «нет данных». В этом и следующих уроках мы приведём таблицу в порядок. Начнём с типов.

Числа, которые стали текстом

[ ]Типы столбцов
supplier.dtypes
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
product_id        str
name              str
category          str
price             str
cost              str
stock         float64
updated           str
dtype: object

price и cost — это цены, но их тип — str, текст. Причина: тип у столбца один, и если хотя бы одно значение не число («нет данных», 1 560 ₽), pandas читает текстом весь столбец. stock (остаток на складе) — числа, но дробные: в нём есть пропуски.

Текстовый столбец с цифрами опасен тем, что не всегда даёт ошибку. Сложение для строк — это склейка, умножение на число — повтор:

[ ]«Сумма» и «удвоение» текста
print(supplier["cost"].head(3).sum())
print((supplier["cost"].head(3) * 2).tolist())
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
920400460
['920920', '400400', '460460']

А вот среднее по тексту посчитать нельзя:

[ ]Среднее по текстовому столбцуошибка: TypeError
supplier["cost"].mean()
Ошибкасохранённый · нажмите «Выполнить», чтобы получить свой
TypeError: Cannot perform reduction 'mean' with string dtype

astype и to_numeric

Метод astype из прошлого модуля переводит столбец в указанный тип. Но он требует, чтобы подошли все значения:

[ ]astype спотыкается о «нет данных»ошибка: ValueError
supplier["cost"].astype(int)
Ошибкасохранённый · нажмите «Выполнить», чтобы получить свой
ValueError: invalid literal for int() with base 10: 'нет данных'

Функция pd.to_numeric с параметром errors="coerce" («принудить») поступает мягче: всё, что не получилось превратить в число, заменяет пропуском NaN:

[ ]Что не число — то пропуск
answers = pd.Series(["12", "7", "нет", "3.5", "?"])
pd.to_numeric(answers, errors="coerce")
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
0    12.0
1     7.0
2     NaN
3     3.5
4     NaN
dtype: float64
[ ]Упражнение 1Себестоимость числами решено

Сохраните в cost_num столбец cost таблицы supplier, переведённый в числа (нечисловые значения — пропуски). В n_bad — сколько значений не распозналось, в cost_total — сумму распознанных.

cost_num = ...
n_bad = ...
cost_total = ...

Нечисловые значения теперь легко найти — по маске пропусков:

[ ]Какие значения не распознались
supplier.loc[cost_num.isna(), ["product_id", "name", "cost"]]
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
product_id name cost
4 P05 Кофе без кофеина 250 г нет данных
12 P13 Зефир нет данных
16 P17 Чайник заварочный —
Вывод появится, когда решите упражнение «Себестоимость числами», — иначе он подскажет ответ. Ячейку можно и выполнить.

Посмотреть на них обязательно: вдруг там не «нет данных», а опечатка, которую можно исправить. Убедившись, что это действительно отсутствующие значения, записываем числовой столбец в таблицу:

[ ]Столбец стал числовым
supplier["cost"] = cost_num
print(supplier["cost"].dtype)
print(supplier["cost"].mean())
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
float64
538.2352941176471

У мягкости есть обратная сторона. Попробуем так же перевести цены:

[ ]Цены со знаком рубля
price = pd.to_numeric(supplier["price"], errors="coerce")
print(price.isna().sum(), "из", len(price))
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
20 из 20

Все двадцать значений стали пропусками: 1 560 ₽ — не число, и to_numeric молча превратил столбец в пустой. Здесь сначала нужно убрать из текста пробелы и знак рубля — этим займёмся в следующем уроке.

Целые числа с пропусками: Int64

Остаток на складе — целое число штук, но pandas показывает 120.0:

[ ]Остатки — дробные
supplier["stock"].head(4)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
0    120.0
1     64.0
2      NaN
3     64.0
Name: stock, dtype: float64

Виноват NaN: это дробное значение, и обычный целый тип int64 хранить его не умеет. Перевести столбец в int не получится — pandas сам подсказывает, что делать:

[ ]Пропуск не переводится в целоеошибка: IntCastingNaNError
supplier["stock"].astype(int)
Ошибкасохранённый · нажмите «Выполнить», чтобы получить свой
IntCastingNaNError: Cannot convert non-finite values (NA or inf) to integer.Replace or remove non-finite values or cast to an integer typethat supports these values (e.g. 'Int64')

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

[ ]Целые с пропуском
stock = supplier["stock"].astype("Int64")
stock.head(4)
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
0     120
1      64
2    <NA>
3      64
Name: stock, dtype: Int64

Пропуск в таком столбце показан как <NA> («not available»). Это тот же пропуск: isna() его находит, а sum и max — пропускают.

[ ]Считаем как обычно
print(stock.isna().sum())
print(stock.sum())
print(stock.max())
print((stock > 100).head(4).tolist())
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
3
1253
138
[True, False, <NA>, False]

Одно отличие от NaN видно в последней строке: сравнение с <NA> даёт не False, а снова <NA> — «неизвестно». Методы sum и mean такие значения маски пропускают, поэтому доля по маске получается уже среди известных значений, а не среди всех строк.

[ ]Упражнение 2Оценки — целые решено

В таблице delivery столбцы rating и days дробные из-за пропусков. Переведите оба в целый тип с пропусками. В fives сохраните число оценок «5».

delivery = pd.read_csv("data/delivery_h1.csv")
# переведите столбцы rating и days в целый тип с пропусками
fives = ...

Дробные в целые и другие переводы

astype(int) для дробных чисел отбрасывает дробную часть, а не округляет:

[ ]Отбросить или округлить
weights = pd.Series([0.25, 0.9, 1.5, 2.99])
print(weights.astype(int).tolist())
print(weights.round().astype(int).tolist())
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
[0, 0, 1, 2]
[0, 1, 2, 3]
Вопрос

Что выведет print(pd.Series([1.7, 2.2]).astype(int).tolist())?

Так же числа переводят в текст, а логические значения — в 1 и 0:

[ ]Числа в текст, True и False в числа
codes = pd.Series([7, 42, 105])
print(codes.astype(str).tolist())
print(pd.Series([True, False, True]).astype(int).tolist())
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
['7', '42', '105']
[1, 0, 1]
[ ]Упражнение 3Пустой остаток — это ноль решено

Поставщик объяснил: пустое поле в stock значит, что товара на складе нет. Сохраните в stock_int столбец stock таблицы supplier, где пропуски заменены нулём, а тип — обычный целый (не дробный и не Int64). В total_stock сохраните общий остаток.

stock_int = ...
total_stock = ...

Здесь заполнение нулём оправдано: пропуск и правда значит «ноль штук». Сравните с оценками из прошлого урока, где ноль исказил бы среднее.

Итоги

  • dtypes — первое, что стоит проверить: числа могли прочитаться как str.
  • astype(тип) переводит, если подходят все значения; pd.to_numeric(столбец, errors="coerce") превращает неподходящие в NaN.
  • После coerce всегда считайте пропуски и смотрите на нераспознанные значения.
  • Int64 — целые числа с пропусками; пропуск в них выглядит как <NA>.
  • astype(int) отбрасывает дробную часть — округляйте заранее.

Подробнее в справочнике

Нашли ошибку?