Рейтинг поставщиков в pandas: как проверить, зависит ли победитель от весов
Закупки выбрали самого дешёвого поставщика, производство — самого надёжного. В общей таблице оба предлагают сложить цену, срок и процент брака, но числа измерены в разных единицах. Построим понятный рейтинг и проверим, сохранится ли решение, если команда немного изменит приоритеты.
Сначала отсев, затем оценка
Неприемлемые варианты надо исключить до ранжирования: отсутствие сертификата или срок больше производственного дедлайна нельзя компенсировать низкой ценой. В нашем примере все три кандидата прошли обязательные требования. Дальше сравниваем стоимость одной и той же поставки, срок в днях и долю дефектных единиц из сопоставимых приёмок.
Чем меньше каждый из трёх показателей, тем лучше. Если использовать сырые значения, цена в рублях подавит срок в днях. Приведём каждую колонку к шкале от нуля до единицы по заранее заданным границам. Ноль соответствует лучшему ориентиру, единица — худшему. Эти границы фиксируются для задачи и не пересчитываются после добавления очередного кандидата.
Откуда берутся границы и веса
Ориентиры по цене от 90 до 110 условных единиц, по сроку от двух до шести дней, по дефектам от 0 до 4%. Это входные допущения примера, а не отраслевые нормативы. Для рабочего выбора границы согласуют с закупками и производством. Выход показателя за пределы диапазона требует пересмотреть ориентиры или отдельно объяснить экстраполяцию.
Веса выражают относительный приоритет после нормирования. Они положительны и в сумме дают единицу. Рассмотрим три сценария: сбалансированный, с усиленным вниманием к цене и с приоритетом качества. Рейтинг — взвешенная сумма нормированных потерь, поэтому меньший итог лучше. Вывод должен содержать и название сценария, иначе число выглядит объективнее, чем оно есть.
Проверяем решение на трёх сценариях
Входы зададим явно, без случайной генерации. Код выводит всех поставщиков по каждому сценарию и отдельно показывает победителей. Добавленная проверка диапазонов останавливает расчёт, если новая цена или дефектность выходят за согласованные ориентиры. Равенство оценок разрешается стабильной сортировкой по имени, но для управленческого решения ничью стоит показывать явно.
import pandas as pd
raw = pd.DataFrame([
('A',90,6,0.04), ('B',100,3,0.01), ('C',110,2,0.0)
],columns=['supplier','price','days','defect']).set_index('supplier')
low = pd.Series({'price':90,'days':2,'defect':0.0})
high = pd.Series({'price':110,'days':6,'defect':0.04})
norm = (raw-low)/(high-low)
assert ((norm>=0)&(norm<=1)).all().all()
weights = pd.DataFrame([
('balanced',0.5,0.25,0.25),
('price_first',0.8,0.1,0.1),
('quality_first',0.2,0.2,0.6)
],columns=['scenario','price','days','defect']).set_index('scenario')
assert (weights>=0).all().all()
assert ((weights.sum(axis=1)-1).abs()<1e-12).all()
scores = norm.dot(weights.T)
print(scores.round(3).to_string())
winners = scores.idxmin(axis=0)
print(winners.to_dict())
assert winners.to_dict() == {'balanced':'B','price_first':'A','quality_first':'C'}
assert abs(scores.loc['B','balanced']-0.375)<1e-12Победитель зависит от решения команды
В сбалансированном сценарии у B оценка 0,375, у A и C — по 0,5. При усилении цены выигрывает A, при приоритете качества — C. Значит, исходная рекомендация неустойчива к выбору приоритетов. Это полезный результат: перед подписанием договора команде нужно договориться, какую потерю она готова принять.
Не следует усреднять победителей трёх сценариев и объявлять самый частый вариант правильным. Сценарии не являются случайной выборкой предпочтений. Они показывают последствия конкретных управленческих решений. Если производство не может принять 4% дефектов, A нужно исключить обязательным ограничением, а не пытаться уменьшить его шансы малым весом цены.
Качество исходных показателей
Сравните объём и период наблюдений: один дефект из десяти единиц и сто из тысячи дают разные основания для уверенности. Для нового поставщика оценка брака может быть неизвестна. Пустую ячейку нельзя заменить нулём и сделать новичка лучшим. Нужна тестовая поставка, внешний подтверждённый источник или отдельный сценарий неизвестного качества.
Цена тоже должна учитывать одинаковые условия: доставку, налоги, объём и отсрочку. Если один кандидат предлагает более долгую оплату, команда может оценить этот эффект отдельно и привести предложения к сопоставимой стоимости. Тогда рейтинг сравнивает реальные варианты заказа, а не разрозненные цифры из коммерческих писем.
Как представить рекомендацию
Покажите исходные показатели, границы шкалы и три сценария рядом. Запишите, при каком приоритете рекомендуете B и что изменит выбор. После согласования сохраните веса вместе с датой решения. Следующее обновление должно показывать, поменялись условия поставщиков или сами предпочтения команды: для закупочного решения это разные причины.
Проверяем, нет ли лишнего кандидата
До обсуждения весов найдите варианты, которые проигрывают другому поставщику сразу по всем показателям. Если цена выше, срок дольше и дефектов больше, такой кандидат не выиграет при положительных весах этих критериев. Его имеет смысл оставить лишь при дополнительном преимуществе: резервной мощности, уникальной номенклатуре или условиях оплаты, которые ещё не включены в модель.
После выбора посмотрите второй результат. Небольшой отрыв от конкурента при неточных входах означает, что стоит уточнить данные или провести пробную поставку. В нашем примере числа заданы точно для объяснения метода. В работе даже простая таблица диапазонов по цене и срокам полезнее лишних знаков после запятой в итоговом балле.
Продолжить практику
Работа аналитика здесь начинается с определения вопроса и заканчивается объяснимой рекомендацией. В платной «Практической аналитике данных» вы тренируете этот путь на продажах, клиентах и рекламе, проверяете данные и оформляете результат в дашборд и записку. Посмотрите программу курса.
Продолжить на практике
- Практическая аналитика данных ↗
Превратите знания SQL или Python в аналитическую работу: проверяйте данные, считайте бизнес-метрики, стройте дашборды и объясняйте выводы на трёх прикладных кейсах.
