机器学习安然数据集分析报告
項目背景
安然曾是 2000 年美國最大的公司之一。輝煌時期,市值高達700億美元。2002 年,由于其存在大量的企業欺詐行為,這個昔日的大集團以極快的速度土崩瓦解。 在隨后聯邦進行的調查過程中,大量有代表性的保密信息進入了公眾的視線,包括成千上萬涉及高管的郵件和詳細的財務數據。 你將在此項目中扮演偵探,運用你的新技能,根據安然丑聞中公開的財務和郵件數據來構建相關人士識別符。利用機器學習算法進行數據分析,從郵件和財務數據中找出犯罪嫌疑人。
數據集初步探索
加載數據集
首先我們加載數據集
with open("final_project_dataset.pkl", "r") as data_file:data_dict = pickle.load(data_file)電子郵件和財務 (E+F) 數據字典被存儲在 pickle 文件中,該文件可直接存儲和加載 python 對象,非常方便。
數據集初步分析
分析發現我們讀取的數據數據實際上是以字典形式進行。隨機取一個字典,其存儲結構如下所示:
{METTS MARK:{'salary': 365788, 'to_messages': 807, 'deferral_payments': 'NaN', 'total_payments': 1061827, 'exercised_stock_options': 'NaN', 'bonus': 600000, 'restricted_stock': 585062, 'shared_receipt_with_poi': 702, 'restricted_stock_deferred': 'NaN', 'total_stock_value': 585062, 'expenses': 94299, 'loan_advances': 'NaN', 'from_messages': 29, 'other': 1740, 'from_this_person_to_poi': 1, 'poi': False, 'director_fees': 'NaN', 'deferred_income': 'NaN', 'long_term_incentive': 'NaN', 'email_address': 'mark.metts@enron.com', 'from_poi_to_this_person': 38}}在預處理此項目時,我們已將安然郵件和財務數據與字典結合在一起,字典中的每對鍵值對應一個人。 字典鍵是人名,值是另一個字典(包含此人的所有特征名和對應的值)。 數據中的特征分為三大類,即財務特征、郵件特征和 POI 標簽。
財務特征 : [‘salary’, ‘deferral_payments’, ‘total_payments’, ‘loan_advances’, ‘bonus’, ‘restricted_stock_deferred’, ‘deferred_income’, ‘total_stock_value’, ‘expenses’, ‘exercised_stock_options’, ‘other’, ‘long_term_incentive’, ‘restricted_stock’, ‘director_fees’] (單位均是美元)
郵件特征 : [‘to_messages’, ‘email_address’, ‘from_poi_to_this_person’, ‘from_messages’, ‘from_this_person_to_poi’, ‘shared_receipt_with_poi’] (單位通常是電子郵件的數量,明顯的例外是 ‘email_address’,這是一個字符串)
POI 標簽 : [‘poi’] (boolean,整數)
數據特征
分析這個數據字典,我們發現每個人一共有20個特征可以用于分析,其中的poi不是特征,而是label/target
數據點總數
分析整個數據字典,我們發現一共有146個數據點(人)。
POI統計
POI( Person of interest )是嫌疑犯的意思,數據集有一個標簽(label)就是嫌疑犯,所以我們只需要統計
data_dict[preson name][‘poi’] == 1
的數量就可以了。
統計發現有18個。
缺失的特征
數據集并不是每個特征后都有明確的值,有很多信息的特征是缺失的。對于salary特征,很多人的信息就是NaN。146個數據點(人)中,只有95個人有salary的具體信息。有111個人有郵箱地址,其他人的郵箱地址信息為NaN。
異常值調查和處理
我們在分析財務數據salary和bounds之間的關系時發現了一個極為異常額異常值,如下圖所示
明顯在右上角有一個極為異常的點,獎金和薪水遠遠高于其他人。我們通過代碼尋找一下獎金和薪水都極高的人,看是否還有其他的異常值。
data_dict = sorted(data_dict.items(), key = lambda x : x[1]["salary"] ,reverse=True)for x in data_dict :if x[1]['salary'] > 1000000 and x[1]['bonus'] > 5000000 :print x[0], x[1]['salary'], x[1]['bonus']審查發現一共有三個異常值。第一個為TOTAL,很明顯不是一個人名,而且薪水和獎金都極度異常,我們將他作為真正的異常值刪除掉。
data_dict = dict(data_dict)data_dict.pop('TOTAL', '52')剩下兩個分別是SKILLING JEFFREY K和LAY KENNETH L。他們分別是安然公司的CEO和董事長,他們是整個安然欺詐事件中最大的嫌疑犯。他們能有這么高的薪水和獎金也就不足為奇了。他們不是真的異常值,因此不對他們進行處理。
優化特征選擇
創建新的特征
我們有特征to_messages和from_poi_to_this_person這兩個特征,因此我想我們可以建立一個新的特征命名為 to_poi_ratio,其值為from_poi_to_this_person和to_messages的比值,比值越大也就意味著這個人收到的郵件中來自嫌疑人的郵件越多,往往也就意味著這個人和嫌疑人的關系越密切,很有可能這個人也是一個嫌疑人。具體創立代碼如下:
def poi_email_ratio(from_poi_to_this_person, to_messages):if from_poi_to_this_person or to_messages == 'NaN':to_poi_ratio = 0else:to_poi_ratio = float(from_poi_to_this_person)/to_messagesreturn to_poi_ratio# create new key and value for key in my_dataset:my_dataset[key]['to_poi_ratio'] = poi_email_ratio(my_dataset[key]['from_poi_to_this_person'], my_dataset[key]['to_messages'])測試新特征是否會對分類算法的結果產生影響的代碼如下:
### 添加新特征之后的數據集 data = featureFormat(my_dataset, features_list, sort_keys = True) labels, features = targetFeatureSplit(data)### 未添加新特征的數據集 data = featureFormat(data_dict, features_list, sort_keys = True) labels, features = targetFeatureSplit(data)我們分別運行這兩段代碼,比較結果就可以知道新特征是否會對分類算法產生影響了。運行結果分別如下:
### new feature The naive_bayes's recall is: 0.871794871795 The naive_bayes's precision is : 0.871794871795 The Decession_tree's recall is: 0.897435897436 The Decession_tree's precision is : 0.897435897436### orignal feature The naive_bayes's recall is: 0.871794871795 The naive_bayes's precision is : 0.871794871795 The Decession_tree's recall is: 0.846153846154 The Decession_tree's precision is : 0.846153846154通過對比發現添加新特征對于樸素貝葉斯的結果完全沒有任何影響,而對于決策樹算法有一定影響。添加新特征之后決策樹算法的準確率提高了。
選擇最佳特征
選擇和調整算法
選擇算法
我們這里郵件信息的學習過程實際上是一個監督學習的過程,我們這里分別使用樸素貝葉斯和決策樹來對模型進行訓練和評估。因為這個數據集很不平衡(imbalance), 也就說明accuracy并不是很好的評估指標,因此我們選擇precision和recall來作為模型的評估指標。
樸素貝葉斯的機器學習模型建立如下:
from sklearn.naive_bayes import GaussianNB clf = GaussianNB()clf.fit(features_train, labels_train) y_pred = clf.predict(features_test) recall = recall_score(labels_test, y_pred, average='micro') precision = precision_score(labels_test, y_pred, average='micro') print "The naive_bayes's recall is: %s " % recall print "The naive_bayes's precision is : %s" % precision該模型預測的準確率為0.85
決策樹的機器學習模型建立如下:
from sklearn import tree from sklearn.model_selection import GridSearchCV trees = tree.DecisionTreeClassifier() parameters = {'min_samples_split' : range(5,80,5), 'splitter' : ('best', 'random')}clf = GridSearchCV(trees, parameters) clf.fit(features_train, labels_train) y_pred = clf.predict(features_test) recall = recall_score(labels_test, y_pred, average='micro') precision = precision_score(labels_test, y_pred, average='micro') print "The Decession_tree's recall is: %s " % recall print "The Decession_tree's precision is : %s" % precision決策樹訓練模型涉及到較多的參數,要想得到更好的訓練效果,對于參數的調整是絕對必要的。
調整算法
使用決策樹有一個缺點就是容易過擬合,因此我們發應當盡可能的合理調整參數以達到最好的訓練效果。
決策樹有一個參數為min_samples_split,用于設置最小分割數。另外我們還可以調整splitter參數,該參數可以設置分割方法,有兩種:一種是’best’策略,用于選擇最好的分割,另一種是’random’策略,用于選擇最好的隨機分割。通常情況下當樣本量比較小的時候我們采取’best’策略進行分割,而當樣本量比較大的時候,我們采取‘random’的效果會更好。
使用 GridSearchCV 進行參數調整
GridSearchCV 用于系統地遍歷多種參數組合,通過交叉驗證確定最佳效果參數。它的好處是,只需增加幾行代碼,就能遍歷多種組合。當然與此對應的是機器學習過程所消耗的時間會相對較多。下面我們用GridSearchCV對決策樹參數進行調整:
from sklearn import tree from sklearn.model_selection import GridSearchCV trees = tree.DecisionTreeClassifier() parameters = {'min_samples_split' : range(5,80,5), 'splitter' : ('best', 'random')}clf = GridSearchCV(trees, parameters) clf.fit(features_train, labels_train) print clf.score(features_test, labels_test)經測試發現準確率為0.91,高于樸素貝葉斯的0.87。這里我們使用決策樹效果更好。
驗證和評估
我們分別使用精確度和召回率這兩個指標來評估模型的好壞。精確度概括的說可以是:猜對真的/(猜對真的+誤以為真的)。召回率概括的說可以是猜對真的/(猜對真的+誤以為假的)。我們分別對兩個算法模型進行評估
驗證及其重要性
驗證是用于評估模型好壞的一個重要方法,我們通常將數據集分為訓練集和測試集就是為了驗證的方便。前者用以建立模型(model),后者則用來評估該模型對未知樣本進行預測時的泛化能力。我們需要在測試集上進行驗證,來確定訓練集是否“過擬合”或者“欠擬合”。不同的數據集和訓練集的劃分方法,也會對驗證的效果產生一定影響。
訓練集和數據集的拆分
我使用如下方法拆分訓練集和數據集的
from sklearn.model_selection import train_test_split features_train, features_test, labels_train, labels_test = train_test_split(features, labels, test_size=0.3, random_state=42)數據集的70%作為訓練集,30%作為測試集
參考資料
我在此確認,所提交的項目為我的工作成果,其中引用的信息出自網站、書籍、論壇、博客文章和 GitHub 代碼庫等。下面列出我在完成項目過程中所參考的資料:
Recall和Precision的理解 http://blog.csdn.net/Relocy/article/details/51453950
Precision-Recall metric: http://scikit-learn.org/stable/auto_examples/model_selection/plot_precision_recall.html
recall score :http://scikit-learn.org/stable/modules/generated/sklearn.metrics.recall_score.html
交叉驗證:http://blog.csdn.net/cherdw/article/details/54986863
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的机器学习安然数据集分析报告的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第一次上课:特征值特征向量的几何直观
- 下一篇: Dimple.js基础