Раздел 42 · Аналитика данных с нуля

Чистка данных в pandas: типы, пропуски, дубли, строки и выбросы

middle~20 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

Бран · продюсер «Хроник Пограничья»

Платёжный партнёр прислал свою выгрузку за полгода и говорит, что мы заработали 726 тысяч. А у тебя в отчёте 657. Файл я открыть не смог, там каша. Кто прав?

В прошлом уроке groupby, merge и pivot_table работали на аккуратной выгрузке. Файлы от чужих систем такими не бывают. Сегодня чистим выгрузку партнёра в pandas: типы, строки, пропуски, дубли и выбросы. Все болячки ты уже лечил на SQL в уроках про строки и дубли, так что новое здесь только инструмент.

Первый взгляд: info

Файл partner_export.csv содержит те же 1250 покупок, что таблица purchases, но сохранён из русского Excel. Мы испортили его честно и по правилам: суммы и даты в русском формате, у части строк платформа с заглавной буквы или с пробелом в конце, у части почта заглавными буквами или с пробелом в начале. Пропуски в стране настоящие. Открываем как обычно:

import pandas as pd

df = pd.read_csv("partner_export.csv")
df.shape   # (1250, 1)

Один столбец. pandas ждал запятую, а русский Excel разделяет поля точкой с запятой, потому что запятая у него занята под дробную часть. Говорим разделитель явно и смотрим на таблицу через info():

df = pd.read_csv("partner_export.csv", sep=";")
df.info()
 #   Column      Non-Null Count  Dtype
---  ------      --------------  -----
 0   id          1250 non-null   int64
 1   receipt_id  1250 non-null   object
 2   player_id   1250 non-null   int64
 3   email       1250 non-null   object
 4   country     1174 non-null   object
 5   platform    1250 non-null   object
 6   status      1250 non-null   object
 7   amount      1250 non-null   object
 8   paid_at     1250 non-null   object

info() это медосмотр таблицы на один экран. Две строки в нём тревожные. У amount тип object, то есть текст, хотя там деньги. А у country всего 1174 непустых значения из 1250. Тип отдельно показывает df.dtypes, но info() сразу добавляет счётчик непустых, поэтому начинай с него.

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

Посмотрим на суммы глазами:

   id        receipt_id    amount              paid_at
0   1  and-d3a1049244b3    499,00  06.01.2026 09:52:49
1   2  ios-db23380eade5    199,00  06.01.2026 13:32:13
2   3  ios-4bab244cfc6d  1 990,00  07.01.2026 05:14:28

Десятичная запятая и пробел между тысячами, таких крупных сумм 135. Превратить текст в число помогает pd.to_numeric, аналог ::numeric из урока про типы. На такой строке он падает: ValueError: Unable to parse string "499,00". Падение это хорошо, оно честное.

Хуже, если заглушить ошибку параметром errors="coerce". Он превращает всё, что не разобрал, в NaN, и молчит:

amount = pd.to_numeric(df["amount"], errors="coerce")
amount.isna().sum()   # 1250
amount.sum()          # 0.0

Все 1250 сумм стали пропусками, а sum() их пропустил и вернул ноль. Никакой ошибки, просто выручка полгода равна нулю. Поэтому coerce годится как сетка, а не как лекарство: после него всегда считай isna().sum() и сравнивай с тем, что было до.

Лекарство: убрать пробел, заменить запятую точкой и только потом разбирать:

amount = pd.to_numeric(
    df["amount"].str.replace(" ", "").str.replace(",", "."),
    errors="coerce",
)
amount.isna().sum(), amount.sum()   # (0, 726433.0)

Ноль пропусков и 726 433 ₽, ровно сырая сумма из урока про дубли. Ещё короче попросить сам read_csv: он понимает русский формат, если назвать оба знака.

df = pd.read_csv("partner_export.csv", sep=";", decimal=",", thousands=" ")
df["amount"].dtype   # float64

Даты, которые пришли текстом

С paid_at та же беда, и тут pandas может ошибиться тише. Без подсказки pd.to_datetime(df["paid_at"]) угадывает формат по первой строке. 06.01.2026 он прочитал как месяц.день и упал на 35-й строке, где стоит 14.01.2026: четырнадцатого месяца не бывает. Повезло, что упал. Если бы все дни в файле были не больше 12, январь молча стал бы июнем.

df["paid_at"] = pd.to_datetime(df["paid_at"], format="%d.%m.%Y %H:%M:%S")

format описывает строку по буквам: %d день, %m месяц, %Y год, %H:%M:%S время. Часовые пояса, resample и скользящие окна разберём в уроке про даты.

урок из курса

Урок из курса «Аналитика данных с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.

Оплата пока не подключена: премиум и курсы открываются промокодом.