-
Tuần 1 - Ngày 10 tháng 7 năm 2019
- Giới thiệu về khóa học
- Hướng dẫn viết chương trình Python trên web
- Hướng dẫn sử dụng PyCharm
- Tổng quan về Python
- Kỹ năng sử dụng Google search
- Viết tài liệu kỹ thuật dùng Markdown
- Hàm xây dựng sẵn trong Python – math và random
- Cài đặt các công thức toán cơ bản
- Xây dựng hàm trong python
- Điều kiện if-else
- Những lỗi thường gặp trong Python
- Reading assignment
-
Tuần 2 - Ngày 17 tháng 7 năm 2019
-
Tuần 3 - Ngày 24 tháng 7 năm 2019
-
Tuần 4 - Ngày 31 tháng 7 năm 2019
-
Tuần 5 - Ngày 7 tháng 8 năm 2019
-
Advanced Python
-
Tuần 6 - Ngày 14 tháng 8 năm 2019
-
Tuần 7 - Ngày 28 tháng 8 năm 2019
-
Tuần 8
-
Tuần 9
Áp dụng GA cho dự đoán doanh thu và giá nhà
Tiên đoán doanh thu bán hàng
Trong phần này, chúng ta sẽ dùng GA để dự đoán doanh thu bán hàng (sale) dựa vào các loại marketing khác nhau. Chúng ta sẽ sử dụng dataset advertising sau
https://www.kaggle.com/ashydv/advertising-dataset/downloads/advertising.csv/data
Các bạn có thể download data ở link sau
https://www.dropbox.com/s/ejes8s6x87dhfif/advertising.csv?dl=0
Bộ dữ liệu này bao gồm 200 mẫu, và mỗi mẫu gồm 3 đặc trưng gồm số tiền quảng cáo trên TV, trên radio, và trên newspaper. Giá trị sale (thực) được cung cấp cho mỗi mẫu. Hình sau hiển thị minh họa một số mẫu từ bộ dữ liệu advertising.
Chúng ta giả sử bộ dữ liệu này có dạng phân bố theo phương trình (1) như sau \(sale = c_1*TV + c_2*Radio + c_3*Newspaper + c_4\). Do đó, chúng ta sẽ dùng GA để tìm ra các giá trị tham số \(c_1\), \(c_2\), \(c_3\), và \(c_4\) tốt nhất cho bộ dữ liệu advertising.
Từ yêu cầu bài toán, chúng ta xác định được một số thông tin cho GA
– Chiều dài của chromosome là 4
– Gen có kiểu dữ liệu là floating-point
– Miền giá trị của các tham số \(c_i \ge 0\)
Để thuận tiện cho việc cài đặt, phương trình (1) có thể viết lại như sau \(sale = c_1*TV + c_2*Radio + c_3*Newspaper + c_4*1.0\). Chúng ta sẽ thêm giá trị 1.0 vào mỗi mẫu để số lượng đặc trưng là 4, bằng với số lượng tham số.
Code sau đọc dữ liệu lên và lưu các đặc trưng vào list features (mỗi phần tử gồm 4 đặc trưng: TV, Radio, Newspaper, và 1.0). List prices chứa giá trị sale cho từng mẫu.
Hàm load_data()
đọc dữ liệu từ file advertising.csv
, và đọc tất cả các dòng lên với kiểu string
. Các đặc trưng được tách ra và lưu vào biến list feature
; sau đó thêm giá trị 1.0 ở cuối list. Cuối cùng, list feature
và giá trị doanh thu được lưu vào biến features
và prices
.
Một việc quan trọng khi áp dụng GA vào một bài toán nào đó là việc viết hàm tính fitness cho chromosome. Như đã phân tích ở trên, chúng ta sẽ dựa vào phương trình (1) để tính doanh thu ước lượng. Sau đó so sánh với doanh thu thực tế để tính loss cho một dự đoán. Code cho hàm tính fitness như sau
Các phần code còn lại gần không thay đổi. Dưới đây là source code đầy đủ của chương trình
# aivietnam.ai - advertising import random n = 4 # size of individual (chromosome); 3 coefficients and 1 bias m = 200 # size of population n_generations = 2000 # number of generations losses = [] # để vẽ biểu đồ quá trình tối ưu # Hàm load data def load_data(): # kết nối với file file = open('advertising.csv','r') # readlines giúp việc đọc file theo từng dòng , mỗi dòng là 1 chuỗi lines = file.readlines() features = [] prices = [] for i in range(1, 201): strings = lines[i].split(',') feature = [float(s.strip()) for s in strings[:len(strings)-1]] feature.append(1.0) # for bias features.append(feature) prices.append(float(strings[-1])) # Đóng kết nối với file file.close() return features, prices # load data features, prices = load_data() def generate_random_value(bound = 100): return (random.random())*bound def compute_loss(individual): estimated_prices = [] for feature in features: estimated_price = sum(c*x for x, c in zip(feature, individual)) estimated_prices.append(estimated_price) losses = [abs(y_est-y_gt) for y_est, y_gt in zip(estimated_prices, prices)] return sum(losses) def compute_fitness(individual): loss = compute_loss(individual) fitness = 1 / (loss + 1) return fitness def create_individual(): return [generate_random_value() for _ in range(n)] def crossover(individual1, individual2, crossover_rate = 0.9): individual1_new = individual1.copy() individual2_new = individual2.copy() for i in range(n): if random.random() < crossover_rate: individual1_new[i] = individual2[i] individual2_new[i] = individual1[i] return individual1_new, individual2_new def mutate(individual, mutation_rate = 0.05): individual_m = individual.copy() for i in range(n): if random.random() < mutation_rate: individual_m[i] = generate_random_value() return individual_m def selection(sorted_old_population): index1 = random.randint(0, m-1) while True: index2 = random.randint(0, m-1) if (index2 != index1): break individual_s = sorted_old_population[index1] if index2 > index1: individual_s = sorted_old_population[index2] return individual_s def create_new_population(old_population, elitism=2, gen=1): sorted_population = sorted(old_population, key=compute_fitness) if gen%1 == 0: losses.append(compute_loss(sorted_population[m-1])) #print("Best loss:", compute_loss(sorted_population[m-1])) new_population = [] while len(new_population) < m-elitism: # selection individual_s1 = selection(sorted_population) individual_s2 = selection(sorted_population) # duplication # crossover individual_c1, individual_c2 = crossover(individual_s1, individual_s2) # mutation individual_m1 = mutate(individual_c1) individual_m2 = mutate(individual_c2) new_population.append(individual_m1) new_population.append(individual_m2) for ind in sorted_population[m-elitism:]: new_population.append(ind.copy()) return new_population population = [create_individual() for _ in range(m)] for i in range(n_generations): population = create_new_population(population, 2, i)
Sau khi chạy chương trình trên để GA tối ưu hóa các tham số \(c_i\). Chúng ta cần hiển thị các giá trị loss để kiểm tra xem quá trình tối ưu hóa. Hình sau hiển thị giá trị loss cho 200 generation đầu tiên.
Source để hiển thị biểu đồ loss ở trên.
Để kiểm tra một cách trực quan độ chính xác của chương trình. Chúng ta sẽ hiển thị các giá trị sale tiên đoán (màu blue) bởi chương trình và giá trị sale thực (màu green) như sau
Source để hiển thị biểu đồ trên.
Tiên đoán giá nhà dùng bộ dữ liệu Boston House Price
Bộ dữ liệu Boston có 506 dòng và 14 cột, trong đó cột cuối cùng medv
chứa giá trị giá nhà (thực). Các cột được trình bày ở bảng sau.
Bài toán yêu cầu dựa vào dữ liệu trên để viết chương trình tiên đoán giá nhà (cho những data mới, không bao gồm ở trên). Các bạn có thể download file dữ liệu ở link sau
https://www.dropbox.com/s/yyqlzj2yqum45re/Boston_Dataset.csv?dl=0
Hình sau hiển thị một số dòng từ file dữ liệu Boston_Dataset.csv
.
Chúng ta thấy cột đầu tiên ID
không quan trọng và chúng ta cần loại bỏ khi xử lý dữ liệu. Còn lại, dữ liệu có 13 đặc trưng và một cột label (giá nhà thực). Chúng ta giả định dữ liệu phân bố theo phương trình sau
$$price = \sum_{i=1}^{14} c_i*f_i$$
trong đó \(c_i\) là các tham số cần tìm và \(f_i\) bao gồm 13 đặc trưng theo thứ tự xuất hiện theo cột dữ liệu, và \(f_{14} = 1.0\).
Từ công thức trên, chúng ta xác định được chiều dài của chromosome là 14 và có kiểu floating-point; cũng như biết được cách thức tính fitness cho mỗi chromosome.
Dưới đây là code cho chương trình
# aivietnam.ai - estimation of Boston house prices import random # size of individual (chromosome); 13 coefficients and 1 bias n = 14 m = 600 # size of population n_generations = 4000 # number of generations losses = [] # để vẽ biểu đồ quá trình tối ưu # Hàm load data def load_data(): # kết nối với file file = open('Boston_Dataset.csv','r') # readlines giúp việc đọc file theo từng dòng , mỗi dòng là 1 chuỗi lines = file.readlines() print(len(lines)) features = [] prices = [] for i in range(1, 334): strings = lines[i].split(',') feature = [float(s.strip()) for s in strings[1:len(strings)-1]] feature.append(1.0) # for bias features.append(feature) prices.append(float(strings[-1])) # Đóng kết nối với file file.close() return features, prices # load data features, prices = load_data() def generate_random_value(bound = 100): return (random.random())*bound def compute_loss(individual): estimated_prices = [] for feature in features: estimated_price = sum(c*x for x, c in zip(feature, individual)) estimated_prices.append(estimated_price) losses = [abs(y_est-y_gt) for y_est, y_gt in zip(estimated_prices, prices)] return sum(losses) def compute_fitness(individual): loss = compute_loss(individual) fitness = 1 / (loss + 1) return fitness def create_individual(): return [generate_random_value() for _ in range(n)] def crossover(individual1, individual2, crossover_rate = 0.9): individual1_new = individual1.copy() individual2_new = individual2.copy() for i in range(n): if random.random() < crossover_rate: individual1_new[i] = individual2[i] individual2_new[i] = individual1[i] return individual1_new, individual2_new def mutate(individual, mutation_rate = 0.05): individual_m = individual.copy() for i in range(n): if random.random() < mutation_rate: individual_m[i] = generate_random_value() return individual_m def selection(sorted_old_population): index1 = random.randint(0, m-1) while True: index2 = random.randint(0, m-1) if (index2 != index1): break individual_s = sorted_old_population[index1] if index2 > index1: individual_s = sorted_old_population[index2] return individual_s def create_new_population(old_population, elitism=2, gen=1): sorted_population = sorted(old_population, key=compute_fitness) if gen%50 == 0: losses.append(compute_loss(sorted_population[m-1])) print("Best loss:", compute_loss(sorted_population[m-1])) #print(sorted_population[m-1]) new_population = [] while len(new_population) < m-elitism: # selection individual_s1 = selection(sorted_population) individual_s2 = selection(sorted_population) # duplication # crossover individual_c1, individual_c2 = crossover(individual_s1, individual_s2) # mutation individual_m1 = mutate(individual_c1) individual_m2 = mutate(individual_c2) new_population.append(individual_m1) new_population.append(individual_m2) for ind in sorted_population[m-elitism:]: new_population.append(ind.copy()) return new_population population = [create_individual() for _ in range(m)] for i in range(n_generations): population = create_new_population(population, 2, i)
Hình sau hiển thị giá trị loss cho 200 generation đầu tiên.
Hình sau hiển thị các giá trị sale dự đoán và sale thực
Chúng ta có thể quan sát thấy kết quả không tốt như bài advertising. Có một số cách để nâng cao kết quả
1) Tăng population size
2) Tăng generation
3) Dùng thuật toán mạnh hơn GA như Artificial Bee Colony, hay LSHADE