Обнаружение глубоких аномалий для крупномасштабных корпоративных данных

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

Говоря обобщенно, обнаружение аномалий призвано помочь различать довольно редкие события и / или отклоняющиеся от нормы. Это очень важно для финансовой индустрии, так же как и в потребительском банкинге, аномалии могут быть критическими вещами - например, мошенничество с кредитными картами. В других случаях аномалия может быть чем-то, что компании ищут, чтобы извлечь из нее выгоду. Некоторые из других приложений включают вторжения в сети связи, фальшивые новости и дезинформацию, анализ здравоохранения, обнаружение промышленных повреждений, производство, безопасность и наблюдение и т. Д.

Пример использования, показанный в этой статье, взят из области SAP, в частности, Финансы. Бизнес-цель - найти аномальное поведение в финансовых транзакциях.

Типичная финансовая операция в Бухгалтерской информационной системе будет выглядеть так.

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

В этой статье я расскажу о новейшем методе обнаружения аномалий с помощью Autoencoder Neural Network (AENN). Это метод обнаружения аномалий, основанный на глубоком обучении.

Ну про датасет

Набор данных, используемый для этого варианта использования, можно найти по предоставленной ссылке GitHub. Это синтетический набор финансовых данных, измененный, чтобы он выглядел более похожим на набор реальных данных, который обычно наблюдается в системах SAP-ERP, особенно в модуле управления финансами и затратами.

Набор данных содержит 7 категориальных и 2 числовых атрибута, доступных в таблице FICO BKPF (содержащей заголовки опубликованных записей журнала) и таблице BSEG (содержащей сегменты опубликованных записей журнала).

Другой атрибут «метка» также можно найти в данных, объясняющих истинный характер транзакции: обычная или аномалия (локальная или глобальная). Это необходимо для проверки модели и не будет использоваться в обучающей части.

Классификация аномалий:

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

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

На основании этого наблюдения можно выделить два класса аномальных записей в журнале, а именно «глобальные» и «локальные» аномалии.

Глобальные аномалии бухгалтерского учета - это занесенные в журнал записи, для которых характерны необычные или редкие значения отдельных атрибутов. Такие аномалии обычно связаны с перекосом атрибутов, например редко используемые бухгалтерские книги или необычное время публикации. Традиционно тесты «красного флага», проводимые аудиторами во время ежегодного аудита, предназначены для выявления аномалий этого типа. Однако такие тесты часто приводят к большому количеству ложноположительных предупреждений из-за таких событий, как обратные проводки, резервы и корректировки на конец года, обычно связанные с низким риском мошенничества. Кроме того, при консультациях с аудиторами и судебными бухгалтерами «глобальные» аномалии часто относятся к «ошибке», а не «мошенничеству».

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

Предварительные требования: ожидается, что аудитория будет знакома с основами работы нейронов и нейронных сетей в глубоком обучении. Здесь - отличный учебник, который даст вам точное представление о нейронных сетях.

Обнаружение аномалий с помощью нейронных сетей автоэнкодера - теория

Автоэнкодеры широко используются в компьютерном зрении и обработке речи. Но малоизвестный факт, что они также могут использоваться для обнаружения аномалий. В этом разделе мы познакомим вас с основными элементами нейронных сетей автоэнкодера.

Типичный автокодер состоит из двух функций нелинейного сопоставления, называемых нейронными сетями Кодировщик -f (x) и Декодер -g (x). Кодер обычно следует парадигме воронки с уменьшающимся набором нейронов, а декодер обычно является симметричным зеркалом кодировщика. Существует скрытый центральный слой, называемый скрытым слоем более низких размеров, который будет представлять собой сжатое богатое представление входных данных, достаточное для его восстановления с минимальной ошибкой реконструкции.

Идея использования этой алгоритмической парадигмы для обнаружения аномалий состоит из двух основных этапов: изучение нормального поведения системы (на основе прошлых данных) и обнаружение аномального поведения в реальном времени (путем обработки данных в реальном времени).

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

Loss function(reconstruction error) = arg min || x — g(f(x)) ||

В этом случае мы использовали двоичную кросс-энтропийную потерю, равную.

−(xlog(x’)+(1−x)log(1−x’))

x - входные данные, x ’- g (f (x)). Это измерение того, насколько похожи данные два распределения. Чем меньше потери, тем больше аналогичен ввод и его реконструкция.

Реализация

Примечание. Здесь все становится немного техническим, поэтому я советую всем нетехническим специалистам пропустить этот раздел. Вы можете пройти через это, но не пугайтесь :)

Импортируйте необходимые библиотеки и задайте некоторые параметры.

# importing utilities
import os
import sys
from datetime import datetime
# importing data science libraries
import pandas as pd
import random as rd
import numpy as np
# importing pytorch libraries
import torch
from torch import nn
from torch import autograd
from torch.utils.data import DataLoader
# import visualization libraries
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import seaborn as sns
from IPython.display import Image, display
sns.set_style('darkgrid')
# ignore potential warnings
import warnings
warnings.filterwarnings("ignore")

Установите случайное начальное число и используйте графический процессор, если он доступен.

rseed = 1234 
rd.seed(rseed)
np.random.seed(rseed)
torch.manual_seed(rseed) 
if (torch.backends.cudnn.version() != None and USE_CUDA == True):
    torch.cuda.manual_seed(rseed)
USE_CUDA = True

Импортируйте данные во фрейм данных pandas.

ad_dataset = pd.read_csv('./data/fraud_dataset_v2.csv')
ad_dataset.head()

Посмотрите на форму и подпись value_counts.

ad_dataset.shape
Out[#]: (533009, 10)
ad_dataset.label.value_counts()
Out[#]: regular    532909
         global         70
         local          30
         Name: label, dtype: int64

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

Давайте удалим этикетку для дальнейшей обработки, так как автоэнкодер - это неконтролируемый метод.

label = ad_dataset.pop('label')

Теперь давайте разделим категориальные и числовые атрибуты. Добавьте горячие кодировки к категориальным атрибутам, чтобы векторизовать их. Примените масштабирование журнала и минимальное-максимальное масштабирование к числовым переменным.

categorical_attr = ['KTOSL', 'PRCTR', 'BSCHL', 'HKONT', 'WAERS', 'BUKRS']
ad_dataset_categ_transformed = pd.get_dummies(ad_dataset[categorical_attr])
numeric_attr_names = ['DMBTR', 'WRBTR']
# add a small epsilon to eliminate zero values from data for log scaling
numeric_attr = ad_dataset[numeric_attr] + 1e-7
numeric_attr = numeric_attr.apply(np.log)
ad_dataset_numeric_attr = (numeric_attr - numeric_attr.min()) / (numeric_attr.max() - numeric_attr.min())

Свяжите числовые и категориальные атрибуты.

ad_subset_transformed = pd.concat([ad_dataset_categ_transformed, ad_dataset_numeric_attr], axis = 1)
ad_subset_transformed.shape
Out[#]: (533009, 618)

Теперь давайте реализуем сеть кодировщика (618–512–256–128–64–32–16–8–4–3).

# implementation of the encoder network
class encoder(nn.Module):
def __init__(self):
super(encoder, self).__init__()
# specify layer 1 - in 618, out 512
        self.encoder_L1 = nn.Linear(in_features=ori_subset_transformed.shape[1], out_features=512, bias=True) # add linearity 
        nn.init.xavier_uniform_(self.encoder_L1.weight) # init weights according to [9]
        self.encoder_R1 = nn.LeakyReLU(negative_slope=0.4, inplace=True) # add non-linearity according to [10]
# specify layer 2 - in 512, out 256
        self.encoder_L2 = nn.Linear(512, 256, bias=True)
        nn.init.xavier_uniform_(self.encoder_L2.weight)
        self.encoder_R2 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 3 - in 256, out 128
        self.encoder_L3 = nn.Linear(256, 128, bias=True)
        nn.init.xavier_uniform_(self.encoder_L3.weight)
        self.encoder_R3 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 4 - in 128, out 64
        self.encoder_L4 = nn.Linear(128, 64, bias=True)
        nn.init.xavier_uniform_(self.encoder_L4.weight)
        self.encoder_R4 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 5 - in 64, out 32
        self.encoder_L5 = nn.Linear(64, 32, bias=True)
        nn.init.xavier_uniform_(self.encoder_L5.weight)
        self.encoder_R5 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 6 - in 32, out 16
        self.encoder_L6 = nn.Linear(32, 16, bias=True)
        nn.init.xavier_uniform_(self.encoder_L6.weight)
        self.encoder_R6 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 7 - in 16, out 8
        self.encoder_L7 = nn.Linear(16, 8, bias=True)
        nn.init.xavier_uniform_(self.encoder_L7.weight)
        self.encoder_R7 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 8 - in 8, out 4
        self.encoder_L8 = nn.Linear(8, 4, bias=True)
        nn.init.xavier_uniform_(self.encoder_L8.weight)
        self.encoder_R8 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 9 - in 4, out 3
        self.encoder_L9 = nn.Linear(4, 3, bias=True)
        nn.init.xavier_uniform_(self.encoder_L9.weight)
        self.encoder_R9 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# init dropout layer with probability p
        self.dropout = nn.Dropout(p=0.0, inplace=True)
        
    def forward(self, x):
# define forward pass through the network
        x = self.encoder_R1(self.dropout(self.encoder_L1(x)))
        x = self.encoder_R2(self.dropout(self.encoder_L2(x)))
        x = self.encoder_R3(self.dropout(self.encoder_L3(x)))
        x = self.encoder_R4(self.dropout(self.encoder_L4(x)))
        x = self.encoder_R5(self.dropout(self.encoder_L5(x)))
        x = self.encoder_R6(self.dropout(self.encoder_L6(x)))
        x = self.encoder_R7(self.dropout(self.encoder_L7(x)))
        x = self.encoder_R8(self.dropout(self.encoder_L8(x)))
        x = self.encoder_R9(self.encoder_L9(x))
return x

Создайте экземпляр кодировщика и включите

# init training network classes / architectures
encoder_train = encoder()
# push to cuda if cudnn is available
if (torch.backends.cudnn.version() != None and USE_CUDA == True):
    encoder_train = encoder().cuda()

Теперь о сетевой реализации декодера, которая является симметричным зеркалом кодировщика. (3–4–8–16–32–64–128–256–512–618)

# implementation of the decoder network
class decoder(nn.Module):
def __init__(self):
super(decoder, self).__init__()
# specify layer 1 - in 3, out 4
        self.decoder_L1 = nn.Linear(in_features=3, out_features=4, bias=True) # add linearity 
        nn.init.xavier_uniform_(self.decoder_L1.weight)  # init weights according to [9]
        self.decoder_R1 = nn.LeakyReLU(negative_slope=0.4, inplace=True) # add non-linearity according to [10]
# specify layer 2 - in 4, out 8
        self.decoder_L2 = nn.Linear(4, 8, bias=True)
        nn.init.xavier_uniform_(self.decoder_L2.weight)
        self.decoder_R2 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 3 - in 8, out 16
        self.decoder_L3 = nn.Linear(8, 16, bias=True)
        nn.init.xavier_uniform_(self.decoder_L3.weight)
        self.decoder_R3 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 4 - in 16, out 32
        self.decoder_L4 = nn.Linear(16, 32, bias=True)
        nn.init.xavier_uniform_(self.decoder_L4.weight)
        self.decoder_R4 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 5 - in 32, out 64
        self.decoder_L5 = nn.Linear(32, 64, bias=True)
        nn.init.xavier_uniform_(self.decoder_L5.weight)
        self.decoder_R5 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 6 - in 64, out 128
        self.decoder_L6 = nn.Linear(64, 128, bias=True)
        nn.init.xavier_uniform_(self.decoder_L6.weight)
        self.decoder_R6 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
        
        # specify layer 7 - in 128, out 256
        self.decoder_L7 = nn.Linear(128, 256, bias=True)
        nn.init.xavier_uniform_(self.decoder_L7.weight)
        self.decoder_R7 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 8 - in 256, out 512
        self.decoder_L8 = nn.Linear(256, 512, bias=True)
        nn.init.xavier_uniform_(self.decoder_L8.weight)
        self.decoder_R8 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# specify layer 9 - in 512, out 618
        self.decoder_L9 = nn.Linear(in_features=512, out_features=ori_subset_transformed.shape[1], bias=True)
        nn.init.xavier_uniform_(self.decoder_L9.weight)
        self.decoder_R9 = nn.LeakyReLU(negative_slope=0.4, inplace=True)
# init dropout layer with probability p
        self.dropout = nn.Dropout(p=0.0, inplace=True)
def forward(self, x):
# define forward pass through the network
        x = self.decoder_R1(self.dropout(self.decoder_L1(x)))
        x = self.decoder_R2(self.dropout(self.decoder_L2(x)))
        x = self.decoder_R3(self.dropout(self.decoder_L3(x)))
        x = self.decoder_R4(self.dropout(self.decoder_L4(x)))
        x = self.decoder_R5(self.dropout(self.decoder_L5(x)))
        x = self.decoder_R6(self.dropout(self.decoder_L6(x)))
        x = self.decoder_R7(self.dropout(self.decoder_L7(x)))
        x = self.decoder_R8(self.dropout(self.decoder_L8(x)))
        x = self.decoder_R9(self.decoder_L9(x))
        
        return x

Создайте экземпляр декодера и поместите его на GPU.

# init training network classes / architectures
decoder_train = decoder()
# push to cuda if cudnn is available
if (torch.backends.cudnn.version() != None) and (USE_CUDA == True):
    decoder_train = decoder().cuda()

Теперь настраиваем функцию потерь и некоторые гиперпараметры.

# define the optimization criterion / loss function
loss_function = nn.BCEWithLogitsLoss(reduction='mean')
# define learning rate and optimization strategy
learning_rate = 1e-3
encoder_optimizer = torch.optim.Adam(encoder_train.parameters(), lr=learning_rate)
decoder_optimizer = torch.optim.Adam(decoder_train.parameters(), lr=learning_rate)
# specify training parameters
num_epochs = 8
mini_batch_size = 128

Загрузите данные в тензор и на GPU.

# convert pre-processed data to pytorch tensor
torch_dataset = torch.from_numpy(ad_subset_transformed.values).float()
# convert to pytorch tensor - none cuda enabled
dataloader = DataLoader(torch_dataset, batch_size=mini_batch_size, shuffle=True, num_workers=0)
# note: we set num_workers to zero to retrieve deterministic results
# determine if CUDA is available at compute node
if (torch.backends.cudnn.version() != None) and (USE_CUDA == True):
    dataloader = DataLoader(torch_dataset.cuda(), batch_size=mini_batch_size, shuffle=True)

Теперь к нашему обучению. (Примечание: я советую не копировать и вставлять приведенный ниже код, поскольку форматирование может быть неправильным. Получите код по ссылке GitHub, указанной ниже.)

# init collection of mini-batch losses
losses = []
# convert encoded transactional data to torch Variable
data = autograd.Variable(torch_dataset)
# train autoencoder model
for epoch in range(num_epochs):
# init mini batch counter
    mini_batch_count = 0
    
    # determine if CUDA is available at compute node
    if(torch.backends.cudnn.version() != None) and (USE_CUDA == True):
        
        # set networks / models in GPU mode
        encoder_train.cuda()
        decoder_train.cuda()
# set networks in training mode (apply dropout when needed)
    encoder_train.train()
    decoder_train.train()
# start timer
    start_time = datetime.now()
        
    # iterate over all mini-batches
    for mini_batch_data in dataloader:
# increase mini batch counter
        mini_batch_count += 1
# convert mini batch to torch variable
        mini_batch_torch = autograd.Variable(mini_batch_data)
# =================== (1) forward pass ============================
# run forward pass
        z_representation = encoder_train(mini_batch_torch) # encode mini-batch data
        mini_batch_reconstruction = decoder_train(z_representation) # decode mini-batch data
        
        # =================== (2) compute reconstruction loss ======
# determine reconstruction loss
        reconstruction_loss = loss_function(mini_batch_reconstruction, mini_batch_torch)
        
        # =================== (3) backward pass ====================
# reset graph gradients
        decoder_optimizer.zero_grad()
        encoder_optimizer.zero_grad()
# run backward pass
        reconstruction_loss.backward()
        
        # =================== (4) update model parameters =========
# update network parameters
        decoder_optimizer.step()
        encoder_optimizer.step()
# =================== monitor training progress ===================
# print training progress each 1'000 mini-batches
        if mini_batch_count % 1000 == 0:
            
            # print the training mode: either on GPU or CPU
            mode = 'GPU' if (torch.backends.cudnn.version() != None) and (USE_CUDA == True) else 'CPU'
            
            # print mini batch reconstuction results
            now = datetime.utcnow().strftime("%Y%m%d-%H:%M:%S")
            end_time = datetime.now() - start_time
            print('[LOG {}] training status, epoch: [{:04}/{:04}], batch: {:04}, loss: {}, mode: {}, time required: {}'.format(now, (epoch+1), num_epochs, mini_batch_count, np.round(reconstruction_loss.item(), 4), mode, end_time))
# reset timer
            start_time = datetime.now()
# =================== evaluate model performance ================
    
    # set networks in evaluation mode (don't apply dropout)
    encoder_train.cpu().eval()
    decoder_train.cpu().eval()
# reconstruct encoded transactional data
    reconstruction = decoder_train(encoder_train(data))
    
    # determine reconstruction loss - all transactions
    reconstruction_loss_all = loss_function(reconstruction, data)
            
    # collect reconstruction loss
    losses.extend([reconstruction_loss_all.item()])
    
    # print reconstuction loss results
    now = datetime.utcnow().strftime("%Y%m%d-%H:%M:%S")
    print('[LOG {}] training status, epoch: [{:04}/{:04}], loss: {:.10f}'.format(now, (epoch+1), num_epochs, reconstruction_loss_all.item()))
# =================== save model snapshot to disk ================
    
    # save trained encoder model file to disk
    encoder_model_name = "ep_{}_encoder_model.pth".format((epoch+1))
    torch.save(encoder_train.state_dict(), os.path.join("./models", encoder_model_name))
# save trained decoder model file to disk
    decoder_model_name = "ep_{}_decoder_model.pth".format((epoch+1))
    torch.save(decoder_train.state_dict(), os.path.join("./models", decoder_model_name))

Нанесение убытков.

# plot the training progress
plt.plot(range(0, len(losses)), losses)
plt.xlabel('[training epoch]')
plt.xlim([0, len(losses)])
plt.ylabel('[reconstruction-error]')
#plt.ylim([0.0, 1.0])
plt.title('AENN training performance')

На этом наше обучение закончено. Теперь давайте посмотрим, как использовать наши модели для получения прогнозов.

Загрузите предварительно обученные модели.

# restore pretrained model checkpoint
encoder_model_name = "ep_8_encoder_model.pth"
decoder_model_name = "ep_8_decoder_model.pth"
# init training network classes / architectures
encoder_eval = encoder()
decoder_eval = decoder()
# load trained models
encoder_eval.load_state_dict(torch.load(os.path.join("models", encoder_model_name)))
decoder_eval.load_state_dict(torch.load(os.path.join("models", decoder_model_name)))

Выполните реконструкцию для всех данных.

# convert encoded transactional data to torch Variable
data = autograd.Variable(torch_dataset)
# set networks in evaluation mode (don't apply dropout)
encoder_eval.eval()
decoder_eval.eval()
# reconstruct encoded transactional data
reconstruction = decoder_eval(encoder_eval(data))

Получите потери реконструкции для всех данных.

# determine reconstruction loss - all transactions
reconstruction_loss_all = loss_function(reconstruction, data)
print(reconstruction_loss_all)
reconstruction loss: 0.0034663924

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

# init binary cross entropy errors
reconstruction_loss_transaction = np.zeros(reconstruction.size()[0])
# iterate over all detailed reconstructions
for i in range(0, reconstruction.size()[0]):
# determine reconstruction loss - individual transactions
    reconstruction_loss_transaction[i] = loss_function(reconstruction[i], data[i]).item()

Постройте точки данных в соответствии с потерями реконструкции, прикрепленными к этим меткам.

# prepare plot
fig = plt.figure()
ax = fig.add_subplot(111)
# assign unique id to transactions
plot_data = np.column_stack((np.arange(len(reconstruction_loss_transaction)), reconstruction_loss_transaction))
# obtain regular transactions as well as global and local anomalies
regular_data = plot_data[label == 'regular']
global_outliers = plot_data[label == 'global']
local_outliers = plot_data[label == 'local']
# plot reconstruction error scatter plot
ax.scatter(regular_data[:, 0], regular_data[:, 1], c='C0', alpha=0.4, marker="o", label='regular') # plot regular transactions
ax.scatter(global_outliers[:, 0], global_outliers[:, 1], c='C1', marker="^", label='global') # plot global outliers
ax.scatter(local_outliers[:, 0], local_outliers[:, 1], c='C2', marker="^", label='local') # plot local outliers
# add plot legend of transaction classes
ax.legend(loc='best')

График показывает, как выбранный подход элегантно обнаружил аномалии из набора данных с высокой степенью предвзятости. Посмотрим, сколько аномалий было выявлено.

ad_dataset['label'] = label
ad_dataset[reconstruction_loss_transaction >= 0.1].label.value_counts()
Out[#]: global    59
        local      2
        Name: label, dtype: int64
ad_dataset[(reconstruction_loss_transaction >= 0.018) & (reconstruction_loss_transaction < 0.05)].label.value_counts()
Out[#]: local   23
        Name: label, dtype: int64

Как видите, из 70 глобальных было обнаружено 59, что составляет 84%, а из 30 локальных обнаружено 23, что составляет 76,6%. Это намного лучшая производительность, чем у любых других старых методов, учитывая, что выбросы составляли всего 0,018% от всех данных.

Вот ссылка на Github для реализации кода вместе с набором данных.

Надеюсь, это дает четкое представление о подходе и о том, как его реализовать.

Заключение

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

использованная литература

Обнаружение аномалий в крупномасштабных учетных данных с использованием сетей глубокого автоэнкодера

Обзор методов обнаружения аномалий в финансовой сфере

Глубокое обучение для обнаружения аномалий: исследование

Обо мне

Я старший эксперт по ИИ в Wavelabs.ai. Мы в Wavelabs помогаем вам использовать искусственный интеллект (AI), чтобы революционизировать пользовательский опыт и сократить расходы. Мы уникальным образом улучшаем ваши продукты с помощью ИИ, чтобы полностью раскрыть ваш рыночный потенциал. Мы стараемся внедрять передовые исследования в ваши приложения.

Не стесняйтесь узнавать больше на Wavelabs.ai.

Ну вот и все в этом посте. Спасибо за прочтение :)

Оставайтесь любопытными!

Вы можете связаться со мной в LinkedIn.