3.4.1 Chuẩn bị dữ liệu
Sử dụng 60 điểm dữ liệu làm đầu vào để dựđoán cho điểm thứ61. Các thư viện cần thiết cho bước tiền xử lý là:
import matplotlib.pyplot as plt import numpy as np
import pandas
from sklearn.preprocessing import MinMaxScaler
Hàm read_csvđược sử dụng để tải dữ liệụ concat được sử dụng để ghép nối dữ liệụ Sau khi tải và ghép nối dữ liệu, dữ liệu được hiển thị 5 hàng cuối cùng của bộ dữ liệu bằng hàm datạtail(). Bộ dữ liệu để đào tạo bắt đầu từ
06h00 05/02/2019 đến 00h00 ngày 09/10/2019.
thang_2=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/2.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_3=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/3.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_4=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/4.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_5=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/5.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_6=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/6.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_7=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/7.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_8=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/8.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
thang_9=pandas.read_csv('E:/Thac si/Luan van/1. bao cao luan van/Final/Thu_nghiem_du_lieu/2019/9.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
60
luan van/Final/Thu_nghiem_du_lieu/2019/10.csv', usecols=['Daté, 'Hour', 'Temperature Number'])
nam_2019=pandas.concat([thang_2,thang_3,thang_4,thang_5,than g_6,thang_7,thang_8,thang_9, thang_10])
nam_2019.tail()
Dữ liệu sau khi được tải, sẽ được làm sạch bằng cách loại bỏ các cột không cần thiết là Date và Hour, điều chỉnh dữ liệu lại trong khoảng [0, 1] bằng cách sử dụng MinMaxScaler(). Điều này nhằm cải thiện hiệu suất dựđoán.
data_training = nam_2019.copy().drop(['Daté, 'Hour'], axis=1)
scaler = MinMaxScaler()
data_training = scaler.fit_transform(data_training) data_training
Dữ liệu sau khi đã điều chỉnh (Hình 3.9).
Hình 3.9: Kết quả dữ liệu sau khi điều chỉnh
Dữ liệu được chia thành X_train và y_train đảm bảo cho 60 điểm đầu vào dự báo 1 điểm đầu ra (điểm thứ 61).
X_train = [] y_train = []
for i in range(60, data_training.shape[0]): X_train.append(data_training[i-60:i]) y_train.append(data_training[i, 0])
X_train, y_train = np.array(X_train), np.array(y_train)
Làm tương tự như vậy với bộ dữ liệu kiểm thử. Bộ dữ liệu kiểm thử bắt đầu từ 06h00 09/10/2019 đến 12h00 ngày 16/12/2019.
61
3.4.2 Xây dựng mô hình
Như đã trình bày phần trước, mô hình được lựa chọn là mô hình Long Short Term Memory (LSTM). Từ mô hình đó việc triển khai áp dụng mô hình trên server được thực hiện như sau:
LSTM_model = Sequential()
LSTM_model.ađ(LSTM(units = 60, activation = 'relú, return_sequences=True,input_shape = (X_train.shape[1], 1))) LSTM_model.ađ(Dropout(0.1))
LSTM_model.ađ(LSTM(units = 60, activation = 'relú, return_sequences = True))
LSTM_model.ađ(Dropout(0.1))
LSTM_model.ađ(LSTM(units = 80, activation = 'relú, return_sequences = True))
LSTM_model.ađ(Dropout(0.1))
LSTM_model.ađ(LSTM(units = 120, activation = 'relú)) LSTM_model.ađ(Dropout(0.1))
LSTM_model.ađ(Dense(units = 1))
Bằng cách sử dụng lệnh model.summary() nó sẽ hiện mô tả ngắn gọn các lớp và cấu trúc đầu ra, và sốlượng các tham số tầng lớp (Hình 3.10):
62 Sốlượng tham sốnày được tính như sau:
- Đối với LSTM, thì thì số lượng tham số là: 4 × (inputsize + outputsize + 1)* inputsize;
- Đối với lớp kết nối đầy đủ (Dense layer hay fully-connected layer) thì số lượng tham số là: outputsize × (inputsize + 1)
Trong đó:
- inputsize là kích thước đầu vào của lớp đó. - outputsize là kích thước đầu ra của lớp đó.
3.4.3 Đào tạo và lưu lại mô hình
Sau khi xây dựng mô hình, mô hình được đào tạo với thuật toán tối ưu là Adam và hàm lỗi là sai số bình phương trung bình với epochs = 50 và batch_size = 32 là 2 lựa chọn phổ biến nhất. Đối với những mẫu có kích thước nhỏ, đa số lời khuyên sẽ là batch_size là 32 hoặc 25.
LSTM_model.compile(optimizer='adam', loss='mean_squared_error')
LSTM_model.fit(X_train,y_train, epochs=50, batch_size=32)
Sau quá trình đào tạo, mô hình được lưu lại để có thể sử dụng sau này:
LSTM_model.save('LSTM_model.h5')
Kết quảsau khi được lưu lại sẽ tái sử dụng để dựđoán bằng cách gọi hàm:
load_model
3.4.4 Xây dựng cách kiểm thử mô hình và đánh giá
Với việc phân chia đầu vào và đầu ra nhưở trên, ta có dữ liệu để kiểm thử là ma trận 2 chiều X_test và ma trận 1 chiều y_test. Đối với tham số nhiệt độ, bộ dữ liệu kiểm thử X_test và y_test là có độ dài là 2916. Đối với 6 tham số khác, bộ dữ liệu kiểm thửX_test và y_test có độ dài là 411.
Sau khi phân chia dữ liệu, X_test được đưa vào mô hình để dựđoán:
y_pred = LSTM_model.predict(X_test)
Vì kết quả X_test đã được điều chỉnh, nên kết quả dự báo cũng sẽ nằm trong khoảng 0 đến 1, vì vậy cần chuyển kết quả dự báo về dạng ban đầụ
y_pred = scaler.inverse_transform(y_pred)
63 - Vẽ cả kết quả dự báo và kết quả thực tế trên cùng 1 đồ thị để có
cách nhìn trực quan nhất.
- Thống kê lại sự chênh lệch bằng cách lấy |y_test - y_pred|. Kết quả thống kê sự chênh lệch được tổng hợp, tính toán và vẽ đồ thị phân phối tích lũy sai số
64
CHƯƠNG 4.TRIỂN KHAI THỰC HIỆN TRÊN MOBILE
Nhằm giúp cho các hộ dân nuôi tôm có cái nhìn trực quan về sự thay đổi của các tham số nguồn nước, đềtài đã sử dụng các mẫu đồ thị để biểu diễn tham sốtrên điện thoại di động.
4.1 Lựa chọn thư viện đồ thị
Từ các giao diện đồ thị đã tìm hiểu, nhóm nghiên cứu đã lựa chọn thư viện MPAndroidChart để tạo ra các mẫu đồ thị tham số cho ứng dụng do sựđơn giản nhưng phù hợp về mặt thẩm mỹ. Về mặt triển khai lập trình thì thư viện cũng hỗ trợ nhiều, làm đơn giản hóa quá trình lập trình.
4.1.1 Thư viện MPAndroidChart
• Đặc điểm
Đây là một thư viện mạnh mẽ và dễ dàng sử dụng để vẽcác đồ thị trên hệđiều hành Android.
Có phiên bản thư viện khác trên hệđiều hành iOS là Charts
Hỗ trợ các giải pháp vẽ đồ thị realtime (thời gian thực) thông qua SciChart
Hỗ trợ tất cả các loại biểu đồ
• Lựa chọn loại đồ thị
Do mục đích của việc vẽ các mẫu đồ thị là giúp người dùng có thể dễ dàng quan sát các mẫu tham số nguồn nước nên nhóm nghiên cứu đã lựa chọn loại đồ thị dạng đường LineChart phục vụ cho ứng dụng của mình.
• Triển khai vẽđồ thị trong lập trình Tạo LineChart trong file .xml
Ánh xạ LineChart từ file .xml sang code
65 Thêm List<Entry> vào đối tượng LineDataSet
Thêm đối tượng LineDataSet vào đối tượng LineData
4.1.2 Phát triển mẫu đồ thị biểu diễn tham số
4.1.2.1. Thiết kế đồ thị biểu diễn tham số
Sau khi đã chọn được loại đồ thị cần sử dụng, tiếp theo tới việc thiết kế các giao diện biểu diễn các đồ thị của các tham số nguồn nước. Nhóm nghiên cứu thiết kế các đồ thị bao gồm các thành phần cấu thành như sau:
• Tên đồ thị biểu diễn tham số
• Đồ thị biểu diễn tham số: trong đồ thị bao gồm ba đường gồm có đường biểu diễn ngưỡng cực đại của tham số, đường biểu diễn ngưỡng cực tiểu của tham sốvà đường biểu diễn giá trị tham số thực tếđo được.
66 Trên Hình 4.1 là đồ thị biểu diễn tham số pH trong đó đường màu đỏ là đường thể hiện ngưỡng giá trị cực đại của tham số (High Warning), đường màu vàng là đường thể hiện ngưỡng giá trị cực tiểu của tham số (Low Waring) và đường màu xanh là đường thể hiện giá trị đo được thực tế (Current). Với các đồ thị của tham sốkhác cũng tương tựnhư vậỵ Màu của các đường biểu diễn có thể được thay đổi theo hệ điều hành Android hay iOS cho phù hợp với giao diện người dùng.
4.1.3 Thiết kế giao diện biểu diễn đồ thị
Các đồ thị biểu diễn các tham số sẽđược hiển thị trên giao diện ứng dụng có thể theo dạng danh sách trên hệđiều hành Android (Hình 4.2).
Hình 4.2: Giao diện biểu diễn đồ thị trên Android
4.1.4 Thiết kế các bước thực hiện
Về mặt thuật toán để hiển thị các giá trị tham sốtrên đồ thị đề tài đã xây dựng sơ đồ khối tổng quát các bước vẽ đồ thị có sử dụng thư viện của MPAndroidChart và thư viện Retrofit do Google cung cấp – có sẵn các API giúp thuận tiện cho việc lập trình (Hình 4.3).
Khối thứ nhất Create list Entries and Labels với mục đích tạo các đầu vào trên đồ thịứng với trục tung Oy (trong MPAndroidChart gọi là các Entry) và các
67 nhãn ghi giá trị của điểm ứng với trục hoành Ox (trong MPAndroidChart gọi là các Label). Sau khi tạo được danh sách các Entries và Labels tiếp tục tạo ra danh sách đồ thị qua khối thứ hai Create list graph. Ở khối này, các Entries và Labels
sẽ được thêm vào các Graph tương ứng. Sau khối thứhai đầu ra thu được sẽ là danh sách các đồ thị trống chưa có dữ liệụ Đểcác đồ thị hiển thị các dữ liệu trên đó cần phải thực hiện việc lấy dữ liệu của các tham số nguồn nước (param) tương ứng với các thiết bị và các biểu đồ bằng khối thứ ba Get list data by param, sau đó thêm các dữ liệu đó vào các đồ thị trống bằng việc thực thi khối thứtư Ađ data to graphs.
Get list data by param Create list Entries and Labels
Create list graph
Ađ data to graphs
Update list graphs on UI
Hình 4.3: Sơ đồ khối tổng quát các bước vẽ đồ thị các tham số
Cuối cùng sau khi các đồ thịđã có dữ liệu, lúc này công việc cuối cùng là cập nhật lại danh sách đồ thị trên giao diện qua khối thứ năm Update list graph on UỊ
4.2 Triển khai trong lập trình
• Tạo đối tượng List Entries và List Labels
//All components of all graphs
private ArrayList<Entry> entriesPH=new ArrayList<>();
private ArrayList labelsPH = new ArrayList<String>();
private ArrayList<Entry> entriesSalt=new ArrayList<>();
private ArrayList labelsSalt = new ArrayList<String>();
private ArrayList<Entry> entriesOxy=new ArrayList<>();
68
private ArrayList<Entry> entriesTemp=new ArrayList<>();
private ArrayList labelsTemp = new ArrayList<String>();
private ArrayList<Entry> entriesH2S=new ArrayList<>();
private ArrayList labelsH2S = new ArrayList<String>();
private ArrayList<Entry> entriesNH3=new ArrayList<>();
private ArrayList labelsNH3 = new ArrayList<String>();
private ArrayList<Entry> entriesNH4Min=new ArrayList<>();
private ArrayList labelsNH4Min = new ArrayList<String>();
private ArrayList<Entry> entriesNH4Max=new ArrayList<>();
private ArrayList labelsNH4Max = new ArrayList<String>();
private ArrayList<Entry> entriesNO2Min=new ArrayList<>();
private ArrayList labelsNO2Min = new ArrayList<String>();
private ArrayList<Entry> entriesNO2Max=new ArrayList<>();
private ArrayList labelsNO2Max = new ArrayList<String>();
private ArrayList<Entry> entriesH2SMax=new ArrayList<>();
private ArrayList labelsH2SMax = new ArrayList<String>();
private ArrayList<Entry> entriesH2SMin=new ArrayList<>();
private ArrayList labelsH2SMin = new ArrayList<String>();
• Tạo danh sách biểu đồ
listGraph=new ArrayList<>();
Graph gPH=new Graph(arrLabels[0],entriesPH,labelsPH);
Graph gSalt=new Graph(arrLabels[1],entriesSalt,labelsSalt);
Graph gOxy=new Graph(arrLabels[2],entriesOxy,labelsOxy);
Graph gTemp=new Graph(arrLabels[3],entriesTemp,labelsTemp);
Graph gH2S=new Graph(arrLabels[4],entriesH2S,labelsH2S);
Graph gNH3=new Graph(arrLabels[5],entriesNH3,labelsNH3);
Graph gNH4Max=new
Graph(arrLabels[6],entriesNH4Max,labelsNH4Max);
Graph gNH4Min=new
Graph(arrLabels[7],entriesNH4Min,labelsNH4Min);
Graph gNO2Max=new
Graph(arrLabels[8],entriesNO2Min,labelsNO2Max);
Graph gNO2Min=new
Graph(arrLabels[9],entriesNO2Min,labelsNO2Min);
Graph gH2SMax=new
Graph(arrLabels[10],entriesH2SMax,labelsH2SMax);
69
Graph(arrLabels[11],entriesH2SMin,labelsH2SMin);
Graph [] arrGraph=new Graph[]{gPH,gSalt,gTemp,
gH2S,gH2SMax,gH2SMin,
for (Graph g:arrGraph){
listGraph.ađ(g);
}
• Lấy dữ liệu theo tham số và thêm dữ liệu vào đồ thị
//lay du lieu ung voi tung thong so
public void getDataThongKe(final int tempSelectThongSo) {
String urlThongKe = Constant.URL +
Constant.API_GET_DATA_PACKAGE + "date=" +
BieuDoActivity.tmpNgayThangNam +
"&deviceid=" + tmpSelectedDeviceId + "¶mid="
+ String.valueOf(tempSelectThongSo);
Uri builder = Uri.parse(urlThongKe)
.buildUpon()
.build();
downloadJSON = new DownloadJSON(getContext());
downloadJSON.GetJSONArray(builder, new
DownloadJSON.DownloadJSONCallBack() {
@Override
public void onSuccess(String msgData) {
try{
JSONArray jsonArray = new
JSONArray(msgData);
if(jsonArray.length()==0){
txtContent.setVisibility(View.VISIBLE);
}
else{
String
nameGraph=arr_thongso[tempSelectThongSo-1];
ArrayList<Entry> entries = new
ArrayList<>();
ArrayList labels = new
ArrayList<String>();
for(int i=0; i<jsonArray.length(); i++){
JSONObject objTmp =
jsonArray.getJSONObject(i);
double value =
objTmp.getDouble("value");
String time =
objTmp.getString("time");
String[] words = time.split("T");
Log.d("time",words[0]+words[1]);
70
Entry(i,(float)value));
labels.ađ(words[1]);
}
Graph graph=new
Graph(nameGraph,entries,labels);
if (listGraph.size() > 0) {
txtItemContent.setVisibility(View.GONE);
}
int index = -1;
for (int k = 0; k < arr_thongso.length;
k++) {
if (nameGraph == arr_thongso[k]) {
index = k;
}
}
listGraph.set(index, graph);
adapter.notifyDataSetChanged(); } } catch (JSONException e) { e.printStackTrace(); } } @Override
public void onFail(String msgError) {
Log.i("Error", msgError);
}
});
}
4.3 Kết quảđạt được trên mô hình
Thời gian kiểm thử đối với các thông số Nhiệt độ, Độ mặn, pH, NH3, TSS, DO, COD: 06h00 ngày 9/10/2019 đến 12h00 ngày 16/12/2019 với 472 điểm để kiểm thử.
4.3.1 Đối với tham số độ mặn
Kết quả tổng kết là:
- Sai số trung bình là: 0.6108 - Sai số nhỏ nhất là: 0.004 - Sai số lớn nhất là: 4.1177 - Phương sai là: 0.4868
71 - Độ lệch chuẩn là: 0.6977
Biểu đồ so sánh kết quả dự báo với kết quả trong tập kiểm thử của tham số độ mặn được thể hiện trong Hình 4.4.
Hình 4.4: So sánh kết quả dự báo độ mặn với giá trị đo thực tế
Biểu đồ phân phối sai số tích lũy đối với tham số độ mặn được thể hiện trên Hình 4.5.
Hình 4.5: Phân phối sai số tích lũy đối với tham số độ mặn
4.3.2 Đối với tham số pH
Kết quả tổng kết là: - Sai số trung bình là: 0.13533 - Sai số nhỏ nhất là: 3.8337×10-5 - Sai số lớn nhất là: 0.79313 - Phương sai là: 0.03208 - Độ lệch chuẩn là: 0.17911
Biểu đồ so sánh kết quả dự báo với kết quả trong tập kiểm thử của tham số pH được thể hiện trong Hình 4.6.
72
Hình 4.6: So sánh kết quả dự báo pH với giá trị đo thực tế
Biểu đồ phân phối sai số tích lũy đối với tham số pH được thể hiện trên Hình 4.7.
Hình 4.7: Phân phối sai số tích lũy đối với tham số pH
Từ biểu đồ ta thấy, về cơ bản với sai số cho phép là 0.5 thì kết quả đạt
được trên 90%.
4.3.3 Đối với tham số NH4
Kết quả tổng kết là: - Sai số trung bình là 0.01670 - Sai số nhỏ nhất chỉ là 1.283×10-5 - Dai số lớn nhất: 0.1291 - Phương sai: 0.0004 - Độ lệch chuẩn: 0.0197
Biểu đồ so sánh kết quả dự báo với kết quả trong tập kiểm thử của tham số NH4 được thể hiện trong Hình 4.8.
73
Hình 4.8: So sánh kết quả dự báo NH4 với giá trị đo thực tế
Biểu đồ phân phối sai sốtích lũy đối với tham sốNH4 được thể hiện trong Hình 4.9.
Hình 4.9: Phân phối sai số tích lũy của tham số NH4
4.3.4 Đối với tham số H2S
Kết quả tổng kết là: - Sai số trung bình là: 0.00176 - Sai số nhỏ nhất là: 9.609×10-7 - Sai số lớn nhất là: 0.025 - Phương sai là: 6.478×10-6 - Độ lệch chuẩn là: 0.0025
Biểu đồ so sánh kết quả dự báo với kết quả trong tập kiểm thử của tham số H2S được thể hiện trong Hình 4.10.
74 Biểu đồ phân phối sai sốtích lũy đối với tham sốH2S được thể hiện trong Hình 4.11.
Hình 4.11: Phân phối sai số tích lũy của tham số H2S
4.3.5 Đối với tham số DO
Kết quả tổng kết là: - Sai số trung bình là 0.2147 - Sai số nhỏ nhất là 0.00097 - Sai số lớn nhất là 1.215 - Phương sai là 0.02874 - Độ lệch chuẩn là 0.16954
Biểu đồ so sánh kết quả dự báo với kết quả trong tập kiểm thử của tham số DO được thể hiện trong Hình 4.12.
Hình 4.12: So sánh kết quả dự báo DO với giá trị đo thực tế
Biểu đồ phân phối sai số tích lũy đối với tham số DO được thể hiện trên Hình 4.13.
75
Hình 4.13: Phân phối sai số tích lũy của tham số DO
4.3.6 Đối với tham số COD
Kết quả tổng kết là: - Sai số trung bình là: 0.3935 - Sai số nhỏ nhất là: 0.000416