數據科學原理與數據處理第二週

特徵工程

1 機器學習

機器學習簡單來說就是選擇一種學習算法,從數據中學習並建立成模型來對新的數據進行預測的計算機科學 。

機器學習是人工智能的一個分支。人工智能的研究是從以“推理”爲重點—以“知識”爲重點—再到以“學習”爲重點,一條自然、清晰的脈絡。機器學習是實現人工智能的一個途徑,即以機器學習爲手段解決人工智能中的問題。機器學習算法是一類從數據中自動分析獲得規律(模型),並利用規律對未知數據進行預測的算法。

我們的數據量越來越多,硬件越來越強悍。急需要解放人的生產力,自動去尋找數據的規律。解決更多專業領域的問題。機器學習已廣泛應用於數據挖掘、計算機視覺、自然語言處理、生物特徵識別、搜索引擎、醫學診斷、檢測信用卡欺詐、證券市場分析、DNA序列測序、語音和手寫識別、戰略遊戲和機器人等領域。

機器學習適用於以下等問題:

  • 不存在已知算法解決方案的複雜問題
  • 需要大量手動調整或者規則列表超長的問題
  • 可以適應環境波動的系統

1.1 基礎概念

  • 樣本與標籤

標籤是提供給算法的包含所需解決方案的訓練數據,是我們要預測的事物,即簡單線性迴歸中的 y 變量。

樣本每一條數據叫一個樣本,即數據的特定實例:x

  • 特徵

屬性加上其值 就是特徵,也可以理解爲輸入變量,即簡單線性迴歸中的 x 變量。

  • 迴歸任務

關注預測值和真實值之間的差別,就是通過給定的特徵來預測一個目標數值。

  • 訓練集

用於訓練模型的數據叫訓練集

  • 測試集

用於測試模型精度的數據叫測試集

  • 過擬合與欠擬合

從字面的意義上理解就是過度擬合的意思,常發生在線性分類器或者線性模型的訓練和預測當中。過擬合的原理就是機器學習算法過度學習了訓練集數據。反之欠擬合。

  • 模型訓練

是指創建或學習模型。也就是說,向模型展示有標籤樣本,讓模型逐漸學習特徵與標籤之間的關係。通過訓練數據找到算法最合適的參數。

1.2 機器學習執行流程

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-4bGMbJC1-1574825755327)(image/1574144721121.png)]

  1. 理解實際問題,抽象爲機器學習能處理的數學問題

    理解實際業務場景問題是機器學習的第一步, 機器學習中特徵工程和模型訓練都是非常費時的,深入理解要處理的問題,能避免走很多彎路。理解問題,明確可以獲得的數據。

  2. 獲取數據

    獲取數據包括獲取原始數據,以及從原始數據中經過特徵工程,從原始數據中提取訓練、測試數據。數據數量不要有多個數量級的差距。不僅如此還要對評估數據的量級,樣本數量、特徵數量,估算訓練模型對內存的消耗。

  3. 特徵工程

    特徵工程包括從原始數據中特徵構建、特徵提取、特徵選擇。特徵工程做的好能發揮原始數據的最大效力,往往能夠使得算法的效果和性能得到顯著的提升,有時能使簡單的模型的效果比複雜的模型效果好。

  4. 模型訓練、診斷、調優

    對算法的理解、調節參數,使模型達到最優。模型診斷中至關重要的是判斷過擬合、欠擬合,常見的方法是繪製學習曲線,交叉驗證。通過增加訓練的數據量、降低模型複雜度來降低過擬合的風險,提高特徵的數量和質量、增加模型複雜來防止欠擬合。診斷後的模型需要進行進一步調優, 調優後的新模型需要重新診斷,這是一個反覆迭代不斷逼近的過程,需要不斷的嘗試,進而達到最優的狀態。

  5. 模型預測,獲得結果

    我們通過訓練數據集得到模型,然後將想要預測的數據加入模型中進行測試,得到測試結果。

這就是我們大致的機器學習流程。

1.3 數據處理與特徵工程

  • 數據處理

“數據決定了機器學習的上限,而算法只是儘可能逼近這個上限”,這句話很好的闡述了數據在機器學習中的重要性。大部分直接拿過來的數據都是特徵不明顯的、沒有經過處理的或者說是存在很多無用的數據,那麼需要進行一些特徵處理,特徵的縮放等等,滿足訓練數據的要求。

數據處理主要解決的問題是:

  1. 數據量不足

  2. 訓練數據不具備代表性

  3. 質量差的數據

  4. 特徵篩選

  • 特徵工程

機器學習的關鍵是 提取出一組好的用來訓練的特徵集,這個過 程叫特徵工程,包括:

  1. 特徵選擇 從現有特徵中選擇最有用的特徵進行訓練

  2. 特徵提取 將現有特徵進行整合,產生更有用的特徵,比 如降維算法

  3. 通過收集 新數據創造新特徵

2 Scikit-learn 與特徵工程

2.1 Scikit-learn概述

2007年發佈以來,scikit-learn已經成爲最給力的Python機器學習庫(library)了。scikit-learn支持的機器學習算法包括分類,迴歸,降維和聚類。還有一些特徵提取(extracting features)、數據處理(processing data)和模型評估(evaluating models)的模塊。作爲Scipy庫的擴展,scikit-learn也是建立在Python的NumPy和matplotlib庫基礎之上。NumPy可以讓Python支持大量多維矩陣數據的高效操作,matplotlib提供了可視化工具,SciPy帶有許多科學計算的模型。

  • Python語言的機器學習工具
  • 可在不同的上下文中重用
  • 基於NumPy、SciPy和matplotlib構建
  • 開源、商業可用 - BSD許可

2.2 數據的特徵工程

從數據中抽取出來的對預測結果有用的信息,通過專業的技巧進行數據處理,是的特徵能在機器學習算法中發揮更好的作用。優質的特徵往往描述了數據的固有結構。 最初的原始特徵數據集可能太大,或者信息冗餘,因此在機器學習的應用中,一個初始步驟就是選擇特徵的子集,或構建一套新的特徵集,減少功能來促進算法的學習,提高泛化能力和可解釋性。

2.2.1 特徵工程的意義

  • 更好的特徵意味着更強的魯棒性
    • 所謂“魯棒性”,指控制系統在一定(結構,大小)的參數攝動下,維持其它某些性能的特性。
  • 更好的特徵意味着只需用簡單模型
  • 更好的特徵意味着更好的結果

2.2.2 特徵處理

特徵工程中最重要的一個環節就是特徵處理,特徵處理包含了很多具體的專業技巧

  • 單個特徵
    • 歸一化
    • 標準化
    • 缺失值
  • 多個特徵
    • 降維
功能 說明
StandardScaler 無量綱化 標準化,基於特徵矩陣的列,將特徵值轉換至服從標準正態分佈
MinMaxScaler 無量綱化 區間縮放,基於最大最小值,將特徵值轉換到[0, 1]區間上
Normalizer 歸一化 基於特徵矩陣的行,將樣本向量轉換爲“單位向量”
Binarizer 二值化 基於給定閾值,將定量特徵按閾值劃分
OneHotEncoder 啞編碼 將定性數據編碼爲定量數據
Imputer 缺失值計算 計算缺失值,缺失值可填充爲均值等
PolynomialFeatures 多項式數據轉換 多項式數據轉換
FunctionTransformer 自定義單元數據轉換 使用單變元的函數來轉換數據函數來轉換數據

2.2.3 特徵選擇與特徵抽取

如果說特徵處理其實就是在對已有的數據進行運算達到我們目標的數據標準。特徵抽取則是將任意數據格式(例如文本和圖像)轉換爲機器學習的數字特徵。而特徵選擇是在已有的特徵中選擇更好的特徵。後面會詳細介紹特徵選擇主要區別於降維。

2.3 數據的來源與類型

  • 數據的來源

通過爬蟲爬取、購買數據、網上的開放數據等。

  • 數據的類型

按照機器學習的數據分類我們可以將數據分成:

  • 標稱型:標稱型目標變量的結果只在有限目標集中取值,如真與假
  • 數值型:數值型目標變量則可以從無限的數值集合中取值,

按照數據的本身分佈特性

  • 離散型【無規律】
  • 連續型【有規律】
    • 離散變量是指其數值只能用自然數或整數單位計算的則爲離散變量。例如,班級人數
    • 連續型數據是指在指定區間內可以是任意一個數值。例如,票房數據

2.4 數據的特徵抽取

現實世界中多數特徵都不是連續變量,比如分類、文字等,爲了對非連續變量做特徵表述,需要對這些特徵做數學化表述,因此就用到了特徵提取. sklearn.feature_extraction提供了特徵提取的很多方法

2.4.1 分類特徵提取變量

我們將城市和環境作爲字典數據,來進行特徵的提取。將映射列表轉換爲Numpy數組。

from sklearn.feature_extraction import DictVectorizer
# sparse 是否轉換爲scipy.sparse矩陣表示,默認開啓,如果結果不用toarray,請開啓sparse= False
onehot = DictVectorizer(sparse= False)
instances = [{'city': '北京', 'temperature': 100}, {'city': '上海', 'temperature': 60}, {'city': '深圳', 'temperature': 30}]

# 應用並轉化映射列表X,y爲目標類型
X = onehot.fit_transform(instances)

# 將Numpy數組或scipy.sparse矩陣轉換爲映射列表
Y = onehot.inverse_transform(X)

2.4.2 文本特徵處理(只限英文)

文本的特徵提取應用於很多方面,比如說文檔分類、垃圾郵件分類和新聞分類。那麼文本分類是通過詞是否存在、以及詞的概率(重要性)來表示。

from sklearn.feature_extraction.text import CountVectorizer


# 構建文章【英文】

content = ['This is the first document.', 'This is the second second document.', 'And the third one.', 'Is this the first document? i x y']

#構建實例
con_vet = CountVectorizer()
#進行提取詞語
x = con_vet.fit_transform(content)

print(x)   # (0, 1) 1 (文章下標,分詞下標) 詞在文章中出現的次數  sparse矩陣
print(x.toarray()) # 將 sparse矩陣 轉化爲 數組

# 獲取提取到詞語
names = con_vet.get_feature_names()
print(names) # 提取到的詞

  • 處理中文,我們可以使用jieba分詞,進行分詞之後,進行處理
# pip install jieba

import jieba
from sklearn.feature_extraction.text import CountVectorizer

# 構建文章【中文】

content = ["今天陽光真好","我要去看北京天安門","逛完天安門之後我要去王府井","吃烤蠍子與烤蜈蚣","晚上去後海蹦個迪"]

content_list = []

for tmp in content:
    # 使用精確模式進行分詞 cut_all默認爲精確模式
    res = jieba.cut(tmp,cut_all= False)
    res_str = ','.join(res)
    content_list.append(res_str)


#構建實例
con_vet = CountVectorizer()

#進行提取詞語
x = con_vet.fit_transform(content_list)

print(x)   # (0, 1)	1 (文章下標,分詞下標) 詞在文章中出現的次數  sparse矩陣
print(x.toarray()) # 將 sparse矩陣 轉化爲 數組

# 獲取提取到詞語
names = con_vet.get_feature_names()
print(names) # 提取到的詞

2.5 特徵預處理

  • 單個特徵
    • 歸一化

      歸一化首先在特徵(維度)非常多的時候,可以防止某一維或某幾維對數據影響過大,也是爲了把不同來源的數據統一到一個參考區間下,這樣比較起來纔有意義,其次可以程序可以運行更快。】常用的方法是通過對原始數據進行線性變換把數據映射到[0,1]之間,變換的函數爲:

    X=xminmaxmin X^{'}{=}\frac{x-min}{max-min}

    ​ 其中min是樣本中最小值,max是樣本中最大值,注意在數據流場景下最大值最小值是變化的,另外,最 大值與最小值非常容易受異常點影響,所以這種方法魯棒性較差,只適合傳統精確小數據場景。

    • 標準化

      將數據轉化爲同一量級,避免量級對結果產生不利的影響①離差標準化②標準差標準化③小數定標標準化常用的方法是z-score標準化,經過處理後的數據均值爲0,標準差爲1,處理方法是:

    X=xμσ X^{'}{=}\frac{x-\mu}{\sigma}

    ​ 其中μ是樣本的均值,σ是樣本的標準差,它們可以通過現有的樣本進行估計,在已有的樣本足夠多的情 況下比較穩定,適合嘈雜的數據場景

    • 缺失值

      由於各種原因,許多現實世界的數據集包含缺少的值,通常編碼爲空白,NaN或其他佔位符。然而,這樣的數據集與scikit的分類器不兼容,它們假設數組中的所有值都是數字,並且都具有和保持含義。使用不完整數據集的基本策略是丟棄包含缺失值的整個行和/或列。然而,這是以丟失可能是有價值的數據(即使不完整)的代價。更好的策略是估算缺失值,即從已知部分的數據中推斷它們。

      • 刪除 ----會對數據產生很大的影響,造成數據缺失,所以在數據大部分爲缺失值,才使用刪除法;
      • 填充 — 填充之後對結果影響不大的情況,可以使用(均值,中位數,衆數);
      • 插值(線性插值;多項式插值;樣條插值)
  • 多個特徵
    • PCA(Principal component analysis),主成分分析。特點是保存數據集中對方差影響最大的那些特徵,PCA極其容易受到數據中特徵範圍影響,所以在運用PCA前一定要做特徵標準化,這樣才能保證每維度特徵的重要性等同。
    class PCA(n_components, whiten, svd_solver)
       """
       主成成分分析
       :param n_components: int, float, None or string
           這個參數可以幫我們指定希望PCA降維後的特徵維度數目。最常用的做法是直接指定降維到的維度數目,此時n_components是一個大於1的整數。
           我們也可以用默認值,即不輸入n_components,此時n_components=min(樣本數,特徵數)
    
       :param whiten: bool, optional (default False)
          判斷是否進行白化。所謂白化,就是對降維後的數據的每個特徵進行歸一化。對於PCA降維本身來說一般不需要白化,如果你PCA降維後有後續的數據處理動作,可以考慮白化,默認值是False,即不進行白化
    
       :param svd_solver:
          選擇一個合適的SVD算法來降維,一般來說,使用默認值就夠了。
        """
    

2.6 數據特徵選擇

降維本質上是從一個維度空間映射到另一個維度空間,特徵的多少別沒有減少,當然在映射的過程中特徵值也會相應的變化。舉個例子,現在的特徵是1000維,我們想要把它降到500維。降維的過程就是找個一個從1000維映射到500維的映射關係。原始數據中的1000個特徵,每一個都對應着降維後的500維空間中的一個值。假設原始特徵中有個特徵的值是9,那麼降維後對應的值可能是3。而對於特徵選擇來說,有很多方法:

  • Filter(過濾式):VarianceThreshold
  • Embedded(嵌入式):正則化、決策樹
  • Wrapper(包裹式)

其中過濾式的特徵選擇後,數據本身不變,而數據的維度減少。而嵌入式的特徵選擇方法也會改變數據的值,維度也改變。Embedded方式是一種自動學習的特徵選擇方法,後面講到具體的方法的時候就能理解了。

特徵選擇主要有兩個功能:

  • 減少特徵數量,降維,使模型泛化能力更強,減少過擬合
  • 增強特徵和特徵值之間的理解

3 sklearn 數據集

sklearn中的數據集類,模塊包括用於加載數據集的實用程序,包括加載和獲取流行參考數據集的方法。它還具有一些人工數據生成器。sklearn數據集源代碼

3.1 數據集概述

datasets.load_*() # 獲取小規模數據集,數據包含在datasets裏

# 獲取大規模數據集,需要從網絡上下載,函數的第一個參數是data_home,表示數據集下載的目錄,默認是 ~/scikit_learn_data/,要修改默認目錄,可以修改環境變量SCIKIT_LEARN_DATA
datasets.fetch_*()

datasets.make_*() # 本地生成數據集
  • load*和 fetch* 函數返回的數據類型是 datasets.base.Bunch,本質上是一個 dict,它的鍵值對可用通過對象的屬性方式訪問。主要包含以下屬性:
    • data:特徵數據數組,二維 數組
    • target:標籤數組,一維 數組
    • DESCR:數據描述
    • feature_names:特徵名
    • target_names:標籤名
  • 數據集目錄可以通過datasets.get_data_home()獲取,clear_data_home(data_home= None)刪除所有下載數據
    • datasets.get_data_home(data_home= None)

      返回scikit學習數據目錄的路徑。這個文件夾被一些大的數據集裝載器使用,以避免下載數據。默認情況下,數據目錄設置爲用戶主文件夾中名爲“scikit_learn_data”的文件夾。或者,可以通過“SCIKIT_LEARN_DATA”環境變量或通過給出顯式的文件夾路徑以編程方式設置它。’〜'符號擴展到用戶主文件夾。如果文件夾不存在,則會自動創建。

    • sklearn.datasets.clear_data_home(data_home= None)

      刪除存儲目錄中的數據

3.2 獲取小數據集

  • 加載虹膜數據集
名稱 數量
類別 3
特徵 4
樣本數量 150
每個類別數量 50
from sklearn.datasets import load_iris
data = load_iris()
# 查看數據
data
  • 加載數字數據集
名稱 數量
類別 10
特徵 64
樣本數量 1797
from sklearn.datasets import load_digits

digits = load_digits()

# 數據格式
digits.data.shape
# 標籤
digits.target
# 標籤名
digits.target_names
# 數據展示
digits.images
  • 加載波士頓房價數據集
名稱 數量
目標類別 5-50
特徵 13
樣本數量 506
from sklearn.datasets import load_boston
boston = load_boston()

# 數據格式
boston.data.shape

# 數據列名
boston.feature_names

3.3 獲取大數據集

  • 加載20個新聞組數據集中的文件名和數據【14兆左右】
參數說明
subset ‘train’或者’test’,‘all’,可選,選擇要加載的數據集:訓練集的“訓練”,測試集的“測試”,兩者的“全部”,具有洗牌順序
data_home 可選,默認值:無,指定數據集的下載和緩存文件夾。如果沒有,所有scikit學習數據都存儲在’〜/ scikit_learn_data’子文件夾中
categories 無或字符串或Unicode的集合,如果沒有(默認),加載所有類別。如果不是無,要加載的類別名稱列表(忽略其他類別)
shuffle 是否對數據進行洗牌
random_state numpy隨機數生成器或種子整數
download_if_missing 可選,默認爲True,如果False,如果數據不在本地可用而不是嘗試從源站點下載數據,則引發IOError
from sklearn.datasets import fetch_20newsgroups

# 'train'或者'test','all',可選,選擇要加載的數據集:訓練集的“訓練”,測試集的“測試”,兩者的“全部”,具    有洗牌順序
# 是否對數據進行洗牌
# numpy隨機數生成器或種子整數
data_test = fetch_20newsgroups(subset= 'test', shuffle= True, random_state= 42)

data_train = fetch_20newsgroups(subset= 'train', shuffle= True, random_state= 42)

3.4 獲取本地生成數據

  • 生成本地分類數據
參數說明
n_samples int,optional(default = 100),樣本數量
n_features:int 可選(默認= 20),特徵總數
n_classes 可選(default = 2),類(或標籤)的分類問題的數量
random_stat RandomState實例或無,可選(默認=無) 如果int,random_state是隨機數生成器使用的種子; 如果RandomState的實例,random_state是隨機數生成器; 如果沒有,隨機數生成器所使用的RandomState實例np.random
from sklearn.datasets.samples_generator import make_classification
X,y= datasets.make_classification(n_samples= 100000, n_features= 20, n_informative= 2, n_redundant= 10, random_state= 42)
  • 生成本地迴歸數據
參數說明
n_samples int,optional(default = 100),樣本數量
n_features int,optional(default = 100),特徵數量
coef boolean,optional(default = False),如果爲True,則返回底層線性模型的係數
random_state int,RandomState實例或無,可選(默認=無) 如果int,random_state是隨機數生成器使用的種子; 如果RandomState的實例,random_state是隨機數生成器; 如果沒有,隨機數生成器所使用的RandomState實例np.random
from sklearn.datasets.samples_generator import make_regression
X, y = make_regression(n_samples= 200, n_features= 5000, random_state= 42)

3.5 estimator的工作流程

在sklearn中,估計器(estimator)是一個重要的角色,分類器和迴歸器都屬於estimator。在估計器中有有兩個重要的方法是fit和transform。

  • fit方法用於從訓練集中學習模型參數
  • transform用學習到的參數轉換數據

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NsbAHL4F-1574825755329)(image\1574418658501.png)]

使用sklearn工具可以方便地進行特徵工程和模型訓練工作,特徵處理類都有三個方法fit、transform和fit_transform,從命名中可以看到,fit_transform方法是先調用fit然後調用transform,我們只需要關注fit方法和transform方法即可。

transform方法主要用來對特徵進行轉換。從可利用信息的角度來說,轉換分爲無信息轉換和有信息轉換。無信息轉換是指不利用任何其他信息進行轉換,反之,有信息轉換利用其他信息進行轉換。

fit方法的主要工作是獲取特徵信息和目標值信息,通過分析特徵和目標值,提取有價值的信息,對於轉換類來說是某些統計量,對於模型來說可能是特徵的權值係數等。

4 機器學習流程實踐

  • 真實數據觀察全局
  • 選擇性能指標、檢查假設
  • 獲取數據
    • 創建工作區,快速查看數據結構,創建測試集
  • 從可視化中探索數據
    • 將數據可視化、尋找相關性、試驗不同的屬性組合
  • 機器學習前的數據準備
    • 數據清理、自定義轉換器、特徵縮放、轉換流水線
  • 選擇訓練模型
    • 評估訓練集、交叉驗證、分析最佳模型及其錯誤、測試集評
  • 模型調優
  • 分析最佳模型和測試集評估
  • 系統維護和監控

4.1 觀察數據、選擇指標、檢查假設

4.1.1 觀察數據

  • 機器學習最好使用真實數據,而不僅僅是使用人工數據。可以選擇開源數據集。
  • 使用加州人口的普查的數據建立起加州的房價模型。數據中包含很多指標:每個街區人口的數量,收入中位數等,
  • 加州房產價格數據集

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-TWnmPZqc-1574825755330)(image/1574214898683.png)]

4.1.2 選擇指標

  • 瞭解建立模型的目的,盈利模式,從而選擇相應的指標。因爲模型不是最終目的,這些問題將決定你怎麼設定問題,選擇什麼算法,使用什麼測量方式來衡量模型的性能。
  • 劃定問題:監督或非監督,還是強化學習?這是個分類任務、迴歸任務,還是其它的?【本章特徵工程主要是處理數據,具體的機器學習劃分在下一模塊‘機器學習’】
    • 這是一個典型的監督學習任務,因爲你要使用的是有標籤的訓練樣本(每個實例都有預定的產出,即分區的房價中位數)。並且,這是一個典型的迴歸任務,因爲你要預測一個值。講的更細些,這是一個多變量回歸問題,因爲系統要使用多個變量進行預測(要使用分區的人口,收入中位數等等)。
  • 選擇性能指標。迴歸問題的典型指標是均方根誤差(RMSE)。均方根誤差測量的是系統預測誤差的標準差。

4.1.3 檢查假設

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-BBsylL2t-1574825755332)(image/1574216445901.png)]

最好列出並覈對迄今(你或其他人)作出的假設。,這樣可以儘早發現嚴重的問題。例如,你的系統輸出的分區房價,會傳入到下游的機器學習系統,我們假設這些價格確實會被當做分區房價使用。但是如果下游系統實際上將價格轉化成了分類(例如,便宜、中等、昂貴),然後使用這些分類,而不是使用價格。這樣的話,獲得準確的價格就不那麼重要了,你只需要得到合適的分類。問題相應地就變成了一個分類問題,而不是迴歸任務。

4.2 獲取數據

4.2.1 創建工作區

推薦創建一個隔離環境,這樣可以在庫版本不衝突的情況下處理不同的項目

  • 用pip安裝virtualenv
pip install virtualenv
  • 創建目錄,並進入文件夾
mkdir myproject
cd myproject
  • 創建一個獨立的python環境,命名爲venv【命令virtualenv就可以創建一個獨立的Python運行環境,我們還加上了參數--no-site-packages,這樣,已經安裝到系統Python環境中的所有第三方包都不會複製過來,這樣,我們就得到了一個不帶任何第三方包的“乾淨”的Python運行環境。】
virtualenv --no-site-packages venv
  • 激活環境
activate myproject
  • 安裝模塊
pip install jupyter numpy pandas scipy matplotlib  scikit-learn
  • 測試安裝模塊
python -c 'import jupyter, numpy, pandas, scipy, matplotlib, scikit-learn'
  • 退出獨立環境
deactivate 

4.2.2 查看數據,創建測試集

  • 數據獲取
## 獲取數據
import os
import pandas as pd
def load_housing_data(housing_path = './'):
    csv_path = os.path.join(housing_path, 'housing.csv')
    return pd.read_csv(csv_path)
housing = load_housing_data() # 讀取數據
housing.head() # 查看前五條數據
housing.shape  # 查看數據結構
housing.info() # 查看數據集的簡單描述, 得到每個屬性類型和非空值數據量

#  total_bedrooms  20433 有一部分空值
housing['ocean_proximity'].value_counts()  # 查看多少種分類,5 種分類,獲得每種分類下有少區域

housing.describe()  # 顯示數值屬性摘要

# 使用直方圖展示數據
import matplotlib.pyplot as plt
housing.hist(bins = 50, figsize = (20, 15))
plt.show()
  • 創建測試集,訓練集
#訓練集用於模型訓練 佔整個數據集的80% ,測試佔20%
import numpy as np
def split_train_test(data, test_radio):
    np.random.seed(42)
    indices = np.random.permutation(len(data)) #對原來的數組進行重新洗牌,隨機打亂原來的元素順序
    test_set_size = int(len(data) * test_radio)
    test_indices = indices[:test_set_size]
    train_indices = indices[test_set_size:]
    return data.iloc[train_indices], data.iloc[test_indices]
train_set, test_set = split_train_test(housing, 0.2)



#對樣本設置唯一的標識符,對標識符取hash值, 去hash的最後一個字節, 值小於等於51 ,256*20%,放入測試集,hash值相同,對象不一定相同,hash不同,對象一定不同
import hashlib

def test_set_check(identifier, test_radio, hash = hashlib.md5):
     #返回摘要,作爲二進制數據字符串
    return hash(np.int64(identifier)).digest()[-1] < 256 * test_radio 

def split_train_test_by_id(data, test_ratio, id_column):
    ids = data[id_column]
    in_test_set = ids.apply(lambda id_:test_set_check(id_, test_ratio))
    return data.loc[~in_test_set], data.loc[in_test_set]

housing_with_id = housing.reset_index()  # 使用行索引作爲標識符 ID

housing_with_id.head() # 查看數據

train_set, test_set = split_train_test_by_id(housing_with_id, 0.2, 'index') # 返回測試集,訓練集

# 基於行索引,不能刪除和中間插入數據,只能末尾插入,否則行索引會變
# 尋找穩定特徵來創建唯一標識符,
housing_with_id['id'] = housing['longitude'] * 1000 + housing['latitude']
housing_with_id.head()
train_set, test_set = split_train_test_by_id(housing_with_id, 0.2, 'id')



from sklearn.model_selection import train_test_split
train_set, test_set = train_test_split(housing, test_size = 0.2, random_state = 42)
train_set.head()

# 如果數據集一直更新,使用最後一種,數據集一直不變使用最基礎就行,

4.3 從可視化中探索數據

4.3.1 可視化數據

將數據可視化、尋找相關性、試驗不同的屬性組合,將數據進行可視化展示,可以幫助我們快速的瞭解數據類型。

  • 分層採樣

分層抽樣(保留類別比例的採樣方式) :先將總體按照某種特徵分爲若干次級(層),然後從每一層內進行單純的隨機抽樣,組成一個樣本羣。

抽樣偏差:調查公司給1000個人來調研幾個問題,不會在電話簿中隨機查找1000人,他們視圖確保1000人代表全體人口,美國人,51.3女性,48.7男性,你的調查應該維持這一比例,513名女性,487男性,這就是分層採樣,人口劃分爲均勻的子集,每個子集稱爲一層,然後從每層中抽取正確的實例數量
# 希望測試集能夠代表整個數據集中各種不同類型的收入
  #1. 創建一個收入類別屬性 
  #2. 不應該數據分層太多,但每一層應該有足夠的數據量
  #3. 將收入中位數除以1.5,限制收入類別數量,使用ceil取整,得到離散類別,將大於5的列別合併爲類別5

#中位數除以1.5,限制收入類別數量,使用ceil取整
housing['income_cat'] = np.ceil(housing['median_income'] / 1.5)
housing['income_cat'].head(20) # 查看數據

#將大於5的列合併爲類別5
housing['income_cat'].where(housing['income_cat'] < 5, 5.0, inplace= True )
housing['income_cat'].head(20)

housing['income_cat'] = pd.cut(housing['median_income'], bins= [0., 1.5, 3.0, 4.5, 6., np.inf], labels = [1,2, 3, 4, 5]) # 把連續值轉換成類別標籤  

housing['income_cat'].head(20)

# 收入類別直方圖
housing['income_cat'].hist()

# 根據收入類別進行分層採樣
from sklearn.model_selection import StratifiedShuffleSplit

# 獲取訓練集與測試集數據
split = StratifiedShuffleSplit(n_splits= 1, test_size= 0.2, random_state= 42 )

for  train_index, test_index in split.split(housing, housing['income_cat']):
    strat_train_set = housing.loc[train_index]
    strat_test_set = housing.loc[test_index]
strat_train_set.shape
strat_train_set.head(20)


# 查看所有住房數據根據收入類別比例分佈,收入佔類別百分比
strat_test_set['income_cat'].value_counts() / len(strat_test_set)  # 分層抽樣測試集合

housing['income_cat'].value_counts() / len(housing)  # 完整數據集合

def income_cat_proportions(data):
    return data["income_cat"].value_counts() / len(data)

train_set, test_set = train_test_split(housing, test_size= 0.2, random_state= 42)

compare_props = pd.DataFrame({
    "全部數據": income_cat_proportions(housing),
    "分層抽樣": income_cat_proportions(strat_test_set),
    "隨機抽樣": income_cat_proportions(test_set),
}).sort_index()
compare_props["隨機. %error"] = 100 * compare_props["隨機抽樣"] / compare_props["全部數據"] - 100
compare_props["分層. %error"] = 100 * compare_props["分層抽樣"] / compare_props["全部數據"] - 100



# 把測試集已經處理完成,用分層抽樣的訓練集數據來進行分析,分層抽樣的測試集的比例分佈與完整數據集中的分佈幾乎-致。
  • 將地理數據可視化
# 一般來說,我們的大腦非常善於從圖片中發現模式,但是你需要玩轉可視化參數,才能讓這些模式凸顯出來
# 建立一個各區域的分佈圖,以便於數據可視化
housing.plot(kind= 'scatter', x= 'longitude', y= 'latitude')

# 將alpha 設置爲 0.1 , 可以看出高密度數據點的位置
housing.plot(kind= 'scatter', x= 'longitude', y= 'latitude', alpha= 0.1)

# 我們的大腦非常善於從圖片中發現模式,但是需要玩轉可視化參數才能讓這些模式凸顯出來
housing.plot(kind= "scatter", x= "longitude", y= "latitude", alpha= 0.4,
    s= housing["population"] / 100, label= "population", figsize= (10, 7),
    c= "median_house_value", cmap= plt.get_cmap("jet"), colorbar= True,
    sharex= False)

# 加載本地圖片
import matplotlib.image as mpimg
california_img = mpimg.imread('./california.png')

# 設置參數,標題
housing.plot(kind= "scatter", x= "longitude", y= "latitude", alpha= 0.4,
    s= housing["population"] / 100, label= "population", figsize= (10, 7),
    c= "median_house_value", cmap= plt.get_cmap("jet"), colorbar= False,
    sharex= False)
# 展示圖片,extent參數: x軸的起始點,y軸的起始點
plt.imshow(california_img, extent= [-124.55, -113.80, 32.45, 42.05], alpha= 0.5,
           cmap= plt.get_cmap("jet"))
# x,y軸顯示
plt.ylabel("Latitude", fontsize= 14)
plt.xlabel("Longitude", fontsize= 14)

# 房屋價格中位數
prices = housing["median_house_value"]

# 最大值 ,最小值之間11等分
tick_values = np.linspace(prices.min(), prices.max(), 11)
cbar = plt.colorbar()
# 轉化可視化輸出
cbar.ax.set_yticklabels(["$%dk"%(round(v / 1000)) for v in tick_values], fontsize= 14)
cbar.set_label('Median House Value', fontsize= 16)

plt.legend(fontsize= 16)

plt.show()

# 從圖片中告訴我們,房屋價格與地理位置靠海,和人口密度息息相關

4.3.2 尋找相關度

  • 統計方法
# corr() 計算出每對特徵之間的相關係數, 稱爲皮爾遜相關係數
corr_matrix =  housing.corr()
corr_matrix

corr_matrix['median_house_value'].sort_values(ascending= False)

# 相關係數範圍 從 -1 變化到 1,越接近1 ,表示越強的正相關,,比如,當收入中位數上升時,房價中位數也趨於上升,
# 當係數接近-1 ,則表示有強烈的負相關,緯度和房價中位數之間出現輕微的負相關,越往北走,房價傾向於下降,
# 係數靠近0 ,說明二者之間沒有線性相關性,
# 相關係數僅檢測 線性相關性 ,如果x上升,y上升或者下降,可能會徹底遺漏非線性相關性,例如 如果x接近於0,y上升
  • 圖示方法
# 使用padans scatter_matrix 函數,可以繪製特徵之間的相關性
from pandas.plotting import scatter_matrix

attributes = ['median_house_value', 'median_income', 'total_rooms', 'housing_median_age']
scatter_matrix(housing[attributes], figsize= (12, 8) )

housing.plot(kind= 'scatter', x= 'median_income', y= 'median_house_value', alpha= 0.1)
plt.axis([0, 16, 0, 550000])

# 50萬美元是一條清晰的線,被設置上限了, 45w,35w,28w,也有虛線, 可能是異常值,我可以在後期把數據刪除掉
  • 在給機器學習算法輸入數據之前,我們識別出了一些異常數據,需要提前清理掉,也發現了不同屬性之間的某些聯繫,跟目標屬性相關的聯繫
  • 某些屬性分佈顯示出了明顯的“重尾”分佈,對進行轉換處理,計算其對數
  • 在給機器學習算法輸入數據之前,最後一件事兒,嘗試各種屬性的組合
  • 每個項目歷程都不一樣,大致思路都相識

4.3.3 試驗不同的組合

在準備給機器學習算法輸入數據之前,我們還需要做最後一件事,嘗試各種屬性的組合。

  • 比如:如果不知道一個地區有多少家庭,那麼知道一個地區的房間總數’也沒有什麼用。我們真正想知道的是,一個家庭的房間的數量。
  • 或者,單看臥室總數這個屬性本身,也沒有什麼意義。你可能是想拿它和“房間總數來對比,或者拿來同“每個家庭的人口數”這個屬性結合着使用。
## 試驗不同特徵的組合
housing.head()
housing['rooms_per_household'] = housing['total_rooms'] / housing['households']
housing['bedrooms_per_room'] = housing['total_bedrooms'] / housing['total_rooms']
housing['population_per_household'] = housing['population'] / housing['households']

# 關聯矩陣
corr_matrix = housing.corr()
corr_matrix['median_house_value'].sort_values(ascending= False)

# 新的屬性較之“房間總數”、‘臥室總數等屬性,與房價中位數的相關性要好很多。

5 機器學習數據準備

5.1 加載數據、分離測試集

## 獲取數據
import os
import pandas as pd
def load_housing_data(housing_path = './'):
    csv_path = os.path.join(housing_path, 'housing.csv')
    return pd.read_csv(csv_path)
housing = load_housing_data() # 讀取數據
housing.head() # 查看前五條數據
housing.shape  # 查看數據結構
housing.info() # 查看數據集的簡單描述, 得到每個屬性類型和非空值數據量


#中位數除以1.5,限制收入類別數量,使用ceil取整
housing['income_cat'] = np.ceil(housing['median_income'] / 1.5)
housing['income_cat'].head(20) # 查看數據

#將大於5的列合併爲類別5
housing['income_cat'].where(housing['income_cat'] < 5, 5.0, inplace= True )
housing['income_cat'].head(20)

housing['income_cat'] = pd.cut(housing['median_income'], bins= [0., 1.5, 3.0, 4.5, 6., np.inf], labels= [1,2, 3, 4, 5]) # 把連續值轉換成類別標籤  

housing['income_cat'].head(20)

# 收入類別直方圖
housing['income_cat'].hist()

# 根據收入類別進行分層採樣
from sklearn.model_selection import StratifiedShuffleSplit

# 獲取訓練集與測試集數據
split = StratifiedShuffleSplit(n_splits= 1, test_size= 0.2, random_state= 42 )

for  train_index, test_index in split.split(housing, housing['income_cat']):
    strat_train_set = housing.loc[train_index]
    strat_test_set = housing.loc[test_index]
strat_train_set.shape
strat_train_set.head(20)


# 查看所有住房數據根據收入類別比例分佈,收入佔類別百分比
strat_test_set['income_cat'].value_counts() / len(strat_test_set)  # 分層抽樣測試集合

housing['income_cat'].value_counts() / len(housing)  # 完整數據集合

def income_cat_proportions(data):
    return data["income_cat"].value_counts() / len(data)

train_set, test_set = train_test_split(housing, test_size= 0.2, random_state= 42)



# 分離測試集
# 得到一個分層抽樣代表全局數據集的  訓練集和測試集
strat_train_set.head()

# 將數據集的數據和標籤分開 
housing_labels = strat_train_set['median_house_value'].copy()

housing = strat_train_set.drop('median_house_value', axis= 1)

housing.head()

housing.info()

5.2 數據清洗

大多數機器學算法無法在缺失的特徵上工作,創建一些函數輔助,total_bedrooms有缺失,

  • 放棄這些區域
  • 放棄這個屬性
  • 將缺失值設置爲某個值,(0,平均數或者中位數都可以)
# 創建一個imputer實例,指定你要用屬性中的中位數值替換該屬性的缺失值 
from sklearn.preprocessing import Imputer as SimpleImputer

imputer = SimpleImputer(strategy = 'median')

# 使用fit() 方法將 imputer實例適配到訓練集
housing_num = housing.drop('ocean_proximity', axis= 1)
imputer.fit(housing_num)

# 獲得特徵中位數【內置方法】
imputer.statistics_

#獲得中位數
housing_num.median().values

# 每個特徵的值
X = imputer.transform(housing_num)

# 再次檢測一下,觀察是否存在缺失值
housing_tr = pd.DataFrame(X, columns= housing_num.columns, index= housing_num.index)
housing_tr.head()
# info也可以查看
housing_tr.info()

#scikit-Learn【具體見下一章機器學習】
#* 一致性
#   1. 估算器
#       比如:各種機器學習算法
#       fit()執行估算器
#
#   2. 轉換器  
#       比如:LabelBinarizer
#       transform()  執行轉換數據集
#       fit_transform()  先估算,再轉換
#   3. 預測器
#       predict()  對給定的新數據集進行預測
#       score()    評估測試集的預測質量
#* 檢查
#    1. imputer.strategy_學習參數通過公共實例變量訪問

5.3 處理文本和分類屬性

大部分的機器學習算法,更容易更數值打交道,所以我們先將文本轉化爲數字。

housing_cat = housing[['ocean_proximity']]
housing_cat.head(10)


housing['ocean_proximity'].value_counts()

# 將文本轉化成對應的數字分類 , 使用轉換器
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()
housing_cat = housing['ocean_proximity']
housing_cat_encoder = encoder.fit_transform(housing_cat) # 將字符轉化爲數字
housing_cat_encoder
# 私有屬性,可以用來查看字符屬性
encoder.classes_

# 1. 機器學習算法會以爲兩個相近的數字比遠的數字更相似,比如0,4 比  0,1相似度更高,
# 2. 創建獨熱編碼,當 <1H ,第0個屬性爲1,其餘都爲0, 列別是InLand時候,另一個屬性爲1,其餘爲0,1爲熱,0爲冷,獨熱編碼
# 3. OneHotEncoder編碼器, fit_trans需要二維數組, 轉換housing_cat

# 我們按照上述的方式進行轉化,數據編碼後的標籤具有一定的依賴關係,我們是有onehot編碼
from sklearn.preprocessing import OneHotEncoder
encoder = OneHotEncoder()
housing_cat_encoder

housing_cat_encoder.reshape(-1, 1)

housing_cat_hot = encoder.fit_transform(housing_cat_encoder.reshape(-1, 1))
housing_cat_hot

# 從稀疏矩陣 轉換成 numpy【上述是一個稀疏矩陣, 而不是numpy的一個二 維數組。 稀疏矩陣選擇僅存儲非零元素的位置。但是你依舊可以像使用一個普通的二維數組那樣來使用他。使用toarray()即可以轉化爲二維數】
housing_cat_hot.toarray()

# 一次完成兩個轉換 文本--整數類型--獨熱類型
housing_cat
from sklearn.preprocessing import LabelBinarizer
encoder = LabelBinarizer()
housing_cat_1hot = encoder.fit_transform(housing_cat)
# 返回二維數組
housing_cat_1hot 

# 輸出稀疏矩陣
from sklearn.preprocessing import LabelBinarizer
encoder = LabelBinarizer(sparse_output= True)
housing_cat_1hot = encoder.fit_transform(housing_cat)
housing_cat_1hot

5.4 自定義轉化器

#希望自定義的轉換器與skleam自身的功能無縫銜接,所以需要創建一個類,然後應用以下三個方法: fit、transform、fit_transform.

from sklearn.base import BaseEstimator, TransformerMixin
rooms_ix, bedrooms_ix, population_ix, household_ix = [list(housing.columns).index(col) for col in ("total_rooms", "total_bedrooms", "population", "households")]
rooms_ix, bedrooms_ix, population_ix, household_ix 

class CombinedAttributesAdder(BaseEstimator, TransformerMixin):
    def __init__(self, add_bedrooms_per_room = True):
        self.add_bedrooms_per_room = add_bedrooms_per_room
    def fit(self, X, y= None):
        return self
    def transform(self, X,  = None):
        rooms_per_household = X[:, rooms_ix] / X[:, household_ix]
        population_per_household = X[:, population_ix] / X[:, household_ix]
        if self.add_bedrooms_per_room:
            bedrooms_per_room = X[:, bedrooms_ix] / X[:, rooms_ix]
            return np.c_[X, rooms_per_household,population_per_household, bedrooms_per_room]
        else:
            return np.c_[X, rooms_per_household,population_per_household]
        
# 傳入自己的變量     
attr_adder = CombinedAttributesAdder(add_bedrooms_per_room= False)
housing_extra_attribs = attr_adder.transform(housing.values)

# 查看數據
housing_tr = pd.DataFrame(housing_extra_attribs)
housing_tr.head()

# 給數據添加列名
housing_extra_attribs = pd.DataFrame(
    housing_extra_attribs,
    columns=list(housing.columns)+["rooms_per_household", "population_per_household"],
    index=housing.index)
housing_extra_attribs.head()

5.5 特徵縮放

最重要也是最需要應用在數據上的轉換器,就是特徵縮放,輸入數值屬性有很大的比例差異,會導致機器學習算法性能表現不佳

  • 注意:目標值通常不進行縮放。
  • 常見的縮放的方法:最小-最大縮放、標準化
    • 最小最大縮放(MinMaxScaler)又叫歸一化,將值重新縮放到0到1之間,將值減去最小值併除以最大值和最小值差,如果你不希望是0到1,可以調整超參數feature_range進行更改
    • 標準化減去平均值 ,所以標準化均值總是0,然後除以方差,結果的分佈具備單位方差,不同於歸一化,標準化不將值綁定到特定範圍,受異常值影響小
  • 注意:和所有的轉換器一樣, 縮放器僅用來擬合訓練集,而不是完整的數據集。

5.6 轉換流水線

# 許多數據轉換的步驟需要以正確的順序來執行, PipeLine來支持這樣的轉換
# pipline構造函數會通過一系列名稱/估算器的配對來定義步驟的序列,必須是轉換器,必須有fit_fransform()方法
# 調用流水芡的fit方法時,會在所有轉換器上按照順序依次調用fit_transform(),將一個調用的輸出作爲參數傳遞給下一個調用方法,直到傳遞到最終
# 估算器,只會調用fit方法
  • 估算器:能夠根據數據集對某系參數進行估算的任意對象都可以被稱爲估算器。估算由fit方法執行,他只需要一個數據集作爲參數。 引導估算過程的任何其他參數都算作是超參數,它必須被設置爲一個實例變量。

  • 轉換器:有些估算器也可以轉換數據集,這些被稱爲轉換器。由transform()方法和作爲參數的待轉換數據集一起執行。返回轉換後的數據集。這些轉換器是依賴於學習的參數的, 如imputer.所有的轉換器都可以使用一個很方便的方法t transform () ,相當於先調用fit方法,後調用transform()。

  • 預測器:還有一-些估算器能夠基於個給定的數據集進行預測, 這個被稱爲預測器。預測器的predict()方法會接受-個新實例的數據集, 然後返回一個包含相應預測的數據集。值得一提的是,還有一個score方法,可以用來衡量給定測試集的預測質量。

  • 所有估算器的超參數都可以使用公共實例變量直接訪問,並且所有估算器的學習參數也可以通過有下劃線後綴的公共實例變量來訪問。

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

num_pipeline = Pipeline([
        ('imputer', SimpleImputer(strategy= "median")),
        ('attribs_adder', CombinedAttributesAdder()),
        ('std_scaler', StandardScaler())
    ])

housing_num_tr = num_pipeline.fit_transform(housing_num)

housing_num.info()

# dataFrame -> series -> ndarray
class DataFrameSelector(BaseEstimator, TransformerMixin):
    def __init__(self, attribute_names):
        self.attribute_names = attribute_names
    def fit(self, X, y= None):
        return self
    def transform(self, X):
        return X[self.attribute_names].values
#獲得所有的列名
num_attribs =list(housing_num) 
num_attribs


# 數據集
num_pipeline = Pipeline([
        ('selector', DataFrameSelector(num_attribs)), # dataFrame -> series
        ('imputer', SimpleImputer(strategy= "median")),# 缺失值轉換【中位數】
        ('attribs_adder', CombinedAttributesAdder()),# 合成屬性
        ('std_scaler', StandardScaler()),# 標準化值比較大的數據
    ])

from sklearn.base import TransformerMixin 
#自定義轉化器
class MyLabelBinarizer(TransformerMixin):
    def __init__(self, *args, **kwargs):
        self.encoder = LabelBinarizer(*args, **kwargs)
    def fit(self, x, y= 0):
        self.encoder.fit(x)
        return self
    def transform(self, x, y= 0):
        return self.encoder.transform(x)
    
# 獲得文本列  
cat_attribs = ['ocean_proximity']
# 對文本列進行轉化
from sklearn.preprocessing import LabelBinarizer
cat_pipeline = Pipeline([
        ('selector', DataFrameSelector(cat_attribs)),               
        ('LabelBinarizer', MyLabelBinarizer()),
    ])


#特徵合併
from sklearn.pipeline import FeatureUnion

full_pipeline = FeatureUnion(transformer_list= [
        ("num_pipline", num_pipeline,),
        ('cat_pipline', cat_pipeline),
    ])
#調用
housing_prepared = full_pipeline.fit_transform(housing)
housing_prepared
# 上述得到的ndarry 轉化爲df格式
housing_prepared = pd.DataFrame(housing_prepared)
housing_prepared.head()

6 選擇和訓練模型

到目前爲止,定義了問題,獲得了數據,也進行了數據探索,然後對訓練集和測試集進行了抽樣並編寫了轉換流水線。從而可以自動清理和準備機器學習的數據。

6.1 訓練和評估訓練集

## 初始化估算器
from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
# 匹配數據,做模擬訓練
lin_reg.fit(housing_prepared, housing_labels)

# 預測數據
# 取出少量數據進行測試
some_data = housing.iloc[:5]
some_labels = housing_labels.iloc[:5]

# 
some_data_prepared = full_pipeline.transform(some_data)

print("Predictions:", lin_reg.predict(some_data_prepared))

# 均方根誤差處理數據
from sklearn.metrics import mean_squared_error

housing_predictions = lin_reg.predict(housing_prepared)
lin_mse = mean_squared_error(housing_labels, housing_predictions)
lin_mse
lin_rmse = np.sqrt(lin_mse)
lin_rmse

# 大多數地區的房屋中位數 在120000到265000美元之間,預測誤差高達 68628,這是一個典型的模型對訓練數據擬合不足的案例,
# 原因可能是特徵無法提供足夠的信息來做出更好的預測,或者模型本身不夠強大,
# 1. 選擇強大的模型,2 爲算法提供更好的特徵,3.減少對模型的限制等方法,


# 決策樹可以找到複雜的非線性關係
from sklearn.tree import DecisionTreeRegressor

tree_reg = DecisionTreeRegressor(random_state= 42)
tree_reg.fit(housing_prepared, housing_labels)

housing_predictions = tree_reg.predict(housing_prepared)
tree_mse = mean_squared_error(housing_labels, housing_predictions)
tree_rmse = np.sqrt(tree_mse)
tree_rmse
# 完美,也可能是這個模型對數據嚴重過度擬合了,如何確認?輕易不要啓動測試集,拿訓練集中的一部分用於訓練,另一部分用於模型的驗證

6.2 交叉驗證


# 使用train_test_split函數將訓練集分爲較小的訓練集和驗證集,然後根據這些較小的訓練集來訓練模型,並對其進行評估
# sklearn的交叉驗證,將訓練集隨機分割成10個不同的子集,每個子集稱爲一個摺疊,對模型進行10次訓練和評估,每次挑選1個摺疊進行評估,另外9個進行訓練
from sklearn.model_selection import cross_val_score
# neg_mean_squared_error‘ 也就是 均方差迴歸損失 該統計參數是預測數據和原始數據對應點誤差的平方和的均值

# 決策樹交叉驗證
scores = cross_val_score(tree_reg, housing_prepared, housing_labels,
                         scoring= "neg_mean_squared_error", cv= 10)
tree_rmse_scores = np.sqrt(-scores)
tree_rmse_scores


def display_scores(scores):
    print("Scores:", scores)
    print("Mean:", scores.mean())
    print("Standard deviation:", scores.std())

display_scores(tree_rmse_scores)

# 線性 交叉驗證
lin_scores = cross_val_score(lin_reg, housing_prepared, housing_labels,
                             scoring= "neg_mean_squared_error", cv= 10)
lin_rmse_scores = np.sqrt(-lin_scores)
display_scores(lin_rmse_scores)


# 隨機森林模型
from sklearn.ensemble import RandomForestRegressor

forest_reg = RandomForestRegressor(n_estimators= 10, random_state= 42)
forest_reg.fit(housing_prepared, housing_labels)

# 均方根誤差
housing_predictions = forest_reg.predict(housing_prepared)
forest_mse = mean_squared_error(housing_labels, housing_predictions)
forest_rmse = np.sqrt(forest_mse)
forest_rmse

# 隨機森林 交叉驗證
from sklearn.model_selection import cross_val_score
forest_scores = cross_val_score(forest_reg, housing_prepared, housing_labels,
                                scoring= "neg_mean_squared_error", cv= 10)
forest_rmse_scores = np.sqrt(-forest_scores)
display_scores(forest_rmse_scores)

6.3 模型調優

6.3.1 網格搜索

1.手動調整超參數,找到很好的組合很困難
2.使用GridSearchCV替你進行搜索,告訴它,進行試驗的超參數是什麼,和需要嘗試的值,它會使用交叉驗證評估所有超參數的可能組合

from sklearn.model_selection import GridSearchCV

# 參數組合
param_grid = [
    {'n_estimators': [3, 10, 30], 'max_features': [2, 4, 6, 8]},
    {'bootstrap': [False], 'n_estimators': [3, 10], 'max_features': [2, 3, 4]},
  ]

# 初始化隨機森林
forest_reg = RandomForestRegressor(random_state=4 2)
# 網格確定參數
grid_search = GridSearchCV(forest_reg, param_grid, cv= 5,
                           scoring= 'neg_mean_squared_error', return_train_score= True)
grid_search.fit(housing_prepared, housing_labels)

# 查看最好的參數
grid_search.best_params_
# 查看最好估算器
grid_search.best_estimator_

# 顯示分數結果
cvres = grid_search.cv_results_
for mean_score, params in zip(cvres["mean_test_score"], cvres["params"]):
    print(np.sqrt(-mean_score), params)

# 數據準備步驟也可以當作超參數來處理,網格搜索會自動查找是否添加你不確定的特徵,比如是否使用轉換器 combinedAttre的超參數add_bedrooms_per_rom
# 也可是使用它自動尋找處理問題的最佳方法,比如異常值,缺失特徵,特徵選擇等

6.3.2 隨機搜索


# 如果探索的組合數少的時候,可以考慮使用網格搜索,但是如果探索的組合數較多的時候,應該使用隨機搜索
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import randint
# 給定隨機數
param_distribs = {
        'n_estimators': randint(low= 1, high= 200),
        'max_features': randint(low= 1, high= 8),
    }

forest_reg = RandomForestRegressor(random_state= 42)
rnd_search = RandomizedSearchCV(forest_reg, param_distributions= param_distribs,
                                n_iter= 10, cv= 5, scoring= 'neg_mean_squared_error', random_state= 42)
rnd_search.fit(housing_prepared, housing_labels)
# 最佳模型參數
cvres = rnd_search.cv_results_
for mean_score, params in zip(cvres["mean_test_score"], cvres["params"]):
    print(np.sqrt(-mean_score), params)

6.3.3 分析最佳模型

# 獲得特徵重要度
feature_importances = grid_search.best_estimator_.feature_importances_
feature_importances

# num_attribs
# 合併特徵
extra_attribs = ["rooms_per_household", "population_per_household", "bedrooms_per_room"]
cat_one_hot_attribs = list(encoder.classes_)
attributes = num_attribs + extra_attribs + cat_one_hot_attribs
sorted(zip(feature_importances, attributes), reverse= True)

6.3.4 通過測試集評估系統

# 通過測試集評估系統
   1. 從測試集中獲取預測器和標籤
   2. 運行full_pipline來轉換數據
   3. 在測試集上評估最終模型
# 最佳模型
final_model = grid_search.best_estimator_

# 測試集獲取
X_test = strat_test_set.drop('median_house_value', axis= 1)
y_test = strat_test_set['median_house_value'].copy()

# 準備數據
X_test_prepared = full_pipeline.transform(X_test)
# X_test_prepared

# df = pd.DataFrame(X_test_prepared)
# df.head()


# 進行預測
final_predictions = final_model.predict(X_test_prepared)

# 均方根誤差,等到最優值
final_mse = mean_squared_error(y_test, final_predictions)
final_rmse = np.sqrt(final_mse)
final_rmse

6.4 啓動、監控、維護系統

## 項目啓動階段
   1. 展示解決方案 學習了什麼
   2. 什麼有用
   3. 什麼沒有用
   4. 基於什麼假設
   5. 以及系統的限制有哪些
   6. 製作漂亮的演示文稿,例如收入中位數是預測房價的首要指標

## 啓動,監控和維護系統
   1. 爲生產環境做好準備,將生產數據源接入系統
   2. 編寫監控代碼,定期檢查系統的實時性能,性能下降時觸發警報,系統崩潰和性能退化
   3. 時間推移,模型會漸漸腐壞,定期使用新數據訓練模型

## 評估系統性能 
   1. 需要對系統的預測結果進行抽樣評估,需要人工分析,分析師可能是專家,平臺工作人員,都需要將人工評估的流水線接入你的系統
   2. 評估輸入系統的數據質量
   3. 使用新鮮數據定期訓練你的模型,最多6個月

總結

本週主要學習 數據準備,構建監控工作,建立人工評估流水線,自動化定期訓練模型上,熟悉整個機器學習流程。源代碼

發佈了5 篇原創文章 · 獲贊 162 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章