接下來,我們將帶各位實際分析一筆數據,並從中獲得資訊。
此篇文是由 Joyce 所撰寫
使用sklearn提供的數據,來做分析,如此一來就不用再引入csv檔,而我們用來舉例的是load_boston(),接下來就讓我們一步步的來瞭解資料,使用分析的結果,獲得資訊吧。
因為是sklearn提供的數據,直接從datasets裡引入即可。
from sklearn import datasets # 引入sklearn裏頭的資料集
import pandas as pd # 引入Pandas
data = datasets.load_boston() # 取得波士頓房價的數據
df_data = pd.DataFrame(data.data, columns=data.feature_names) # 將數據以改成DataFrame的方式呈現
在分析資料前,一定要先了解有多少筆資料,每個特徵的意義,因此我們先將資料列印出來討論。
df_data # 查看資料
output
CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT
0 0.00632 18.0 2.31 0.0 0.538 6.575 65.2 4.0900 1.0 296.0 15.3 396.90 4.98
1 0.02731 0.0 7.07 0.0 0.469 6.421 78.9 4.9671 2.0 242.0 17.8 396.90 9.14
2 0.02729 0.0 7.07 0.0 0.469 7.185 61.1 4.9671 2.0 242.0 17.8 392.83 4.03
3 0.03237 0.0 2.18 0.0 0.458 6.998 45.8 6.0622 3.0 222.0 18.7 394.63 2.94
4 0.06905 0.0 2.18 0.0 0.458 7.147 54.2 6.0622 3.0 222.0 18.7 396.90 5.33
... ... ... ... ... ... ... ... ... ... ... ... ... ...
501 0.06263 0.0 11.93 0.0 0.573 6.593 69.1 2.4786 1.0 273.0 21.0 391.99 9.67
502 0.04527 0.0 11.93 0.0 0.573 6.120 76.7 2.2875 1.0 273.0 21.0 396.90 9.08
503 0.06076 0.0 11.93 0.0 0.573 6.976 91.0 2.1675 1.0 273.0 21.0 396.90 5.64
504 0.10959 0.0 11.93 0.0 0.573 6.794 89.3 2.3889 1.0 273.0 21.0 393.45 6.48
505 0.04741 0.0 11.93 0.0 0.573 6.030 80.8 2.5050 1.0 273.0 21.0 396.90 7.88
506 rows × 13 columns
data.DESCR # 查看data的特徵說明
由output可知,共有506筆資料,有13種特徵,而每個特徵的意義分別為
data.target # 查看正確的房價
output
array([24. , 21.6, 34.7, 33.4, 36.2, 28.7, 22.9, 27.1, 16.5, 18.9, 15. ,
18.9, 21.7, 20.4, 18.2, 19.9, 23.1, 17.5, 20.2, 18.2, 13.6, 19.6,
15.2, 14.5, 15.6, 13.9, 16.6, 14.8, 18.4, 21. , 12.7, 14.5, 13.2,
13.1, 13.5, 18.9, 20. , 21. , 24.7, 30.8, 34.9, 26.6, 25.3, 24.7,......])
target 取的是該城鎮房價的中間值
我們先查看每一行是否具有缺失值,有的話再來決定如何處理它。由下面的輸出資訊,我們可以知道所有的資料都是完整的。
df_data.isnull().any() # 檢查是否有缺失值
output
CRIM False
ZN False
INDUS False
CHAS False
NOX False
RM False
AGE False
DIS False
RAD False
TAX False
PTRATIO False
B False
LSTAT False
dtype: bool
有些特徵的定義是比率,那麼值是必然會介於0到100之間,而判斷是否在河邊的值也只會有0和1,我們檢查這些值是否異常。而檢查的結果都沒有異常。
flag = False
for i in df_data["CRIM"]: # 檢查CRIM是否都為合理值
if(i < 0 or i > 100):
flag = True
break
print(flag)
output
False
其餘特徵的檢查,把CRIM這個特徵改掉就好,而執行完你會發現全部的結果都是False。
df_data["CHAS"].unique()
output
array([0., 1.])
這份資料提供了波士頓各個城鎮的資料,像是犯罪率、師生比、平均房間數,每一個特徵都有可能會影響房價,而我們的目標就是使用這些特徵來預測出房價。
在此我們就舉三個特徵來做討論
下圖,我們可以推測犯罪率與房價成反比關係,亦即當犯罪率越高,房價會越低。
x = data.target # 房價數據
y = df_data["CRIM"] # 犯罪率數據
plt.xlabel("house price") # x軸的標題
plt.ylabel("crime rate") # y軸的標題
plt.scatter(x, y) # 繪製散點圖
plt.show() # 顯示圖形
由下圖我們可知雖然有些值有偏離,但大約呈線性的關係,為正相關。
x = data.target # 房價數據
y = df_data["RM"] # 房間數數據
plt.xlabel("house price") # x軸的標題
plt.ylabel("number of rooms") # y軸的標題
plt.scatter(x, y) # 繪製散點圖
plt.show() # 顯示圖形
在初步分析的時候,我們推測黑人比率越高房價會越低,顯然對波士頓的房價不適用。
x = data.target # 房價數據
y = df_data["B"] # 黑人比率數據
plt.xlabel("house price") # x軸的標題
plt.ylabel("proportion of blacks") # y軸的標題
plt.scatter(x, y) # 繪製散點圖
plt.show() # 顯示圖形
由下表可知每個特徵各自的相關性,通常我們會定義大於0.7為高度相關,像是TAX與RAD之間的相關係數高達0.91,我們可以去思考其背後的意義,將數據變的更有價值。
df_data.corr(method="pearson")
output
CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT
CRIM 1.000000 -0.200469 0.406583 -0.055892 0.420972 -0.219247 0.352734 -0.379670 0.625505 0.582764 0.289946 -0.385064 0.455621
ZN -0.200469 1.000000 -0.533828 -0.042697 -0.516604 0.311991 -0.569537 0.664408 -0.311948 -0.314563 -0.391679 0.175520 -0.412995
INDUS 0.406583 -0.533828 1.000000 0.062938 0.763651 -0.391676 0.644779 -0.708027 0.595129 0.720760 0.383248 -0.356977 0.603800
CHAS -0.055892 -0.042697 0.062938 1.000000 0.091203 0.091251 0.086518 -0.099176 -0.007368 -0.035587 -0.121515 0.048788 -0.053929
NOX 0.420972 -0.516604 0.763651 0.091203 1.000000 -0.302188 0.731470 -0.769230 0.611441 0.668023 0.188933 -0.380051 0.590879
RM -0.219247 0.311991 -0.391676 0.091251 -0.302188 1.000000 -0.240265 0.205246 -0.209847 -0.292048 -0.355501 0.128069 -0.613808
AGE 0.352734 -0.569537 0.644779 0.086518 0.731470 -0.240265 1.000000 -0.747881 0.456022 0.506456 0.261515 -0.273534 0.602339
DIS -0.379670 0.664408 -0.708027 -0.099176 -0.769230 0.205246 -0.747881 1.000000 -0.494588 -0.534432 -0.232471 0.291512 -0.496996
RAD 0.625505 -0.311948 0.595129 -0.007368 0.611441 -0.209847 0.456022 -0.494588 1.000000 0.910228 0.464741 -0.444413 0.488676
TAX 0.582764 -0.314563 0.720760 -0.035587 0.668023 -0.292048 0.506456 -0.534432 0.910228 1.000000 0.460853 -0.441808 0.543993
PTRATIO 0.289946 -0.391679 0.383248 -0.121515 0.188933 -0.355501 0.261515 -0.232471 0.464741 0.460853 1.000000 -0.177383 0.374044
B -0.385064 0.175520 -0.356977 0.048788 -0.380051 0.128069 -0.273534 0.291512 -0.444413 -0.441808 -0.177383 1.000000 -0.366087
LSTAT 0.455621 -0.412995 0.603800 -0.053929 0.590879 -0.613808 0.602339 -0.496996 0.488676 0.543993 0.374044 -0.366087 1.000000
因為有13個特徵,滿滿的數字我們無法一下看出低度相關還是高度相關,因此我們將它改成塗色的呈現。
import seaborn as sns # 引入seaborn
import matplotlib.pyplot as plt # 引入pyplot
plt.figure(figsize= (13, 13)) # 圖形大小
sns.heatmap(df_data.corr(),annot = True) # 塗顏色
plt.show() # 顯示圖形
output
要做線性迴歸的第一個步驟需要將資料分成兩個部分,一個是訓練的資料,另一個是測試的資料,這個比例要拿捏好,準確性太高跟太低都不好,接下來訓練的模型,我們都採取73比,也就是把70%的資料拿去訓練,留下30%的資料作測試用。
首先我們將13個特徵全部拿去做分析,來看看結果在來考慮下一步。
from sklearn.linear_model import LinearRegression # 引入LinearRegression
from sklearn.model_selection import train_test_split # 引入train_test_split
import matplotlib.pyplot as plt # 引入pyplot
x = data.data # 13個特徵的數據
y = data.target # 房價數據
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.3, random_state = 1) # 將數據分成73比
lnregr = LinearRegression()
lnregr.fit(x_train, y_train) # 將資料拿去訓練
y_predict = lnregr.predict(x_test) # 北test的資料用訓練出來的模型去預測
plt.xlabel("actual price") # x軸的標題
plt.ylabel("predict pcice") # y軸的標題
plt.plot([0,50], [0,50]) # 劃一條基準線
plt.scatter(y_test, y_predict) # 比對預測跟實際的差別
plt.show() # 察看結果
output
lnregr.score(x_train, y_train) # 訓練模型的正確率
output
0.7103879080674731
思考 : 為甚麼正確率這麼低呢?因為線性迴歸的的方程式為一條直線,當特徵與房價不成線性關係的話,那麼再怎麼分析,正確率都不會高。
解決:
而前兩種解決方法這裡就不再詳細討論了。
我們在上面的分析是使用直接13個特徵,如果我們可以只選取比較重要的特徵出來討論,會不會得到更好的結果呢?特別注意到如果要找尋重要性的話,一定要先做標準化,不然數據跑出來的結果會整個失真。
import pandas as pd # 引入pandas
import numpy as np # 引入numpy
from sklearn.tree import DecisionTreeClassifier # 引入DecisionTreeClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA # 引入PCA
import matplotlib.pyplot as plt # 引入pyplot
x = data.data # 13個特徵的數據
y = data.target # 特徵名稱
std_tool = StandardScaler()
x = std_tool.fit_transform(x) # 將資料標準化
dt_model = LinearRegression()
dt_model.fit(x,y)
feature_importance = dt_model.coef_ # 重要性
plt.figure(figsize=(12, 6)) # 圖形大小
plt.bar(df_data.columns , feature_importance) # 繪製成直方圖
plt.show() # 顯示圖形
基本上數值(取絕對值後)越大代表越重要。因此我們決定將CRIM、INDUS、CHAS、AGE、B刪除,再做一次線性迴歸。
df_data2 = df_data.drop(["CRIM", "INDUS", "CHAS", "AGE", "B"], axis = 1)
x = df_data2 # 重要特徵的數據
y = data.target # 房價數據
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.3, random_state = 1) # 將數據分成73比
std_tool = StandardScaler()
x_train = std_tool.fit_transform(x_train) # 將資料標準化
lnregr = LinearRegression()
lnregr.fit(x_train, y_train) # 將資料拿去訓練
x_test = std_tool.transform(x_test)
y_predict = lnregr.predict(x_test) # 北test的資料用訓練出來的模型去預測
plt.xlabel("actual price") # x軸的標題
plt.ylabel("predict pcice") # y軸的標題
plt.plot([0,50], [0,50]) # 劃一條基準線
plt.scatter(y_test, y_predict) # 比對預測跟實際的差別
plt.show() # 察看結果
output
lnregr.score(x_train, y_train) # 訓練模型的正確率
output
0.7723543146059919
0.7609335561698132
因為數據只有506筆,基本上當數據量越少,所需的維度就要少,因此我們使用PCA降維的方式,它是屬於線性的降維。
from sklearn.model_selection import train_test_split # 引入train_test_split
from sklearn import decomposition # 引入decomposition
from sklearn.preprocessing import StandardScaler
x = data.data # pca降維後的數據
y = data.target # 房價數據
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.3, random_state = 1) # 將數據分成73比
# Standarize our training data
std_tool = StandardScaler()
std_tool.fit(x_train)
x_train = std_tool.transform(x_train)
# PC降維
pca = decomposition.PCA(n_components=0.95)
pca.fit(x_train)
x_train = pca.transform(x_train)
from sklearn.linear_model import LinearRegression # 引入LinearRegression
import matplotlib.pyplot as plt # 引入pyplot
lnregr = LinearRegression()
lnregr.fit(x_train, y_train) # 將資料拿去訓練
# Standarize x_test
x_test = std_tool.transform(x_test)
# Dimension reduction usng PCA
x_test = pca.transform(x_test)
y_predict = lnregr.predict(x_test) # 將test的資料用訓練出來的模型去預測
plt.xlabel("actual price") # x軸的標題
plt.ylabel("predict pcice") # y軸的標題
plt.plot([0,50], [0,50]) # 劃一條基準線
plt.scatter(y_test, y_predict) # 比對預測跟實際的差別
plt.show() # 察看結果
lnregr.score(x_train, y_train) # 訓練模型的正確率
output
0.7723543146059919
我們在這篇文章僅做了一些初步的分析,尚未找到最好的模型,可以考慮SVM或決策樹,但是它的分析步驟,就類似這樣模式,在分析的過程中延伸問題,改變問題,尋找更好的方向,得到更加有用的結果。