一、項目簡介
Credit Card Fraud Detection是一個典型的分類問題,欺詐分類的比例比較小,直接使用分類模型容易忽略。在實(shí)際應(yīng)用場景下往往是保證一定準(zhǔn)確率的情況下盡量提高召回率。一個典型案例是汽車制造行業(yè),一旦發(fā)生一例汽車安全故障,同批次的車輛需要全部召回,造成了巨大的經(jīng)濟(jì)損失。
二、數(shù)據(jù)印象
詳細(xì)分析過程見在線腳本。
2.1. 簡單數(shù)據(jù)分析
數(shù)據(jù)規(guī)模:中度規(guī)模(對于mac而言)。數(shù)據(jù)共284807條,后期算法選擇需要注意復(fù)雜度。
數(shù)據(jù)特征:V1~V28是PCA的結(jié)果,而且進(jìn)行了規(guī)范化,可以做一些統(tǒng)計上的特征學(xué)習(xí);Amount字段和Time字段可以進(jìn)行額外的統(tǒng)計學(xué)和bucket統(tǒng)計。
數(shù)據(jù)質(zhì)量:無缺失值,數(shù)據(jù)規(guī)整,享受啊。
經(jīng)驗(yàn):時間字段最好可以處理為月份、小時和日期,直接的秒數(shù)字段往往無意義。
2.2. 探索性數(shù)據(jù)分析
三、數(shù)據(jù)預(yù)處理
數(shù)據(jù)已經(jīng)十分規(guī)整了,所以先直接使用基礎(chǔ)模型來預(yù)測下數(shù)據(jù)。
from sklearn.linear_model import LogisticRegression
from sklearn.cross_validation import cross_val_score
from sklearn.model_selection import StratifiedShuffleSplit
from sklearn import metrics
def train_lr(X, y, plot_roc=False):
sss = StratifiedShuffleSplit(n_splits=10, test_size=0.2, random_state=10)
lr = None
for train_index, test_index in sss.split(X, y):
X_train, X_test = X.iloc[train_index], X.iloc[test_index]
y_train, y_test = y.iloc[train_index], y.iloc[test_index]
lr = LogisticRegression(C=0.01, penalty='l1')
lr.fit(X_train, y_train)
y_predict = lr.predict(X_test)
print "roc_auc:", metrics.roc_auc_score(y_test, y_predict)
print "f1score:", metrics.f1_score(y_test, y_predict)
print "precision:", metrics.precision_score(y_test, y_predict)
print "recall:", metrics.precision_score(y_test, y_predict)
print ""
if plot_roc:
fpr, tpr, thresholds = metrics.roc_curve(y_test, y_predict)
roc_auc = metrics.auc(fpr,tpr)
# Plot ROC
plt.title('Receiver Operating Characteristic')
plt.plot(fpr, tpr, 'b',label='AUC = %0.2f'% roc_auc)
plt.legend(loc='lower right')
plt.plot([0,1],[0,1],'r--')
plt.xlim([-0.1,1.0])
plt.ylim([-0.1,1.01])
return lr
lr = train_lr(X, y, plot_roc=False)
L1規(guī)劃化
L2規(guī)范化
Baseline基礎(chǔ)模型:采用線性模型,利用L1的稀疏性,precision和recall均可以達(dá)到0.85左右,roc_auc可以達(dá)到0.79左右。
由上圖可見:
- precision較大時波動波動比較大。recall大于0.8后,準(zhǔn)確率下滑嚴(yán)重。
- AUC面積是0.97,后來根據(jù)參考文獻(xiàn)3知,AUC大于0.92時之后比較難修正。
Baseline模型的評價metric:
- 收集更多的數(shù)據(jù),不適合這個場景。
- 改變評價標(biāo)準(zhǔn):
- 使用混淆矩陣計算準(zhǔn)確度和回收度。
- F1score
- Kappa
- ROC curves - sensitivity/specificity ratio
數(shù)據(jù)采樣處理
- 收集等多數(shù)據(jù):不適合這個場景。
- 過采樣Over-sampling:當(dāng)數(shù)據(jù)集較少時,主動添加少類別的數(shù)據(jù);SMOT算法通過插值來實(shí)現(xiàn)。不適合本數(shù)據(jù)集。容易過擬合,運(yùn)算時間長。
- 欠采樣Under-sampling:當(dāng)數(shù)據(jù)集足夠大時,刪除大類別的數(shù)據(jù);集成方法EasyEnsemble/BalanceCascade通過將反例放在不同學(xué)習(xí)器中使用,從全局看不會丟失重要信息。
本案例數(shù)據(jù)量中等:選用欠采樣+EasyEnsemble的方式進(jìn)行數(shù)據(jù)處理。
使用im-balanced生成測試數(shù)據(jù)。
from imblearn.ensemble import EasyEnsemble
n_subsets = X.size * 2 / (us_X.size) - 1
ee = EasyEnsemble(n_subsets=n_subsets)
sample_X, sample_y = ee.fit_sample(X, y)
四、模型印象
模型:
選用easy_ensemble模型來優(yōu)化。
具體實(shí)現(xiàn)代碼見在線腳本
核心adboost代碼如下:
def boost_data(X, y, weight):
size = y.shape[0]
index_list = np.linspace(0, size-1, size).astype(int)
train_index = np.random.choice(index_list, size, p=weight)
train_X = X[train_index, :]
train_y = y[train_index]
return train_X, train_y
def adboost(X, y, rounds):
ensemble = EnsembleModel(rounds)
# 初始化weight
size = y.shape[0]
weight = np.zeros(size)
weight[y == 1] = float(1) / sum(y == 1)
weight[y == 0] = float(1) / sum(y == 0)
weight /= sum(weight)
result = np.zeros(size)
for i in xrange(rounds):
train_X, train_y = boost_data(X, y, weight)
dt = DecisionTreeClassifier()
ensemble.trees[i] = dt
dt.fit(train_X, train_y)
y_predict = dt.predict(X)
# print "sum:", sum(y_predict != y)
train_error = sum(weight * (y_predict != y))
# print "train:", train_error
beta = (1 - train_error) / float(train_error)
ensemble.alpha[i] = 0.5 * np.log(beta)
weight *= np.exp(-ensemble.alpha[i] * (y -0.5) * (y - 0.5) * 4)
weight /= sum(weight)
ensemble.thresh = sum(ensemble.alpha) / 2
return ensemble
結(jié)果如下:
對比普通的adboost數(shù)據(jù)
由上圖可知,easy_ensemble提升了平滑度,但是AUC未有提升。
五、特征選擇和特征學(xué)習(xí)
- L1模型進(jìn)行了嵌入式的特征選擇,效果優(yōu)于L2模型。在尋找解釋性時會有幫助。
根據(jù)數(shù)據(jù)的統(tǒng)計特征,可以學(xué)習(xí)一些統(tǒng)計變量。
增加如下的特征。
new_X = X_train.copy()
new_X['V1_'] = new_X.V1.map(lambda x: 1 if x < -3 else 0)
new_X['V2_'] = new_X.V2.map(lambda x: 1 if x > 2.5 else 0)
new_X['V3_'] = new_X.V3.map(lambda x: 1 if x < -4 else 0)
new_X['V4_'] = new_X.V4.map(lambda x: 1 if x > 2.5 else 0)
六、分析結(jié)果
使用SNE分析(常用于非線性可視化分析)來觀看一次under_sample的結(jié)果。如下圖所示
由上圖可知兩種類別的數(shù)據(jù)是可以區(qū)分的,但是部分?jǐn)?shù)據(jù)融合在一起,當(dāng)追求recall較大時,將會誤判大量數(shù)據(jù)。
七、迭代問題
可以優(yōu)化的方向:
- 可以通過學(xué)習(xí)新的特征,將數(shù)據(jù)在新維度上拉開距離
- 在計算機(jī)能力允許的情況下,設(shè)置合適的round輪次來調(diào)參。
八、表述模型
- 根據(jù)模型的SNE圖和數(shù)據(jù)性可知,數(shù)據(jù)質(zhì)量是比較好的。
- easy_ensemble模型本身使用了adboost和bagging,每棵tree的復(fù)雜度不高,降低了bias;通過bagging,降低了variance。最終得到了較好的P-R圖和AUC值。
- 通過LR模型的稀疏性特征值,可以制作出一個解釋性報告。