Hoc may voi Python (3)

(Tiếp theo của học máy với Python 2)



Lựa chọn mô hình và giải thuật phù hợp


Tới đây, bạn đã có những ấn tượng, những cảm nhận ban đầu về dữ liệu. Tuy nhiên, yêu cầu đặt ra cho ứng dụng này là chúng ta phải dự báo “khi nào thì số lượng truy cập sẽ chạm ngưỡng 100 000 lần/giờ? hay dự báo khi nào sẽ phải nâng cấp hệ thống?”

Để trả lời câu hỏi này, cần phải giải quyết hai vấn đề sau:
­ 
- Tìm ra mô hình phù hợp dựa trên các dữ liệu đã quan sát được. (Nói nôm na là tìm ra được một biểu thức thể hiện mối liên hệ giữa x và y). 

- Sử dụng mô hình để dự báo: thời điểm nào thì số lượng truy cập sẽ chạm ngưỡng 100 000 lần/giờ?

Khi nói về mô hình (model), bạn có thể nghĩ đến một mô phỏng của thế giới thật, tất nhiên, nó mang tính giả định và đã được đơn giản hóa. Mô hình luôn luôn có độ sai khác so với thực tế, còn được gọi là sai số xấp xỉ (approximate error). Sai  số xấp xỉ chính là một tiêu chí giúp chúng ta đánh giá được mô hình nào là phù hợp với bài toán. Sai số xấp xỉ được tính bằng bình phương khoảng cách (squared distance) giữa dữ liệu thật (quan sát được) và kết quả dự báo của mô hình.

Giả sử f là hàm số của mô hình, để tính sai số, chúng ta định nghĩa hàm error để tính sai số như sau:

Def error (f, x, y): return sp.sum((f(x) – y ** 2)

Trong đó, x và y là hai vector chứa dữ liệu (x: giờ, y: số lần truy cập) đã quan sát được; f là hàm số chúng ta đã rút trích được từ dữ liệu, đó chính là hàm mô phỏng mối liên hệ giữa x và y.

 

Bắt đầu với mô hình đường thẳng đơn giản


Giả sử mô hình cho bài toán chúng ta đang xem xét là một đường thẳng, viết dưới dạng biểu thức (hàm số) sẽ là y = ax + b. Khi đó, vấn đề cần quan tâm tiếp theo là sẽ đặt đường thẳng này theo vị trí nào để sai số xấp xỉ là nhỏ nhất. Hàm polyfit() của SciPy sẽ giúp bạn thực hiện điều này.

Với dữ liệu đầu vào là các giá trị đã quan sát được của x, y, cộng với bậc của đa thức cần tìm (vì là đường thẳng, nên bậc của đa thức là bậc 1), hàm polyfit() sẽ tìm ra được hàm số của mô hình, với sai số xấp xỉ là nhỏ nhất.

Cú pháp của hàm polyfit():

fp1, residuals, rank, sv, rcond = sp.polyfit(x, y, 1, full = True)

Hàm polyfit() sẽ trả về các tham số của hàm fp1; với tham số full = True, hàm polyfit() cũng sẽ cung cấp thêm cho chúng ta các thông tin liên quan khác. Trong các thông tin liên quan khác, bạn sẽ quan tâm tới giá trị của residuals, đây là sai số giữa các giá trị y quan sát và các giá trị y dự báo của mô hình.

Chạy thử trên SciPy:

In [1]: import scipy as sp
In [2]: data = sp.genfromtxt("D:\Liv\Re\Ebooks\ML\web_traffic.tsv", delimiter="\t")
In [3]: x = data[:,0]
In [4]: y = data[:,1]
In [5]: x = x[~sp.isnan(y)]
In [6]: y = y[~sp.isnan(y)]
In [7]: fp1, residuals, rank, sv, rcond = sp.polyfit(x, y, 1, full = True)
In [8]: print ("Cac tham so cua mo hinh: %s" % fp1)
Cac tham so cua mo hinh: [ 2.59619213       989.02487106]
In [10]: print(residuals)
[ 3.17389767e+08]

Vậy hàm số (hay đường thẳng) chúng ta cần tìm có dạng:

y = f(x) = 2.59619213* x + 989.02487106

Dựa vào các tham số trả về của polyfit(), sử dụng hàm poly1d() của SciPy để tạo ra hàm số của mô hình.

In [11]: f1 = sp.poly1d(fp1)

Định nghĩa hàm error (), để tính và  xuất sai số xấp xỉ của hàm số mô hình.

In [14]: def error(f, x, y):return sp.sum((f(x) - y)**2)
In [15]: print (error(f1, x, y))
317389767.34

Chúng ta sẽ biểu diễn dữ liệu đã quan sát và mô hình đường thẳng vừa tìm được.

Đầu tiên, chúng ta sẽ biểu diễn dữ liệu đã quan sát dưới dạng đồ thị không gian hai chiều (xem lại bài viết số 2).

Tiếp theo, chúng ta thực hiện vẽ đường thẳng của mô hình.

In [25]: fx = sp.linspace(0, x[-1], 1000) # tao cac gia tri tren truc X
In [26]: plt.plot(fx, f1(fx), linewidth=4)
Out[26]: [<matplotlib.lines.Line2D at 0x66d7890>]
In [27]: plt.legend(["Bac = %i" % f1.order], loc = "upper left")
Out[27]: <matplotlib.legend.Legend at 0x66d7eb0>

Kết quả:



Quan sát đường thẳng trên đồ thị, bạn sẽ nhận thấy bước sang tuần thứ năm thì mô hình đã thể hiện sai rất nhiều so với quan sát thực tế. Ngoài ra, với sai số xấp xỉ là 317389767,34, bạn cũng không biết là nó có phải là một mô hình phù hợp nhất hay không?

Giá trị tuyệt đối của sai số rất ít khi được sử dụng riêng biệt. Tuy nhiên, khi thực hiện so sánh giữa hai mô hình, thì bạn có thể sử dụng nó để đánh giá xem mô hình nào phù hợp hơn.

Mặc dù chúng ta sẽ không sử dụng mô hình đường thẳng này để dự đoán, nhưng nó sẽ là mô hình xuất phát, làm cơ sở để chúng ta tìm các mô hình khác phù hợp hơn. Các mô hình chúng ta tìm ra sau này sẽ được so sánh với mô hình xuất phát.

 

Tăng thêm độ phức tạp của mô hình


Chúng ta sẽ chọn một mô hình khác phức tạp hơn, đó là một đa thức bậc 2. Chúng ta sẽ xem đa thức bậc 2 này có mô phỏng dữ liệu tốt hơn hay không.

Hàm số bậc 2 có dạng: y = ax**2 + bx + c.

Rút trích hàm số bậc 2 từ dữ liệu quan sát:

In [28]: f2p = sp.polyfit(x, y, 2)

Xuất kết quả:

In [29]: print(f2p)
[ 1.05322215e-02       -5.26545650e+00      1.97476082e+03]

Vậy hàm số bậc 2 rút trích được là:

y  =  f(x) = 0,0105322215*x**2  - 5.26545650*x + 1974,76082

Sai số xấp xỉ của hàm số:

In [30]: f2=sp.poly1d(f2p)
In [31]: print(error(f2, x, y))
179983507.878

Vẽ đồ thị của hàm số bậc 2 (đường nét đứt, màu đỏ):

Để đỡ phải gõ lại các dòng lệnh, bạn có thể viết riêng đoạn mã vẽ đồ thị. Để thực hiện, bạn chạy phần mềm Enthought Canopy, chọn Editor, chọn Create a new file, nhập vào đoạn mã cần thực thi, lưu lại, bấm Run\Run file để xem kết quả.

import scipy as sp
import matplotlib.pyplot as plt

# Nhap du lieu tu tap tin
data = sp.genfromtxt("D:\Liv\Re\Ebooks\ML\web_traffic.tsv", delimiter="\t")

# Tao hai vector du lieu
x = data[:,0]
y = data[:,1]

# Loai bo cac gia tri NAN
x = x[~sp.isnan(y)]
y = y[~sp.isnan(y)]

# tao cac gia tri tren truc X cho cac mo hinh
fx = sp.linspace(0, x[-1], 1000)

# Chuan bi ve duong 1
fp1 = sp.polyfit(x, y, 1)
f1 = sp.poly1d(fp1)
plt.plot(fx, f1(fx), label = 'Bac = 1', linewidth=4)

# Chuan bi ve duong 2
fp2 = sp.polyfit(x, y, 2)
f2 = sp.poly1d(fp2)
plt.plot(fx, f2(fx), 'r--', label = 'Bac = 2', linewidth=4)

# Hien thi ket qua
plt.scatter(x,y)
plt.title("Luu luong truy cap web")
plt.xlabel("Thoi gian")
plt.ylabel("Truy cap/gio")
plt.xticks([w*7*24 for w in range(5)],['Tuan %i'%(w+1) for w in range(5)])
plt.autoscale(tight=True)
plt.grid()
plt.legend(loc='upper left')
plt.show()
Kết quả:




--------------------------
Tham khảo (lược dịch)
Willi Richert, Luis Pedro Coelho, Building Machine Learning Systems with Python, PACKT publishing, 2013
--------------------------
Cập nhật (2015/2/3)
--------------------------
Đọc thêm
Hoc may voi Python (4)