目前為止,我們已經對資料有了初步的認識,大體上明白了我們要處理的資料型別。現在,我們將進入更深入的研究。
首先,確保已經劃分了測試集並放置一邊,我們只會對訓練集進行操作。另外,如果訓練集很大,可以從中取樣一些作為探索集(exploration set),方便進行快速處理。在我們這個例子中,資料集比較小,所以直接在訓練集上處理即可。我們還要建立一個訓練集的複製副本,這樣就不會改動原來的訓練集了。
housing = strat_train_set.copy()
1. 地理資料視覺化
因為資料集中包含了地理位置資訊(經緯度),所以建立所有地區的散點圖來視覺化資料是個好主意(如下圖所示)。
housing.plot(kind="scatter", x="longitude", y="latitude")
這看起來有點像加州,但是很難看出任何規律。我們設定引數 alpha = 0.1,這樣就更容易看出資料點的密度了(如下圖所示)。
housing.plot(kind="scatter", x="longitude", y="latitude", alpha=0.1)
現在,我們可以很清晰地看出這些密度較大的區域了。
通常來說,人類的大腦非常善於發現圖片中的模式,但是也需要使用一些視覺化引數來讓這些模式更加突出。
接下來,我們來看一下房屋價格(如下圖所示)。其中,圓的半徑代表地區人口(引數 s),圓的顏色代表房價(引數 c)。我們將使用預先定義好的顏色圖 jet(引數 cmap),顏色範圍從藍色(低房價)到紅色(高房價)。
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)
plt.legend()
save_fig("housing_prices_scatterplot")
注意,引數 sharex=False
修復了顯示 x 軸和 legend 不顯示的 bug。感謝 Wilmer Arellano 給的建議。出處:https://github.com/pandas-dev/pandas/issues/10611。
這張圖顯示出房價與地理位置(例如沿海)和人口密度關係很大,這一點你可能早就知道。可以使用聚類演算法檢測主要的聚集,增加新的特徵測量到聚類中心的距離。儘管加州北部沿海地區的房價並不高,但是 ocean_proximity 屬性仍然非常有用。總的來說,預測房價並不是使用一個簡單規則就行的。
2. 尋找關聯性
因為資料集不是很大,我們可以使用 corr() 方法直接計算任意兩個屬性的標準相關係數(也稱皮爾遜相關係數)。
corr_matrix = housing.corr()
現在,我們來看一下每個屬性與房價中位數的相關係數分別是多少:
>>> corr_matrix["median_house_value"].sort_values(ascending=False)
median_house_value 1.000000
median_income 0.687170
total_rooms 0.135231
housing_median_age 0.114220
households 0.064702
total_bedrooms 0.047865
population -0.026699
longitude -0.047279
latitude -0.142826
Name: median_house_value, dtype: float64
相關係數範圍在 [-1, 1] 之間,越接近 1 表示正相關性越強,例如房價中位數與收入中位數。相關係數越接近 -1 表示負相關性越強。你可以看到房價中位數與維度呈現負相關性(資料顯示越往北方,房價呈下降趨勢)。最後,相關係數接近 0 表示無線性相關。下圖展示了 x 軸與 y 軸對應資料的相關係數。
相關係數僅僅測量的是線性相關性(如果 x 增大,y 也同樣增大或減小),可能完全忽略非線性關係(例如,x 在 0 附近,y 會增大)。注意,上圖中最下面的那幾張圖表示的都是相關係數為零的情況,但是它們是非線性相關。第二行展示的幾個圖形相關係數為 1 或 -1,注意與直線的斜率無關。
另外一種檢查不同屬性特徵之間的相關係數的方法是使用 Pandas 的 scatter_matrix
函式。它將對每個數值屬性與其它所有數值屬性的相關性進行作圖。因為現在有 9 個數值屬性,總共有 9×9=81 個圖,頁面放不下這麼多。所以,我們只選擇幾個與房價中位數關係較大的屬性來作圖。
from pandas.tools.plotting import scatter_matrix
attributes = ["median_house_value", "median_income", "total_rooms",
"housing_median_age"]
scatter_matrix(housing[attributes], figsize=(12, 8))
上圖中,主對角線對應的相關係數全是直線(自己與自己的相關係數始終為 1),作圖沒有實質意義,因此顯示的實際上是每個屬性的柱狀圖。關於其它選項設定,可以參閱 Pandas 的文件。
看起來,最有可能用來預測房價中位數的屬性是收入中位數,讓我們把該圖放大來看:
housing.plot(kind="scatter", x="median_income", y="median_house_value",
alpha=0.1)
這張圖說明了幾點:第一,相關性較強。你可以清楚看到資料點整體呈上升趨勢,並不分散。第二,我們之前提過的價格上限 $500,000 呈現一條水平直線。同樣在 $450,000、$350,000 和 $280,000 的位置也呈現了較弱的水平直線。在訓練模型的時候最好移除這些樣本點,防止演算法學習到這些不好的資料。
3. 嘗試結合不同的屬性
希望前面的章節給了你一些探索資料、獲取規律的方法。你發現了一些資料怪癖,在把資料放入機器學習演算法之前,將其清除。你也發現了不同屬性之間的相關性,尤其是與目標屬性的相關性。你也注意到有些屬性呈現長尾分佈,可以進行轉換處理(例如計算它們的對數)。當然,不同專案的處理方法並不完全相同,但是大致思路是類似的。
在準備資料給機器學習演算法之前,你還可以嘗試進行不同的屬性組合。例如,如果你不知道地區有多少戶,只知道地區總的房間數也沒什麼作用。你最想知道的是每戶有多少房間。類似地,知道臥室數量也沒什麼用,你可能需要將其與房屋數量進行比較。還有,每戶人口數應該也比較重要。下面,我們來建立這些屬性:
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)
median_house_value 1.000000
median_income 0.687170
rooms_per_household 0.199343
total_rooms 0.135231
housing_median_age 0.114220
households 0.064702
total_bedrooms 0.047865
population_per_household -0.021984
population -0.026699
longitude -0.047279
latitude -0.142826
bedrooms_per_room -0.260070
Name: median_house_value, dtype: float64
看起來還不錯!bedrooms_per_room
屬性與房價中位數的相關性比單獨的 total_rooms
和 total_bedrooms
與房價中位數的相關性更大。可以看出,bedroom/room
比值越小,房價越高。rooms_per_household
屬性也比 total_rooms
包含了更多的資訊——顯然,房屋越大,價格就越高。
這一輪的探索不一定要非常完備。重要的是正確開始並快速發現一些規律,這將幫助你得到第一個合理的原型。這是一個迭代的過程:一旦你得到一個原型開始執行,你就可以分析它的輸出,發現更多規律,然後回過頭來繼續探索資料,不斷優化模型。
專案地址:
https://github.com/RedstoneWill/Hands-On-Machine-Learning-with-Sklearn-TensorFlow