В Части 1 этой статьи мы обсудили две важные концепции полевого тестирования, такие как тестирование стабильности и A/B-тестирование.

в этой статье мы предоставим то же самое на Python.

В первой части этой статьи есть код, касающийся тестирования стабильности модели ИИ (подход к бэк-тестированию), а во второй части этой статьи упоминается реализация A/B-тестирования.

  1. Тестирование модели ИИ на стабильность

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

Шаг 1. Импортируйте все необходимые библиотеки Python.

import pandas as pd
import numpy as np
from datetime import timedelta
from datetime import datetime
from dateutil. relativedelta import relativedelta
from sklearn.metrics import confusion_matrix, classification_report,accuracy_score,precision_score,recall_score,f1_score
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from tensorflow.keras.backend import epsilon

Шаг 2. Загрузите данные и выполните их обработку.

Чтобы продемонстрировать пример использования тестирования стабильности, были использованы синтетически сгенерированные данные для понимания характера дохода (1 — высокий, а 0 — низкий) на основе драйверов функций, используемых в наборе данных.

modelDF = pd.read_csv("Back_Testing_Sample.csv")
# Converting the column from object to datetime format 
modelDF['Baseline_Date']=pd.to_datetime(modelDF['Baseline_Date'].astype(str), format='%Y-%m-%d') 
# Select only the required feature drivers 
filterGroupDF =  modelDF.copy() 
selected_features = ['Baseline_Date', 'Amount', 'RPM', 'Marketing Spend', 'Paper Advertising Spend', 'Digital or not', 'TV Advertising Spend', 'Revenue', 'Revenue_Response'] 
filterGroupDF = filterGroupDF[selected_features]
filterGroupDF.head()

Шаг 3: Определите функции полезности, чтобы вернуть параметры матрицы путаницы и пометить целевую переменную на основе порога вероятности.

# Computing TP, FP, TN and FN
# TP: True Positive
# FP: False Positive
# TN: True Negative
# FN: False Negative
def confusion_metrics(y_test, y_pred):
    TP = 0
    TN = 0
    FP = 0
    FN = 0
CM = confusion_matrix(y_test,y_pred)
    TN = CM[0][0]
    FP = CM[0][1]
    FN = CM[1][0]
    TP = CM[1][1]
    return (TP, FP, TN, FN)
# Function to create y_pred using y_pred_prob & thresholds
def create_y_pred(y_pred_prob, thresh):
    y_pred_list = []
    for i in range(len(y_pred_prob)):
        y_pred = 1 if y_pred_prob[i] > thresh else 0
        y_pred_list.append(y_pred)
    return y_pred_list

Существует шесть переменных, которые вы должны определить на основе данных и размера окна в зависимости от требований.

windowStartDate = datetime.strptime('2019-07-01', '%Y-%m-%d')
windowEndDate = datetime.strptime('2020-07-01', '%Y-%m-%d')
trainWindowSize = 4
testWindowSize = 4
slideWindowSize = 1

Примечание. Параметр number_iterations должен быть получен на основе общего окна данных и размера скользящего окна. Следующее изображение иллюстрирует то же самое

Case 1:
trainWindowSize = 4
testWindowSize = 4
slideWindowSize = 1

number_iterations будет 4

Case 2:
trainWindowSize = 4
testWindowSize = 4
slideWindowSize = 2

number_iterations будет 2

# Define thresholds in a list to iterate for each threshold
threshold_list = [0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9]
for threshold in threshold_list:
    WindowStartDate = datetime.strptime('2019-07-01', '%Y-%m-%d')
    WindowEndDate = datetime.strptime('2020-07-01', '%Y-%m-%d')
    trainWindowSize = 4
    testWindowSize = 4
    slideWindowSize = 1
    Number_iterations = 4
    back_testing_df = pd.DataFrame(columns = ['Iteration','Probability_Threshold','Train_Starte_Date','Train_End_Date','Test_Start_Date','Test_End_Date','Train_Sample_Size','Test_Sample_Size','TP','TN','FP','FN','Recall','Precision','Accuracy','F-Score'], index = range(Number_iterations))
for i in range(Number_iterations):
        trainStartDate = WindowStartDate
        trainEndDate = trainStartDate + relativedelta(months=trainWindowSize)
        testStartDate = trainEndDate
        testEndDate = testStartDate + relativedelta(months=testWindowSize)
if(testEndDate>WindowEndDate):
            break
trainDF = filterGroupDF[(filterGroupDF['Date']>=trainStartDate)  & (filterGroupDF['Date']<trainEndDate)]
        testDF = filterGroupDF[(filterGroupDF['Date']>=testStartDate) & (filterGroupDF['Date']<testEndDate)]
X_train_stage_1 = trainDF.drop(['Date','Revenue_Response'], axis=1)
        y_train_stage_1 = trainDF['Revenue_Response']
X_test_stage_1 = testDF.drop(['Date','Revenue_Response'], axis=1)
        y_test_stage_1 = testDF['Revenue_Response']
clf = RandomForestClassifier(max_depth=8, max_features='auto', min_samples_leaf=4, n_estimators=500,random_state=41)
clf.fit(X_train_stage_1,y_train_stage_1)
        y_pred_test = clf.predict(X_test_stage_1)
        y_pred_proba = clf.predict_proba(X_test_stage_1)
back_testing_df['Iteration'][i] = i+1
        back_testing_df['Probability_Threshold'][i] = threshold
        back_testing_df['Train_Starte_Date'][i] = trainStartDate
        back_testing_df['Train_End_Date'][i] = trainEndDate + timedelta(days=-1)
        back_testing_df['Test_Start_Date'][i] = testStartDate
        back_testing_df['Test_End_Date'][i] = testEndDate + timedelta(days=-1)
        back_testing_df['Train_Sample_Size'][i] = X_train_stage_1.shape[0]
        back_testing_df['Test_Sample_Size'][i] = X_test_stage_1.shape[0]
        y_pred_prob = np.array(y_pred_proba[:,-1])
        y_pred_thresh = create_y_pred(y_pred_prob, threshold)
        TP, FP, TN, FN = confusion_metrics(y_test_stage_1, y_pred_thresh)
        back_testing_df['TP'][i] = TP
        back_testing_df['TN'][i] = TN
        back_testing_df['FP'][i] = FP
        back_testing_df['FN'][i] = FN
        back_testing_df['Recall'][i] = TP/(TP + FN + epsilon())
        back_testing_df['Precision'][i] = TP/(TP + FP + epsilon())
        back_testing_df['Accuracy'][i] = float((TP + TN)/(TP + TN + FP + FN + epsilon()))
        back_testing_df['F-Score'][i] = 2*back_testing_df['Precision'][i]*back_testing_df['Recall'][i]/(back_testing_df['Precision'][i] + back_testing_df['Recall'][i] + epsilon())
# Update the Window start date based on the sliding window size
        WindowStartDate = WindowStartDate + relativedelta(months=slideWindowSize)
print(back_testing_df.head(20))

Здесь показатели производительности для порога вероятности 0,5 указывают на то, что точность неодинакова в разных окнах тестирования, что ясно указывает на необходимость улучшения модели ИИ.

2. A/B-тестирование

Как мы упоминали в Части 1 этой статьи, для проведения A/B-тестирования мы должны разделить результат ИИ на тестовую и контрольную группы, и они должны быть схожими по своему характеру, потому что результаты ИИ следует сравнивать в одинаковых условиях для эффективного A/B-тестирования. Б тестирование.

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

Шаг 1. Импортируйте все необходимые библиотеки Python.

import pandas as pd
import numpy as np

Шаг 2: Загрузите данные и выполните обработку данных

df = pd.read_csv("Back_Testing_Sample.csv")
df.head()

Здесь столбец идентификатора является синонимом любой нечисловой (категориальной) переменной, такой как бизнес-единица, подразделение, регион и т. д.

Шаг 3:

## Stratify sampling
list_pk=list(df['ID'].unique())
def stratified_sample(df,perc):
    df_final=pd.DataFrame()
    for i in list_pk:
        df_stratified = df[df['ID']==i]
        if len(df_stratified)>1:
            df_stratified = df_stratified.sample(frac=perc)
        df_final=df_final.append(df_stratified)
    
    return df_final
test_data=stratified_sample(df=df,perc=0.5)
df=df.reset_index()
test_data=test_data.reset_index()
control_data=df[~df['index'].isin(list(test_data['index']))]
control_data=control_data.reset_index()
print(control_data.shape,test_data.shape,df.shape)
test_data['ID'].value_counts()
control_data['ID'].value_counts()

Предположения:

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

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

Об авторах

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

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

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