买房子,就该用线性回归
線性回歸
美國房價問題
Alex經過一年的努力,終于拿到了美國波士頓麻省理工學院的研究生錄取通知書,在遠離家鄉的地方上學,Alex想在波士頓買一套房子,他手頭有一些積蓄,在網上找了幾套自己滿意的房子,但是又不敢相信網上的價格,人生地不熟的,Alex怕被宰,就從自己做數據分析的朋友Bachelor手里要到了過去幾年一些有關波士頓房價的資料。
import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt !dir 驅動器 G 中的卷是 Code卷的序列號是 AC81-1911G:\Python\PythonAI\第二模塊_人工智能之機器學習、智能玩具\Linear_Regression_Learn 的目錄2020/02/17 21:36 <DIR> . 2020/02/17 21:36 <DIR> .. 2020/01/27 09:01 <DIR> .ipynb_checkpoints 2019/12/15 21:33 13,370 data_description.txt 2020/02/10 10:16 195,892 HousePrices.zip 2020/02/17 21:36 43,963 Linear_Regression_Learn.ipynb 2019/12/15 21:33 31,939 sample_submission.csv 2020/02/10 09:08 35,527 submisson.csv 2019/12/15 21:33 451,405 test.csv 2019/12/15 21:33 460,676 train.csv 2020/02/14 16:40 565,862 線性回歸.pptx8 個文件 1,798,634 字節3 個目錄 92,257,865,728 可用字節 house_prices = pd.read_csv("train.csv")Bachelor給的數據非常非常多,包含各個方面。
house_prices| 1 | 60 | RL | 65.0 | 8450 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 2 | 2008 | WD | Normal | 208500 |
| 2 | 20 | RL | 80.0 | 9600 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 5 | 2007 | WD | Normal | 181500 |
| 3 | 60 | RL | 68.0 | 11250 | Pave | NaN | IR1 | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 9 | 2008 | WD | Normal | 223500 |
| 4 | 70 | RL | 60.0 | 9550 | Pave | NaN | IR1 | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 2 | 2006 | WD | Abnorml | 140000 |
| 5 | 60 | RL | 84.0 | 14260 | Pave | NaN | IR1 | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 12 | 2008 | WD | Normal | 250000 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 1456 | 60 | RL | 62.0 | 7917 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 8 | 2007 | WD | Normal | 175000 |
| 1457 | 20 | RL | 85.0 | 13175 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | MnPrv | NaN | 0 | 2 | 2010 | WD | Normal | 210000 |
| 1458 | 70 | RL | 66.0 | 9042 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | GdPrv | Shed | 2500 | 5 | 2010 | WD | Normal | 266500 |
| 1459 | 20 | RL | 68.0 | 9717 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 4 | 2010 | WD | Normal | 142125 |
| 1460 | 20 | RL | 75.0 | 9937 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 6 | 2008 | WD | Normal | 147500 |
1460 rows × 81 columns
為了方便分析呢,先提取其中三個特征作為分析素材,分別是LotArea表示房屋面積,TotalBsmtSF表示地下室的總面積,SalePrice表示的就是房價了。
house_prices[['LotArea', 'TotalBsmtSF', 'SalePrice']]| 8450 | 856 | 208500 |
| 9600 | 1262 | 181500 |
| 11250 | 920 | 223500 |
| 9550 | 756 | 140000 |
| 14260 | 1145 | 250000 |
| ... | ... | ... |
| 7917 | 953 | 175000 |
| 13175 | 1542 | 210000 |
| 9042 | 1152 | 266500 |
| 9717 | 1078 | 142125 |
| 9937 | 1256 | 147500 |
1460 rows × 3 columns
理工科出生的Alex想起了曾經學過的知識,想計算一下自己喜歡的那幾套房子的大概房價是多少,到買房的時候心里好有點數。
于是他把數據重新處理了一下。
sample_test_data = house_prices[['LotArea', 'TotalBsmtSF', 'SalePrice']].copy() sample_test_data.rename(columns={'LotArea':'x1', 'TotalBsmtSF':'x2', 'SalePrice':'y'}, inplace=True) sample_test_data| 8450 | 856 | 208500 |
| 9600 | 1262 | 181500 |
| 11250 | 920 | 223500 |
| 9550 | 756 | 140000 |
| 14260 | 1145 | 250000 |
| ... | ... | ... |
| 7917 | 953 | 175000 |
| 13175 | 1542 | 210000 |
| 9042 | 1152 | 266500 |
| 9717 | 1078 | 142125 |
| 9937 | 1256 | 147500 |
1460 rows × 3 columns
作為一名優秀的理科生,看見熟悉的x和y覺得舒服多了。
接下來就是建立一個數學模型了,簡單的說就是找一個符合x1、x2與y關系的式子,這個簡單嘛,高中就學過的東西,待定系數法唄,只不過從一個x變成了x1、x2而已,那設兩個未知數不就可以了。
設:y=ax1+bx2y=ax_1+bx_2y=ax1?+bx2?
這公式那么一寫阿,瞅起來像是一個線性模型,簡單理解也就是一條線嘛。
再仔細一看,這條線還必須過原點,那就麻煩了,還不能確定這個x1、x2跟y組成的函數圖像一定過原點阿,必須要經過原點這個限制可就太大了。
沒辦法,再加一個未知數吧,把方程改成y=ax1+bx2+cy=ax_1+bx_2+cy=ax1?+bx2?+c
這樣以來,在沒確定a、b、c之前,函數圖像可以是空間中任意的。
接下來就是把a、b、c確定下來了,只要它們三個確定下來就好辦了,把自己喜歡的房子的總面積和地下室的總面積直接代入x1、x2,不就能計算出來一個大概的房價y了么。
看著
y=ax1+bx2+cy=ax_1+bx_2+cy=ax1?+bx2?+c
這個式子,Alex自己都笑了,這玩意是高中才寫的方程,自己孬好也是上過大學的人,于是把方程又改了改:
y=θ1x1+θ2x2+θ0y=θ_1x_1+θ_2x_2+θ_0y=θ1?x1?+θ2?x2?+θ0?
這樣,如果跟房價有關的x特征很多的話,就能把方程寫成矩陣相乘的形式了:
yθ(x)=θ0x0+θ1x1+θ2x2+...+θixi+...+θn?1xn?1+θnxn=∑i=0n=θTxy_\theta(x)=\theta_0x_0+\theta_1x_1+\theta_2x_2+...+\theta_ix_i+...+\theta_{n-1}x_{n-1}+\theta_nx_n=\sum_{i=0}^n=\theta^Txyθ?(x)=θ0?x0?+θ1?x1?+θ2?x2?+...+θi?xi?+...+θn?1?xn?1?+θn?xn?=i=0∑n?=θTx
這個θi阿,有個學名叫權重項。
這個θ0x0呢,讓x0=1不就是之前寫的θ0。
也就是說,得在我的特征中再加一列x0的數據,值全部設置為1就行了。
sample_test_data['x0'] = 1 sample_test_data = sample_test_data[['y', 'x0', 'x1', 'x2']] # 更換一下y、x1、x2、x0的順序,方便看而已,無意義 sample_test_data| 208500 | 1 | 8450 | 856 |
| 181500 | 1 | 9600 | 1262 |
| 223500 | 1 | 11250 | 920 |
| 140000 | 1 | 9550 | 756 |
| 250000 | 1 | 14260 | 1145 |
| ... | ... | ... | ... |
| 175000 | 1 | 7917 | 953 |
| 210000 | 1 | 13175 | 1542 |
| 266500 | 1 | 9042 | 1152 |
| 142125 | 1 | 9717 | 1078 |
| 147500 | 1 | 9937 | 1256 |
1460 rows × 4 columns
我們現在的任務就是計算θi,假設最后我們綜合所有的數據算出來了θi,但是這個θi是為了擬合大部分的數據,所以按照θi計算出來的房價跟真實的房價之間還是有一定的差距的。
如果說根據我們這個方程計算出來的房價跟真實的房價相差無幾,那才是我們想要的結果,這樣我們輸入想要買的房子的x特征值,計算出來的房價y就越接近真實房價。
當然這是后話,現在咱們的目的是啥,就是讓通過咱們方程計算出來的房價跟真實的房價的差值越小越好嘛。
y(i)=θTxi+?iy_{(i)}=\theta^Tx_i+\epsilon_iy(i)?=θTxi?+?i?
對于每一套房子,y(i)表示真實的房價,通過θTxi計算出來的是模型預測房價,εi是預測房價跟真實房價之間的差距,當然εi有可能是正數也有可能是負數。
目的什么來著,讓差距越來越小對吧,也就是讓εi越來越小,當然這個越來越小是說差距越來越小,也就是絕對值越來越接近于0。
給方程移下項:
?i=y(i)?θTxi\epsilon_i=y_{(i)}-\theta^Tx_i?i?=y(i)??θTxi?
這時候咱們再來回顧一下阿,對于方程
y(i)=θTxi+?iy_{(i)}=\theta^Tx_i+\epsilon_iy(i)?=θTxi?+?i?
θTxi是表示系數,如果在坐標系表示的話是由x確定一個圖像。
當只有一個x的時候,圖像是一維的,也就是平面上的一條線;
當有兩個x的時候,圖像是二維的,也就是空間里的一個面;
當有更多x的時候,我是想象不出來了……
就拿只有兩個x舉例隨便畫一個圖像:
在這個圖像里,假設青綠色的那個平面表示的就是θTxi,真實房價y(i)在圖中表示的紅色的點。
這樣看就清晰了,目的是讓
?i=y(i)?θTxi\epsilon_i=y_{(i)}-\theta^Tx_i?i?=y(i)??θTxi?
的絕對值越小越好,表示在圖像上就是紅色的點越接近青藍色的平面越近越好。
這里要明確一個思想,真實房價是確定了,也就是y(i)、紅色的點是確定的,而青藍色的平面θTxi才是變動的,也就是說,在空間里,我們要移動平面來擬合點,找到哪一個平面到所有點的距離和最小。
這個預測房價與真實房價之間的距離,也就是誤差ε(i)是獨立同分布的,并且服從均值為0方差為σ2的高斯分布。
這里突然間冒出來三個不熟悉的名詞,解釋一下阿:
獨立:各個樣本點之間是相互獨立的。也就是說,Alex去波士頓買房,跟Bachelor去波士頓買房,只要兩個人買的不是同一套房子,它們之間是沒有關系的,花多少錢只跟房屋的屬性和房東有關。
同分布:數據的來源必須相同。Alex是想在波士頓買房,所以需要的是過去幾年波士頓的房價數據,如果拿得是紐約的房價數據,顯然是不符合需求的,建立的數學模型也不準確。
高斯分布:也就是正態分布,一種連續型隨機變量的概率密度函數。先來看一下正態分布的函數圖像:
看起來是不是特別圓潤,符合一種對稱美,是不是覺得手感肯定特別好。
為什么要用高斯分布?
其實我們一開始并不能確定誤差一定服從高斯分布,只不過根據前人的經驗,大多數誤差經過測量被證實都是服從高斯分布的,說明高斯分布對誤差假設來說是一種很好的模型。
在自然界與生產中,一些現象受到許多相互獨立的隨機因素的影響,也就是我們買房過程中的房屋面積和地下室面積,如果每個因素所產生的影響都很微小,總的影響可以看作是服從正態分布的。
當然上面那個高斯分布的圖像看起來不是很清晰,我們可以用numpy和matplotlib自己來畫一個簡單的高斯分布函數圖像。
在數學上,正態分布的概率密度函數:
f(x)=12πσe?(x?u)22σ2f(x)=\frac{1}{\sqrt{2π}\sigma}e^{\frac{-(x-u)^2}{2\sigma^2}}f(x)=2π?σ1?e2σ2?(x?u)2?
當u=0,σ=1時,正態分布稱為標準正態分布:
f(x)=12πe?x22f(x)=\frac{1}{\sqrt{2π}}e^{\frac{-x^2}{2}}f(x)=2π?1?e2?x2?
def gaussian(x, mean, sigma):return (np.exp((-(x - mean) ** 2) / (2 * sigma ** 2)) / (np.sqrt(2 * np.pi) * sigma))mean, sigma = 0, 1 x = np.arange(-3, 3, 0.001) plt.plot(x, gaussian(x, mean, sigma)) plt.show()從高斯分布圖中可以看出,[-2,2]之間的分布占大部分,也就是說我們假設預測房價跟真實房價在大多數情況下都是差異不大的。
在我們的房價預測問題中,均值μ=0,所以可以把公式寫成:
f(x)=12πσe?x22σ2f(x)=\frac{1}{\sqrt{2π}\sigma}e^{-\frac{x^2}{2\sigma^2}}f(x)=2π?σ1?e?2σ2x2?
之前所假設的是誤差ε(i)服從正態分布,所以ε(i)就是正態分布函數中的x,我們再把ε(i)代入到公式中:
f(ε(i))=12πσe?ε(i)22σ2f(ε_{(i)})=\frac{1}{\sqrt{2π}\sigma}e^{-\frac{ε_{(i)}^2}{2\sigma^2}}f(ε(i)?)=2π?σ1?e?2σ2ε(i)2??
我們把之前推導出的結果
?i=y(i)?θTxi\epsilon_i=y_{(i)}-\theta^Tx_i?i?=y(i)??θTxi?
也就是預測房價與真實房價之間的差距,再代入到公式中:
f(y(i)?θTxi)=12πσe?(y(i)?θTxi)22σ2f(y_{(i)}-θ^Tx_i)=\frac{1}{\sqrt{2π}\sigma}e^{-\frac{(y_{(i)}-θ^Tx_i)^2}{2\sigma^2}}f(y(i)??θTxi?)=2π?σ1?e?2σ2(y(i)??θTxi?)2?
在這個公式中,y(i)表示的真實房價,是已知的,x(i)呢,是每間房子的特征,也就是房屋的面積和地下室的面積,也是已知的。
也就是說,整個公式中,只有θT是未知的。
這樣的話,咱們把自變量換一下,整成一個關于未知數θ的函數:
L(θ)=12πσe?(y(i)?θTxi)22σ2L(θ)=\frac{1}{\sqrt{2π}\sigma}e^{-\frac{(y_{(i)}-θ^Tx_i)^2}{2\sigma^2}}L(θ)=2π?σ1?e?2σ2(y(i)??θTxi?)2?
我們一開始的目的是想讓誤差ε(i)變小,在正態分布中,對于自變量x,絕對值越小,越接近于0,因變量的值越大。
好了,現在我們的目的進階了一下,讓L(θ)的值越大越好。
那么,怎么計算L(θ)的值呢?
我們不是有往年的波士頓房價資料么,把以前的一些資料全部代入進去不就行了。
代入一個,得到一個L(θ1),再代入一個得到一個L(θ2),然后一直代入,一直代入……
咱們是想讓建立的數學模型最好能夠擬合所有的樣本,也就是說,讓所有的L(θ)都最大。
現在把所有的L(θ)整合起來,做一個累乘:
L(θ)=∏i=1n12πσe?(y(i)?θTxi)22σ2L(θ)=\prod_{i=1}^{n}\frac{1}{\sqrt{2π}\sigma}e^{-\frac{(y_{(i)}-θ^Tx_i)^2}{2\sigma^2}}L(θ)=i=1∏n?2π?σ1?e?2σ2(y(i)??θTxi?)2?
為什么要做累乘而不是累加呢?
這個其實跟數學有關,多個樣本之間的累乘依然保留原本的分布模式,并且會使常見的概率更常見,這個概率對所有的樣本關聯性更強。
累加當然可以用,假如說L(θi)={1,2,3,4,5,6,7,8,9},把所有的數累加起來,其結果sum_L(θi)=45,但是如果把所有的結果累乘起來,其結果ride_L(θi)=362880。
這個時候,如果缺了一個數7,那么sum_L(θi)’=38,ride_L(θi)’=51840,累乘的結果降低的更多,說明累乘的結果對每一個樣本的關聯性更大。
對于L(θ),它有一個學名叫似然函數。
來看一下定義:似然函數也是一個概率密度函數L(θ∣x),表示在樣本值x已知的情況下求最可能的θ值;實際運用中,根據我們的樣本去估計參數值,找到最符合的參數,使得與我們的數據組合后恰好最近接真實值。
暫時不需要去深刻的理解似然函數的概念,咱現在的主要目的是買房。
現在得到了一個累乘的結果L(θ),但是累乘算起來比較麻煩,咱們可以把累乘轉換為累加,方法是對等式兩邊同時取對數:
lnL(θ)=ln∏i=1n12πσe?(y(i)?θTxi)22σ2ln^{L(θ)}=ln^{\prod_{i=1}^{n}\frac{1}{\sqrt{2π}\sigma}e^{-\frac{(y_{(i)}-θ^Tx_i)^2}{2\sigma^2}}}lnL(θ)=ln∏i=1n?2π?σ1?e?2σ2(y(i)??θTxi?)2?
雖然轉換了,但是效果還是一樣的,只是通過累加來計算而已。
根據對數運算的性質,可以將累乘計算提到ln前邊,變成累加運算:
lnL(θ)=∑i=1nln12πσe?(y(i)?θTxi)22σ2ln^{L(θ)}=\sum_{i=1}^nln^{\frac{1}{\sqrt{2π}\sigma}e^{-\frac{(y_{(i)}-θ^Tx_i)^2}{2\sigma^2}}}lnL(θ)=i=1∑n?ln2π?σ1?e?2σ2(y(i)??θTxi?)2?
再看一下右式ln運算的真數:
12πσe?(y(i)?θTxi)22σ2\frac{1}{\sqrt{2π}\sigma}e^{-\frac{(y_{(i)}-θ^Tx_i)^2}{2\sigma^2}}2π?σ1?e?2σ2(y(i)??θTxi?)2?
這也是一個乘法運算,而且前一項
12πσ\frac{1}{\sqrt{2π}\sigma}2π?σ1?
是一個常數,后一項
e?(y(i)?θTxi)22σ2e^{-\frac{(y_{(i)}-θ^Tx_i)^2}{2\sigma^2}}e?2σ2(y(i)??θTxi?)2?
根據對數運算的性質可以消去e。
化簡一下,公式就變成了:
lnL(θ)=∑i=1n(ln12πσ+lne?(y(i)?θTxi)22σ2)ln^{L(θ)}=\sum_{i=1}^n(ln^{\frac{1}{\sqrt{2π}\sigma}}+ln^{e^{-\frac{(y_{(i)}-θ^Tx_i)^2}{2\sigma^2}}})lnL(θ)=i=1∑n?(ln2π?σ1?+lne?2σ2(y(i)??θTxi?)2?)
=∑i=1n(ln12πσ?(y(i)?θTxi)22σ2)=\sum_{i=1}^n(ln^{\frac{1}{\sqrt{2π}\sigma}}-\frac{(y_{(i)}-θ^Tx_i)^2}{2\sigma^2})=i=1∑n?(ln2π?σ1??2σ2(y(i)??θTxi?)2?)
=∑i=1nln12πσ?∑i=1n(y(i)?θTxi)22σ2=\sum_{i=1}^nln^{\frac{1}{\sqrt{2π}\sigma}}-\sum_{i=1}^n\frac{(y_{(i)}-θ^Tx_i)^2}{2\sigma^2}=i=1∑n?ln2π?σ1??i=1∑n?2σ2(y(i)??θTxi?)2?
之前我們分析過了,整個式子里只有θ𝑇是未知數,所以可以先把常數項能化簡的化簡,能提前的提前,將公式化簡為:
lnL(θ)=nln12πσ?12σ2∑i=1n(y(i)?θTxi)2ln^{L(θ)}=nln^{\frac{1}{\sqrt{2π}\sigma}}-{\frac{1}{2\sigma^2}}\sum_{i=1}^n{(y_{(i)}-θ^Tx_i)^2}lnL(θ)=nln2π?σ1??2σ21?i=1∑n?(y(i)??θTxi?)2
這時候再看一下公式的常數項:
nln12πσ和1σ2nln^{\frac{1}{\sqrt{2π}\sigma}}和{\frac{1}{\sigma^2}}nln2π?σ1?和σ21?
把1/2保留到變量項里,后續有用。
我們的目的是讓似然函數L(θ)越大越好,即讓lnL(θ)越大越好,也就是讓
12∑r=1n(y(i)?θTxi)2{\frac{1}{2}}\sum_{r=1}^n{(y_{(i)}-θ^Tx_i)^2}21?r=1∑n?(y(i)??θTxi?)2
越小越好。
寫成目標函數:
J(θ)=12∑r=1n(y(i)?θTxi)2J(θ)={\frac{1}{2}}\sum_{r=1}^n{(y_{(i)}-θ^Tx_i)^2}J(θ)=21?r=1∑n?(y(i)??θTxi?)2
你可能覺得,
y(i)?θTxiy_{(i)}-θ^Tx_iy(i)??θTxi?
這個式子不就是之前推導出來的么,整了那么一大圈,最后的出來的還是這個。
實則不然,現在要計算的是:J(θ)的最小值,
J(θ)=(y(i)?θTxi)2J(θ)=(y_{(i)}-θ^Tx_i)^2J(θ)=(y(i)??θTxi?)2
當x只有一維取值的時候,用高中的話講就是一個開口向上的二次函數,有最小值,怎么求呢?
求導,導數為0的時候取極值,極值中存在最值。
現在得到了目標函數:
J(θ)=12∑i=1n(y(i)?θTxi)2J(θ)={\frac{1}{2}}\sum_{i=1}^n{(y_{(i)}-θ^Tx_i)^2}J(θ)=21?i=1∑n?(y(i)??θTxi?)2
轉換成矩陣相乘的形式并化簡一下:
J(θ)=12(Xθ?y)T(Xθ?y)J(θ)={\frac{1}{2}}({Xθ-y})^T({Xθ-y})J(θ)=21?(Xθ?y)T(Xθ?y)
=12((Xθ)T?yT)(Xθ?y)={\frac{1}{2}}({{(Xθ)}^T-y^T})({Xθ-y})=21?((Xθ)T?yT)(Xθ?y)
=12(θTXT?yT)(Xθ?y)={\frac{1}{2}}({θ^TX^T-y^T})({Xθ-y})=21?(θTXT?yT)(Xθ?y)
=12(θTXTXθ?θTXTy?yTXθ+yTy)={\frac{1}{2}}(θ^TX^TXθ-θ^TX^Ty-y^TXθ+y^Ty)=21?(θTXTXθ?θTXTy?yTXθ+yTy)
咱們的未知數是θ,現在是一個關于θ的函數,對θ求導得:
J′(θ)=XTXθ?XTyJ'(θ)=X^TXθ-X^TyJ′(θ)=XTXθ?XTy
令J’(θ)=0得:
XTXθ?XTy=0X^TXθ-X^Ty=0XTXθ?XTy=0
XTXθ=XTyX^TXθ=X^TyXTXθ=XTy
θ=(XTX)?1XTyθ=(X^TX)^{-1}X^Tyθ=(XTX)?1XTy
現在,我們終于得到最終的θ了,為什么說最終了呢?X是已經獲得的房屋的數據,y是房價,都是已知的,直接代入就OK了。
有了公式,現在回頭來看看真實的問題和真實的數據該怎么處理:
House Prices: Advanced Regression Techniques
housing = pd.read_csv("train.csv") housing| 1 | 60 | RL | 65.0 | 8450 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 2 | 2008 | WD | Normal | 208500 |
| 2 | 20 | RL | 80.0 | 9600 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 5 | 2007 | WD | Normal | 181500 |
| 3 | 60 | RL | 68.0 | 11250 | Pave | NaN | IR1 | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 9 | 2008 | WD | Normal | 223500 |
| 4 | 70 | RL | 60.0 | 9550 | Pave | NaN | IR1 | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 2 | 2006 | WD | Abnorml | 140000 |
| 5 | 60 | RL | 84.0 | 14260 | Pave | NaN | IR1 | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 12 | 2008 | WD | Normal | 250000 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 1456 | 60 | RL | 62.0 | 7917 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 8 | 2007 | WD | Normal | 175000 |
| 1457 | 20 | RL | 85.0 | 13175 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | MnPrv | NaN | 0 | 2 | 2010 | WD | Normal | 210000 |
| 1458 | 70 | RL | 66.0 | 9042 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | GdPrv | Shed | 2500 | 5 | 2010 | WD | Normal | 266500 |
| 1459 | 20 | RL | 68.0 | 9717 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 4 | 2010 | WD | Normal | 142125 |
| 1460 | 20 | RL | 75.0 | 9937 | Pave | NaN | Reg | Lvl | AllPub | ... | 0 | NaN | NaN | NaN | 0 | 6 | 2008 | WD | Normal | 147500 |
1460 rows × 81 columns
數據預處理
拿到數據之后,不是上來就要進行計算的,首先要做的就是數據預處理。
首先,我們來分析一下每一個x特征:
MSSubClass: Identifies the type of dwelling involved in the sale.
MSSubClass:標識參與銷售的住宅類型。
20 1-STORY 1946 & NEWER ALL STYLES1946年1層和更新的所有樣式30 1-STORY 1945 & OLDER1945年1層及以上40 1-STORY W/FINISHED ATTIC ALL AGES1層,帶成品閣樓,所有年齡段45 1-1/2 STORY - UNFINISHED ALL AGES1-1/2層-未完成所有年齡段50 1-1/2 STORY FINISHED ALL AGES1-1/2層完成所有年齡段60 2-STORY 1946 & NEWER1946年2層及以上70 2-STORY 1945 & OLDER1945年2層及以上75 2-1/2 STORY ALL AGES2-1/2層,所有年齡段80 SPLIT OR MULTI-LEVEL拆分或多級85 SPLIT FOYER分體式門廳90 DUPLEX - ALL STYLES AND AGES復式-所有樣式和年齡120 1-STORY PUD (Planned Unit Development) - 1946 & NEWER一層建筑(計劃單元開發)-1946年及更新版本150 1-1/2 STORY PUD - ALL AGES1-1/2層布德-所有年齡段160 2-STORY PUD - 1946 & NEWER兩層樓的PUD-1946及更新版本180 PUD - MULTILEVEL - INCL SPLIT LEV/FOYERPUD-多級-包括分離式LEV/門廳190 2 FAMILY CONVERSION - ALL STYLES AND AGES2家庭轉換-所有風格和年齡雖然沒太看懂啥意思,但是大致就是MSSubClass越高越好,從一兩層的到復式再到什么家庭轉換,看著就感覺挺貴的樣子。
先看一下MSSubClass這一列有沒有缺失值。
housing["MSSubClass"].isnull().sum() 0MSSubClass這一列數據狀況良好,沒有缺失值,看一下它的分布情況。
plt.scatter(housing["MSSubClass"], housing["SalePrice"], ) plt.show()這么一看分布的話,我們之前的猜測不成立啊,MSSubClass和SalePrice不是正相關的關系,那它倆的關系先待定。
通過散點圖雖然能看到不同房價的分布,但是有些地方很多點重合在一起,很難看出房價密度。
這時候,我們給MSSubClass和SalePrice添加一個抖動,抖動只是讓它在圖上的顯示位置稍微偏離一下,并不會更改真實的數據,然后再設置一下透明度,重疊的點越多,圖像顏色越深。
sns.regplot(data=housing, x="MSSubClass", y="SalePrice", x_jitter=3, scatter_kws={"alpha":0.3})
如圖可見,大部分MSSubClass都在0~100之內,而MSSubClass與SalePrice的擬合線接近于一條直線,而且有點偏向于負相關。
MSZoning: Identifies the general zoning classification of the sale.
MSZoning:標識銷售的一般分區分類。
A Agriculture農業C Commercial商業FV Floating Village Residential流動村住宅I Industrial工業RH Residential High Density住宅高密度RL Residential Low Density住宅低密度RP Residential Low Density Park 住宅低密度公園RM Residential Medium Density住宅中密度上來還是先看有沒有缺失值:
housing["MSZoning"].isnull().sum() housing["MSZoning"].value_counts()沒有缺失值,還是看一下MSZoning跟SalePrice的關系,但是我們看一下數據:
housing["MSZoning"]數據并不是常規的數值,而是字母變量,我們要把字母變量對應到數值。
確定一個簡單的對應關系:
1 <—— A Agriculture
2 <—— C Commercial
3 <—— FV Floating Village Residential
4 <—— I Industrial
5 <—— RH Residential High Density
6 <—— RL Residential Low Density
7 <—— RP Residential Low Density Park
8 <—— RM Residential Medium Density
housing.loc[housing["MSZoning"] == "A", "MSZoning"] = 1.0 housing.loc[housing["MSZoning"] == "C (all)", "MSZoning"] = 2.0 housing.loc[housing["MSZoning"] == "FV", "MSZoning"] = 3.0 housing.loc[housing["MSZoning"] == "I", "MSZoning"] = 4.0 housing.loc[housing["MSZoning"] == "RH", "MSZoning"] = 5.0 housing.loc[housing["MSZoning"] == "RL", "MSZoning"] = 6.0 housing.loc[housing["MSZoning"] == "RP", "MSZoning"] = 7.0 housing.loc[housing["MSZoning"] == "RM", "MSZoning"] = 8.0 housing["MSZoning"].value_counts() sns.regplot(data=housing, x="MSZoning", y="SalePrice", x_jitter=0.4, scatter_kws={"alpha":0.3})
哎呀我去,我就隨便一對應,沒想到對應出來一個正相關。
LotFrontage: Linear feet of street connected to property
地塊臨街:連接到地產的街道的直線英尺
housing["LotFrontage"] housing["LotFrontage"].isnull().sum()終于找到一個含有缺失值的了,LotFrontage列含有259個缺失值,這時候,我們需要對缺失值做填充。
我比較喜歡的一種方案是利用均值和標準差的信息進行填充。
當然,并不是只有LotFrontage采用缺失值,所以我們可以把缺失值填充抽象成一個函數。
def fill_null(df, col):mean = df[col].dropna().mean()std = df[col].dropna().std()null_sum = df[col].isnull().sum()fill_num = np.random.randint(mean - std, mean + std, null_sum)df.loc[df[col].isnull(), col] = fill_num fill_null(housing, "LotFrontage") sns.regplot(data=housing, x="LotFrontage", y="SalePrice", scatter_kws={"alpha":0.3})
這么一看的話,LotFrontage和SalePrice也是成正相關的關系。
LotArea: Lot size in square feet
housing["LotArea"].isnull().sum() sns.regplot(data=housing, x="LotArea", y="SalePrice", scatter_kws={"alpha":0.4})總結
找一下套路,對于每一個特征數據:
1.判斷該列數據是否含有缺失值1.1、如果不含有缺失值,繼續后續操作1.2、如果含有缺失值,對缺失值進行填充2.判斷該列數據是不是數值2.1、如果是數值繼續后續操作2.2、如果不是數值,定義對應關系,將數據對應到數值3.去除異常數據4.繪制散點圖和線性關系那么接下來我們吧數據統一重新處理一下:
train_house = pd.read_csv("http://kaggle.shikanon.com/house-prices-advanced-regression-techniques/train.csv")第一列數據是ID,是我們人為標注的數據,對房價并無影響,先把它單獨抽離出來。
train_house_ID = train_house["Id"] train_house.drop("Id", axis=1, inplace=True)我們第一步要做的就是缺失值處理,缺失值處理有兩種方案,一種是分析含缺失值的特征對任務有沒有用,沒用的特征直接刪除,有用的特征依據缺失量,少則刪除樣本,多則用mean,median或mod補全;另一種方案是分析這些缺失值缺失的原因,并用一定方法將其轉換為一類數據(成為類型變量的一個類型)。
na_count = train_house.isnull().sum().sort_values(ascending=False) na_rate = na_count / len(train_house) na_data = pd.concat([na_count,na_rate],axis=1,keys=['count','ratio']) pd.set_option('display.max_rows',None) # 將pandas的輸出數據不省略顯示 print(na_data)首先,如果某一特征的數據缺失量達到15%以上,那這項特征應該予以刪除并認為數據集中不存在這樣的特征。
也就是說我們并不會設法去填補這些特征的缺失值,因為假定它是不存在的,因此刪除數據的 ’PoolQC’, ‘MiscFeature’, ‘Alley’, ‘Fence’, ‘FireplaceQu’和‘LotFrontage’這幾列。
這應該不會導致數據的有效信息量下降,因為這些特征的字面含義似乎根本與房價無關,難怪會有這么多缺失值,而且這些特征的有效數據具有各種離群值。
其次,在剩下的含缺失值變量中,以Garage開頭的5個GarageX特征具有相同數量的缺失值,據此推測他們可能代表的是同一組觀測值,而關于Garage的信息,’GarageCars’已經能夠很好地表征了,因此刪除這幾個特征,對BsmtX也可以進行同樣的操作。
之后,對于MasVnrArea和MasVnrType,根據其字面意思我們認為它們并不重要,而且它們與YearBuilt和OverallQual有較強的相關性。因此,我們刪除這兩個特征也不會丟失任何信息。
然后,除了Electrical,其它無意義的含缺失值的變量我們都已經刪除了,Electrical這個變量下只有一個樣本帶有缺失值,因此我們不妨刪除帶有這個缺失值的那各樣本。
最后,經過我們的嚴密分析哈,所有的含有缺失值的特征都可以刪除。
train_house.drop(na_data[na_data['count'] > 1].index, axis=1, inplace=True) train_house.drop(train_house.loc[train_house['Electrical'].isnull()].index, inplace=True) train_house.shape第二步我們要做的就是講數據中的字符串型特征映射為數值型特征,這樣才能方便計算,但是我總不能一列一列的看是不是數值型數據然后再做數據對應吧,那還不如不學了,pandas給我提供好了這樣的功能——factorize函數可以將Series中的標稱型數據映射稱為一組數字,相同的標稱型映射為相同的數字。
舉個簡單的例子看一下factorize函數:
由上面可見,我們送入一串序列[‘b’, ‘b’, ‘a’, ‘c’, ‘b’],該函數做了什么事,其實,它是將送入的字符映射成數字,原則是相同的字符對應同一個數字。
比如上面,函數先處理 ‘b’,將其映射成 1, 然后處理第二個字符還是 ‘b’,因為已經映射成功,所以直接返回 1, 接著處理到 ‘a’,將其映射為 0,然后處理 ‘c’,將其映射成 2, 最后處理 ‘b’,已經映射過了,所以直接輸出 1。
將上述輸出匯總成序列,輸出到 labels 中,codes里面其實就是存儲我們輸入序列中互異的元素,即上面的[‘a’, ‘b’, ‘c’]。
有了這個函數,就可以幫助我們將所有的非數值型數據轉換為數值型數據:
for col in train_house.columns:if train_house[col].dtypes == "object":train_house[col], uniques = pd.factorize(train_house[col]) train_house.dtypes所有的缺失值都被處理,所有的字符串型數據都被替換為數值型數據,這樣就可以計算了。
我們把之前計算的θ公式拿過來:
θ=(XTX)?1XTyθ=(X^TX)^{-1}X^Tyθ=(XTX)?1XTy
求出了θ,我們就可以根據自己輸入的特征預測房價了:
test_house = pd.read_csv("test.csv")在計算之前,需要把測試集的數據做一遍跟訓練集一樣的處理:
test_house_ID = test_house["Id"] test_house.drop("Id", axis=1, inplace=True) test_house.drop(na_data[na_data['count'] > 1].index, axis=1, inplace=True) for col in test_house.columns:if test_house[col].dtypes == "object":test_house[col], uniques = pd.factorize(test_house[col])test_house[col].fillna(test_house[col].mean(), inplace=True) test_house.shape再把房價的計算公式拿過來:
Y=θTxY=\theta^TxY=θTx
我們把submission提交到Kaggle的平臺上,看看能獲得什么樣的分數:
結果顯示并不是很好,當然,我們還有好多因素沒有考慮,不過,線性回歸,我們就先講到這里,后續我們有更好的方法來解決房價問題。
總結
以上是生活随笔為你收集整理的买房子,就该用线性回归的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据库开发——MySQL——数据类型——
- 下一篇: 并发编程——协程