閱讀771 返回首頁    go 阿裏雲 go 技術社區[雲棲]


構建你的數據科學作品集:機器學習項目

數據科學公司在決定雇傭時越來越關注你在數據科學方麵的作品集Portfolio。這其中的一個原因是,這樣的作品集是判斷某人的實際技能的最好的方法。好消息是構建這樣的作品集完全要看你自己。隻要你在這方麵付出了努力,你一定可以取得讓這些公司欽佩的作品集。

構建高質量的作品集的第一步就是知道需要什麼技能。公司想要在數據科學方麵擁有的、他們希望你能夠運用的主要技能有:

  • 溝通能力
  • 協作能力
  • 技術能力
  • 數據推理能力
  • 動機和主動性

任何好的作品集都由多個項目表現出來,其中每個都能夠表現出以上一到兩點。這是本係列的第三篇,本係列我們主要講包括如何打造麵麵俱到的數據科學作品集。在這一篇中,我們主要涵蓋了如何構建組成你的作品集的第二個項目,以及如何創建一個端對端的機器學習項目。在最後,我們將擁有一個展示你的數據推理能力和技術能力的項目。如果你想看一下的話,這裏有一個完整的例子。

一個端到端的項目

作為一個數據科學家,有時候你會拿到一個數據集並被問如何用它來講故事。在這個時候,溝通就是非常重要的,你需要用它來完成這個事情。像我們在前一篇文章中用過的,類似 Jupyter notebook 這樣的工具,將對你非常有幫助。在這裏你能找到一些可以用的報告或者總結文檔。

不管怎樣,有時候你會被要求創建一個具有操作價值的項目。具有操作價值的項目將直接影響到公司的日常業務,它會使用不止一次,經常是許多人使用。這個任務可能像這樣 “創建一個算法來預測周轉率”或者“創建一個模型來自動對我們的文章打標簽”。在這種情況下,技術能力比講故事更重要。你必須能夠得到一個數據集,並且理解它,然後創建腳本處理該數據。這個腳本要運行的很快,占用係統資源很小。通常它可能要運行很多次,腳本的可使用性也很重要,並不僅僅是一個演示版。可使用性是指整合進操作流程,並且甚至是是麵向用戶的。

端對端項目的主要組成部分:

  • 理解背景
  • 瀏覽數據並找出細微差別
  • 創建結構化項目,那樣比較容易整合進操作流程
  • 運行速度快、占用係統資源小的高性能代碼
  • 寫好安裝和使用文檔以便其他人用

為了有效的創建這種類型的項目,我們可能需要處理多個文件。強烈推薦使用 Atom 這樣的文本編輯器或者PyCharm 這樣的 IDE。這些工具允許你在文件間跳轉,編輯不同類型的文件,例如 markdown 文件,Python 文件,和 csv 文件等等。結構化你的項目還利於版本控製,並上傳一個類似 Github 這樣的協作開發工具上也很有用。

Github 上的這個項目

Github 上的這個項目

在這一節中我們將使用 Pandas 和 scikit-learn 這樣的庫,我們還將大量用到 Pandas DataFrames,它使得 python 讀取和處理表格數據更加方便。

找到好的數據集

為一個端到端的作品集項目的找到好的數據集很難。在內存和性能的限製下,數據集需要盡量的大。它還需要是實際有用的。例如,這個數據集,它包含有美國院校的錄取標準、畢業率以及畢業以後的收入,是個很好的可以講故事的數據集。但是,不管你如何看待這個數據,很顯然它不適合創建端到端的項目。比如,你能告訴人們他們去了這些大學以後的未來收入,但是這個快速檢索卻並不足夠呈現出你的技術能力。你還能找出院校的招生標準和更高的收入相關,但是這更像是常理而不是你的技術結論。

這裏還有內存和性能約束的問題,比如你有幾千兆的數據,而且當你需要找到一些差異時,就需要對數據集一遍遍運行算法。

一個好的可操作的數據集可以讓你構建一係列腳本來轉換數據、動態地回答問題。一個很好的例子是股票價格數據集,當股市關閉時,就會給算法提供新的數據。這可以讓你預測明天的股價,甚至預測收益。這不是講故事,它帶來的是真金白銀。

一些找到數據集的好地方:

  • /r/datasets – 有上百的有趣數據的 subreddit(Reddit 是國外一個社交新聞站點,subreddit 指該論壇下的各不同版塊)。
  • Google Public Datasets – 通過 Google BigQuery 使用的公開數據集。
  • Awesome datasets – 一個數據集列表,放在 Github 上。

當你查看這些數據集時,想一下人們想要在這些數據集中得到什麼答案,哪怕這些問題隻想過一次(“房價是如何與標準普爾 500 指數關聯的?”),或者更進一步(“你能預測股市嗎?”)。這裏的關鍵是更進一步地找出問題,並且用相同的代碼在不同輸入(不同的數據)上運行多次。

對於本文的目標,我們來看一下 房利美Fannie Mae貸款數據。房利美是一家在美國的政府讚助的企業抵押貸款公司,它從其他銀行購買按揭貸款,然後捆綁這些貸款為貸款證券來轉賣它們。這使得貸款機構可以提供更多的抵押貸款,在市場上創造更多的流動性。這在理論上會帶來更多的住房和更好的貸款期限。從借款人的角度來說,它們大體上差不多,話雖這樣說。

房利美發布了兩種類型的數據 – 它獲得的貸款的數據,和貸款償還情況的數據。在理想的情況下,有人向貸款人借錢,然後還款直到還清。不管怎樣,有些人多次不還,從而喪失了抵押品贖回權。抵押品贖回權是指沒錢還了被銀行把房子給收走了。房利美會追蹤誰沒還錢,並且哪個貸款需要收回抵押的房屋(取消贖回權)。每個季度會發布此數據,發布的是滯後一年的數據。當前可用是 2015 年第一季度數據。

“貸款數據”是由房利美發布的貸款發放的數據,它包含借款人的信息、信用評分,和他們的家庭貸款信息。“執行數據”,貸款發放後的每一個季度公布,包含借貸人的還款信息和是否喪失抵押品贖回權的狀態,一個“貸款數據”的“執行數據”可能有十幾行。可以這樣理解,“貸款數據”告訴你房利美所控製的貸款,“執行數據”包含該貸款一係列的狀態更新。其中一個狀態更新可以告訴我們一筆貸款在某個季度被取消贖回權了。

一個沒有及時還貸的房子就這樣的被賣了

一個沒有及時還貸的房子就這樣的被賣了

選擇一個角度

這裏有幾個我們可以去分析房利美數據集的方向。我們可以:

  • 預測房屋的銷售價格。
  • 預測借款人還款曆史。
  • 在獲得貸款時為每一筆貸款打分。

最重要的事情是堅持單一的角度。同時關注太多的事情很難做出效果。選擇一個有著足夠細節的角度也很重要。下麵的角度就沒有太多細節:

  • 找出哪些銀行將貸款出售給房利美的多數被取消贖回權。
  • 計算貸款人的信用評分趨勢。
  • 找到哪些類型的家庭沒有償還貸款的能力。
  • 找到貸款金額和抵押品價格之間的關係。

上麵的想法非常有趣,如果我們關注於講故事,那是一個不錯的角度,但是不是很適合一個操作性項目。

在房利美數據集中,我們將僅使用申請貸款時有的那些信息來預測貸款是否將來會被取消贖回權。實際上, 我們將為每一筆貸款建立“分數”來告訴房利美買還是不買。這將給我們打下良好的基礎,並將組成這個漂亮的作品集的一部分。

理解數據

我們來簡單看一下原始數據文件。下麵是 2012 年 1 季度前幾行的貸款數據:


  1. 100000853384|R|OTHER|4.625|280000|360|02/2012|04/2012|31|31|1|23|801|N|C|SF|1|I|CA|945||FRM|
  2. 100003735682|R|SUNTRUST MORTGAGE INC.|3.99|466000|360|01/2012|03/2012|80|80|2|30|794|N|P|SF|1|P|MD|208||FRM|788
  3. 100006367485|C|PHH MORTGAGE CORPORATION|4|229000|360|02/2012|04/2012|67|67|2|36|802|N|R|SF|1|P|CA|959||FRM|794

下麵是 2012 年 1 季度的前幾行執行數據:


  1. 100000853384|03/01/2012|OTHER|4.625||0|360|359|03/2042|41860|0|N||||||||||||||||
  2. 100000853384|04/01/2012||4.625||1|359|358|03/2042|41860|0|N||||||||||||||||
  3. 100000853384|05/01/2012||4.625||2|358|357|03/2042|41860|0|N||||||||||||||||

在開始編碼之前,花些時間真正理解數據是值得的。這對於操作性項目優為重要,因為我們沒有交互式探索數據,將很難察覺到細微的差別,除非我們在前期發現他們。在這種情況下,第一個步驟是閱讀房利美站點的資料:

在看完這些文件後後,我們了解到一些能幫助我們的關鍵點:

  • 從 2000 年到現在,每季度都有一個貸款和執行文件,因數據是滯後一年的,所以到目前為止最新數據是 2015 年的。
  • 這些文件是文本格式的,采用管道符號|進行分割。
  • 這些文件是沒有表頭的,但我們有個文件列明了各列的名稱。
  • 所有一起,文件包含 2200 萬個貸款的數據。
  • 由於執行數據的文件包含過去幾年獲得的貸款的信息,在早些年獲得的貸款將有更多的執行數據(即在 2014 獲得的貸款沒有多少曆史執行數據)。

這些小小的信息將會為我們節省很多時間,因為這樣我們就知道如何構造我們的項目和利用這些數據了。

構造項目

在我們開始下載和探索數據之前,先想一想將如何構造項目是很重要的。當建立端到端項目時,我們的主要目標是:

  • 創建一個可行解決方案
  • 有一個快速運行且占用最小資源的解決方案
  • 容易可擴展
  • 寫容易理解的代碼
  • 寫盡量少的代碼

為了實現這些目標,需要對我們的項目進行良好的構造。一個結構良好的項目遵循幾個原則:

  • 分離數據文件和代碼文件
  • 從原始數據中分離生成的數據。
  • 有一個 README.md 文件幫助人們安裝和使用該項目。
  • 有一個 requirements.txt 文件列明項目運行所需的所有包。
  • 有一個單獨的 settings.py 文件列明其它文件中使用的所有的設置
    • 例如,如果從多個 Python 腳本讀取同一個文件,讓它們全部 import 設置並從一個集中的地方獲得文件名是有用的。
  • 有一個 .gitignore 文件,防止大的或密碼文件被提交。
  • 分解任務中每一步可以單獨執行的步驟到單獨的文件中。
    • 例如,我們將有一個文件用於讀取數據,一個用於創建特征,一個用於做出預測。
  • 保存中間結果,例如,一個腳本可以輸出下一個腳本可讀取的文件。
    • 這使我們無需重新計算就可以在數據處理流程中進行更改。

我們的文件結構大體如下:


  1. loan-prediction
  2. ├── data
  3. ├── processed
  4. ├── .gitignore
  5. ├── README.md
  6. ├── requirements.txt
  7. ├── settings.py

創建初始文件

首先,我們需要創建一個 loan-prediction 文件夾,在此文件夾下麵,再創建一個 data 文件夾和一個processed 文件夾。data 文件夾存放原始數據,processed 文件夾存放所有的中間計算結果。

其次,創建 .gitignore 文件,.gitignore 文件將保證某些文件被 git 忽略而不會被推送至 GitHub。關於這個文件的一個好的例子是由 OSX 在每一個文件夾都會創建的 .DS_Store 文件,.gitignore 文件一個很好的範本在這裏。我們還想忽略數據文件,因為它們實在是太大了,同時房利美的條文禁止我們重新分發該數據文件,所以我們應該在我們的文件後麵添加以下 2 行:


  1. data
  2. processed

這裏是該項目的一個關於 .gitignore 文件的例子。

再次,我們需要創建 README.md 文件,它將幫助人們理解該項目。後綴 .md 表示這個文件采用 markdown 格式。Markdown 使你能夠寫純文本文件,同時還可以添加你想要的神奇的格式。這裏是關於 markdown 的導引。如果你上傳一個叫 README.md 的文件至 Github,Github 會自動處理該 markdown,同時展示給瀏覽該項目的人。例子在這裏

至此,我們僅需在 README.md 文件中添加簡單的描述:


  1. Loan Prediction
  2. -----------------------
  3. Predict whether or not loans acquired by Fannie Mae will go into foreclosure. Fannie Mae acquires loans from other lenders as a way of inducing them to lend more. Fannie Mae releases data on the loans it has acquired and their performance afterwards [here](http://www.fanniemae.com/portal/funding-the-market/data/loan-performance-data.html).

現在,我們可以創建 requirements.txt 文件了。這會幫助其它人可以很方便地安裝我們的項目。我們還不知道我們將會具體用到哪些庫,但是以下幾個庫是需要的:


  1. pandas
  2. matplotlib
  3. scikit-learn
  4. numpy
  5. ipython
  6. scipy

以上幾個是在 python 數據分析任務中最常用到的庫。可以認為我們將會用到大部分這些庫。這裏是該項目requirements.txt 文件的一個例子。

創建 requirements.txt 文件之後,你應該安裝這些包了。我們將會使用 python3。如果你沒有安裝 python,你應該考慮使用 Anaconda,它是一個 python 安裝程序,同時安裝了上麵列出的所有包。

最後,我們可以建立一個空白的 settings.py 文件,因為我們的項目還沒有任何設置。

獲取數據

一旦我們有了項目的基本架構,我們就可以去獲得原始數據。

房利美對獲取數據有一些限製,所以你需要去注冊一個賬戶。在創建完賬戶之後,你可以找到在這裏的下載頁麵,你可以按照你所需要的下載或多或少的貸款數據文件。文件格式是 zip,在解壓後當然是非常大的。

為了達到我們這個文章的目的,我們將要下載從 2012 年 1 季度到 2015 年 1 季度的所有數據。接著我們需要解壓所有的文件。解壓過後,刪掉原來的 .zip 格式的文件。最後,loan-prediction 文件夾看起來應該像下麵的一樣:


  1. loan-prediction
  2. ├── data
  3. ├── Acquisition_2012Q1.txt
  4. ├── Acquisition_2012Q2.txt
  5. ├── Performance_2012Q1.txt
  6. ├── Performance_2012Q2.txt
  7. └── ...
  8. ├── processed
  9. ├── .gitignore
  10. ├── README.md
  11. ├── requirements.txt
  12. ├── settings.py

在下載完數據後,你可以在 shell 命令行中使用 head 和 tail 命令去查看文件中的行數據,你看到任何的不需要的數據列了嗎?在做這件事的同時查閱列名稱的 pdf 文件可能有幫助。

讀入數據

有兩個問題讓我們的數據難以現在就使用:

  • 貸款數據和執行數據被分割在多個文件中
  • 每個文件都缺少列名標題

在我們開始使用數據之前,我們需要首先明白我們要在哪裏去存一個貸款數據的文件,同時到哪裏去存儲一個執行數據的文件。每個文件僅僅需要包括我們關注的那些數據列,同時擁有正確的列名標題。這裏有一個小問題是執行數據非常大,因此我們需要嚐試去修剪一些數據列。

第一步是向 settings.py 文件中增加一些變量,這個文件中同時也包括了我們原始數據的存放路徑和處理出的數據存放路徑。我們同時也將添加其他一些可能在接下來會用到的設置數據:


  1. DATA_DIR = "data"
  2. PROCESSED_DIR = "processed"
  3. MINIMUM_TRACKING_QUARTERS = 4
  4. TARGET = "foreclosure_status"
  5. NON_PREDICTORS = [TARGET, "id"]
  6. CV_FOLDS = 3

把路徑設置在 settings.py 中使它們放在一個集中的地方,同時使其修改更加的容易。當在多個文件中用到相同的變量時,你想改變它的話,把他們放在一個地方比分散放在每一個文件時更加容易。這裏的是一個這個工程的示例 settings.py 文件

第二步是創建一個文件名為 assemble.py,它將所有的數據分為 2 個文件。當我們運行 Python assemble.py,我們在處理數據文件的目錄會獲得 2 個數據文件。

接下來我們開始寫 assemble.py 文件中的代碼。首先我們需要為每個文件定義相應的列名標題,因此我們需要查看列名稱的 pdf 文件,同時創建在每一個貸款數據和執行數據的文件的數據列的列表:


  1. HEADERS = {
  2. "Acquisition": [
  3. "id",
  4. "channel",
  5. "seller",
  6. "interest_rate",
  7. "balance",
  8. "loan_term",
  9. "origination_date",
  10. "first_payment_date",
  11. "ltv",
  12. "cltv",
  13. "borrower_count",
  14. "dti",
  15. "borrower_credit_score",
  16. "first_time_homebuyer",
  17. "loan_purpose",
  18. "property_type",
  19. "unit_count",
  20. "occupancy_status",
  21. "property_state",
  22. "zip",
  23. "insurance_percentage",
  24. "product_type",
  25. "co_borrower_credit_score"
  26. ],
  27. "Performance": [
  28. "id",
  29. "reporting_period",
  30. "servicer_name",
  31. "interest_rate",
  32. "balance",
  33. "loan_age",
  34. "months_to_maturity",
  35. "maturity_date",
  36. "msa",
  37. "delinquency_status",
  38. "modification_flag",
  39. "zero_balance_code",
  40. "zero_balance_date",
  41. "last_paid_installment_date",
  42. "foreclosure_date",
  43. "disposition_date",
  44. "foreclosure_costs",
  45. "property_repair_costs",
  46. "recovery_costs",
  47. "misc_costs",
  48. "tax_costs",
  49. "sale_proceeds",
  50. "credit_enhancement_proceeds",
  51. "repurchase_proceeds",
  52. "other_foreclosure_proceeds",
  53. "non_interest_bearing_balance",
  54. "principal_forgiveness_balance"
  55. ]
  56. }

接下來一步是定義我們想要保留的數據列。因為我們要預測一個貸款是否會被撤回,我們可以丟棄執行數據中的許多列。我們將需要保留貸款數據中的所有數據列,因為我們需要盡量多的了解貸款發放時的信息(畢竟我們是在預測貸款發放時這筆貸款將來是否會被撤回)。丟棄數據列將會使我們節省下內存和硬盤空間,同時也會加速我們的代碼。


  1. SELECT = {
  2. "Acquisition": HEADERS["Acquisition"],
  3. "Performance": [
  4. "id",
  5. "foreclosure_date"
  6. ]
  7. }

下一步,我們將編寫一個函數來連接數據集。下麵的代碼將:

  • 引用一些需要的庫,包括 settings
  • 定義一個函數 concatenate,目的是:
    • 獲取到所有 data 目錄中的文件名。
    • 遍曆每個文件。
      • 如果文件不是正確的格式 (不是以我們需要的格式作為開頭),我們將忽略它。
      • 通過使用 Pandas 的 read_csv 函數及正確的設置把文件讀入一個 DataFrame
        • 設置分隔符為,以便所有的字段能被正確讀出。
        • 數據沒有標題行,因此設置 header 為 None 來進行標示。
        • 從 HEADERS 字典中設置正確的標題名稱 – 這將會是我們的 DataFrame 中的數據列名稱。
        • 僅選擇我們加在 SELECT 中的 DataFrame 的列。
  • 把所有的 DataFrame 共同連接在一起。
  • 把已經連接好的 DataFrame 寫回一個文件。

  1. import os
  2. import settings
  3. import pandas as pd
  4. def concatenate(prefix="Acquisition"):
  5. files = os.listdir(settings.DATA_DIR)
  6. full = []
  7. for f in files:
  8. if not f.startswith(prefix):
  9. continue
  10. data = pd.read_csv(os.path.join(settings.DATA_DIR, f), sep="|", header=None, names=HEADERS[prefix], index_col=False)
  11. data = data[SELECT[prefix]]
  12. full.append(data)
  13. full = pd.concat(full, axis=0)
  14. full.to_csv(os.path.join(settings.PROCESSED_DIR, "{}.txt".format(prefix)), sep="|", header=SELECT[prefix], index=False)

我們可以通過調用上麵的函數,通過傳遞的參數 Acquisition 和 Performance 兩次以將所有的貸款和執行文件連接在一起。下麵的代碼將:

  • 僅在命令行中運行 python assemble.py 時執行。
  • 將所有的數據連接在一起,並且產生 2 個文件:
    • processed/Acquisition.txt
    • processed/Performance.txt

  1. if __name__ == "__main__":
  2. concatenate("Acquisition")
  3. concatenate("Performance")

我們現在擁有了一個漂亮的,劃分過的 assemble.py 文件,它很容易執行,也容易建立。通過像這樣把問題分解為一塊一塊的,我們構建工程就會變的容易許多。不用一個可以做所有工作的淩亂腳本,我們定義的數據將會在多個腳本間傳遞,同時使腳本間完全的彼此隔離。當你正在一個大的項目中工作時,這樣做是一個好的想法,因為這樣可以更加容易修改其中的某一部分而不會引起其他項目中不關聯部分產生預料之外的結果。

一旦我們完成 assemble.py 腳本文件,我們可以運行 python assemble.py 命令。你可以在這裏查看完整的assemble.py 文件。

這將會在 processed 目錄下產生 2 個文件:


  1. loan-prediction
  2. ├── data
  3. ├── Acquisition_2012Q1.txt
  4. ├── Acquisition_2012Q2.txt
  5. ├── Performance_2012Q1.txt
  6. ├── Performance_2012Q2.txt
  7. └── ...
  8. ├── processed
  9. ├── Acquisition.txt
  10. ├── Performance.txt
  11. ├── .gitignore
  12. ├── assemble.py
  13. ├── README.md
  14. ├── requirements.txt
  15. ├── settings.py

計算來自執行數據的值

接下來我們會計算來自 processed/Performance.txt 中的值。我們要做的就是推測這些資產是否被取消贖回權。如果能夠計算出來,我們隻要看一下關聯到貸款的執行數據的參數 foreclosure_date 就可以了。如果這個參數的值是 None,那麼這些資產肯定沒有收回。為了避免我們的樣例中隻有少量的執行數據,我們會為每個貸款計算出執行數據文件中的行數。這樣我們就能夠從我們的訓練數據中篩選出貸款數據,排除了一些執行數據。

下麵是我認為貸款數據和執行數據的關係:

在上麵的表格中,貸款數據中的每一行數據都關聯到執行數據中的多行數據。在執行數據中,在取消贖回權的時候 foreclosure_date 就會出現在該季度,而之前它是空的。一些貸款還沒有被取消贖回權,所以與執行數據中的貸款數據有關的行在 foreclosure_date 列都是空格。

我們需要計算 foreclosure_status 的值,它的值是布爾類型,可以表示一個特殊的貸款數據 id 是否被取消贖回權過,還有一個參數 performance_count ,它記錄了執行數據中每個貸款 id 出現的行數。 

計算這些行數有多種不同的方法:

  • 我們能夠讀取所有的執行數據,然後我們用 Pandas 的 groupby 方法在 DataFrame 中計算出與每個貸款 id 有關的行的行數,然後就可以查看貸款 id 的 foreclosure_date 值是否為 None 。
    • 這種方法的優點是從語法上來說容易執行。
    • 它的缺點需要讀取所有的 129236094 行數據,這樣就會占用大量內存,並且運行起來極慢。
  • 我們可以讀取所有的執行數據,然後在貸款 DataFrame 上使用 apply 去計算每個貸款 id 出現的次數。
    • 這種方法的優點是容易理解。
    • 缺點是需要讀取所有的 129236094 行數據。這樣會占用大量內存,並且運行起來極慢。
  • 我們可以在迭代訪問執行數據中的每一行數據,而且會建立一個單獨的計數字典。
    • 這種方法的優點是數據不需要被加載到內存中,所以運行起來會很快且不需要占用內存。
    • 缺點是這樣的話理解和執行上可能有點耗費時間,我們需要對每一行數據進行語法分析。

加載所有的數據會非常耗費內存,所以我們采用第三種方法。我們要做的就是迭代執行數據中的每一行數據,然後為每一個貸款 id 在字典中保留一個計數。在這個字典中,我們會計算出貸款 id 在執行數據中出現的次數,而且看看 foreclosure_date 是否是 None 。我們可以查看 foreclosure_status 和performance_count 的值 。

我們會新建一個 annotate.py 文件,文件中的代碼可以計算這些值。我們會使用下麵的代碼:

  • 導入需要的庫
  • 定義一個函數 count_performance_rows 。
    • 打開 processed/Performance.txt 文件。這不是在內存中讀取文件而是打開了一個文件標識符,這個標識符可以用來以行為單位讀取文件。 
    • 迭代文件的每一行數據。
    • 使用分隔符|分開每行的不同數據。
    • 檢查 loan_id 是否在計數字典中。
      • 如果不存在,把它加進去。
    • loan_id 的 performance_count 參數自增 1 次,因為我們這次迭代也包含其中。
    • 如果 date 不是 None ,我們就會知道貸款被取消贖回權了,然後為foreclosure_status` 設置合適的值。

  1. import os
  2. import settings
  3. import pandas as pd
  4. def count_performance_rows():
  5. counts = {}
  6. with open(os.path.join(settings.PROCESSED_DIR, "Performance.txt"), 'r') as f:
  7. for i, line in enumerate(f):
  8. if i == 0:
  9. # Skip header row
  10. continue
  11. loan_id, date = line.split("|")
  12. loan_id = int(loan_id)
  13. if loan_id not in counts:
  14. counts[loan_id] = {
  15. "foreclosure_status": False,
  16. "performance_count": 0
  17. }
  18. counts[loan_id]["performance_count"] += 1
  19. if len(date.strip()) > 0:
  20. counts[loan_id]["foreclosure_status"] = True
  21. return counts

獲取值

隻要我們創建了計數字典,我們就可以使用一個函數通過一個 loan_id 和一個 key 從字典中提取到需要的參數的值:


  1. def get_performance_summary_value(loan_id, key, counts):
  2. value = counts.get(loan_id, {
  3. "foreclosure_status": False,
  4. "performance_count": 0
  5. })
  6. return value[key]

上麵的函數會從 counts 字典中返回合適的值,我們也能夠為貸款數據中的每一行賦一個foreclosure_status 值和一個 performance_count 值。如果鍵不存在,字典的 get 方法會返回一個默認值,所以在字典中不存在鍵的時候我們就可以得到一個可知的默認值。

轉換數據

我們已經在 annotate.py 中添加了一些功能,現在我們來看一看數據文件。我們需要將貸款到的數據轉換到訓練數據集來進行機器學習算法的訓練。這涉及到以下幾件事情:

  • 轉換所有列為數字。
  • 填充缺失值。
  • 為每一行分配 performance_count 和 foreclosure_status
  • 移除出現執行數據很少的行(performance_count 計數低)。

我們有幾個列是文本類型的,看起來對於機器學習算法來說並不是很有用。然而,它們實際上是分類變量,其中有很多不同的類別代碼,例如 RS 等等. 我們可以把這些類別標簽轉換為數值:

通過這種方法轉換的列我們可以應用到機器學習算法中。

還有一些包含日期的列 (first_payment_date 和 origination_date)。我們可以將這些日期放到兩個列中:

在下麵的代碼中,我們將轉換貸款數據。我們將定義一個函數如下:

  • 在 acquisition 中創建 foreclosure_status 列,並從 counts 字典中得到值。
  • 在 acquisition 中創建 performance_count 列,並從 counts 字典中得到值。
  • 將下麵的列從字符串轉換為整數:
    • channel
    • seller
    • first_time_homebuyer
    • loan_purpose
    • property_type
    • occupancy_status
    • property_state
    • product_type
  • 將 first_payment_date 和 origination_date 分別轉換為兩列:
    • 通過斜杠分離列。
    • 將第一部分分離成 month 列。
    • 將第二部分分離成 year 列。
    • 刪除該列。
    • 最後,我們得到 first_payment_monthfirst_payment_yearrigination_month 和origination_year
  • 所有缺失值填充為 -1

  1. def annotate(acquisition, counts):
  2. acquisition["foreclosure_status"] = acquisition["id"].apply(lambda x: get_performance_summary_value(x, "foreclosure_status", counts))
  3. acquisition["performance_count"] = acquisition["id"].apply(lambda x: get_performance_summary_value(x, "performance_count", counts))
  4. for column in [
  5. "channel",
  6. "seller",
  7. "first_time_homebuyer",
  8. "loan_purpose",
  9. "property_type",
  10. "occupancy_status",
  11. "property_state",
  12. "product_type"
  13. ]:
  14. acquisition[column] = acquisition[column].astype('category').cat.codes
  15. for start in ["first_payment", "origination"]:
  16. column = "{}_date".format(start)
  17. acquisition["{}_year".format(start)] = pd.to_numeric(acquisition[column].str.split('/').str.get(1))
  18. acquisition["{}_month".format(start)] = pd.to_numeric(acquisition[column].str.split('/').str.get(0))
  19. del acquisition[column]
  20. acquisition = acquisition.fillna(-1)
  21. acquisition = acquisition[acquisition["performance_count"] > settings.MINIMUM_TRACKING_QUARTERS]
  22. return acquisition

聚合到一起

我們差不多準備就緒了,我們隻需要再在 annotate.py 添加一點點代碼。在下麵代碼中,我們將:

  • 定義一個函數來讀取貸款的數據。
  • 定義一個函數來寫入處理過的數據到 processed/train.csv
  • 如果該文件在命令行以 python annotate.py 的方式運行:
    • 讀取貸款數據。
    • 計算執行數據的計數,並將其賦予 counts
    • 轉換 acquisition DataFrame。
    • acquisition DataFrame 寫入到 train.csv

  1. def read():
  2. acquisition = pd.read_csv(os.path.join(settings.PROCESSED_DIR, "Acquisition.txt"), sep="|")
  3. return acquisition
  4. def write(acquisition):
  5. acquisition.to_csv(os.path.join(settings.PROCESSED_DIR, "train.csv"), index=False)
  6. if __name__ == "__main__":
  7. acquisition = read()
  8. counts = count_performance_rows()
  9. acquisition = annotate(acquisition, counts)
  10. write(acquisition)

修改完成以後,確保運行 python annotate.py 來生成 train.csv 文件。 你可以在這裏找到完整的annotate.py 文件。

現在文件夾看起來應該像這樣:


  1. loan-prediction
  2. ├── data
  3. ├── Acquisition_2012Q1.txt
  4. ├── Acquisition_2012Q2.txt
  5. ├── Performance_2012Q1.txt
  6. ├── Performance_2012Q2.txt
  7. └── ...
  8. ├── processed
  9. ├── Acquisition.txt
  10. ├── Performance.txt
  11. ├── train.csv
  12. ├── .gitignore
  13. ├── annotate.py
  14. ├── assemble.py
  15. ├── README.md
  16. ├── requirements.txt
  17. ├── settings.py

找到誤差標準

我們已經完成了訓練數據表的生成,現在我們需要最後一步,生成預測。我們需要找到誤差的標準,以及該如何評估我們

最後更新:2017-06-06 07:33:02

  上一篇:go  《JavaScript開發框架權威指南》——2.6 創建Grunt插件
  下一篇:go  阿裏雲生態日沙龍申請及落地規則