Данные Наука Стилистика

Стилистические различия между R и Python при моделировании данных с помощью классификатора N aïve Bayes

Как использовать R и Python для прогнозирования вероятности события, основываясь на предварительных знаниях условий, которые к нему относятся

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

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

1. Теорема Байеса

В науке о данных теорема Байеса применяется для обновления наших знаний о конкретных параметрах данных путем объединения наших предыдущих знаний (называемых априорным распределением) с новой информацией, полученной из наблюдаемых данных. Это приводит к обновленным знаниям о параметрах, также называемым апостериорным распределением.

Основная формула для объяснения теоремы рассматривает два события. В науке о данных два события могут быть типами переменных (предикторы и цель). Мы можем рассматривать набор данных, состоящий из двух предикторов (X * = X1, X2), а переменная ответа Y может состоять из нескольких классов (y1, y2, y3…). С помощью теоремы Байеса мы можем определить, какой класс наиболее вероятен для конкретной комбинации переменных-предикторов.

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

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

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

2. Наивная теорема Байеса в Python

Отправной точкой в ​​Python для применения теоремы Байеса является загрузка соответствующих библиотек, среди которых полиномиальный наивный байесовский классификатор с именем MultinomialNB, который подходит для классификации с дискретными функциями (например, подсчетом слов для классификации текста) .

import pandas as pd
import numpy as np
from sklearn.naive_bayes import MultinomialNB
import statsmodels.tools.tools as stattools

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

df = pd.DataFrame(np.random.randint(0,1000,size=(1000,1)), columns= ['AidMillion'])
category = pd.cut(df.AidMillion,bins=[0,500,1000],labels=['Below_500_Mill','Above_500_Mill'])
df.insert(2,'Aid_Given',category)
df.Aid_Given = df.Aid_Given.tolist()
df["TypeShock"] = np.random.choice(TypeShock, p=[0.40, 0.30, 0.30], size=len(df))
Location = (['Urban','Rural'])
df["Location"] = np.random.choice(Location, size=len(df))
df.head()

Чтобы продолжить анализ в Python, нам потребуется рассмотреть один тестовый и один обучающий фреймы данных. Можно либо разделить основной фрейм данных, либо выбрать другой источник информации с теми же переменными. В этом случае разделение основного фрейма данных может быть выполнено с помощью команды train_test_split. Кроме того, мы можем получить предельную и условную вероятность предикторов через pd.crosstab в случае, если намерение состоит в том, чтобы выполнить вычисление Байеса вручную.

df_train, df_test=train_test_split(df, test_size=0.40, random_state=8)
t1=pd.crosstab(df_train['Aid_Given'], df_train['TypeShock'])
t1['Total']=t1.sum(axis=1)
t1.loc['Total']=t1.sum()
t1
t2=pd.crosstab(df_train['Aid_Given'], df_train['Location'])
t2['Total']=t2.sum(axis=1)
t2.loc['Total']=t2.sum()
t2

Чтобы применить алгоритм Байеса в Python, нам нужно преобразовать каждый предиктор в фиктивный. Это можно сделать, используя команду stattools.categorical для каждой переменной (тип удара, местоположение), необходимую для объяснения целевой переменной и объединения их в фрейм данных с помощью command pd.concat.

x_loc_ind= np.array(df_train['Location'])
(x_loc_ind, x_loc_dict)= stattools.categorical(x_loc_ind, drop= True, dictnames=True)
x_loc_ind= pd.DataFrame(x_loc_ind)
x_shock_ind= np.array(df_train['TypeShock'])
(x_shock_ind, x_shock_dict)= stattools.categorical(x_shock_ind, drop=True, dictnames= True)
x_shock_ind=pd.DataFrame(x_shock_ind)
X=pd.concat((x_loc_ind, x_shock_ind), axis=1)
X.head()

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

Y= df_train['Aid_Given']
Bayes_01=MultinomialNB().fit(X,Y)

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

x_loc_ind_test= np.array(df_test['Location'])
(x_loc_ind_test, x_loc_dict_test)= stattools.categorical(x_loc_ind_test, drop=True, dictnames= True)
x_loc_ind_test= pd.DataFrame(x_loc_ind_test)
x_shock_ind_test= np.array(df_test['TypeShock'])
(x_shock_ind_test, x_shock_dict_test)= stattools.categorical(x_shock_ind_test, drop= True, dictnames= True)
x_shock_ind_test=pd.DataFrame(x_shock_ind_test)
X_test= pd.concat((x_loc_ind_test, x_shock_ind_test), axis=1)
Y_predicted= Bayes_01.predict(X_test)

После использования команды predict для байесовского объекта (названного Bayes_01 в этом примере) мы, наконец, можем создать таблицу непредвиденных обстоятельств для фактических и прогнозируемых целевых классов (выше и ниже 500 миллионов), которая может помочь нам понять точность нашей модели.

ypred = pd.crosstab(df_test['Aid_Given'], Y_predicted, rownames=['Actual'], colnames=['Predicted'])
ypred['Total'] = ypred.sum(axis=1); ypred.loc['Total']=ypred.sum(); ypred

Чтобы проверить уровень точности в Python, мы можем просто просуммировать, насколько часто фактические записи соответствуют прогнозируемым по общему количеству записей в тестовом наборе данных. В глобальном масштабе модель является точной только в 51% случаев, что означает, что только в 1 из 2 случаев прогноз будет правильным. Модель работает лучше при прогнозировании класса Above_500_Mill, чем базовая модель (58,3% против 48%), в то время как она работает хуже, чем базовая модель для прогнозирования класса Lower_500_Mill (44,3% против 48%).

PerformanceGlobal=(112+92)/400
PerformanceAbove500=(112/192)
PerformanceBelow500=(92/208)
PerformanceGlobal, PerformanceAbove500, PerformanceBelow500

3. Наивная теорема Байеса в R

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

df <- data.frame(replicate(1,sample(0:1000, 1000, rep=TRUE)))
colnames(df) <- c("AidMillion")
df$Aid_Given <- ifelse(df$AidMillion <= 500, "Above_500_Mill", "Below_500_Mill")
df$TypeShock <- sample(c('Draught','Floods','Famine'), size = nrow(df), replace = TRUE)
df$Location <- sample(c('Urban','Rural'), size = nrow(df), replace = TRUE)
df$Aid_Given <- as.factor(df$Aid_Given)
head(df)

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

set.seed(8)
n<- dim(df)[1]
train_df<-runif(n)<0.60
df_train<- df[train_df, ]
df_test<- df[!train_df, ]

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

t1<- table(df_train$Aid_Given, df_train$TypeShock) 
colnames(t1)<- c("Draught","Floods","Famine")
rownames(t1)<- c("Above_500_Mill","Below_500_Mill")
addmargins(A=t1, FUN=list(Total=sum), quiet=TRUE)
t2<- table(df_train$Aid_Given, df_train$Location) 
colnames(t2)<- c("Urban","Rural")
rownames(t2)<- c("Above_500_Mill","Below_500_Mill")
addmargins(A=t2, FUN=list(Total=sum), quiet=TRUE)

После того, как мы создали таблицы непредвиденных обстоятельств, следующим шагом в R является применение алгоритма Байеса через библиотеку e1071. Команда naiveBayes дает гораздо больше информации о априорной и условной вероятности, чем ее эквивалент в Python. Еще одно стилистическое различие между ними - явная спецификация формулы, объясняющей взаимосвязь между предикторами и целевыми переменными внутри команды Байеса.

library(e1071)
Bayes01 <- naiveBayes(formula= Aid_Given~ TypeShock+ Location, data=df_train)
Bayes01

Последним шагом в R является применение предсказанных классов целевых переменных, сгенерированных в объекте Bayes01, к набору тестовых данных с помощью команды predict, которая генерирует окончательную таблицу непредвиденных обстоятельств. . Как и для предыдущих таблиц, нам нужно определить rownames, colnames и поля, чтобы создать читаемую таблицу. Это ключевое стилистическое отличие от Python.

ypred <- predict(object=Bayes01, newdata=df_test)
test.preds <- table (df_test$Aid_Given, ypred)
rownames(test.preds)<- c("Actual:Above_500_Mill","Actual:Below_500_Mill")
colnames(test.preds)<- c("Predicted:Above_500_Mill","Predicted:Below_500_Mill")
addmargins(A=test.preds, FUN=list(Total=sum), quiet=TRUE)

После создания таблицы непредвиденных обстоятельств мы можем оценить производительность модели по сравнению с базовыми значениями, указанными в априорных вычислениях. В глобальном масштабе модель точна в 50,4% случаев, что означает, что только в 1 из 2 случаев прогноз будет правильным, как в нашем предыдущем примере. Модель работает лучше при прогнозировании класса Lower_500_Mill по сравнению с базовым (51,8% против 46,5%), в то время как она работает немного хуже, чем базовая модель для прогнозирования класса Above_500_Mill (49,62% против 53,4%).

PerformanceGlobal=(131+71)/401
PerformanceAbove500=131/264
PerformanceBelow500=71/137
PerformanceGlobal; PerformanceAbove500; PerformanceBelow500

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

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