Летом, будучи стажером в Elder Research, я узнал об очень интуитивном алгоритме обнаружения аномалий под названием CADE, или оценка плотности с поправкой на классификатор. Алгоритм показался очень простым, поэтому мне захотелось попробовать реализовать его самому и попытаться найти аномальных игроков в MLB.

Я использовал данные из Baseball Reference, в частности их стандартную и расширенную статистику отбивания мяча за 2016 год. Это обеспечило показатели за весь год.

Цель

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

Внедрение КАДЕ

Как я упоминал выше, CADE — это особенно интуитивный метод обнаружения аномалий. Основная идея заключается в том, что мы создадим поддельный набор данных, где каждая переменная имеет равномерное распределение в том же диапазоне, что и фактическое распределение, и объединим его с исходным, реальным набором данных. Затем мы добавим столбец, указывающий для каждой строки, получена ли она из реального набора данных или нет, а затем обучим классификатор находить поддельные строки. Затем мы можем запустить этот классификатор обратно к нашему исходному набору данных, и он сообщит нам вероятность того, что любой данный игрок является «фальшивым», то есть аномалией.

Таким образом, CADE полагается на две вещи:

1. Создайте равномерное распределение для каждого признака
2. Создайте классификатор, который может дать вероятность

Функция для создания равномерного распределения довольно проста:

def generate_uniform(col):
 “””Returns a uniform distribution in the same range and
 with the same length as col”””
 if col.dtype == np.dtype(‘int64’):
   return np.random.randint(col.min(), col.max(), len(col))
 if col.dtype == np.dtype(‘float64’):
   return np.random.uniform(col.min(), col.max(), len(col))
 else:
   return np.random.choice(list(set(col)), len(col))

Например, фактическое распределение средних показателей:

И результат передачи его через функцию «generate_uniform»:

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

Всю функцию CADE можно записать менее чем в десять строк кода:

def cade(df, clf):
 “””Returns the original dataset df with an added column indicating the probability that the row is an anomaly. clf is the classifier used to calculate the probability. clf must be able to output a probability using the predict_proba method.”””
 real = df.copy() # The original data, will be the ‘no’ case
 fake = df.copy().apply(generate_uniform) # similar but uniform data
 real[‘y’] = 0 # assign all the real players a probability of 0
 fake[‘y’] = 1 # assign all the fake players a probability of 1
 data = pd.concat([real, fake], ignore_index=True)
 # train the model to predict the “realness” of a player
 clf.fit(data.drop(‘y’, 1), data[‘y’])
 probabilities = [x[1] for x in clf.predict_proba(df)]
 df[‘prob’] = probabilities
 return df

Результаты

Так что же происходит, когда мы передаем данные MLB через CADE?
Вот 20 игроков с наибольшей вероятностью возникновения аномалий:

Вывод

Кажется, это работает довольно хорошо, многие из топ-20 самых аномальных игроков на самом деле являются звездами. Следующим естественным шагом будет выяснить, почему эти игроки были выбраны как аномальные. Но определить, почему что-то является выбросом, часто бывает сложнее, чем найти сами выбросы.