Привет, Хабр! На связи Егор Гершевский и Никита Горбачёв, участники профессионального сообщества NTA.
Аудит является неотъемлемой частью бизнес-практики, обеспечивая независимую оценку финансовой отчётности и процессов в организации. Аудиторы полагаются на опыт и статистическую выборку для ручной проверки сотен документов и свидетельств, определения сильных сторон и углублённого анализа организационных процедур и транзакций. Однако этот ручной процесс превратил аудит в трудоёмкую деятельность.
Сегодня почти каждая крупная технологическая компания внедряет машинное обучение (ML) в аудит. Вот, например, как оно применяется в Facebook и Amazon. Его можно задействовать в разных аспектах, включая анализ данных, обнаружение мошенничества, прогнозирование рисков и оптимизацию процессов. Алгоритмы машинного обучения могут обрабатывать и анализировать огромные объёмы данных, выявлять скрытые зависимости и аномалии, что помогает аудиторам принимать более обоснованные и точные решения. Далее мы рассмотрим различные типы задач машинного обучения, которые могут быть применены в аудите.
Задача классификации
В качестве примера проанализируемуем данные с сайта Kaggle, а именно Audit Data: набор данных для классификации мошеннических фирм.
# Импортируем библиотеки
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# Считываем данные
df = pd.read_csv('audit_data.csv')
df.head()
df.info()
# Создаём копию data-фрейма
df_ml = df.copy()
# Заполняем пустые значения медианными
df_ml.Money_Value.fillna(value = df_ml.Money_Value.median(), inplace=True)
df_ml['LOCATION_ID'].unique()
Так как в столбце есть строковые значения, нужно его перекодировать.
location_dummies = pd.get_dummies(df_ml['LOCATION_ID'], prefix='location')
df_ml = pd.concat([df_ml, location_dummies], axis=1)
df_ml = df_ml.drop('LOCATION_ID', axis=1)
X = df_ml.drop(columns = 'Risk')
y = df_ml.Risk
# Создаем обучающую и тестовую выборку
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7,stratify = y, shuffle=True, random_state=42)
# Импортируем модели
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn import svm
from sklearn import metrics
# Обучим модели и сравним их показатели на тестовой выборке
models = {
"Logistic Regression": LogisticRegression(solver= 'liblinear', random_state=42),
"Decision Tree": DecisionTreeClassifier(),
"Random Forest": RandomForestClassifier(n_estimators=100, random_state=0),
"GB": GradientBoostingClassifier()
}
model_list=[]
accuracy_list=[]
recall_list=[]
precision_list=[]
specificity_list=[]
f1_score_list=[]
for i in range(len(list(models))):
model=list(models.values())[i]
model.fit(X_train,y_train)
y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)
score = round(model.score(X_test, y_test), 4)
tn, fp, fn, tp = metrics.confusion_matrix(y_test, y_test_pred).ravel()
recall = round(tp/(tp+fn), 3)
precision = round(tp/(tp+fp), 3)
specificity =round(tn/(tn+fp),3)
f1_score = round(2*precision*recall/(precision + recall), 3)
print(list(models.keys())[i])
model_list.append(list(models.keys())[i])
print('Model performance for Test set')
print("- Accuracy: {}".format(score))
print("- Recall: {}".format(recall))
print("- Precision: {}".format(precision))
print("- Specificity: {}".format(specificity))
print("- f1_score: {}".format(f1_score))
accuracy_list.append(score)
recall_list.append(recall)
precision_list.append(precision)
specificity_list.append(specificity)
f1_score_list.append(f1_score)
print('='*35)
print('\n')
А теперь разберём, что сейчас произошло. Мы только что решили стандартную задачу классификации, обучили наши модели на исторических данных. Теперь можем передавать им новые данные по фирмам, тогда наши модели предскажут, являются ли эти фирмы мошенническими. Мы использовали и сравнили несколько моделей, а именно:
логистическая регрессия, предсказывающая вероятность принадлежности к определенному классу;
решающие деревья, представляющие собой древовидную структуру решений, где каждый узел представляет тест на признак, а каждое ответвление соответствует возможному значению этого признака;
случайный лес, представляющий собой несколько моделей решающих деревьев, где каждое дерево обучается на случайной предвыборке данных, а предсказание получается усреднением предсказаний всех деревьев;
градиентный бустинг — ансамбль моделей, в который новые модели добавляются последовательно и корректируют ошибки предыдущих моделей.
В итоге мы получили следующие показатели:
Accuracy (точность): этот показатель измеряет долю правильно классифицированных образцов среди всех образцов. Формула для вычисления выглядит так:
accuracy = (TP + TN) / (TP + TN + FP + FN)
, где TP (True Positive) — количество правильно предсказанных положительных классов, TN (True Negative) — количество правильно предсказанных отрицательных классов, FP (False Positive) — количество неправильно предсказанных положительных классов, и FN (False Negative) — количество неправильно предсказанных отрицательных классов.Precision (точность): этот показатель измеряет долю правильно предсказанных положительных классов среди всех классифицированных положительных образцов. Формула для вычисления выглядит так:
precision = TP / (TP + FP)
.Recall (полнота): этот показатель измеряет долю правильно предсказанных положительных классов среди всех фактически положительных образцов. Формула для вычисления выглядит так:
recall = TP / (TP + FN)
.Specificity (специфичность): этот показатель измеряет долю правильно предсказанных отрицательных классов среди всех фактически отрицательных образцов. Формула для вычисления выглядит так:
specificity = TN / (TN + FP)
.F1 score: это гармоническое среднее между precision и recall. Показатель отражает баланс между этими двумя метриками. Формула для вычисления выглядит так:
F1 score = 2 * (precision * recall) / (precision + recall)
.
Они являются важными для оценки производительности модели классификации и помогают понять, насколько хорошо модель справляется с предсказанием классов. В зависимости от задачи и контекста некоторые показатели могут быть важнее других.
Представим полученные данные в виде таблицы.
Задача регрессии
В аудите могут использоваться и другие типы задач машинного обучения. Задача регрессии отличается от задачи классификации тем, что её цель — предсказать числовое значение, а не категориальное.
С Kaggle возьмём набор данных Salary Prediction Data, в нём содержится информация об опыте работы сотрудника и его зарплате. Обучим модель регрессии.
# Считываем данные
df = pd.read_csv('Salary_Data.csv')
df.head(10)
target = 'Salary'
X = df.loc[:,df.columns!=target]
y = df.loc[:,df.columns==target]
# Создаём обучающую и тестовую выборку
x_train, x_test, y_train, y_test= train_test_split(X, y, test_size= .2, random_state=0)
# Импортируем и обучаем модель
from sklearn.linear_model import LinearRegression
lr= LinearRegression()
lr.fit(x_train, y_train)
y_pred= lr.predict(x_test)
x_pred= lr.predict(x_train)
# Отрисовываем графики зависимости зарплаты от опыта работы
import matplotlib.pyplot as mtp
mtp.scatter(x_train, y_train, color="green")
mtp.plot(x_train, x_pred, color="red")
mtp.title("Salary vs Experience (Training Dataset)")
mtp.xlabel("Years of Experience")
mtp.ylabel("Salary(In Rupees)")
mtp.show()
mtp.scatter(x_test, y_test, color="blue")
mtp.plot(x_train, x_pred, color="red")
mtp.title("Salary vs Experience (Test Dataset)")
mtp.xlabel("Years of Experience")
mtp.ylabel("Salary(In Rupees)")
mtp.show()
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
regressor = LinearRegression()
regressor.fit(x_train,y_train)
r2_score = regressor.score(x_test,y_test)
r2_score = r2_score*100
predict = lr.predict(x_test)
mse = mean_squared_error(predict,y_test, squared=False)
mae = mean_absolute_error(predict,y_test)
У модели регрессии также свои метрики.
Mean Squared Error, MSE (Среднеквадратичная ошибка): это наиболее распространённая метрика для задач регрессии. MSE измеряет среднюю квадратичную разницу между предсказанными и фактическими значениями целевой переменной. Чем меньше MSE, тем лучше производительность модели.
Mean Absolute Error, MAE (Средняя абсолютная ошибка): измеряет среднюю абсолютную разницу между предсказанными и фактическими значениями целевой переменной. MAE также предоставляет информацию о средней величине ошибки модели.
Coefficient of Determination, R^2 (Коэффициент детерминации): измеряет пропорцию дисперсии зависимой переменной, которая может быть объяснена моделью. Значение R^2 находится в диапазоне от 0 до 1, где 1 означает, что модель идеально объясняет вариацию данных, а 0 — что модель не объясняет вариацию данных лучше, чем простое среднее значение.
В нашем случае эти значения получились следующими:
R^2 = 98,8169515729126 %
MAE = 2446,1723690465064
MSE = 3580,979237321345
Эта модель может в дальнейшем применяться для предсказания заработной платы сотрудника в зависимости от его стажа, но может работать и с более сложными наборами данных, содержали гораздо больше информации.
Задача кластеризации
Рассмотрим ещё один тип задач машинного обучения, с которым может столкнуться аудитор, а именно задачу кластеризации. Ведь может быть такое, что нужно выявить группы, схожие по каким-либо характеристикам. Возвращаемся на Kaggle и берём data-фрейм Credit Card Dataset, содержащий набор данных о кредитных картах и характеристиках клиентов, таких как пол, возраст, занятость, семейное положение и история использования кредитной карты. Нужно выявить группы клиентов со схожим поведением и сегментировать их на основе этих характеристик. Это может помочь аудиторам лучше понять своих клиентов и улучшить стратегии организации.
# Считываем данные
df=pd.read_csv('CC GENERAL.csv')
df.head()
df.info()
df.isnull().sum()
# Заполняем нулевые значения средними
df['MINIMUM_PAYMENTS']=df['MINIMUM_PAYMENTS'].fillna(df['MINIMUM_PAYMENTS'].mean())
from sklearn.cluster import KMeans
wcss=[]
for k in range(1,11):
kmeans=KMeans(n_clusters=k, init='k-means++', random_state=0)
kmeans.fit(X)
wcss.append(kmeans.inertia_)
# Для выбора оптимального количества кластеров используем метод «локтя»
plt.plot(range(1,11), wcss)
plt.title('The elbow method')
plt.xlabel('Number of Clusters')
plt.ylabel('WCSS')
plt.show()
kmeans=KMeans(n_clusters=4, init='k-means++', random_state=0)
y_kmeans=kmeans.fit_predict(X)
cdf['cluster']=y_kmeans
cdf1=cdf[cdf.cluster==0]
cdf2=cdf[cdf.cluster==1]
cdf3=cdf[cdf.cluster==2]
cdf4=cdf[cdf.cluster==3]
plt.figure(figsize=(10,10))
plt.scatter(cdf1['PURCHASES'], cdf1["PAYMENTS"], color='green')
plt.scatter(cdf2['PURCHASES'], cdf2["PAYMENTS"], color='red')
plt.scatter(cdf3['PURCHASES'], cdf3["PAYMENTS"], color='orange')
plt.scatter(cdf4['PURCHASES'], cdf4["PAYMENTS"], color='blue')
plt.xlabel("Purchases")
plt.ylabel("Payments")
plt.legend()
Как видите, наша модель разделила клиентов на 4 кластера. В аудите такое разделение может быть использовано для выявления необычных групп или кластеров клиентов, которые могут иметь потенциальные риски.
Использование компьютерного зрения
Компьютерное зрение открывает новые возможности для повышения точности аудиторской работы, её облегчения, а также повышения эффективности. Аудиторы используют компьютерное зрение для анализа фотографий, видео с камер; оно может помочь в определении типа документа, извлечении из него какой-либо информации, проверке на соответствие определенным стандартам.
Рассмотрим следующий пример: возьмём с Kaggle набор Handwritten Signature Identification, в нём есть изображения подписей. Перед нами стоит задача их верификации и идентификации. То есть нам следует проверить, является ли подпись подлинной для конкретного человека, а также нужно определить, кто является автором подписи.
# Импортируем библиотеки
import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt
import pathlib
import cv2
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
import warnings
warnings.filterwarnings('ignore')
os.environ["KMP_WARNINGS"] = "FALSE"
TRAIN_PATH = pathlib.Path("Train")
VAL_PATH = pathlib.Path("Test")
img = cv2.imread("Train/PersonA/Copy of personA_1.png")
plt.imshow(img)
img.shape
num_classes = 5 # имеется 5 человек: A,B,C,D,E
img_height = 224
img_width = 224
from tensorflow.keras.applications import MobileNetV3Large
from tensorflow.keras.applications.mobilenet import preprocess_input
from tensorflow.keras.preprocessing import image
Загрузим данные с помощью DataGen и предварительно обработаем их.
BATCH_SIZE = 32
IMAGE_SIZE = (img_height, img_width)
train_data_generator = image.ImageDataGenerator(
horizontal_flip=True,
preprocessing_function=preprocess_input
)
test_data_generator = image.ImageDataGenerator(
preprocessing_function=preprocess_input)
train_generator = train_data_generator.flow_from_directory
(directory= TRAIN_PATH,
target_size=IMAGE_SIZE,
color_mode= 'rgb',
class_mode= 'categocal',
batch_size= BATCH_SIZE)
val_generator = test_data_generator.flow_from_directory
(directory= VAL_PATH,
target_size=IMAGE_SIZE,
color_mode= 'rgb',
class_mode= 'categorical',
batch_size= BATCH_SIZE)
Мы будем использовать модель MobileNetv3, предварительно обученную на ImageNet, в качестве задачи трансферного обучения с оптимизатором Adam.
base = MobileNetV3Large(weights='imagenet', include_top=False)
base.trainable = False
model = Sequential([
base,
layers.GlobalAveragePooling2D(),
layers.Dense(256, activation='relu'),
layers.Dropout(0.1),
layers.Dense(128, activation='relu'),
layers.Dense(num_classes, activation = 'softmax')
])
model.compile(
optimizer="adam",
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
Начинаем обучение на 10 эпохах. Эпоха (Epoch) — количество повторений циклов обучения для всей выборки данных.
# Импортируем библиотеку time, чтобы измерить время обучения модели
import time
start = time.time()
history = model.fit_generator(train_generator, validation_data=val_generator, epochs=10)
print("Total time: ", time.time() - start, "seconds")
Визуализация потерь и точности
Точность — доля правильных предсказаний модели.
Потери — расхождение между предсказанными и истинными значениями.
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
plt.style.use('ggplot')
# Отрисовываем график изменения точности
plt.figure(figsize=(8, 8))
plt.subplot(2, 1, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.ylabel('Accuracy')
plt.title('Training and Validation Accuracy')
# Отрисовываем график изменения потерь
plt.subplot(2, 1, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.ylabel('Cross Entropy')
plt.title('Training and Validation Loss')
plt.xlabel('epoch')
plt.show()
model.save('MobileNetV3Large.h5')
На этих графиках видно, как изменяется точность и потери в зависимости от количества эпох. Можно сделать вывод, что после обучения на 8 эпохах наша модель работает с максимальной точностью и минимальными потерями.
Протестируем её на случайном изображении из тестового набора.
from keras.preprocessing import image
from tensorflow.keras.utils import load_img
# Загружаем изображение
img = load_img("/kaggle/input/signature-verification-and-identification/Test/PersonE/Copy of personE_22.png",target_size=(224,224))
img = np.asarray(img)
plt.imshow(img)
img = np.expand_dims(img, axis=0)
img= preprocess_input(img)
output = saved_model.predict(img)
print(output)
if np.argmax(output) == 0 :
print("PersonA")
elif np.argmax(output) == 1 :
print("PersonB")
elif np.argmax(output) == 2 :
print("PersonC")
elif np.argmax(output) == 3 :
print("PersonD")
elif np.argmax(output) == 4 :
print("PersonE")
Результат:
1/1 [==============================] - 1s 1s/step
[[4.0784580e-06 1.9883872e-04 1.6808448e-05 5.4550100e-08 9.9978024e-01]]
PersonE
В итоге наша модель определила, чья это подпись, что наглядно демонстрирует, как компьютерное зрение может применяться в аудите.
Преимущества и риски, связанные с машинным обучением
Применение машинного обучения в аудите может дать следующие преимущества:
Автоматизация и повышение эффективности: машинное обучение позволяет автоматизировать рутинные задачи аудита, такие как анализ больших объёмов данных, обнаружение аномалий и классификацию транзакций. Это может значительно ускорить работу и освободить аудиторов от монотонных задач.
Улучшение точности и качества: машинное обучение позволяет анализировать данные с точностью и скоростью, недоступными для человека. Алгоритмы могут обнаруживать скрытые закономерности и зависимости в данных, что способствует выявлению потенциальных ошибок, мошенничества и неправильных действий.
Улучшенное прогнозирование и предсказание: машинное обучение может помочь в прогнозировании будущих тенденций, рисков и результатов аудита на основе исторических данных и моделей. Это позволяет аудиторам принимать основанные на данных решения и предупреждать о потенциальных проблемах или рисках заранее.
Но применение машинного обучения в аудите также сопряжено с некоторыми рисками:
Неправильные результаты: некорректное обучение моделей машинного обучения или использование неподходящих алгоритмов может привести к неверным результатам и выводам. Неправильные предсказания или классификация могут повлечь за собой неправильные решения и потенциальные упущения в аудите.
Неадекватные данные: качество и надежность результатов машинного обучения зависит от доступности и качества данных. Недостаточные или искажённые данные могут привести к неправильным выводам и ошибочным результатам анализа.
Сложность интерпретации: некоторые модели машинного обучения, такие как нейронные сети или ансамбли моделей, могут быть сложными для интерпретации и объяснения результатов. Это может создать трудности в объяснении выводов аудиторской работы и прозрачности процесса.
Зависимость от технической экспертизы: применение машинного обучения требует наличия специалистов по данным и машинному обучению в аудиторских командах. Недостаток необходимых знаний и навыков может ограничить возможности использования машинного обучения в аудите.
В целом, применение машинного обучения в аудите может дать значительные преимущества, но требует осторожного подхода, правильного подбора моделей и алгоритмов, а также надлежащего учёта рисков и нюансов, связанных с данными и интерпретацией результатов.
Итог
Подытожить можно так: ML — довольно перспективное направление, которое может значительно улучшить эффективность и точность аудиторской работы, но важно подходить к использованию ML с осторожностью, учитывая особенности каждой конкретной ситуации.