5 способов подсчета уникальных значений в pandas: полное руководство

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Для кого эта статья:

  • специалисты по аналитике данных и программисты-практики
  • студенты и начинающие аналитики, желающие улучшить навыки работы с pandas
  • профессионалы, работающие с большими объемами данных и заинтересованные в оптимизации процессов анализа

Работа с дубликатами в данных — ключевой навык каждого аналитика, меняющий результаты исследований кардинально. Подсчет уникальных значений в pandas, казалось бы, тривиальная задача, но она скрывает множество нюансов, влияющих на скорость обработки больших датасетов и точность ваших выводов. Разница между неоптимальным и эффективным методом может составлять минуты, а иногда и часы вычислительного времени! 📊 Разберем пять проверенных техник, позволяющих превратить эту рутинную операцию в мощный инструмент анализа.

Погружение в тонкости вычисления уникальных значений — лишь первый шаг в становлении профессионального аналитика данных. Хотите овладеть полным арсеналом инструментов для работы с данными? Курс «Python-разработчик» с нуля от Skypro предлагает глубокое погружение в pandas, numpy и другие библиотеки, с практическими кейсами от действующих экспертов. Научитесь не только чистить данные, но и создавать законченные аналитические решения, востребованные на рынке.

Почему подсчет уникальных значений важен при анализе данных

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

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

Александр Викторов, Lead Data Scientist

Однажды мой проект едва не провалился из-за игнорирования простой проверки уникальности. Мы строили рекомендательную систему для крупного маркетплейса, и модель показывала впечатляющие метрики на тестовой выборке. Но в продакшене что-то пошло не так — пользователи жаловались на странные рекомендации.

Оказалось, что в колонке customer_id присутствовали дубликаты, созданные после миграции с другой CRM-системы. При проверке уникальных значений мы обнаружили, что вместо ожидаемых 1.2 млн уникальных пользователей у нас было всего 900 тысяч. Для некоторых клиентов история покупок смешивалась, что полностью искажало персонализацию. Простой вызов df['customer_id'].nunique() мог предотвратить недели работы команды над поиском причин проблемы.

На практике существует несколько сценариев, где подсчет уникальных значений становится критичным:

СценарийПочему важен подсчет уникальных значенийПоследствия игнорирования
Предварительная обработка данныхОпределяет стратегию кодирования категориальных признаковНеэффективное использование памяти, медленные вычисления
Разведочный анализПомогает выявить структуру и распределения в данныхНеполное понимание особенностей датасета
Оценка качества данныхВыявляет потенциальные дубликаты и аномалииНекорректные аналитические выводы
Агрегация данныхПринципиально важна для правильных GROUP BY операцийИскажение результатов агрегации
Оценка признаков для MLВлияет на выбор алгоритмов и проектирование признаковСнижение предсказательной силы моделей

Теперь, понимая важность правильного подсчета уникальных значений, давайте рассмотрим пять мощных методов, которые предлагает pandas для этой задачи в 2025 году. 🔍

Кинга Идем в IT: пошаговый план для смены профессии

Метод pandas.Series.nunique() для быстрого count unique values

Самый элегантный и лаконичный способ подсчета уникальных значений в pandas — метод nunique(). Это встроенная функция для объектов Series, позволяющая с минимальными усилиями получить количество уникальных непустых (non-NA/null) значений:

Python
Скопировать код
import pandas as pd

# Создаем простой пример Series
s = pd.Series([1, 2, 2, 3, 3, 3, 4, None, None])

# Подсчитываем уникальные значения
unique_count = s.nunique()
print(f"Количество уникальных значений: {unique_count}") # Выведет: 4

# С учетом NaN значений
unique_count_with_nan = s.nunique(dropna=False)
print(f"Количество уникальных значений (включая NaN): {unique_count_with_nan}") # Выведет: 5

Метод nunique() обладает несколькими важными преимуществами, делающими его предпочтительным выбором в большинстве сценариев:

  • Лаконичность — требует минимум кода для достижения результата
  • Высокая производительность — оптимизирован на уровне C для быстрой работы
  • Гибкость с пропущенными значениями — параметр dropna позволяет контролировать учет NaN
  • Прямая поддержка для DataFrame — можно применить к целым датафреймам

Когда работаете с DataFrame, nunique() можно использовать двумя способами — для отдельного столбца или для всей таблицы:

Python
Скопировать код
# Подсчет уникальных значений в конкретном столбце
df = pd.DataFrame({
'A': [1, 1, 2, 3],
'B': ['a', 'a', 'b', 'c'],
'C': [None, 1, 2, None]
})

# Для отдельного столбца
print(df['A'].nunique()) # Выведет: 3

# Для всего DataFrame (вернет Series с результатами по каждому столбцу)
print(df.nunique())
# Выведет:
# A 3
# B 3
# C 2
# dtype: int64

Параметр axis позволяет подсчитывать уникальность по строкам (axis=0) или по столбцам (axis=1), что особенно полезно при анализе структуры данных:

Python
Скопировать код
# Подсчет уникальных значений по строкам
print(df.nunique(axis=1))
# Выведет количество уникальных значений для каждой строки

В 2025 году метод nunique() получил дополнительную оптимизацию производительности, особенно для датасетов с миллионами строк, что делает его еще более привлекательным для аналитиков данных, работающих с крупными массивами информации. 🚀

Использование pandas.DataFrame.drop_duplicates() с подсчетом

Более гибкий подход к вычислению уникальных значений предлагает метод drop_duplicates(). В отличие от nunique(), который просто возвращает число, этот метод сначала удаляет дубликаты, а затем позволяет подсчитать оставшиеся записи, предоставляя больше контроля над процессом:

Python
Скопировать код
import pandas as pd

df = pd.DataFrame({
'A': [1, 1, 2, 2, 3],
'B': ['a', 'a', 'b', 'b', 'c'],
'C': [1, 1, 1, 2, 2]
})

# Подсчет уникальных комбинаций значений в столбцах A и B
unique_ab_count = df.drop_duplicates(subset=['A', 'B']).shape[0]
print(f"Уникальных комбинаций A+B: {unique_ab_count}") # Выведет: 3

# Подсчет уникальных значений только по столбцу B
unique_b_count = df.drop_duplicates(subset=['B']).shape[0]
print(f"Уникальных значений B: {unique_b_count}") # Выведет: 3

# Подсчет полностью уникальных строк
unique_rows = df.drop_duplicates().shape[0]
print(f"Полностью уникальных строк: {unique_rows}") # Выведет: 4

Ключевые параметры метода drop_duplicates(), о которых следует знать:

  • subset: список столбцов для проверки дубликатов (по умолчанию все столбцы)
  • keep: 'first' (оставить первый дубликат), 'last' (оставить последний) или False (удалить все дубликаты)
  • ignore_index: если True, результирующий DataFrame будет иметь новые индексы от 0 до n-1

Мария Соколова, Data Analyst

В моей практике был случай, когда простой подсчет уникальных значений с помощью nunique() создал ошибочное представление о данных. Мы анализировали логи пользовательского поведения на крупном e-commerce сайте, где каждая запись содержала множество атрибутов о пользователе и его действиях.

При подготовке еженедельного отчета о конверсии мы заметили аномально высокие показатели. Мой коллега использовал df['user_id'].nunique() для подсчета уникальных пользователей, но это не учитывало бизнес-логику: нас интересовали только пользователи, завершившие определенную последовательность действий.

Я переписала код с использованием drop_duplicates():

Python
Скопировать код
completed_users = df[df['action_completed'] == True].drop_duplicates(subset=['user_id', 'session_id']).shape[0]

Результаты мгновенно изменились, показав реальную картину конверсии, которая была на 23% ниже изначальных расчетов. Этот подход позволил нам точно определить, сколько уникальных пользователей действительно прошли весь путь покупки, а не просто посетили сайт.

Одно из мощных применений drop_duplicates() — анализ уникальности по нескольким измерениям одновременно, что невозможно сделать напрямую через nunique():

СценарийКод с drop_duplicates()Преимущество перед nunique()
Кросс-секционный анализdf.drop_duplicates(['region', 'product']).shape[0]Позволяет оценить уникальность по комбинации критериев
Временные ряды с группировкойdf.drop_duplicates(['customer_id', 'date']).shape[0]Учитывает временное измерение при подсчете
Анализ с фильтрациейdf[df['status']=='active'].drop_duplicates(['id']).shape[0]Комбинирует фильтрацию и удаление дубликатов
Сравнение разных периодовdf[df['year']==2024].drop_duplicates(['customer']).shape[0]Позволяет легко сравнивать метрики между периодами

Подход с drop_duplicates() особенно ценен, когда требуется не просто количество уникальных значений, но и сами эти значения для дальнейшего анализа или обработки. 🧮

Комбинация pandas.value_counts() для подсчета уникальных значений

Функция value_counts() представляет третий мощный метод для анализа уникальных значений, особенно когда нам важно не только их количество, но и частотное распределение. Этот метод возвращает Series с подсчетом вхождений каждого уникального элемента, что дает гораздо более богатую информацию для анализа:

Python
Скопировать код
import pandas as pd
import numpy as np

# Создаем пример данных
df = pd.DataFrame({
'категория': ['A', 'B', 'A', 'C', 'B', 'B', 'A', None, 'D', 'D'],
'ценник': [100, 200, 100, 300, 200, 250, 100, 400, None, 500]
})

# Получаем распределение частот для категорий
category_counts = df['категория'].value_counts()
print("Распределение категорий:")
print(category_counts)

# Выведет:
# B 3
# A 3
# D 2
# C 1
# Name: категория, dtype: int64

# Количество уникальных категорий
unique_categories = len(category_counts)
print(f"Количество уникальных категорий: {unique_categories}") # Выведет: 4

# С учетом NA значений
category_counts_with_na = df['категория'].value_counts(dropna=False)
print("\nС учетом NA:")
print(category_counts_with_na)

Метод value_counts() предлагает множество полезных параметров, значительно расширяющих возможности анализа:

  • normalize: если True, возвращает относительные частоты (доли) вместо абсолютных
  • sort: сортировка по частоте (по умолчанию True)
  • ascending: порядок сортировки (по умолчанию False, т.е. от большей частоты к меньшей)
  • dropna: учитывать ли пропущенные значения (по умолчанию True)
  • bins: группировка числовых данных по интервалам (бинам)

Использование value_counts() для получения относительной частоты (пропорции) уникальных значений:

Python
Скопировать код
# Относительная частота
relative_freq = df['категория'].value_counts(normalize=True)
print("Относительная частота:")
print(relative_freq)

# Выведет:
# B 0.333333
# A 0.333333
# D 0.222222
# C 0.111111
# Name: категория, dtype: float64

Для числовых данных value_counts() можно комбинировать с bins для анализа распределения по интервалам:

Python
Скопировать код
# Группировка числовых данных по интервалам
price_distribution = df['ценник'].value_counts(bins=3)
print("\nРаспределение цен по интервалам:")
print(price_distribution)

Мощь метода value_counts() раскрывается при комбинировании его с другими операциями pandas:

Python
Скопировать код
# Подсчет уникальных значений после фильтрации
expensive_categories = df[df['ценник'] > 200]['категория'].value_counts()
print("\nРаспределение категорий для товаров дороже 200:")
print(expensive_categories)

# Комбинирование с groupby для многомерного анализа
prices_by_category = df.groupby('категория')['ценник'].value_counts()
print("\nРаспределение цен внутри категорий:")
print(prices_by_category)

Для более глубокого анализа часто полезно визуализировать результаты value_counts():

Python
Скопировать код
import matplotlib.pyplot as plt

# Визуализация распределения категорий
df['категория'].value_counts().plot(kind='bar')
plt.title('Распределение категорий')
plt.ylabel('Количество')
plt.xlabel('Категория')
# plt.show() # Раскомментируйте для отображения графика

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

Понимание различных методов подсчета уникальных значений — лишь одна из множества компетенций, необходимых современному специалисту по данным. Если вы задумываетесь о карьере в этой области, но не уверены в своем призвании, Тест на профориентацию от Skypro поможет определить, подходит ли вам аналитика данных или программирование. Объективная оценка ваших сильных сторон и предпочтений позволит избежать карьерных ошибок и найти путь, где практические навыки работы с pandas принесут максимальную отдачу.

Оптимизация производительности при подсчете уникальных значений

При работе с большими объемами данных (от 100+ млн строк) вопрос производительности при подсчете уникальных значений становится критичным. Стандартные методы pandas могут работать неожиданно медленно, особенно при ограниченных ресурсах. Рассмотрим передовые техники оптимизации, актуальные в 2025 году:

Python
Скопировать код
import pandas as pd
import numpy as np
import time

# Создаем крупный датафрейм для тестирования (10 млн строк)
n = 10_000_000
df_large = pd.DataFrame({
'id': np.random.randint(0, 1_000_000, n),
'category': np.random.choice(['A', 'B', 'C', 'D', 'E'], n),
'value': np.random.random(n)
})

# 1. Стандартный подход с nunique()
start = time.time()
nunique_count = df_large['id'].nunique()
nunique_time = time.time() – start
print(f"nunique() нашел {nunique_count} уникальных значений за {nunique_time:.4f} секунд")

# 2. Оптимизация через set (часто быстрее для больших датасетов)
start = time.time()
set_count = len(set(df_large['id']))
set_time = time.time() – start
print(f"set() нашел {set_count} уникальных значений за {set_time:.4f} секунд")

# 3. Использование numpy.unique (может быть быстрее для числовых данных)
start = time.time()
np_count = len(np.unique(df_large['id']))
np_time = time.time() – start
print(f"np.unique() нашел {np_count} уникальных значений за {np_time:.4f} секунд")

На практике выбор оптимального метода зависит от типа данных и размера датасета. Вот сравнительная таблица производительности различных методов для типичных сценариев:

МетодМалые датасеты <br>(<100K строк)Средние датасеты <br>(100K-1M строк)Большие датасеты <br>(>1M строк)Особенности
df['col'].nunique()Очень быстроБыстроСреднеНаиболее удобный API, оптимизирован для pandas
len(set(df['col']))БыстроСреднеБыстро для числовых данныхХорошо для целых чисел, работает медленнее с объектами
len(np.unique(df['col']))БыстроБыстроБыстрее nunique() для числовых данныхСтрого типизирован, не работает с разнородными типами
df['col'].value_counts().shape[0]СреднеМедленноОчень медленноИзбыточен, если нужно только количество
len(df.drop_duplicates(['col']))МедленноОчень медленноКрайне медленноНаименее эффективный для простого подсчета

Для экстремально больших объемов данных можно использовать дополнительные техники оптимизации:

  1. Уменьшение использования памяти с категориальными типами:
Python
Скопировать код
# Преобразование в категориальный тип перед подсчетом
df_large['category'] = df_large['category'].astype('category')
category_unique = df_large['category'].nunique()
  1. Использование параллельных вычислений с dask:
Python
Скопировать код
import dask.dataframe as dd

# Преобразование в dask DataFrame
dask_df = dd.from_pandas(df_large, npartitions=4)
unique_count = dask_df['id'].nunique().compute()
  1. Применение методов приближенного подсчета для экстремальных объемов:
Python
Скопировать код
from datasketch import HyperLogLog

# Приближенный подсчет уникальных значений (для очень больших наборов данных)
hll = HyperLogLog()
for value in df_large['id'].values:
hll.update(str(value).encode('utf8'))

approximate_count = len(hll)
print(f"Приблизительное количество уникальных значений: {approximate_count}")

При оптимизации важно помнить несколько ключевых принципов:

  • Всегда измеряйте время выполнения перед и после оптимизации
  • Для строковых данных преобразование в категориальный тип может дать значительный прирост
  • Параллельные вычисления оправданы только для очень больших объемов данных
  • В крайних случаях можно жертвовать точностью ради скорости, используя вероятностные структуры данных
  • Правильное использование индексов в базе данных до загрузки в pandas может сократить время обработки на порядки

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

Мы рассмотрели пять эффективных методов подсчета уникальных значений в pandas, каждый со своими сильными сторонами. Nunique() остается наиболее универсальным и компактным решением для повседневных задач. Value_counts() незаменим, когда нужна дополнительная информация о распределении данных. Drop_duplicates() предоставляет гибкость при работе с многомерными данными. А для высоконагруженных систем стоит присмотреться к оптимизированным методам с использованием numpy и структур на основе хеширования. Выбор правильного инструмента не только ускоряет аналитические процессы, но и открывает путь к более глубоким выводам — той самой трансформации данных в ценные решения, которая и составляет сущность современной аналитики.