Python snippet: Linear regression

cartoon_guide_regression.png

Linear regression (Hồi quy tuyến tính) thường được ứng dụng vào dự đoán giá trị số thực khi cho trước dữ liệu đầu vào. Ví dụ một số ứng dụng của Linear regression:

  • Dự đoán mức lương sau khi ra trường của một người dựa vào các thông số như điểm trung bình khoá học, số lượng các hoạt động ngoại khoá đã tham gia, giới tính, …
  • Dự đoán giá chứng khoán ngày mai dựa vào lịch sử giá trước đó, các sự kiện xã hội, số lượng vốn đầu kỳ, …
  • Bao nhiêu người sẽ share bài viết của bạn trên facebook dựa trên số lượng bạn bè, số lượng bạn của bạn bè, độ phổ biến của hashtag, những bài viết trước đó, …
  • Điều chỉnh nhiệt độ phòng dựa trên thời gian trong ngày, nhiệt độ ngoài trời, ánh sáng trong phòng, …

Tiếp tục series Python snippet (Python snippet: Visualizing, Python snippet: Thu thập dữ liệu), tuần này tôi sẽ đưa vào một vài snippet liên quan đến linear regression áp dụng trên tập dữ liệu home_data để dự đoán giá nhà dựa trên một vài thuộc tính cơ bản như số lượng phòng ngủ, số lượng phòng tắm, điểm đánh giá, …

Lý thuyết: linear regression
Source code: data-science-works
Thư viện: matplotlib, pandas, scikit-learn

Load dữ liệu vào DataFrame

Đầu tiên, ta sẽ sử dụng pandas để load tập dữ liệu home_data.csv về dạng DataFrame.

import os
import matplotlib.pyplot as plt
import pandas as pd
from sklearn import linear_model
from sklearn.externals import joblib
from sklearn.linear_model import Ridge
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures

def get_home_data():
    """Get home data, from local csv."""
    if os.path.exists("data/home_data.csv"):
        print("-- home_data.csv found locally")
        df = pd.read_csv("data/home_data.csv", index_col=0)

    return df

df = get_home_data()

Lựa chọn thuộc tính và phân chia tập dữ liệu

Tập dữ liệu home_data có nhiều thuộc tính liên quan. Trong ví dụ này, ta sẽ sử dụng ba thuộc tính đơn giản là “bedrooms”, “bathrooms”,  và “grade” để dự đoán giá nhà. Sau đó, ta tiếp tục phân chia tập dữ liệu thành hai phần training (70%) và testing (30%). Sau cùng, ta thử lập biểu đồ mối quan hệ giữa ba thuộc tính này so với giá nhà để xem chúng có tạo ra một xu hướng nào không.

def plotting_features_vs_target(features, x, y):
    # define number of subplot
    num_feature = len(features)
    f, axes = plt.subplots(1, num_feature, sharey=True)

    # plotting
    for i in range(0, num_feature):
        axes[i].scatter(x[features[i]], y)
        axes[i].set_title(features[i])

    plt.show()

# features selection
features = list(["bedrooms", "bathrooms", "grade"])
print "Features name:", list(df.columns.values)
print "Selected features:", features
y = df["price"]
X = df[features]

# split data-set into training (70%) and testing set (30%)
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

# plotting features, target relationships
plotting_features_vs_target(features, x_train, y_train)
features_vs_target.png

Features vs Targets

Huấn luyện và đánh giá theo phương pháp cơ bản

Về cơ bản, quá trình training mô hình của chúng ta sẽ hướng đến tối tiểu hoá hàm lỗi sau:

min_w ||Xw - y||_2^2

Ta sử dụng scikit-learn (linear_model) để huấn luyện mô hình theo giải thuật Gradient Descent. Khi đã có được mô hình, ta sẽ sử dụng tập testing để đánh giá thông qua hàm score(). Hàm score() được định nghĩa như sau:

Returns the coefficient of determination R^2 of the prediction.
The coefficient R^2 is defined as (1 – u/v), where u is the regression
sum of squares ((y_true – y_pred) ** 2).sum() and v is the residual
sum of squares ((y_true – y_true.mean()) ** 2).sum().
Best possible score is 1.0 and it can be negative (because the
model can be arbitrarily worse). A constant model that always
predicts the expected value of y, disregarding the input features,
would get a R^2 score of 0.0.

"""
DEFAULT MODEL
"""
# training model
linear = linear_model.LinearRegression()
linear.fit(x_train, y_train)

# evaluating model
score_trained = linear.score(x_test, y_test)
print "Model scored:", score_trained

>> Model scored: 0.449996847021

Huấn luyện và đánh giá theo phương pháp Lasso (L1 regularization)

Regularization thường được dùng để giảm thiểu vấn đề liên quan đến overfitting/variance. Lasso sử dụng thêm tham số \alpha để điều chỉnh lại quá trình fitting dữ liệu của mô hình. Coordinate Descent được áp dụng để huấn luyện mô hình.

min_w ||Xw - y||_2^2 + \alpha||w||_2^2

"""
LASSO MODEL
"""
# L1 regularization
lasso_linear = linear_model.Lasso(alpha=1.0)
lasso_linear.fit(x_train, y_train)

# evaluating L1 regularized model
score_lasso_trained = lasso_linear.score(x_test, y_test)
print "Lasso model scored:", score_lasso_trained

>> Lasso model scored: 0.454958866436

Huấn luyện và đánh giá theo phương pháp Ridge (L2 regularization)

Ridge sử dụng Stochastic Average Gradient descent để huấn luyện mô hình thoả hàm lỗi được định nghĩa như bên dưới

min_w \frac{1}{2n_{samples}} ||Xw - y||_2^2 + \alpha||w||_1

"""
RIDGE MODEL
"""
# L2 regularization
ridge_linear = Ridge(alpha=1.0)
ridge_linear.fit(x_train, y_train)

# evaluating L2 regularized model
score_ridge_trained = ridge_linear.score(x_test, y_test)
print "Ridge model scored:", score_ridge_trained

>> Ridge model scored: 0.454958309483

Nếu dữ liệu và số lượng thuộc tính đủ lớn, ta có thể quan sát rõ tốc độ hội tụ của phương pháp Lasso nhanh hơn các phương pháp còn lại, nhờ vào cơ chế tính đạo hàm cho từng thuộc tính thay vì tính đạo hàm cùng lúc cho từng thuộc tính. Ridge sử dụng phương pháp Gradient Descent nhưng có áp dụng thêm cơ chế lựa chọn thuộc tính ngẫu nhiên để hy vọng đạt được kết quả hội tụ sớm. Cuối cùng, việc lựa chọn mô hình được dựa vào chỉ số đánh giá mô hình. Mô hình càng tốt thì model score càng gần đến 1.0.

Nâng bậc của mô hình tuyến tính

polynomial_interpolation

Nếu mô hình của chúng ta ở không gian 2 chiều thì hàm mục tiêu của chúng ta có dạng như sau:

\hat{y} (w, x) = w_0 + w_1x_1 + w_2x_2

Nếu chúng ta muốn nâng bậc của mô hình thành bậc 2, nghĩa là ta chuyển đường thẳng thành đường cong Parabol thì mô hình của chúng ta sẽ có dạng như bên dưới:

\hat{y} (w, x) = w_0 + w_1x_1 + w_2x_2 + w_3x_1x_2 + w_4x_1^2 + w_5x_2^2

Ta có thể thấy mô hình này vẫn là mô hình tuyến tính với

z = [x_1, x_2, x_1x_2, x_1^2, x_2^2]

Nếu ta đặt tên lại cho x_1^2 = z_4, x_2^2 = z_5 thì mô hình của chúng ta có dạng:

\hat{y} (w, x) = w_0 + w_1x_1 + w_2x_2 + w_3x_1x_2 + w_4z_4 + w_5z_5

Sử dụng PolynomialFeatures preprocessor ta có thể biến đổi dữ liệu X đầu vào lên bậc 2, 3, … nhờ vào hàm fit_transform(). Giả sử X = [x_1, x_2] thì sau khi nâng bậc ta có X = [1, x_1, x_2, x_1^2, x_1x_2, x_2^2]

"""
POLYNOMIAL REGRESSION
"""
poly_model = Pipeline([('poly', PolynomialFeatures(degree=2)),
           			('linear', linear_model.LinearRegression(fit_intercept=False))])
poly_model = poly_model.fit(x_train, y_train)
score_poly_trained = poly_model.score(x_test, y_test)
print "Poly model scored:", score_poly_trained

>> Poly model scored: 0.573730261394

Ngoài ra, ta có thể lược bỏ các biến x_i^n = x_i do các biến này có thể không hữu ích lắm trong một vài trường hợp và chỉ quan tâm đến x_ix_j bằng cách thêm tham số interaction_only=True cho PolynomialFeatures.

poly_model = Pipeline([('poly', PolynomialFeatures(interaction_only=True, degree=2)),
                       ('linear', linear_model.LinearRegression(fit_intercept=False))])
poly_model = poly_model.fit(x_train, y_train)
score_poly_trained = poly_model.score(x_test, y_test)
print "Poly model (interaction only) scored:", score_poly_trained

>> Poly model (interaction only) scored: 0.570215385105

Lưu lại mô hình cho ứng dụng

Ta có thể lưu lại mô hình đã được huấn luyện vào một file. Sau đó, ứng dụng có thể đọc và áp dụng mô hình này vào thực tế.

from sklearn.externals import joblib

# saving model
joblib.dump(linear, "models/linear_model_v1.pkl")

# loading model
clf = joblib.load("models/linear_model_v1.pkl")
predicted = clf.predict(x_test)
print "Predicted test:", predicted

>> Predicted test: [ 1285209.23958929   621902.19208996   444355.26565693 ...,
   637495.68386442   637495.68386442   637495.68386442]

Nguồn tham khảo:

Advertisements

13 thoughts on “Python snippet: Linear regression

  1. Dear anh, có bài toán thực tế như thế này có áp dụng được nội dung trên để xử lý vấn đề không, anh xem hộ em nhé:
    Với một công ty thì được định nghĩa các khoản chi phí (Các khoản mục nhỏ và chi tiết) theo hàng tháng và hàng tháng đó phát sinh ra các khoản doanh thu. Có thể áp dụng trên để xác định nếu như kế hoạch doanh thu của đơn vị tháng này là A thì chi phí dự đoán phải bỏ ra là bao nhiêu. (Dữ liệu lịch sử có dài trong 3-5 năm)

    Số lượt thích

    • Ứng dụng của LR thì có nhiều (anh có liệt kê vài ứng dụng trong bài viết). Quan trọng ta nắm được nguyên lý để áp dụng cho từng bài toán mình gặp phải. Em có thể sử dụng code trong bài viết để thực nghiệm cho tập dữ liệu khác ngoài dự đoán giá nhà như chứng khoán chẳng hạn.

      Số lượt thích

  2. Cho mình hỏi là khi mình dùng hồi quy tuyến tính để ước lượng tương quan với ví dụ của bạn thì phần intercept_ nó chỉ in ra một giá trị trong khi phần coef_ nó có tới 3 giá trị. Mình chưa hiểu là tại sao intercept_ nó chỉ có một giá trị duy nhất trong khi mình nghĩ là với mỗi feature khác nhau thì nó có mỗi một intercept_ khác nhau? Liệu mình cố gắng train cho mỗi feature có một intercept_ và coef_ riêng biệt thì có làm cho mô hình chuẩn xác hơn so với hiện tại là một intercept_ và 3 coef_ không?

    “””
    DEFAULT MODEL
    “””
    linear = linear_model.LinearRegression()
    linear.fit(x_train, y_train)
    print(“Coef linear:”, linear.coef_)
    print(“Intercept:”, linear.intercept_)
    score_trained = linear.score(x_test,y_test)
    print(“Model scored:”, score_trained)

    Số lượt thích

      • Cám ơn bạn giờ mình hiểu thêm một chút rồi. Như vậy nếu mình lấy 3 features như trong ví dụ theo hồi quy tuyến tính, sau khi mình tìm được coef_ và intercept_ thì mình trình bày nó lên một đồ thị như thế nào nhỉ? Vì nếu là dựa trên 1 feature (ví dụ như bedroom) thì đơn giản

        Code: plt.plot(x_test,linear.predict(x_test))
        Graph: http://imgur.com/a/jzUvU

        Nhưng như ví dụ trên 3 features thì mình phải hiển thị kết quả tìm được như thế nào cho hợp lý vì 3 features có đơn vị trên trục nằm ngang (trục hoành thì phải) khác nhau. Trong trường hợp này mình có phải flat cái ma trận x_test từ 3 cột về 1 cột rồi plot không?

        Số lượt thích

          • Có phải ý Hồng là làm dạng scatter như code bên dưới hả. Nhưng nếu mình muốn biểu diễn cái đồ thị y = ax1 + bx2+cx3 + y0 thì chắc phải dùng plot3d hen? Ý là lung linh giống cái hình bên dưới. Chỗ này thì phải tìm hiểu về sự khác biệt của multiple linear regression và multivariate linear regression rồi.

            Graph: http://imgur.com/a/YciX9

            f,axes = plt.subplots(1,len(features),sharey=True)
            for i in range(0, len(features)):
            axes[i].scatter(x_test[features[i]],linear.predict(x_test))

            Số lượt thích

            • Nếu bạn chỉ có 2 feature và 1 giá trị dự đoán thì có thể sử dụng 3Dplot. Nhiều hơn 2 feature, để 3Dplot bạn cần tổ hợp các feature lại với nhau cùng với giá trị dự đoán để biểu diễn. Ví dụ, y = w0 + w1x1 + w2x2 + w3x3. Các 3Dplot sẽ là (y, x1, x2), (y, x1, x3), (y, x2, x3).

              Số lượt thích

            • Loay hoay cuối cùng cũng plot được với 2 features bedrooms và bathrooms. Cám ơn Hồng. Mới tự học nên còn trẻ trâu quá. Có nhiều cái chưa hiểu. :).

              Graph: http://imgur.com/a/6wjpP
              Code:

              max_bedrooms = max(x_test[features[0]])
              max_bathrooms = max(x_test[features[1]])
              step = 1/pow(2,5)
              plot_data_x = np.arange(1,max_bedrooms,step)
              plot_data_y = np.arange(1,max_bathrooms,step)
              X,Y = np.meshgrid(plot_data_x,plot_data_y)
              Z = linear.intercept_ + linear.coef_[0]*X + linear.coef_[1]*Y

              fig = plt.figure()
              ax = fig.add_subplot(111, projection=’3d’)
              ax.set_xlabel(features[0])
              ax.set_ylabel(features[1])

              ax.plot_surface(X,Y,Z,cmap=cm.Blues, alpha=0.7)
              ax.scatter(x_test[features[0]],x_test[features[1]],y_test)
              plt.show()

              Liked by 1 person

  3. Mình đang tìm hiểu phần Polynomial, mình không hiểu là tại sao kết quả lại không tốt bằng linear regression bình thường. Hồng có thể chỉ cho mình được không? Mình so sánh giữa Linear Regression và Linear Regression Polynomial thì kết quả được như sau:
    – Graph của Linear Regression bình thường: http://imgur.com/a/wADLD
    – Graph của Linear Regression với Polynomial: http://imgur.com/a/j1Iq3

    Code: https://bitbucket.org/rongchaua/machine-learning/src/7708a3dfde69155839673d605a74b3cbd439f65a/polynomial.py?at=default&fileviewer=file-view-default

    Số lượt thích

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất / Thay đổi )

Connecting to %s