第一步 數據加載與觀察
①導包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import torch
import torch.optim as optim
import warnings
warnings.filterwarnings("ignore")
%matplotlib inline
②加載數據
features = pd.read_csv("temps.csv")#觀察數據
features.head()
③整合日期,統一格式
import datetimeyears = features["year"]
months = features["month"]
days = features["day"]dates = [str(int(year)) + "-" +str(int(month)) + "-" +str(int(day)) for year,month,day in zip(years,months,days)]
dates = [datetime.datetime.strptime(date,"%Y-%m-%d") for date in dates]
④繪圖(主要用于觀察數據走向)
# 繪圖
plt.style.use("fivethirtyeight")
plt.rcParams['font.sans-serif'] = ['SimHei']# 設置布局
fig,((ax1,ax2),(ax3,ax4)) = plt.subplots(nrows=2,ncols=2,figsize=(10,10))
fig.autofmt_xdate(rotation=45)# 標簽值
ax1.plot(dates,features["actual"])
ax1.set_xlabel("")
ax1.set_ylabel("Temperature")
ax1.set_title("當天真實最大溫度")ax2.plot(dates,features["temp_1"])
ax2.set_xlabel("")
ax2.set_ylabel("Temperature")
ax2.set_title("昨日最大溫度")ax3.plot(dates,features["temp_2"])
ax3.set_xlabel("Date")
ax3.set_ylabel("Temperature")
ax3.set_title("前日最大溫度")ax4.plot(dates,features["friend"])
ax4.set_xlabel("Date")
ax4.set_ylabel("Temperature")
ax4.set_title("朋友預測最大溫度")plt.tight_layout(pad=2)
注1:值得一提的是,如果日期沒有轉換為datetime類型,而是簡單的字符串,在繪圖的時候是無法正確顯示的
即缺失本句:
dates = [datetime.datetime.strptime(date,"%Y-%m-%d") for date in dates]
注2:
除了 `plot()` 方法,matplotlib 的 Axes 對象還提供了多種其他方法來創建不同類型的圖表。以下是一些常見的方法:
1. **scatter(x, y, [s], [c])**: 創建散點圖。`x` 和 `y` 分別是數據點的橫坐標和縱坐標,`s` 是可選參數,用于指定點的大小,`c` 也是可選參數,用于指定點的顏色。
2. **bar(x, height)** 或 **barh(y, width)**: 創建條形圖。`bar()` 創建垂直條形圖,而 `barh()` 創建水平條形圖。
3. **hist(x, bins)**: 創建直方圖。`x` 是一個連續型變量的數據集,`bins` 參數指定了直方圖中的柱數或區間范圍。
4. **step(x, y)**: 創建階梯圖。與線圖類似,但是值之間的連接是水平和垂直線段構成的臺階狀。
5. **fill_between(x, y1, [y2])**: 在兩條曲線之間填充顏色。`y1` 和 `y2` 分別定義了上下邊界,默認情況下 `y2=0`。
6. **stackplot(x, y)**: 創建堆疊區域圖。
7. **errorbar(x, y, [yerr], [xerr])**: 創建帶誤差棒的線圖。`yerr` 和 `xerr` 分別指定了每個點在y軸和x軸方向上的誤差范圍。
8. **stem(x, y)**: 創建莖葉圖,顯示離散序列相對于x的位置。
9. **pie(sizes, [labels])**: 創建餅圖。`sizes` 指定各部分的大小,`labels` 是可選參數,用來標記餅圖中的各個扇區。
10. **imshow(X)**: 顯示圖像數據。`X` 是一個二維數組,表示圖像的像素值。
11. **contour([X, Y,] Z)** 或 **contourf([X, Y,] Z)**: 創建等高線圖或填充的等高線圖。`Z` 是一個二維數組,表示高度值;`X` 和 `Y` 可選,提供坐標的網格。
這些只是 matplotlib 提供的一部分繪圖方法,每種方法都有自己的參數選項,可以進一步定制圖表的外觀。對于更復雜或特定領域的圖表,還可以使用 seaborn、plotly 等高級繪圖庫,它們基于 matplotlib 并擴展了其功能。
第二步 預處理
①獨熱編碼
features = pd.get_dummies(features)
features.head()
注1:
pd.get_dummies(features)
是 Pandas 庫中的一個函數,用于將分類變量(categorical variable)轉換為啞變量(dummy variables),也稱為 one-hot 編碼。這樣做是為了讓機器學習算法能夠處理非數值型數據,因為大多數機器學習算法需要輸入的數據是數值形式的。
這行代碼會創建一個新的 DataFrame features
,其中原來的分類變量被替換為多個二進制(0 或 1)的列,每個新列代表原始分類變量的一個類別。如果一個樣本屬于某個類別,則對應的新列為 1;否則為 0。
例如,如果你有一個特征 "color" 包含三個類別:"Red", "Green", 和 "Blue",那么調用 pd.get_dummies()
后會生成三列:color_Red
, color_Green
, 和 color_Blue
,并且每個樣本在這三列中只會有一個值為 1,其余為 0。
②處理數據和預測值
labels = np.array(features["actual"])features = features.drop("actual",axis=1)feature_list = list(features.columns)features = np.array(features)
注1:features = np.array(features)
本句將features從Pandas DataFrame的形式轉換為Numpy數組,以便后續操作
③標準化數據
from sklearn import preprocessing
input_features = preprocessing.StandardScaler().fit_transform(features)
注1:
-
preprocessing.StandardScaler()
創建了一個StandardScaler
的實例。StandardScaler
是一個類,它實現了對數據進行標準化的功能。 -
.fit_transform(features)
方法執行了兩個操作:-
fit: 計算訓練數據的均值和標準差。這些統計信息將被用來標準化數據。
-
transform: 使用計算出的均值和標準差來標準化數據,即將每個特征減去其均值并除以其標準差,得到新的特征值。
-
第三步 構建神經網絡模型
x = torch.tensor(input_features,dtype=float)
y = torch.tensor(labels,dtype=float)# 權重參數初始化
weights1 = torch.randn((14,128),dtype=float,requires_grad = True)
biases1 = torch.randn(128,dtype=float, requires_grad = True)
weights2 = torch.randn((128,1),dtype=float,requires_grad = True)
biases2 = torch.randn(1,dtype=float,requires_grad = True)learning_rate=0.001
losses=[]for i in range(1000):# 計算隱藏層hidden = x.mm(weights1)+biases1# 加入激活函數hidden = torch.relu(hidden)# 預測結果predictions = hidden.mm(weights2)+biases2# 計算損失loss = torch.mean((predictions - y)**2)losses.append(loss.data.numpy())if i % 100 ==0:print("loss:",loss)# 反向傳播計算loss.backward()# 更新參數weights1.data.add_(-learning_rate * weights1.grad.data)biases1.data.add_(-learning_rate * biases1.grad.data)weights2.data.add_(-learning_rate * weights2.grad.data)biases2.data.add_(-learning_rate * biases2.grad.data)# 每次迭代完清空weights1.grad.data.zero_()biases1.grad.data.zero_()weights2.grad.data.zero_()biases2.grad.data.zero_()
第四步 優化構建神經網絡模型的方法
①構建模型
input_size = input_features.shape[1]
hidden_size = 128
output_size = 1
batch_size = 16my_nn = torch.nn.Sequential(torch.nn.Linear(input_size,hidden_size),torch.nn.Sigmoid(),torch.nn.Linear(hidden_size,output_size)
)cost = torch.nn.MSELoss(reduction = "mean")
optimizer = torch.optim.Adam(my_nn.parameters(),lr=0.001)
這段代碼創建了一個簡單的兩層神經網絡,定義了損失函數為均方誤差,并選擇了 Adam 作為優化器。Sequential
模塊簡化了模型構建的過程,使得代碼更加簡潔易讀。此外,通過設置批量大小、隱藏層大小、輸出大小等超參數,你可以靈活地調整模型以適應不同的任務需求。
要完成這個模型的訓練過程,還需要編寫一個訓練循環,在其中進行前向傳播、計算損失、反向傳播以及參數更新。如果你想要進一步提升模型性能或復雜度,還可以考慮添加更多層、選擇不同的激活函數、調整優化器及其參數等。
②訓練模型
# 訓練網絡
losses = []
for i in range(1000):batch_loss = []#MINI-Batch方法來進行訓練for start in range(0,len(input_features),batch_size):end = start+batch_size if start+batch_size<len(input_features) else len(input_features)xx = torch.tensor(input_features[start:end],dtype=torch.float,requires_grad = True)yy = torch.tensor(labels[start:end],dtype=torch.float,requires_grad = True)prediction =a my_nn(xx)loss = cost(prediction,yy)optimizer.zero_grad()loss.backward(retain_graph=True)optimizer.step()batch_loss.append(loss.data.numpy())if i%100==0:losses.append(np.mean(batch_loss))print(i,np.mean(batch_loss))
第五步 繪圖觀察
①準備數據
x = torch.tensor(input_features,dtype=torch.float)
predict = my_nn(x).data.numpy()
②處理格式
# 轉換日期格式
dates = [str(int(year)) + "-" + str(int(month)) + "-" + str(int(day)) for year,month,day in zip(years,months,days)]
dates = [datetime.datetime.strptime(date,"%Y-%m-%d") for date in dates]# 創建表格來存日期和其對應的標簽數值
true_data = pd.DataFrame(data = {"date":dates,"actual":labels})# 創建表格來村日期和其對應的模擬預測值
months = features[:,feature_list.index("month")]
days = features[:,feature_list.index("day")]
years = features[:,feature_list.index("year")]test_dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)]
test_dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in test_dates]predictions_data = pd.DataFrame(data={"date":test_dates,"prediction":predict.reshape(-1)})
注1:
-
features
是一個二維數組或類似結構(如 NumPy 數組),其中每一行代表一個樣本,每一列代表一個特征。 -
:
表示選取所有行。 -
feature_list.index("month")
返回的是要選擇的列的索引。 -
因此,
features[:, feature_list.index("month")]
將選取features
中對應于"month"
列的所有元素,形成一個新的一維數組,這個數組包含了所有樣本的月份信息。
注2:
predict.reshape(-1)
的具體含義如下:
-
reshape()
方法:這是 NumPy 數組的一個方法,用于改變數組的形狀而不改變其數據。 -
-1
參數:當你傳遞-1
作為參數時,NumPy 會自動計算該維度的大小,以確保新數組的總元素數量保持不變。換句話說,它會根據其他維度的大小來推斷出合適的長度。例如,如果你有一個形狀為(n, 1)
的二維數組,并調用.reshape(-1)
,結果將是一個形狀為(n,)
的一維數組。
在你的例子中,假設 predict
是一個形狀為 (n, 1)
的二維數組,那么 predict.reshape(-1)
會將其轉換為一個形狀為 (n,)
的一維數組。這樣做是為了確保 predictions_data
中的 prediction
列是一維的,從而與 date
列匹配,并且使得每個日期對應一個預測值。
③繪圖
# 真實值
plt.plot(true_data["date"],true_data["actual"],"b-",label="actual")# 預測值
plt.plot(predictions_data["date"],predictions_data["prediction"],"ro",label="prediction")
plt.xticks(rotation = 60)
plt.legend()# 圖名
plt.xlabel("Date")
plt.ylabel("Maximum Temperature")
plt.title("Actual and Predicted Values")
注1:
plt.legend()
:在圖表中添加一個圖例,顯示之前定義的標簽(如 "actual"
和 "prediction"
),以便區分不同系列的數據。
注2:
"b-"
:指定線條樣式為藍色實線(b
表示藍色,-
表示實線)。
"ro"
:指定標記樣式為紅色圓點(r
表示紅色,o
表示圓形標記)。
至此,構建神經網絡模型實現氣溫預測已完成。