背景:波士頓房價數據集包括506個樣本,每個樣本包括12個特征變量和該地區的平均房價。房價(單價)顯然和多個特征變量相關,不是單變量線性回歸(一元線性回歸)問題;選擇多個特征變量來建立線性方程,這就是多變量線性回歸(多元線性回歸)問題。
房價和多個特征變量相關,本案例嘗試使用多元線性回歸建模 Y=X1*W1+X2*W2+..+X12*W12+b
結果可以由不同特征的輸入值和對應的權重相乘求和,加上偏置項計算求解,多變量線性方程可用矩陣運算表示。
一、數據讀取
CRIM:城鎮人均犯罪率 AGE:1940年之前建成的自用房屋比例
ZN:住宅用地超過25000sq.ft.的比例 DIS:到波士頓5個中心區域的加權距離
INDUS:城鎮非零售商用土地的比例 RAD:輻射性公路的靠近指數
CHAS:邊界是河流為1,否則0 TAX:每10000美元的全值財產稅率
NOX:一氧化氮濃度 PTRATIO:城鎮師生比例
RM:住宅平均房間數 LSTAT:人口中地位低下者的比例
標簽數據 MEDV:自住房的平均房價,單位:干美元
1.1通過pandas讀取數據文件,列出統計概述(分析用)

import tensorflow as tf import numpy as np import matplotlib.pyplot as plt import pandas as pd from sklearn.utils import shuffle #打亂樣本 df = pd.read_csv("data/boston.csv", header=0) print(df.describe()) #線束數據摘要描述信息
pandas是python提供的非常好用的數據分析模塊,但是在使用pandas進行數據分析時,有時候需要查看打印的結果,當dataframe行數或者列數比較多的時候,打印結果總是有一些省略號,不能完整的看到數據的大致分布,比如最大值,最小值,等等,了解數據分布的區間有助於進行可視化和進一步分析。查看pandas的文檔,這個問題可以通過pandas內置的set_option()方法解決,從文檔的屬性設置中可以看到,與顯示的行數列數有關的選項主要是【display】中的【max_columns,max_rows,max_colwidth,line_width】等這幾項,只需要將這幾項屬性值設置得大一些就可以解決。
修改后的程序為:

import tensorflow as tf import numpy as np import matplotlib.pyplot as plt import pandas as pd from sklearn.utils import shuffle #打亂樣本 pd.set_option('display.max_columns',1000) pd.set_option('display.width',1000) pd.set_option('display.max_colwidth',1000) df = pd.read_csv("data/boston.csv", header=0) print(df.describe()) #線束數據摘要描述信息(數量、平均值、標准值、最大最小值等)
從上到下分別為,每一列的數目、平均值、標准值、最小值、25%位置的值、50%位置的值、75%位置的值、最大值。
1.2載入本例所需數據
df = df.values #獲取df的值
df = np.array(df) #把df轉換為np的數組格式
# print(df)
x_data = df[:,:12] #x_data為前12列特征數據
y_data = df[:,12] #y_data為第12列標簽數據
# print(x_data,'\n shape=',x_data.shape)
# print(y_data,'\n shape=',y_data.shape)
二、模型定義
2.1定義特征數據和標簽數據的占位符
x = tf.placeholder(tf.float32,[None,12],name ="X") #12個特征數據(12列)
y = tf.placeholder(tf.float32,[None,1],name ="Y") #1個標簽數據(1列)
Note:shape中None表示行的數量未知,在實際訓練時決定一次代入多少行樣本,從一個樣本的隨機SDG到批量SDG都可以.
2.2定義模型結構
#定義了一個命名空間,對以下語句的節點打包在一起,使計算圖看上去更簡潔 with tf.name_scope("Model"): # w 初始化值為shape=(12,1)的隨機數,標准差為0.01 w = tf.Variable(tf.random_normal([12,1],stddev=0.01),name="W") b = tf.Variable(1.0, name="b") # b 初始化值為1.0 def model(x, w, b): # w 和 b 四矩陣相乘,用matmul,不能用mutiply或者* return tf.matmul(x,w) + b pred = model(x, w, b) #預測計算操作,前向計算節點
三、訓練模型
3.1設置訓練參數(超參數)
train_epochs = 50 #迭代次數(訓練輪數)
learning_rate = 0.01 #學習率,設置為經驗值。
3.2定義均方差損失函數
with tf.name_scope("LossFunction"):
loss_function = tf.reduce_mean(tf.pow(y-pred, 2)) #均方誤差
3.3選擇優化器
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_function) #創建優化器
Note:常用優化器包括
tf.train.MomentumOptimizer tf.train.AdamOptimizer
tf.train.GradientDescentOptimizer tf.train.FtrlOptimizer
tf.train.AdadeltaOptimizer tf.train.ProximalGradientDescentOptimizer
tf.train.AdagradOptimizer tf.train.ProximalAdagradOptimizer
tf.train.AdagradDAOptimizer tf.train.RMSPropOptimizer
3.4聲明並啟動會話
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
3.5迭代訓練
1 for epoch in range (train_epochs): 2 loss_sum = 0.0 3 for xs, ys in zip(x_data,y_data): # 每次各取一行數據(一維) 4 xs = xs.reshape(1,12) # feed數據必須和placeholder的shape一致 5 ys = ys.reshape(1,1) 6 _, loss = sess.run([optimizer,loss_function],feed_dict={x: xs, y: ys}) 7 loss_sum= loss_sum+ loss 8 xvalues,yvalues = shuffle(x_data,y_data) #打亂數據順序 9 bOtemp=b.eval(session=sess) 10 wOtemp=w.eval(session=sess) 11 loss_average =loss_sum/len(y_data) 12 print("epoch=",epoch+1,"loss=",loss_average,"b=",betemp,"w=",wOtemp)
Note:第四行和第五行的解釋,一維變為二維,如把[x1,x2,...x12]變成[[x1,x2,...x12]] 進而滿足之前定義的[None,12] ; 18 變為[[18]]進而滿足之前定義的[None,1]
以上完整程序,運行后結果為:
可以發現,訓練結果出現了異常!
四、探究訓練結果異常的原因
要考慮不同特征值取值范圍大小的影響,機器學習過程中需要避免特征的絕對值取值范圍大小,造成權值過大的影響,需要進行歸一化。
歸一化[0~1]:特征值 /(特征值max - 特征值min)
4.1特征數據歸一化
對1.2節代碼進行修改,其余代碼不變
#對特證數據【0-11】列歸一化 for i in range(12): df[:,i]=df[:,i]/(df[:,i].max() - df[:,i].min()) x_data = df[:,:12] #xdata為歸一化后的前12列特征數據 y_data = df[:,12] #ydata 為最后1列標簽數據
運行后,取最后一輪訓練結果顯示為:
Note:權重絕對值越大說明該特征值影響越大。
五、模型應用
模型一般應該用來預測新的樣本的值,本例506條數據都用來訓練了,暫時沒有新的數據。
n=348 #指定一條來看看效果 # n=np.random.randint(506) #隨機確定一條來看看效果 # print(n) x_test = x_data[n] x_test = x_test.reshape(1,12) predict = sess.run(pred, feed_dict={x:x_test}) print("預測值:%f" % predict) target = y_data[n] print("標簽值:%f" % target)
完整代碼為:

#Created by:Huang #Time:2019/10/8 0007. import tensorflow as tf import numpy as np import matplotlib.pyplot as plt import pandas as pd from sklearn.utils import shuffle #打亂樣本 # pd.set_option('display.max_columns',1000) # pd.set_option('display.width',1000) # pd.set_option('display.max_colwidth',1000) df = pd.read_csv("data/boston.csv", header=0) # print(df.describe()) #線束數據摘要描述信息(數量、平均值、標准值、最大最小值等) df = df.values #獲取df的值 df = np.array(df) #把df轉換為np的數組格式 # print(df) #對特證數據【0-11】列歸一化 for i in range(12): df[:,i]=df[:,i]/(df[:,i].max() - df[:,i].min()) x_data = df[:,:12] #xdata為歸一化后的前12列特征數據 y_data = df[:,12] #ydata 為最后1列標簽數據 # print(x_data,'\n shape=',x_data.shape) # print(y_data,'\n shape=',y_data.shape) x = tf.placeholder(tf.float32,[None,12],name ="X") #12個特征數據(12列) y = tf.placeholder(tf.float32,[None,1],name ="Y") #1個標簽數據(1列) #定義了一個命名空間,對以下語句的節點打包在一起,使計算圖看上去更簡潔 with tf.name_scope("Model"): # w 初始化值為shape=(12,1)的隨機數,標准差為0.01 w = tf.Variable(tf.random_normal([12,1],stddev=0.01),name="W") b = tf.Variable(1.0, name="b") # b 初始化值為1.0 def model(x, w, b): # w 和 b 四矩陣相乘,用matmul,不能用mutiply或者* return tf.matmul(x,w) + b pred = model(x, w, b) #預測計算操作,前向計算節點 train_epochs = 50 #迭代次數(訓練輪數) learning_rate = 0.01 #學習率,設置為經驗值。 with tf.name_scope("LossFunction"): loss_function = tf.reduce_mean(tf.pow(y-pred,2)) #均方誤差 optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_function) #創建優化器 sess = tf.Session() init = tf.global_variables_initializer() sess.run(init) for epoch in range (train_epochs): loss_sum = 0.0 for xs, ys in zip(x_data,y_data): # 每次各取一行數據(一維) xs = xs.reshape(1,12) # feed數據必須和placeholder的shape一致 ys = ys.reshape(1,1) _, loss = sess.run([optimizer,loss_function],feed_dict={x: xs, y: ys}) #下划線表示只接收但之后並不會去用,返回值對我們沒有用 loss_sum= loss_sum+ loss xvalues,yvalues = shuffle(x_data,y_data) #每訓練一輪(506個數據),打亂數據順序 b0temp = b.eval(session=sess) wOtemp = w.eval(session=sess) loss_average =loss_sum/len(y_data) print("epoch=",epoch+1,"loss=",loss_average,"b=",b0temp,"w=",wOtemp) # n=348 #指定一條來看看效果 n=np.random.randint(506) #隨機確定一條來看看效果 print(n) x_test = x_data[n] x_test = x_test.reshape(1,12) predict = sess.run(pred, feed_dict={x:x_test}) print("預測值:%f" % predict) target = y_data[n] print("標簽值:%f" % target)