ZICONG

梓聪的个人主页

0%

Sklearn机器学习:朴素贝叶斯(极简)

特点

  • 通常适用于维度非常高的数据集
  • 运行速度快,可调参数少,因此非常适合为分类问题提供快速粗糙的基本方案

依赖

# import required packages
%matplotlib inline

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB

file_path = '../big_data2/datasets/FlightDelays.csv'

贝叶斯分类

贝叶斯定理

确定一个具有某些特征($F$)的样本属于某类标签($L$)的后验概率

$$
\begin{align}
P(L_c|F_i) &= \frac{P(F_i|L_c)P(L_c)}{P(F_i)} \
&= \frac{P(F_i|L_c)P(L_c)}{\sum_c P(L_c)P(F_i|L_c)}
\end{align}
$$

其中,$P(L_c)$的值可以用样本中标签$L_c$的频次来估计。

用一种模型计算每个标签的$P(F_i|L_c)$,这种模型被称为生成模型。每种标签设置生成模型是贝叶斯分类训练过程的主要过程。

朴素贝叶斯方法

假设每项分类中,数据项的变量之间时独立的:因此可以使用乘法法则

$$
\begin{align}
P(F_i|L_c) = \Pi_j P(F_i^{(j)} = f_i^{(j)} | L_c)
\end{align}
$$

其中,$j$ 表示第$i$种特征(组合)中第 $j$个 特征。

在训练模型时,我们需要得到对每个标签(共$C$种)对每种特征组合(记为共$I$种)的条件概率$P(F_i|L_c)$。假设有$J$个特征,每个特征有$N_j$种可能的取值,则需要估计的参数(先验概率)有:

$$
\begin{align}
C \times I = C \times \Pi^J N_j
\end{align}
$$

朴素贝叶斯的模型训练

如上文所述,朴素贝叶斯的模型训练过程就是估计条件概率$P(F_i|L_c)$的过程。

具体来说,我们可以假定某个标签中的各个特征取值的生成服从某种分布$X(\Theta)$,其中$\Theta$是该分布的参数。然后我们可以从这个分布推出该特征不同取值的条件概率,在模型的训练阶段,这个推出来的先验概率是含有参数的。利用这个先验概率以及全概率公式可以计算出数据取观察到的值的似然率

$$
\begin{align}
P(F_i) = \sum_c P(L_c)P(F_i|L_c)
\end{align}
$$

利用某种方式,将所有数据项的似然率综合成整个样本的似然率,比如假设不同数据项之间的独立同分布的:

$$
\begin{align}
P(F) = \Pi_i P(F_i)
\end{align}
$$

利用最大似然估计的思想,求让这个$P(F)$最大化的参数的值。核心思想是假设我们所能观察到的往往是概率最大的。

朴素贝叶斯的模型预测

上文求出了不同标签下特征的分布的参数。利用此参数,可以从分布中推出条件概率$P(F_i|L_c)$。利用贝叶斯公式,可以计算出取某种特征$F_i$的样本属于标签$L_c$中的概率$P(L_c|F_i)$。假设有4个分类$c=1,2,3,4$,则我们需要计算出$F_i$对应4个标签的条件概率。从贝叶斯公式可以看出,四个计算的分子是一样的:$P(F_i)$,所以只需要计算它对应每种标签的分子部分,比较其大小,即可决定其分类:

$$
\begin{align}
P(F_i|L_c)P(L_c)
\end{align}
$$

例子:飞机延误

变量和导入数据

解释变量:

Day of week: ------------------- 1 = Monday, ..., 7 = Sunday
Scheduled departure time: ------ 分为从 6:00am 到 10:00pm 的18个区间
Origin: ------------------------ 出发机场代码
Destination: ------------------- 到达机场代码
Carrier: ----------------------- 航空公司代码

被解释变量:

Delay:-------------------------- 无延误(0)和延误(1)
delays_df = pd.read_csv(file_path)

delays_df

CRS_DEP_TIME CARRIER DEP_TIME DEST DISTANCE FL_DATE FL_NUM ORIGIN Weather DAY_WEEK DAY_OF_MONTH TAIL_NUM Flight Status
0 1455 OH 1455 JFK 184 01/01/2004 5935 BWI 0 4 1 N940CA ontime
1 1640 DH 1640 JFK 213 01/01/2004 6155 DCA 0 4 1 N405FJ ontime
2 1245 DH 1245 LGA 229 01/01/2004 7208 IAD 0 4 1 N695BR ontime
3 1715 DH 1709 LGA 229 01/01/2004 7215 IAD 0 4 1 N662BR ontime
4 1039 DH 1035 LGA 229 01/01/2004 7792 IAD 0 4 1 N698BR ontime
... ... ... ... ... ... ... ... ... ... ... ... ... ...
2196 645 RU 644 EWR 199 1/31/2004 2761 DCA 0 6 31 N15555 ontime
2197 1700 RU 1653 EWR 213 1/31/2004 2497 IAD 0 6 31 N16976 ontime
2198 1600 RU 1558 EWR 199 1/31/2004 2361 DCA 0 6 31 N14902 ontime
2199 1359 RU 1403 EWR 199 1/31/2004 2216 DCA 0 6 31 N16961 ontime
2200 1730 RU 1736 EWR 199 1/31/2004 2097 DCA 0 6 31 N13994 ontime

2201 rows × 13 columns

转换数据

将日期和飞行状态(ontime, delay)转换为分类变量(categoric variable).

# convert to categorical

delays_df['DAY_WEEK'] = delays_df['DAY_WEEK'].astype('category')
delays_df['Flight Status'] = delays_df['Flight Status'].astype('category')

离散化:将出发时间归类为不同的小时。

# create hourly bins departure time

delays_df['CRS_DEP_TIME'] = [(t // 100) for t in delays_df['CRS_DEP_TIME']]

delays_df['CRS_DEP_TIME'] = delays_df['CRS_DEP_TIME'].astype('category')

提取出解释变量和被解释变量向量

predictors = ['DAY_WEEK', 'CRS_DEP_TIME', 'ORIGIN', 'DEST', 'CARRIER']
outcome = 'Flight Status'

x = pd.get_dummies(delays_df[predictors])   # 对分类变量产生对应的0/1变量(组)
x.columns
Index(['DAY_WEEK_1', 'DAY_WEEK_2', 'DAY_WEEK_3', 'DAY_WEEK_4', 'DAY_WEEK_5',
       'DAY_WEEK_6', 'DAY_WEEK_7', 'CRS_DEP_TIME_6', 'CRS_DEP_TIME_7',
       'CRS_DEP_TIME_8', 'CRS_DEP_TIME_9', 'CRS_DEP_TIME_10',
       'CRS_DEP_TIME_11', 'CRS_DEP_TIME_12', 'CRS_DEP_TIME_13',
       'CRS_DEP_TIME_14', 'CRS_DEP_TIME_15', 'CRS_DEP_TIME_16',
       'CRS_DEP_TIME_17', 'CRS_DEP_TIME_18', 'CRS_DEP_TIME_19',
       'CRS_DEP_TIME_20', 'CRS_DEP_TIME_21', 'ORIGIN_BWI', 'ORIGIN_DCA',
       'ORIGIN_IAD', 'DEST_EWR', 'DEST_JFK', 'DEST_LGA', 'CARRIER_CO',
       'CARRIER_DH', 'CARRIER_DL', 'CARRIER_MQ', 'CARRIER_OH', 'CARRIER_RU',
       'CARRIER_UA', 'CARRIER_US'],
      dtype='object')
y = delays_df[outcome].astype('category')  # 不需要get_dummies因为本身就是0/1的分类变量

划分训练集和测试集

test_frac = 0.4

x_train, x_valid, y_train, y_valid = train_test_split(x, y, test_size=test_frac)

多项式朴素贝叶斯

训练模型:

# run naive Bayes
delays_nb = MultinomialNB(alpha=0.01)
delays_nb.fit(x_train, y_train)
MultinomialNB(alpha=0.01)

这是多项式分布朴素贝叶斯。它假设每个标签中,特征取某个值的数量服从多项式分布。它非常适合用于描述出现次数或者出现次数比例的特征。

$\alpha$是一个平滑参数。当训练量不足的时候,有些特征的取值可能没在训练集出现过,其概率将被当成是0,带来不合理的问题。平滑参数是用来解决这个问题的。具体细节将另文详述。

预测训练集/测试集中不延迟/延迟的概率:

# predict probabilities
pred_prob_train = delays_nb.predict_proba(x_train)
pred_prob_valid = delays_nb.predict_proba(x_valid)

预测训练集/测试集中的分类:

# predict class membership
pred_train = delays_nb.predict(x_train)
pred_valid = delays_nb.predict(x_valid)

# membership of valid set
pred_valid_df = delays_df.iloc[x_valid.index].copy()
pred_valid_df['Flight Status Pred'] = pred_valid
pred_valid_df

CRS_DEP_TIME CARRIER DEP_TIME DEST DISTANCE FL_DATE FL_NUM ORIGIN Weather DAY_WEEK DAY_OF_MONTH TAIL_NUM Flight Status Flight Status Pred
1263 8 RU 841 EWR 213 1/18/2004 2254 IAD 0 7 18 N13929 ontime ontime
641 14 OH 1455 JFK 184 01/10/2004 5935 BWI 0 6 10 N805CA ontime ontime
2093 16 DL 1632 LGA 214 1/30/2004 1760 DCA 0 5 30 N225DL ontime ontime
1252 13 RU 1314 EWR 169 1/18/2004 2703 BWI 0 7 18 N15980 delayed ontime
2068 16 DH 1640 JFK 213 1/30/2004 6155 DCA 0 5 30 N409FJ ontime ontime
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1849 7 CO 750 EWR 199 1/26/2004 806 DCA 1 1 26 N13624 delayed ontime
2052 12 DH 1237 EWR 213 1/29/2004 7303 IAD 0 4 29 N701BR ontime ontime
1169 17 DH 1720 JFK 228 1/17/2004 7812 IAD 0 6 17 N313UE delayed ontime
1692 21 DH 2125 JFK 228 1/24/2004 7814 IAD 0 6 24 N628BR ontime ontime
622 13 CO 1258 EWR 199 01/09/2004 808 DCA 0 5 9 N14664 ontime ontime

881 rows × 14 columns

预测效果

训练集的预测效果:

classificationSummary(y_train, pred_train, class_names = ['ontime', 'delay'])
Confusion Matrix (Accuracy 0.7833)

       Prediction
Actual ontime  delay
ontime     38    230
 delay     56    996

测试集的预测效果:

classificationSummary(y_valid, pred_valid, class_names = ['ontime', 'delay'])
Confusion Matrix (Accuracy 0.7980)

       Prediction
Actual ontime  delay
ontime     19    141
 delay     37    684