特点
- 通常适用于维度非常高的数据集
- 运行速度快,可调参数少,因此非常适合为分类问题提供快速粗糙的基本方案
依赖
# 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