Thư viện xử lý số liệu trong Python

Các thư viện thường dùng để xử lý số liệu trong Python:

Cài đặt các thư viện:

        

                pip instal numpy pandas matplotlib scikit-learn

Numpy

Numpy là thư viện cho phép xử lý các mảng số (một chiều & nhiều chiều). So với kiểu List có sẵn của Python, các mảng của numpy khác ở điểm là các phần tử của mảng có cùng kiểu dữ liệu (int, float, string, …), do đó tốc độ xử lý trên các mảng này nhanh hơn so với xử lý trên kiểu List.

Một số hàm thường sử dụng của numpy

Ví dụ:

>>> import numpy

>>> X = numpy.array([1,2,3,4])

>>> print(X)

[1 2 3 4]

>>> print(X.dtype)

int32

>>> X = numpy.array([1.0,2,3,4])

>>> print(X)

[1. 2. 3. 4.]

>>> print(X.dtype)

float64

>>> X = numpy.array([1,2,3,4], dtype=numpy.float64)

>>> print(X)

[1. 2. 3. 4.]

>>> print(X.dtype)

float64

Nếu kiểu dữ liệu không được chỉ định, numpy sẽ dựa vào giá trị các phần tử của List để chọn kiểu dữ liệu phù hợp.

Nếu shape là một số , mảng tạo ra là mảng một chiều :

>>> X = numpy.zeros(4)

>>> print(X)

[0. 0. 0. 0.]

Nếu shape là một bộ tuple/list , mảng tạo ra là mảng nhiều chiều:

>>> X = numpy.zeros((2,2))

>>> print(X)

[[0. 0.]

 [0. 0.]]

>>> X = numpy.ones(4)

>>> print(X)

[1. 1. 1. 1.]

>>> X = numpy.ones((2,2))

>>> print(X)

[[1. 1.]

 [1. 1.]]

Ví dụ:

>>> X1 = numpy.array([1,2,3,4])

>>> print(X1)

[1 2 3 4]

>>> X2 = numpy.array([5,6,7,8])

>>> print(X2)

[5 6 7 8]

>>> X3 = numpy.concatenate((X1,X2))

>>> print(X3)

[1 2 3 4 5 6 7 8]

>>> X1 = numpy.zeros((2,2))

>>> print(X1)

[[0. 0.]

 [0. 0.]]

>>> X2 = numpy.ones((2,2))

>>> print(X2)

[[1. 1.]

 [1. 1.]]

>>> X3 = numpy.concatenate((X1,X2))

>>> print(X3)

[[0. 0.]

 [0. 0.]

 [1. 1.]

 [1. 1.]]

>>> X4 = numpy.concatenate((X1,X2),axis=0)

>>> print(X4)

[[0. 0.]

 [0. 0.]

 [1. 1.]

 [1. 1.]]

>>> X5 = numpy.concatenate((X1,X2),axis=1)

>>> print(X5)

[[0. 0. 1. 1.]

 [0. 0. 1. 1.]]

>>> X = numpy.array([[1,2],[3,4]])

>>> print(X.dtype)

Int32

>>> print(X.shape)

(2, 2)

>>> X1 = numpy.array([1,2,3,4])

>>> print(X1)

[1 2 3 4]

>>> X2 = X1.reshape((2,2))

>>> print(X2)

[[1 2]

 [3 4]]

Truy nhập phần tử của mảng trong numpy

>>> X = numpy.array([1,2,3,4])

>>> print(X[0])

1

>>> print(X[:2])

[1 2]

>>> print(X[-2:])

[3 4]

>>> print(X)

[[1 2]

 [3 4]]

>>> print(X[0,1])

2

>>> print(X[1,0])

3

Tương tự mảng một chiều hay List, có thể cách dùng các chỉ số dạng hai chấm (start:end, start:, :end, ...) để truy nhập tới từng đoạn nhỏ trong mảng nhiều chiều:

>>> X = numpy.array([[1,2],[3,4]])

>>> print(X)

[[1 2]

 [3 4]]

>>> print(X[:, 0])

[1 3]

>>> print(X[1, :])

[3 4]

Các phép tính trên mảng dữ liệu numpy

Phép tính element-wise

Nếu hai mảng có cùng kích thước thì các phép tính +, -, *, /, **, %, //, … có thể được thực hiện trên hai mảng đó. Kết quả là một mảng có cùng kích thước mà mỗi phần tử là kết quả của phép toán được thực hiện trên từng cặp phần tử của hai mảng đầu vào

Ví dụ:

>>> X1 = numpy.array([[1,2],[3,4]])

>>> print(X1)

[[1 2]

 [3 4]]

>>> X2 = numpy.array([[5,6],[7,8]])

>>> print(X2)

[[5 6]

 [7 8]]

>>> X3 = X1 + X2

>>> print(X3)

[[ 6  8]

 [10 12]]

>>> X4 = X1 ** 2

>>> print(X4)

[[ 1  4]

 [ 9 16]]

So sánh một mảng với một số

Kết quả phép so sánh một mảng với một số là một mảng có kiểu dữ liệu dtype=boolean, cùng kích thước với mảng ban đầu, tương tự như phép tính element-wise

>>> X1 = numpy.array([[1,2],[3,4]])

>>> print(X1)

[[1 2]

 [3 4]]

>>> X2 = X1 > 2

>>> print(X2)

[[False False]

 [ True  True]]

Giá trị của mảng boolean kết quả có thể dùng để làm chỉ số để truy nhập mảng gốc (hoặc các mảng cùng kích thước) :

>>> X1 = numpy.array([1,2,3,4])

>>> print(X1)

[1 2 3 4]

>>> X2 = numpy.array([5,6,7,8])

>>> print(X2)

[5 6 7 8]

>>> X3 = X1[X1>2]

>>> print(X3)

[3 4]

>>> X4 = X2[X1>2]

>>> print(X4)

[7 8]

Các hàm toán học

Numpy cung cấp các hàm toán học cùng tên với các hàm của thư viện math : sin, cos, tan, asin, acos, sqrt, floor, ceil, log, log10, exp,…Các hàm toán học cũng được thực hiện theo cách xử lý element-wise

Ví dụ:

>>> X1 = numpy.array([[1,10],[100,1000]])

>>> print(X1)

[[   1   10]

 [ 100 1000]]

>>> X2 = numpy.log10(X1)

>>> print(X2)

[[0. 1.]

 [2. 3.]]

Các hàm thống kê

>>> X = numpy.array([[1,2],[3,4]])

>>> print(X)

[[1 2]

 [3 4]]

>>> print(numpy.sum(X))

10

>>> print(numpy.sum(X, axis=0))

[4 6]

>>> print(numpy.sum(X, axis=1))

[3 7]

>>> X = numpy.array([[1,2],[3,4]])

>>> print(numpy.mean(X))

2.5

>>> print(numpy.mean(X, axis=0))

[2. 3.]

>>> print(numpy.mean(X, axis=1))

[1.5 3.5]

>>> X = numpy.array([[1,2],[3,4]])

>>> print(numpy.min(X))

1

>>> print(numpy.min(X, axis=0))

[1 2]

>>> print(numpy.min(X, axis=1))

[1 3]

>>> X = numpy.array([[1,2],[3,4]])

>>> print(numpy.max(X))

4

>>> print(numpy.max(X, axis=0))

[3 4]

>>> print(numpy.max(X, axis=1))

[2 4]

Pandas

Pandas là thư viện cho phép xử lý các bảng dữ liệu có cấu trúc. Một bảng dữ liệu bao gồm nhiều cột, mỗi cột tương ứng với một trường của đối tượng dữ liệu. Cách mô tả này tương tự cách lưu trữ dữ liệu trong file excel, csv và trong database

Trong pandas, khái niệm bảng dữ liệu tương đương với đối tượng DataFrame

Khởi tạo một bảng dữ liệu

Để tạo mới một bảng dữ liệu (DataFrame) cần truyền vào tên các cột dữ liệu kèm theo giá trị của các cột

>>> from pandas import DataFrame

>>> table = DataFrame({

       'id' : [1, 2, 3],

       'price' : [50000, 100000, 80000],

       'quantity' : [10, 15, 12]

    })

>>> print(table)

   id   price  quantity

0   1   50000        10

1   2  100000        15

2   3   80000        12

Đọc dữ liệu từ file csv

Để đọc dữ liệu từ file csv, sử dụng hàm:

pandas.read_csv(filepath, sep=', ')

Trong đó:

Ví dụ :

File table.csv có nội dung:

id,price,quantity

1,50000,10 

2,100000,15

3,80000,12

Để đọc dữ liệu từ file trên :

>>> import pandas

>>> table = pandas.read_csv('table.csv')

>>> print(table)

   id   price  quantity

0   1   50000        10

1   2  100000        15

2   3   80000        12

Ghi dữ liệu vào file csv

Để ghi dữ liệu từ một DataFrame vào file csv, sử dụng hàm:

data_frame.to_csv(filepath, sep=', ', index=True)

Trong đó:

Ví dụ:

>>> table = DataFrame({

          'id' : [1, 2, 3],

          'price' : [50000, 100000, 80000],

          'quantity' : [10, 15, 12]

        })

>>> table.to_csv('table.csv')

Kết quả lưu trong file table.csv:

,id,price,quantity

0,1,50000,10

1,2,100000,15

2,3,80000,12

Cột đầu tiên trong file csv là cột chỉ số do pandas tự sinh ra. Để không lưu cột chỉ số này, truyền giá trị index=False vào hàm to_csv :

>>> table = DataFrame({

          'id' : [1, 2, 3],

          'price' : [50000, 100000, 80000],

          'quantity' : [10, 15, 12]

        })

>>> table.to_csv('table.csv', index=False)

Kết quả trong file table.csv:

id,price,quantity

1,50000,10

2,100000,15

3,80000,12

Truy nhập dữ liệu trong DataFrame

Truy nhập đến một hàng trong bảng

Để truy nhập đến hàng thứ index của bảng dữ liệu data_frame, sử dụng cấu trúc:

data_frame.loc[index]

Ví dụ:

>>> table = DataFrame({

          'id' : [1, 2, 3],

          'price' : [50000, 100000, 80000],

          'quantity' : [10, 15, 12]

        })

>>> row0 = table.loc[0]

>>> print(row0['id'], row0['price' ], row0['quantity' ])

1 50000 10

Truy nhập đến một cột trong bảng

Để truy nhập đến cột dữ liệu với tên col_name trong bảng dữ liệu data_frame, sử dụng cấu trúc:

data_frame.col_name

Hoặc:

data_frame['col_name']

Ví dụ:

>>> table = DataFrame({

          'id' : [1, 2, 3],

          'price' : [50000, 100000, 80000],

          'quantity' : [10, 15, 12]

        })

>>> price_col = table.price

>>> for i in range(len(price_col)) : print(price_col[i])

50000

100000

80000

Truy nhập tới toàn bộ bảng dữ liệu dưới dạng bảng numpy 2 chiều

Để truy nhập tới toàn bộ dữ liệu data_frame dưới dạng bảng numpy 2 chiều, sử dụng cấu trúc:

data_frame.values

Cách truy nhập này cho tốc độ nhanh hơn so với cách truy nhập theo từng hàng hay từng cột khi phải xử lý trên nhiều hàng/cột dữ liệu

Ví dụ:

>>> table = DataFrame({

          'id' : [1, 2, 3],

          'price' : [50000, 100000, 80000],

          'quantity' : [10, 15, 12]

        })

>>> data = tables.values

>>> print(data)

[[     1  50000     10]

 [     2 100000     15]

 [     3  80000     12]]

Matplotlib

Matplotlib là thư viện cho phép vẽ các đồ thị.

Một số dạng đồ thị thông dụng

Đồ thị đường (line)

Đồ thị đường (line) thể hiện mối quan hệ giữa 2 đại lượng.

Ví dụ:

import matplotlib.pyplot as plt

X= list(range(-5, 6)))

Y= [x*x for x in X]

plt.plot(X,Y)

plt.show()

Đồ thị dạng đường (line) vẽ bằng matplotlib

Chọn màu và dạng đường vẽ

Để chọn màu vẽ và dạng đường , sử dụng tham số fmt của hàm plot. Tham số này có dạng string gồm 2 phần : Kí tự thứ nhất là màu :

Phần còn lại của fmt là dạng đường:

Ví dụ:

import matplotlib.pyplot as plt

X= list(range(-5, 6))

Y= [x*x for x in X]

plt.plot(X,Y, 'r--')

plt.show()

Chọn màu và dạng của đường vẽ

Vẽ nhiều đường trên một đồ thị:

Để vẽ nhiều đường trên một đồ thị là dùng nhiều lệnh plot liên tiếp nhau trước khi gọi một lênh show duy nhất.

Ví dụ:

import matplotlib.pyplot as plt

X = list(range(-5,        6))

Y1 = [5*abs(x) for x in X]

Y2 = [x*x for x in X]

plt.plot(X, Y1, 'b')

plt.plot(X, Y2, 'r--')

plt.show()

Vẽ nhiều đường trên một đồ thị

Thêm chú thích cho đồ thị:

Các lệnh chú thích:

Ví dụ:

import matplotlib.pyplot as plt

X = list(range(-5,        6))

Y1 = [5*abs(x) for x in X]

Y2 = [x*x for x in X]

plt.plot(X, Y1, 'b', label='Y1')

plt.plot(X, Y2, 'r--', label='Y2')

plt.xlabel('X variable')

plt.ylabel('Y variable')

plt.legend(loc='upper center')

plt.show()

Thêm chú thích cho đồ thị

Các thuật toán cơ bản trong Machine Learning

Linear regression

Linear regression là thuật toán dùng để xấp xỉ đầu ra một hệ thống /đối tượng theo một tổ hợp tuyến tính của các đầu vào:

 

Y ≈ A.X + B

Ví dụ 1: 

Dân số thế giới qua các năm https://en.wikipedia.org/wiki/World_population_estimates

Year

2000

2001

2002

2003

2004

2005

2006

2007

2008

2009

2010

Population (billion)

6.067

6.137

6.215

6.314

6.396

6.477

6.555

6.625

6.705

6.810

6.892

Nếu tốc độ tăng dân số thế giới không đổi theo từng năm thì quan hệ giữa dân số và năm sẽ có dạng một đường thẳng, hay:

Population = a. Year + b

Nếu tìm được các hệ số a, b, có thể dùng công thức trên để dự đoán dân số ở các năm tiếp theo. Thông thường, các hệ số a, b được xác định bằng phương pháp bình phương tối thiểu, tức tìm a,b sao cho tổng bình phương các sai số giữa mô hình và dữ liệu thực tế là nhỏ nhất:

 

trong đó

Sai số giữa mô hình và dữ liệu thực tế

Có nhiều phương pháp để tìm các giá trị tối ưu cho các hệ số của mô hình nhằm làm tối thiểu hóa sai số giữa mô hình và dữ liệu thực tế, trong đó các phương pháp thường sử dụng là:

Python có nhiều thư viện cho phép xác định hệ số tối ưu cho mô hình, trong đó scikit-learn được sử dụng phổ biến nhất.

Chương trình sau đây sử dụng scikit-learn để xây dựng mô hình Linear Regression cho dân số thế giới qua các năm:

from sklearn import linear_model

years = [2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010]

populations = [ 6.067e9, 6.137e9, 6.215e9, 6.314e9, 6.396e9, 6.477e9,

                6.555e9, 6.625e9, 6.705e9, 6.81e9, 6.892e9]

X = [[x] for x in years]

Y = populations

model = linear_model.LinearRegression()

model.fit(X, Y)

a= model.coef_[0]

b= model.intercept_

print(f'a={a}, b={b}')

print('2011 population : ', round(model.predict([[2011]])[0]))

print('2012 population : ', round(model.predict([[2012]])[0]))

Chương trình cho dự đoán dân số thế giới năm 2011, 2012 là 6966709091 và 7049145455. So với dữ liệu thực , sai số là 0.44 %

Để chi tiết hơn, có thể dùng matplotlib để vẽ đồ thị so sánh giữa mô hình & dữ liệu thực:

import matplotlib.pyplot as plt

from sklearn import linear_model

years = [2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010]

populations = [ 6.067e9, 6.137e9, 6.215e9, 6.314e9, 6.396e9, 6.477e9,

                6.555e9, 6.625e9, 6.705e9, 6.81e9, 6.892e9]

X = [[x] for x in years]

Y = populations

model = linear_model.LinearRegression()

model.fit(X, Y)

Y_predict = model.predict(X)

plt.plot(X, Y, '.', label='real')

plt.plot(X, Y_predict, '-', label='prediction')

plt.xlabel('years')

plt.ylabel('populations')

plt.legend(loc='upper left')

plt.show()

Kết quả giữa mô hình và dữ liệu thật - dân số thế giới

Ví dụ 2:

Xây dựng mô hình để ước tính lượng mỡ máu theo tuổi và cân nặng dựa vào bảng dữ liệu sau:

Weight (kilograms)

Age (Years)

Blood fat content (mg/l)

84

46

354

73

20

190

65

52

405

70

30

263

76

57

451

69

25

302

63

28

288

72

36

385

79

57

402

75

44

365

27

24

209

89

31

290

65

52

346

57

23

254

59

60

395

69

48

434

60

34

220

79

51

374

75

50

308

82

34

220

59

46

311

67

23

181

85

37

274

55

40

303

63

30

244

Đặt X1 : tuổi, X2 : cân nặng, Y :  lượng mỡ máu. Cần xác định các hệ số a1, a2, b để:

Chương trình xây dựng mô hình sử dụng scikit-learn:

from sklearn import linear_model

data = [

    [84, 46, 354],

    [73, 20, 190],

    [65, 52, 405],

    [70, 30, 263],

    [76, 57, 451],

    [69, 25, 302],

    [63, 28, 288],

    [72, 36, 385],

    [79, 57, 402],

    [75, 44, 365],

    [27, 24, 209],

    [89, 31, 290],

    [65, 52, 346],

    [57, 23, 254],

    [59, 60, 395],

    [69, 48, 434],

    [60, 34, 220],

    [79, 51, 374],

    [75, 50, 308],

    [82, 34, 220],

    [59, 46, 311],

    [67, 23, 181],

    [85, 37, 274],

    [55, 40, 303],

    [63, 30, 244]

]

N = len(data)

Ntrain = int(0.7*N)

data_train = data[:Ntrain]

data_test = data[Ntrain:]

Xtrain = [item[:2] for item in data_train]

Ytrain = [item[-1] for item in data_train]

Xtest = [item[:2] for item in data_test]

Ytest = [item[-1] for item in data_test]

model = linear_model.LinearRegression()

model.fit(Xtrain, Ytrain)

Ypredict = model.predict(Xtest)

for i in range(len(Xtest)):

    print(f'y={Ytest[i]}, predict={round(Ypredict[i])}')

Kết quả chạy chương trình:

y=374, predict=396.0

y=308, predict=387.0

y=220, predict=316.0

y=311, predict=351.0

y=181, predict=246.0

y=274, predict=333.0

y=303, predict=317.0

y=244, predict=276.0

Ở chương trình trên, chúng ta chia tập dữ liệu gốc (data) thành 2 tập :

Lí do của việc chia dữ liệu thành các tập training & test là để có thể đánh giá độ chính xác của mô hình một cách khách quan. Việc phân chia dữ liệu này là nguyên tắc cơ bản trong các bài toán xây dựng mô hình sử dụng Machine learning.

Logistic regression:

Logistic regression là thuật toán dùng để dự đoán một sự kiện có xảy ra hay không và xác suất xảy ra sự kiện là bao nhiêu.

 

Đầu vào của mô hình có thể có một hoặc nhiều biến số (tương tự Linear regression), đầu ra của mô hình là một giá trị nằm trong đoạn [0,1] thể hiện xác suất sẽ xảy ra sự kiện cần dự đoán.

Cấu trúc của mô hình Logistic Regression:

Mô hình Logistic Regression được xây dựng bằng cách ghép mô hình Linear Regression với hàm logistic:

Cấu trúc của mô hình logistic regression

Công thức toán học của hàm logistic:

Ý nghĩa của hàm logistic là tạo ra giá trị trong đoạn [0,1] ở đầu ra, do giá trị này thể hiện xác suất một sự kiện có thể xảy ra hay không.

Mối quan hệ giữa đầu ra và đầu vào của mô hình Logistic Regression:

Ví dụ 1:

Ước tính khả năng qua bài thi cuối kì theo thời gian học ôn thi của sinh viên. Nguồn : Wikipedia

Số giờ học

0.5

0.75

1

1.25

1.5

1.75

2

2.25

2.5

2.75

3

3.25

3.5

3.75

4

4.25

4.5

4.75

5

5.5

Qua kì thi

0

0

0

0

0

1

0

1

0

1

0

1

0

1

1

1

1

1

1

1

Nếu x là số giờ học và p là khả năng qua kì thi cuối kì của sinh viên thì mối quan hệ giữa x và p thể hiện qua mô hình logistic regression sẽ có dạng:

Tương tự như trong Linear regression, các hệ số a, b được lựa chọn sao cho sai số giữa mô hình và dữ liệu thật là nhỏ nhất. Việc này được thực hiện nhờ các thư viện tối ưu sử dụng các phương pháp số.

Chương trình xây dựng mô hình Logistic Regression sử dụng thư viện scikit-learn:

from sklearn.linear_model import LogisticRegression

data = [

    (0.50, 0),

    (0.75, 0),

    (1.00, 0),

    (1.25, 0),

    (1.50, 0),

    (1.75, 0),

    (1.75, 1),

    (2.00, 0),

    (2.25, 1),

    (2.50, 0),

    (2.75, 1),

    (3.00, 0),

    (3.25, 1),

    (3.50, 0),

    (4.00, 1),

    (4.25, 1),

    (4.50, 1),

    (4.75, 1),

    (5.00, 1),

    (5.50, 1)

]

n = len(data)

X = [[item[0]] for item in data]

Y = [item[1] for item in data]

model = LogisticRegression()

model.fit(X, Y)

print('a = ', model.coef_)

print('b = ', model.intercept_)

score = model.score(X, Y)

print('score = ', score)

P = model.predict_proba(X)

print('x\t y\t Prob\t Predict')

for i in range(0,n):

    x, y, p = X[i][0], Y[i], P[i][1]

    print(f'{x}\t {round(y,2)}\t {round(p,2)}\t {round(p)}')

Kết quả chạy chương trình:

score =  0.8

x        y       Prob    Predict

0.5      0       0.26    0.0

0.75     0       0.29    0.0

1.0      0       0.32    0.0

1.25     0       0.35    0.0

1.5      0       0.39    0.0

1.75     0       0.43    0.0

1.75     1       0.43    0.0

2.0      0       0.46    0.0

2.25     1       0.5     1.0

2.5      0       0.54    1.0

2.75     1       0.58    1.0

3.0      0       0.61    1.0

3.25     1       0.65    1.0

3.5      0       0.68    1.0

4.0      1       0.75    1.0

4.25     1       0.77    1.0

4.5      1       0.8     1.0

4.75     1       0.82    1.0

5.0      1       0.84    1.0

5.5      1       0.88    1.0

Giá trị score phản ánh độ chính xác của mô hình, được đo bằng tỉ lệ mẫu dự đoán đúng trên tổng số mẫu của tập dữ liệu kiểm tra.

Ví dụ 2:

Dự đoán kết quả nộp hồ sơ cao học tại trường đại học UCLA.

Các sinh viên sau khi tốt nghiệp đại học có thể nộp hồ sơ để xin học tiếp chương trình cao học. Trong thông tin hồ sơ của một sinh viên, có các trường dữ liệu sau:

Ví dụ về một số bộ dữ liệu trong hồ sơ của các sinh viên như sau:

gre

gpa

rank

380

3.61

3

660

3.67

3

800

4.00

1

640

3.19

4

520

2.93

4

760

3.00

2

Dữ liệu đầy đủ có thể download từ file binary.csv

Yêu cầu xây dựng mô hình để dự đoán khả năng một sinh viên có thể được nhận vào chương trình cao học hay không căn cứ các thông tin đã có trong hồ sơ.

Đầu vào của mô hình : gre, gpa, rank

Đầu ra của mô hình : khả năng sinh viên được nhận vào chương trình cao học

Chương trình xây dựng & kiểm chứng mô hình sử dụng scikit-learn:

from sklearn.linear_model import LogisticRegression

import pandas as pd

df = pd.read_csv('binary.csv')

X = df[['gre','gpa', 'rank']].values

Y = df['admit'].values

N = len(X)

Ntrain = int(0.7 * N)

Xtrain = X[:Ntrain]

Ytrain = Y[:Ntrain]

Xtest = X[Ntrain:]

Ytest = Y[Ntrain:]

model = LogisticRegression()

model.fit(Xtrain, Ytrain)

Yval = model.predict(Xtest)

print('score = ', model.score(Xtest, Ytest))

Kết quả chạy chương trình:

score =  0.7

Như vậy tỉ lệ dự đoán đúng khả năng sinh viên có được nhận vào chương trình cao học dựa trên gre,gpa, rank là 70%, tỉ lệ này là không cao.

Ví dụ 3:

Dự đoán khả năng mua hàng của khách hàng. Nguồn : LogisticRegressionAnalysis.com

Một tạp chí cần dự đoán khả năng một khách hàng với các thông tin nhân khẩu biết trước sẽ mua ấn bản của tạp chí hay không.

Thông tin về khách hàng mà tạp chí đã thu thập được gồm các trường sau:

Dữ liệu đầy đủ có thể tải về từ KidCreative.csv

Cần xây dựng mô hình Logistic Regression để dự đoán khả năng một khách hàng sẽ mua ấn phẩm của tạp chí dựa trên các thông tin nhân khẩu.

Tương tự ví dụ 2, chúng ta sử dụng scikit-learn để xây dựng mô hình dự đoán như sau:

import pandas as pd

from sklearn.linear_model import LogisticRegression

df = pd.read_csv('KidCreative.csv')

values = df.values

Y = values[:, 1]

X = values[:, 2:]

N = len(X)

Ntrain = int(0.7 * N)

Xtrain = X[:Ntrain]

Ytrain = Y[:Ntrain]

Xtest = X[Ntrain:]

Ytest = Y[Ntrain:]

model = LogisticRegression()

model.fit(Xtrain, Ytrain)

print('score = ', model.score(Xtest, Ytest))

Kết quả chạy chương trình:

score =  0.88

Như vậy tỉ lệ dự đoán đúng khả năng khách hàng mua sản phẩm là 88%, đây là tỉ lệ tương đối cao trong các bài toán về dự đoán.

Decision tree

Decision tree là phương pháp ra quyết định theo các nhánh của một cây quyết định

Một ví dụ về Decision Tree

Ví dụ:

Xây dựng cây quyết định để cho biết có nên ra ngoài chơi thể thao không tùy theo điều kiện thời tiết Nguồn : Decision Trees for Classification: A Machine Learning Algorithm

Day

Outlook

Temperature

Humidity

Wind

Play Golf

1

Sunny

Hot

High

Weak

No

2

Sunny

Hot

High

Strong

No

3

Overcast

Hot

High

Weak

Yes

4

Rain

Mild

High

Weak

Yes

5

Rain

Cool

Normal

Weak

Yes

6

Rain

Cool

Normal

Strong

No

7

Overcast

Cool

Normal

Strong

Yes

8

Sunny

Mild

High

Weak

No

9

Sunny

Cool

Normal

Weak

Yes

10

Rain

Mild

Normal

Weak

Yes

11

Sunny

Mild

Normal

Strong

Yes

12

Overcast

Mild

High

Strong

Yes

13

Overcast

Hot

Normal

Weak

Yes

14

Rain

Mild

High

Strong

No

Nguyên lý để xây dựng cây quyết định:

Nếu tập dữ liệu là giới hạn, về lí thuyết có thể tạo ra cây quyết định khớp hoàn toàn với tất cả các giá trị trong tập dữ liệu (cho độ dài của cây tăng lên cho đến khi khớp tất cả các mẫu). Tuy nhiên, nếu cây có độ dài lớn thì khi dự đoán kết quả của một mẫu dữ liệu không nằm trong tập huấn luyện, tỉ lệ sai sẽ khá lớn. Hiện tượng này gọi là overfitting có nghĩa độ khớp với tập huấn luyện rất cao nhưng khi dùng mô hình trong thực tế lại gặp sai số lớn.

 

Để tránh hiện tượng overfitting khi dựng cây quyết định từ một tập dữ liệu, thông thường độ dài tối đa của cây sẽ bị giới hạn.

Chương trình sau minh họa cách sử dụng scikit-learn để xây dựng mô hình cây quyết định cho bài toán chơi thể thao ở trên:

from sklearn.tree import DecisionTreeClassifier

data = [

    ('Sunny', 'Hot', 'High', 'Weak', False),

    ('Sunny', 'Hot', 'High', 'Strong', False),

    ('Overcast', 'Hot', 'High', 'Weak', True),

    ('Rain', 'Mild', 'High', 'Weak', True),

    ('Rain', 'Cool', 'Normal', 'Weak', True),

    ('Rain', 'Cool', 'Normal', 'Strong', False),

    ('Overcast', 'Cool', 'Normal', 'Strong', True),

    ('Sunny', 'Mild', 'High', 'Weak', False),

    ('Sunny', 'Cool', 'Normal', 'Weak', True),

    ('Rain', 'Mild', 'Normal', 'Weak', True),

    ('Sunny', 'Mild', 'Normal', 'Strong', True),

    ('Overcast', 'Mild', 'High', 'Strong', True),

    ('Overcast', 'Hot', 'Normal', 'Weak', True),

    ('Rain', 'Mild', 'High', 'Strong', False)    

]

weather_encodes =  {'Rain' : 0, 'Overcast' : 1, 'Sunny' : 2}

temperature_encodes = {'Cool' : 0, 'Mild' : 1, 'Hot' : 2}

humidity_encodes = {'Normal' : 0, 'High' : 1}

wind_encodes = {'Weak' : 0, 'Strong' : 1}

   

def encodeInput(x):

    weather, temperature, humidity, wind = x

    return [weather_encodes[weather],

            temperature_encodes[temperature],

            humidity_encodes[humidity],

            wind_encodes[wind]]

X = [encodeInput(item[:-1]) for item in data]

Y = [item[-1] for item in data]

model= DecisionTreeClassifier()

model.fit(X, Y)

def predict(weather, temperature, humidity, wind):

    return model.predict([encodeInput([

                weather, temperature, humidity, wind])])[0]

   

print(predict('Rain', 'Hot', 'High', 'Strong'))

print(predict('Sunny', 'Cool', 'Normal', 'Weak'))

K-nearest neighbour

Thuật toán K-nearest neighbour có thể được tóm tắt như sau:

Ví dụ:

Iris là một loài hoa với 3 chủng khác nhau : setosa, versicolor, virginica. Mỗi chủng có kích thước các phần của bông hoa khác nhau. File iris.csv chứa 150 mẫu giá trị kích thước các phần bông hoa của 3 chủng hoa trên.

sepal_length

sepal_width

petal_length

petal_width

species

5.1

3.5

1.4

0.2

setosa

4.9

3

1.4

0.2

setosa

4.7

3.2

1.3

0.2

setosa

4.6

3.1

1.5

0.2

setosa

5

3.6

1.4

0.2

setosa

5.4

3.9

1.7

0.4

setosa

4.6

3.4

1.4

0.3

setosa

5

3.4

1.5

0.2

setosa

4.4

2.9

1.4

0.2

setosa

4.9

3.1

1.5

0.1

setosa

5.4

3.7

1.5

0.2

setosa

4.8

3.4

1.6

0.2

setosa

4.8

3

1.4

0.1

setosa

Một số mẫu dữ liệu trong file iris.csv

Sử dụng thuật toán k-nearest neighbour với k = 3 để dự đoán chủng hoa dựa trên các kích thước của bông hoa.

Chương trình k-nearest neighbour không sử dụng scikit-learn:

import numpy as np

import pandas as pd

df = pd.read_csv('iris.csv')

values = df.values

X = np.array(values[:, :-1], dtype=np.float)

Y = values[:, -1]

Xtrain = np.concatenate((X[:35], X[50:85], X[100:135]))

Ytrain = np.concatenate((Y[:35], Y[50:85], Y[100:135]))

Xtest = np.concatenate((X[35:50], X[85:100], X[135:]))

Ytest = np.concatenate((Y[35:50], Y[85:100], Y[135:]))

Ntrain = len(Xtrain)

Ntest = len(Xtest)

K = 3

def predict(x):

    distances = [(np.sum((x-Xtrain[i])*(x-Xtrain[i])), i) for i in range(Ntrain)]

    distances = sorted(distances)

        

    y_samples = [Ytrain[distances[i][1]] for i in range(K)]

    map_counts = {}

   

    for species in y_samples:

        map_counts[species] = map_counts.get(species,0) + 1

     

    items = sorted(map_counts.items(), key=lambda x : x[1])

           

    return items[-1][0]

Ypredict = [predict(Xtest[i]) for i in range(Ntest)]

Ncorrect = len([i for i in range(Ntest) if Ypredict[i] == Ytest[i]])

print('test score = ', Ncorrect/Ntest)

Chương trình k-nearest neighbour sử dụng scikit-learn:

import numpy as np import pandas as pd

from sklearn.neighbors import KNeighborsClassifier

df = pd.read_csv('iris.csv')

values = df.values

X= np.array(values[:, :-1], dtype=np.float)

Y= values[:, -1]

Xtrain = np.concatenate((X[:35], X[50:85], X[100:135]))

Ytrain = np.concatenate((Y[:35], Y[50:85], Y[100:135]))

Xtest = np.concatenate((X[35:50], X[85:100], X[135:]))

Ytest = np.concatenate((Y[35:50], Y[85:100], Y[135:]))

Ntrain = len(Xtrain)

Ntest = len(Xtest)

model = KNeighborsClassifier(n_neighbors=3)

model.fit(Xtrain, Ytrain)

score = model.score(Xtest, Ytest)

print('test score = ', score)

Support vector machine (SVM)

Support Vector Machine (SVM) là thuật toán phân loại 2 nhóm đối tượng bằng cách tìm một đường thẳng (mặt phẳng) để phân chia không gian thuộc tính thành 2 nửa sao cho các mẫu của 2 nhóm nằm ở 2 phía của đường thẳng và khoảng cách từ các điểm thuộc tính đến đường thẳng phân chia là lớn nhất.

 

SVM có thể không dùng đường thẳng phân chia mà dùng một số dạng đường cong (kernel) để phân chia 2 nhóm. Trong phần này, chúng ta chỉ quan tâm đến dạng phân chia sử dụng đường thẳng.

Ảnh minh họa cách SVM phân chia không gian thuộc tính.

 

Trong trường hợp các điểm thuộc tính của 2 nhóm không phân tách được ra khỏi nhau và không tồn tại đường thẳng phân chia để toàn bộ mỗi nhóm ở một phía của đường thẳng, SVM sẽ tìm đường thẳng để sai số phân loại là nhỏ nhất.

Ví dụ:

Xây dựng mô hình SVM cho bài toán Iris. Chương trình sử dụng scikit-learn để xây dựng mô hình SVM như sau:

import numpy as np

import pandas as pd

from sklearn import svm

def get_class(species):

    return {

        'setosa': 0,

        'versicolor': 1,

        'virginica': 2 }[species]

df = pd.read_csv('iris.csv')

values = df.values

X= np.array(values[:, :-1], dtype=np.float)

Y= [get_class(species) for species in values[:, -1]]

Xtrain = np.concatenate((X[:35], X[50:85], X[100:135]))

Ytrain = Y[:35] + Y[50:85] + Y[100:135]

Xtest = np.concatenate((X[35:50], X[85:100], X[135:]))

Ytest = Y[35:50] + Y[85:100] + Y[135:]

model = svm.SVC(kernel='linear')

model.fit(Xtrain, Ytrain)

print('score = ', model.score(Xtest, Ytest))

Neural network

Neural network là hệ thống xử lý thông tin gồm nhiều lớp (layer), kết quả xử lý của lớp trước là đầu vào của lớp sau.

Cấu trúc của Neural Network

Một neural network bao gồm nhiều lớp (layer), mỗi lớp bao gồm nhiều phần tử (neuron). Mỗi neuron có cấu trúc như sau:

        

Cấu trúc của một neuron

Các thành phần của một neuron:

Mối quan hệ giữa đầu vào và đầu ra của một neuron:

 

Hàm kích hoạt (activation function) σ thường có một số dạng:

Khi đó neuron trở thành mô hình linear regression

Khi đó neuron trở thành logistic regression

Hàm có giá trị bằng x nếu x > 0 và bằng 0 nếu ngược lại. Hàm này thường được sử dụng trong các mô hình hồi quy (regression)

Huấn luyện mạng neuron:

Quá trình huấn luyện mạng neuron là quá trình đi tìm các tham số trong mạng (wij, bi) sao cho sai số giữa đầu ra của mạng và đầu ra của dữ liệu thực nhỏ nhất. Quá trình này giống như việc đi tìm các hệ số cho các mô hình Linear regression, Logistic regression :

        

Tìm  để

  

trong đó

,

 là hàm mô tả mối quan hệ giữa đầu vào và đầu ra của mạng neuron.

Phương pháp sử dụng trong huấn luyện mạng neuron thường sử dụng là Gradient Descent (đã giới thiệu trong Linear Regression)

Ví dụ 1:

Sử dụng mạng neuron để phân loại 3 chủng hoa iris.

import numpy as np

import pandas as pd

from sklearn.neural_network import MLPClassifier

def get_class(species):

    return {

    'setosa': [1, 0, 0],

    'versicolor': [0, 1, 0],

    'virginica': [0, 0, 1]

    }[species]

   

df = pd.read_csv('data/iris.csv')

values = df.values

X = np.array(values[:, :-1], dtype=np.float)

Y = np.array([get_class(species) for species in values[:, -1]])

Xtrain = np.concatenate((X[:35], X[50:85], X[100:135]))

Ytrain = np.concatenate((Y[:35], Y[50:85], Y[100:135]))

Xtest = np.concatenate((X[35:50], X[85:100], X[135:]))

Ytest = np.concatenate((Y[35:50], Y[85:100], Y[135:]))

model = MLPClassifier(hidden_layer_sizes=(5,), activation='tanh',

                            max_iter=10000, tol=1e-7, verbose=True)

model.fit(Xtrain, Ytrain)

score = model.score(Xtest, Ytest)

print('test score = ', score)

Để sử dụng mạng neuron cho bài toán phân loại đối tượng, có thể sử dụng MLPClassifier của thư viện scikit-learn với các tham số khởi tạo :

Ngoài ra hàm còn các tham số khác, có thể tham khảo theo tài liệu của scikit-learn

Ví dụ 2:

Lượng năng lượng thế giới tiêu thụ qua các năm từ 1990 đến 2007 :

        

1990

1991

1992

1993

1994

1995

1996

1997

1998

8761

8818

8830

8923

8993

9215

9447

9540

9593

1999

2000

2001

2002

2003

2004

2005

2006

2007

9789

10016

10114

10330

10688

11171

11489

11835

12152

Đơn vị năng lượng tiêu thụ là MTOE (million tons of oil equivalent). Nguồn dữ liệu : Enerdata

Xây dựng mạng neural để đưa ra dự đoán năng lượng tiêu thụ của thế giới trong mỗi năm dựa trên năng lượng của các năm trước

from sklearn.neural_network import MLPRegressor

from sklearn.preprocessing import MinMaxScaler

import matplotlib.pyplot as plt

years = list(range(1990, 2008))

energies = [8761, 8818, 8830, 8923, 8993, 9215, 9447, 9540, 9593, 9789,

10016, 10114, 10330, 10688, 11171, 11489, 11835, 12152 ]

X = [[x] for x in years]

Y = [y/1000 for y in energies]

Xtrain = X[:-2]

Ytrain = Y[:-2]

Xtest = X[-2:]

Ytest = Y[-2:]

scaler = MinMaxScaler()

scaler.fit(Xtrain)

Xtrain = scaler.transform(Xtrain)

Xtest = scaler.transform(Xtest)

model = MLPRegressor(50, max_iter=10000, tol=-1, verbose=True)

model.fit(Xtrain, Ytrain)

Ypredict = model.predict(Xtest)

for i in range(2):

    predict = round(1000 * Ypredict[i])

    err = round(100 * (predict - energies[-2+i])/energies[-2+i], 1)

    print(f'Year {years[-2+i]}, real : {energies[-2+i]},\

                    predict : {predict}, err(%) : {err}')

plt.plot(years, energies, '.', label='real')

plt.plot(years[:-2], 1000 * model.predict(Xtrain), label='validate')

plt.plot(years[-2:], 1000 * model.predict(Xtest), '.', label='predict')

plt.legend(loc='upper left')

plt.xlabel('Year')

plt.ylabel('World energy consumption (MTOE)')

plt.show()

Kết quả dự đoán của mô hình

Chương trình sử dụng MLPRegressor của thư viện scikit-learn để xây dựng mô hình dự đoán. Các tham số khởi tạo MLPRegressor  gần giống với tham số khởi tạo của MLPClassifier . Chi tiết tham khảo trong tài liệu của scikit-learn.

Ví dụ 3:

Nhận dạng chữ số viết tay với mạng neuron, sử dụng tập dữ liệu MNIST

Để xây dựng chương trình nhận dạng chữ viết tay, trước hết chúng ta cần download các file dữ liệu:

Sau khi download các file trên, thực hiện giải nén để tạo ra các file:

Để xử lý việc đọc/ghi các file ảnh, cần cài đặt thư viện opencv:

        

                pip install opencv-python

Trước hết cần chuyển các file dữ liệu đã download về sang dạng ảnh:

        

import cv2

import numpy as np

import os

output_dir = 'images'

def convertImages(set_type, tag, num_images_per_class):

    with open(f'{tag}-images.idx3-ubyte', 'rb') as f:

        img_data = f.read()

       

    with open(f'{tag}-labels.idx1-ubyte', 'rb') as f:

        label_data = f.read()

        label_data = label_data[8:]

       

    counts = {}

    for i, digit in enumerate(label_data):

        if counts.get(digit, 0) >= num_images_per_class:

            continue

           

        dir = os.path.join(output_dir, set_type, str(digit))

        if not os.path.exists(dir):

            os.makedirs(dir)

           

        img = img_data[16+i*784:16+(i+1)*784]

        img = np.frombuffer(img, dtype=np.uint8).reshape((28,28))

        counts[digit] = counts.get(digit, 0) + 1

       

        fn = f'{counts[digit]}.png'

        cv2.imwrite(os.path.join(dir, fn), img)

       

convertImages('train', 'train', 1000)

convertImages('test', 't10k', 200)

Sau khi chạy chương trình chuyển đổi trên, các file ảnh sẽ được tạo ra trong thư mục images theo cấu trúc sau:

│   convert_data.py

│   t10k-images.idx3-ubyte

│   t10k-labels.idx1-ubyte

│   train-images.idx3-ubyte

│   train-labels.idx1-ubyte

└───images

    ├───test

    │   ├───0

    │   ├───1

    │   ├───...

    │   └───9

    └───train

        ├───0

        ├───1

        ├───...

        └───9

Mỗi tập dữ liệu train/test có 10 thư mục con (từ 0 đến 9), trong mỗi thư mục con là các ảnh của chữ số ứng với tên thư mục con đó.

Đọc thử ảnh và hiển thị với opencv:

        

import cv2

img = cv2.imread('images/train/0/1.png', cv2.IMREAD_GRAYSCALE)

cv2.imshow("Image", img)

cv2.waitKey()

Đọc ảnh và hiển thị trên cửa sổ của opencv

        

Mỗi ảnh chữ số có kích thước 28x28 và là ảnh đen trắng. Ảnh này được opencv mã hóa dưới dạng mảng numpy kích thước 28x28, mỗi giá trị trong mảng có kiểu dữ liệu uint8 (0-255), tương ứng với độ sáng của một pixel trên ảnh.

Xây dựng mạng neuron và huấn luyện mạng:

Mỗi file ảnh chữ số được mã hóa dưới dạng mảng numpy với kích thước 28x28. Chúng ta chuyển mảng này thành một vector có độ dài 784 để làm đầu vào cho mạng neuron.

Chương trình xây dựng và huấn luyện mạng neuron như sau:

        

import cv2

import os

from sklearn.neural_network import MLPClassifier

from sklearn.externals import joblib

IMG_DIR = 'images'

def read_data(set_type):

    X = []

    y = []

   

    for digit in range(10):

        dir = os.path.join(IMG_DIR, set_type, str(digit))        

        for f in os.listdir(dir):

            file_name = os.path.join(dir, f)

            img = cv2.imread(file_name, cv2.IMREAD_GRAYSCALE)

            x = img/255.0

            X.append(x.reshape(-1))

            y.append(digit)

           

    return X,y

print('Reading data ...')

           

Xtrain, ytrain = read_data('train')

Xtest, ytest = read_data('test')

           

print('Training model ...')

model = MLPClassifier(hidden_layer_sizes=(50,), activation='relu',

                    max_iter=50, tol=-1, verbose=True)

           

model.fit(Xtrain, ytrain)

print('Test accuracy : ', model.score(Xtest, ytest))    

joblib.dump(model, 'mnist.model')

Kết quả chạy chương trình:

...

Iteration 48, loss = 0.02747844

Iteration 49, loss = 0.02652397

Iteration 50, loss = 0.02515414

Test accuracy :  0.9275

Sau khi huấn luyện xong mạng neuron, chương trình trên lưu kết quả mạng đã được huấn luyện vào file mnist.model. Chúng ta sử dụng file model này để nhận dạng các chữ số trong các file ảnh test. Chương trình test model đã huấn luyện như sau:

        

import cv2

import sys

from sklearn.externals import joblib

model = joblib.load('mnist.model')

input_file = 'images/test/0/1.png'

img = cv2.imread(input_file, cv2.IMREAD_GRAYSCALE)

img = cv2.resize(img , (28, 28))

x = img/255.0

x = x.reshape(-1)

print('Input file : ', input_file, ',predict:', model.predict([x])[0])

Ví dụ 4:

Sử dụng mạng neuron để phân loại tài liệu.

Nội dung tóm tắt các bài báo trên dantri.com.vn được lưu trong file dữ liệu data.zip. Mỗi bài báo thuộc 1 trong 3 chủ đề:

Cần xây dựng chương trình xác định chủ đề của nội dung (tóm tắt) một bài báo, sử dụng mạng neuron.

Trước hết, chúng ta cần download file dữ liệu data.zip và giải nén, để có các file dữ liệu theo cấu trúc dưới đây:

                data

    |---  kinhdoanh.txt

    |---  thethao.txt

    |---  vanhoa.txt

    |---  xahoi.txt

Để xử lý tiếng Việt, cần cài đặt thư viện pyvi. Thư viện này có tác dụng tách một câu tiếng Việt thành các từ riêng biệt:

        pip install pyvi

Ví dụ sau minh họa cách hoạt động của việc tách từ tiếng Việt:

        

from pyvi import ViTokenizer

sentence = 'HLV Park Hang Seo tạo ra sự cạnh tranh tích cực ở U22 Việt Nam'

tokens = ViTokenizer.tokenize(sentence).split()

print(tokens)

Chương trình in ra kết quả là các từ của câu được tách ra:

        

['HLV', 'Park', 'Hang_Seo', 'tạo', 'ra', 'sự', 'cạnh_tranh', 'tích_cực',

 'ở', 'U22', 'Việt_Nam']

        

Tiếng Việt (và một số ngôn ngữ châu Á) có hiện tượng khi tách một số từ ghép thành các từ đơn lẻ thì nghĩa của các từ đơn lẻ không liên quan đến từ ghép ban đầu. Việc tách câu thành từng từ đơn lẻ theo dấu trắng (' ') phân cách có thể làm mất một phần nghĩa của câu. Do đó cần có các thư viện tách từ (như pyvi) để tách câu thành các từ mà ý nghĩa không bị thay đổi so với ban đầu.

Tiếp theo, chúng ta xây dựng chương trình tokenizer.py như dưới đây để chuyển các bài báo thành các danh sách từ:

        

# tokenizer.py

import os

import json

from pyvi import ViTokenizer

import unicodedata

topics = ['xahoi' , 'kinhdoanh', 'thethao', 'vanhoa']

def normalize(s):

    s = unicodedata.normalize('NFD', s)

    lst = [c for c in s if 'A' <= c.upper() <= 'Z' or c == ' ']

    return ''.join(lst)

def tokenize(sentence):

    sentence = ViTokenizer.tokenize(sentence)

    tokens = []

    for word in sentence.split():        

        if word.replace('_', '').isalpha() and len(word) > 1:

            tokens.append(word.lower())

    return tokens

if __name__ == '__main__':

    docs = []

    for i, topic in enumerate(topics):

        print('Reading topic : ', topic)

        fn = os.path.join('data', topic + '.txt')

        f = open(fn, encoding='utf-8')

        lines = f.readlines()

        f.close()

        for line in lines[:5000]:

            words = set(tokenize(line))

            words = list(words)

            docs.append({'words' : words, 'sentence': line,

                            'category' : i})

           

    with open('docs.json','w') as f:

        json.dump(docs, f)      

Chương trình trên tạo ra file docs.json với 20000 tài liệu ( 5000 tài liệu cho mỗi chủ đề). Sau khi đã chuyển đổi dữ liệu xong, chúng ta xây dựng mô hình mạng neuron để phân loại các tài liệu theo chủ đề. Chương trình xây dựng và huấn luyện mạng như sau:

        import json

from sklearn.neural_network import MLPClassifier

from sklearn.externals import joblib

from random import shuffle

with open('docs.json') as f:

    docs = json.load(f)

shuffle(docs)

docs = docs[:5000]

word_count = {}

ignore_words = set()

for doc in docs:

    for word in doc['words']:

        word_count[word] = 1 + word_count.get(word, 0)

items = word_count.items()

items = [x for x in items if x[1] <= len(docs)/2]

items = sorted(items, key=lambda x : x[1], reverse=True)

wordlist = [x[0] for x in items[:5000]]

word_indexes = {word:i for (i,word) in enumerate(wordlist)}

with open('wordlist.txt', 'w', encoding='utf-8') as f:

    f.write('\n'.join(wordlist))    

def doc_to_vec(doc):

    vec = [0] * len(wordlist)

    for word in doc['words']:

        index = word_indexes.get(word, -1)

        if index >= 0:

            vec[index] = 1

    return vec

X = [doc_to_vec(doc) for doc in docs]

y = [doc['category'] for doc in docs]

Xtrain, ytrain = X[:4000], y[:4000]

Xtest, ytest = X[4000:5000], y[4000:5000]

model = MLPClassifier(hidden_layer_sizes=(10,), verbose=True)

model.fit(Xtrain, ytrain)

print('Accuracy : ', model.score(Xtest, ytest))

joblib.dump(model, 'model.bin')

Mô hình sau huấn luyện được lưu vào file model.bin. Chúng ta dùng model này để xác định chủ đề của các đoạn tóm tắt của các bài báo. Chương trình xác định chủ để theo nội dung như sau:

        from tokenizer import tokenize

from sklearn.externals import joblib

topics = ['Xã hội' , 'Kinh doanh', 'Thể thao', 'Văn hóa']

model = joblib.load('model.bin')

with open('wordlist.txt', encoding='utf-8') as f:

    wordlist = [line.strip() for line in f]

n_word = len(wordlist)

word_indexes = {word : i for (i, word) in enumerate(wordlist)}

text = '''Thực hiện thí điểm việc không tổ chức hội đồng nhân dân phường tại Hà Nội trong nhiệm kỳ 2021 – 2026, Chính phủ đề xuất bổ sung 2 thẩm quyền cho Chủ tịch UBND quận, một trong số đó là quyền cách chức người đứng đầu cơ quan hành chính cấp dưới.'''

   

tokens = tokenize(text)

x = [0] * n_word

for word in tokens:

    index = word_indexes.get(word, -1)

    if index >= 0:

        x[index] = 1

       

category = model.predict([x])[0]

print(topics[category])        

       

Chương trình sẽ phân tích nội dung văn bản đưa vào và in ra chủ đề (dự đoán) của văn bản đó.