Ý tưởng nảy nở khi mình đang xem thời sự về dân số Việt Nam: Theo thống kê năm 2017 Việt Nam có 95.54 triệu người, vậy liệu tương lai mấy năm tới sẽ thế nào nhỉ?

Thế là bắt đầu lục lọi trên Internet và tìm thấy dữ liệu của World Bank Group thống kê rất nhiều chỉ số như GDP, kinh tế, mặt bằng dân số,.. của tất cả các nước từ năm 1960 trở lại đây. Mình nhặt ra hai chỉ số là GDP theo đầu người và tuổi thọ trung bình (life expectancy) vì mình nghĩ chúng sẽ ảnh hưởng đến dân số, suy luận theo trực giác thôi. Ok, vậy là có data rồi, thử ứng dụng Machine Learning vào bài toán dự đoán dân số xem sao.

Chuẩn bị dữ liệu

Đầu tiên đương nhiên là lấy dữ liệu về rồi, mình có bốn files tải về từ website của World Bank Group về tổng dân số nam, nữ, GDP và tuổi thọ trung bình.

import pandas as pd
from matplotlib import pyplot as plt
# GDP per capita
gdp = pd.read_csv('GDP/GDP.csv', header=2)
# Female population
popfe = pd.read_csv('POP.FE/POP.FE.csv', header=2)
# Male population
popma = pd.read_csv('POP.MA/POP.MA.csv', header=2)
# Life expectancy
le = pd.read_csv('LE/LE.csv', header=2)

Mẫu ví dụ về dữ liệu GDP

gdp.head()
GDP

Như trên thì có thể thấy dữ liệu bao gồm GDP theo đầu người của nhiều nước từ 1960 (kết thúc là 2017). Câu trúc tương tự có thể thấy trên các tập dữ liệu còn lại về dân số và tuổi thọ trung bình.

Bước tiếp theo là tổng hợp tất cả lại vào một tập dữ liệu cho gọn. Mình phác thảo các cột cho tập dữ liệu mới là:

  • country
  • countryCode
  • year
  • lifeExpectancy
  • populationFemale
  • populationMale
  • gdpPerCapita
# Initialize dataframe with pre-defined columns
data = pd.DataFrame(columns=['country', 'countryCode', 'year', 'lifeExpectancy', 'population', 'populationFemale', 'populationMale', 'gdpPerCapita'])

countries = gdp['Country Name'].values
countriesCode = gdp['Country Code'].values
years = gdp.columns[4:-1].values
       
for index, country in enumerate(countries):
    for year in years:
        gdpValue = gdp[gdp['Country Name'] == country][year].values[0]
        popfeValue = popfe[popfe['Country Name'] == country][year].values[0]
        popmaValue = popma[popma['Country Name'] == country][year].values[0]
        population = popfeValue + popmaValue
        leValue  = le[le['Country Name'] == country][year].values[0]
        data = data.append({'country': country, 'countryCode': countriesCode[index], 
                        'year': int(year), 'lifeExpectancy': leValue, 'population':population, 
                        'populationFemale':popfeValue, 'populationMale':popmaValue, 'gdpPerCapita':gdpValue }, ignore_index=True)

Và kết quả nhận được là:

data.head()
MergedData

Tiếp theo là trích dữ liệu của Việt Nam ra xử lý riêng:

vietnam = data [data['country'] == 'Vietnam']
vietnam.head()
VietnamData

Vậy là xong, giờ mình đã có đủ dữ liệu của Việt Nam từ 1960 trở lại đây. Tiếp theo là thử biểu diễn dữ liệu trên đồ thị xem sao, hẳn là các thông số trên trong suốt bấy nhiêu năm sẽ bị ảnh hưởng bởi các sự kiện lịch sử.

Hiển thị dữ liệu

Thử bắt đầu với GDP theo đầu người trước:

plt.plot(vietnam['year'], vietnam['gdpPerCapita'])
plt.legend(['Vietnam'])
plt.xlabel('year')
plt.ylabel('GDP per capita')
plt.grid()
plt.show()
VietnamGDP

Điều đầu tiên có thể thấy là chúng ta chỉ có dữ liệu GDP từ năm 1985 trở lại đây. Vậy có thể là trước năm 1985 GDP của Việt Nam chưa được thu thập bởi World Bank Group.

Điểm thú vị là có một đường cong hình dấu ~ trong giai đoạn 1985-1990. Đây là giai đoạn Việt Nam bước vào thời kỳ Đổi Mới, mở cửa thị trường. Sau một vài năm đầu đi vào ổn định thì GDP Việt Nam đã đạt tăng trưởng ấn tượng.

Tiếp theo thử phân tích về tuổi thọ trung bình của người Việt Nam:

plt.plot(vietnam['year'], vietnam['lifeExpectancy'])
plt.legend(['Vietnam'])
plt.xlabel('Year')
plt.ylabel('Life Expectancy')
plt.grid()
plt.show()
VietnamLife

Chúng ta có thể thấy là giai đoạn 1965 đến 1972 là giai đoạn đi xuống của tuổi thọ trung bình. Đây là giai đoạn chiến tranh ác liệt ở Việt Nam và rõ ràng nó tác động lớn đến tuổi thọ trung bình của người dân. Năm 1972 đánh dấu cột mốc lịch sử của Hiệp Định Paris cũng như giai đoạn tăng vọt của tuổi thọ trung bình ở Việt Nam lên 67.5 tuổi vào năm 1980 và tăng chậm lại trong giai đoạn sau đó.

Cuối cùng là biểu đồ dân số Việt Nam:

plt.plot(vietnam['year'], vietnam['population'])
plt.plot(vietnam['year'], vietnam['populationFemale'])
plt.plot(vietnam['year'], vietnam['populationMale'])
plt.legend(['Total', 'Female', 'Male'])
plt.xlabel('year')
plt.ylabel('Population')
plt.grid()
plt.show()
VietnamLife

Có thể thấy là số lượng nữ giới nhỉnh hơn số lượng nam giới một chút (khoảng 1 triệu). Một tín hiệu tốt cho các chàng trai của chúng ta.

Áp dụng mô hình Machine Learning

Quay lại mục tiêu dự đoán dân số theo GDP và tuổi thọ trung bình áp dụng mô hình Machine Learning. Chúng ta gặp vấn đề đầu tiên là đầu vào vì chúng ta không có dữ liệu GDP hay tuổi thọ trung bình trong tương lai để đưa vào dự đoán dân số. Một giải pháp khá đơn sơ là xây dựng mô hình dự đoán GDP và tuổi thọ trung bình trong tương lai rồi đưa vào mô hình dự đoán dân số.

Dựa theo các biểu đồ đã phân tích ở trên thì mình chọn mô hình cho các thuộc tính là:

  • Mô hình Polynomial Regression để dự đoán GDP
  • Mô hình Linear Regression để dự đoán tuổi thọ trung bình
  • Mô hình Linear Regression cho dự đoán dân số

Làm sao để khảo sát mô hình tốt hay không?
Để đánh giá tính chính xác của dự đoán thì mình sẽ dùng dữ liệu từ năm 1960 đến 2007 để xây dựng mô hình Machine Learning dự đoán dân số năm 2016 rồi so sánh với dữ liệu đã có.

Dữ liệu GDP theo đầu người chỉ có từ năm 1985
Bên cạnh đó thì nhìn vào đồ thị tuổi thọ trung bình lên xuống khá là không ổn định trong giai đoạn chiến tranh. Hơn nữa chúng ta đang ở thời bình nên mình chọn lọc lại chỉ sử dụng dữ liệu từ năm 1985-2007 để xây dựng mô hình.

Định nghĩa mô hình:

from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures

#init 3 models
lr_life = LinearRegression()
pr_gdp = LinearRegression()
lr_population = LinearRegression()

poly_reg = PolynomialFeatures(degree = 10)

Tách dữ liệu Việt Nam theo năm (1985-2007):

year_after_1985_before_2007 = (vietnam['year']<=2016) & (vietnam['year']>=1985)

Bắt đầu với mô hình dự đoán GDP theo đầu người:

X_train_gdp = vietnam[year_after_1985_before_2007][['year']]
X_train_poly_gdp = poly_reg.fit_transform(X_train_gdp)
y_train_gdp = vietnam[year_after_1985_before_2007]['gdpPerCapita']
pr_gdp.fit(X_train_poly_gdp, y_train_gdp)

predicted_train_gdp = pr_gdp.predict (X_train_poly_gdp)

plt.figure(figsize=(8, 5))
plt.plot(X_train_gdp, predicted_train_gdp)
plt.plot(X_train_gdp, y_train_gdp)
plt.legend(['Predicted values','True values'])
plt.xlabel('year')
plt.ylabel('GDP')
plt.grid()
plt.show()
VietnamGDPFit


Có thể thấy là mô hình tương đối khớp với dữ liệu. Tiếp đó là mô hình dự đoán tuổi thọ trung bình:

X_train_life = vietnam[year_after_1985_before_2007][['year']]
y_train_life = vietnam[year_after_1985_before_2007]['lifeExpectancy']
lr_life.fit( X_train_life, y_train_life)

predicted_train_life = lr_life.predict (X_train_life)

plt.figure(figsize=(8, 5))
plt.plot(X_train_life, predicted_train_life)
plt.plot(X_train_life, y_train_life)
plt.legend(['Predicted values','True values'])
plt.xlabel('year')
plt.ylabel('Life Expectancy')
plt.grid()
plt.show()
VietnamLifeFit

Cuối cùng là xây dựng mô hình dự đoán dân số theo GDP và tuổi thọ trung bình:

population_features = ['year','gdpPerCapita','lifeExpectancy']
X_train_population = vietnam[year_after_1985_before_2007][population_features]
y_train_population = vietnam[year_after_1985_before_2007]['population']
lr_population.fit(X_train_population, y_train_population)

predicted_train_population = lr_population.predict (X_train_population)

plt.figure(figsize=(8, 5))
plt.plot(vietnam[year_after_1985_before_2007]['year'], predicted_train_population)
plt.plot(vietnam[year_after_1985_before_2007]['year'], y_train_population)
plt.legend(['Predicted values','True values'])
plt.xlabel('year')
plt.ylabel('Population')
plt.grid()
plt.show()
VietnamPopulationFit

Dự đoán dân số

Vậy là mọi thứ đã sẵn sàng cho việc dự đoán và kiểm nghiệm mô hình. Chúng ta sẽ bắt đầu với việc dự đoán GDP theo đầu người và tuổi thọ trung bình năm 2016 rồi đưa kết quả vào dự đoán dân số:

target_year = 2016

poly_target_year =  poly_reg.fit_transform([[target_year]])

predicted_gdp = pr_gdp.predict (poly_target_year)
predicted_life = lr_life.predict ([[target_year]])

predicted_population = lr_population.predict ([[target_year, predicted_gdp, predicted_life]])

Và kết quả:

Predicted ValuesTrue ValuesGDP23062170Life Expectancy7676Population96,605,78694,569,072

Có thể thấy là mô hình của chúng ta đã dự đoán chính xác tuổi thọ trung bình nhưng có sai số khoảng 130$ ở GDP theo đầu người. Về dân số mô hình dự đoán là dân số Việt Nam sẽ đạt 96,6 triệu người vào năm 2016, trên thực tế là 94.6 triệu. Sai số không quá lớn cho một mô hình Machine Learning đơn giản.

Tiếp theo ?

Trong bài này thì mình chỉ ứng dụng những mô hình đơn giản, thoả mãn trí tò mò về dữ liệu là chính. Và đó mới chỉ là một góc rất nhỏ về Việt Nam trong tập dữ liệu này. Còn rất nhiều vấn đề có thể hấp dẫn bạn:

  • Biểu thị và so sánh GDP theo đầu người, tuổi thọ trung bình và dân số Việt Nam với các nước khác trong khu vực và thế giới.
  • Tìm thêm dữ liệu về tỷ lệ sinh để dự đoán dân số chính xác hơn.
  • Áp dụng các mô hình Machine Learning khác và so sánh kết quả
  • ...

Ok, cảm ơn mọi người đã đọc bài của mình!