Download as pdf or txt
Download as pdf or txt
You are on page 1of 455

1

Kinh Tế Lượng Ứng Dụng Với

(Phiên bản ngày 10/10/2017)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


2

Nguyễn Chí Dũng http://rpubs.com/chidungkt


3

Lời Nói Đầu

Tại sao dùng R?

Với nhiều công cụ cho tích dữ liệu mà bạn có thể lựa chọn như Eviews, Stata, SPSS – AMOS, Excel, S-
PLUS, MATLAB thì rõ ràng câu hỏi đầu tiên là tại sao phải dùng R? Có ít nhất năm lí do để bạn lựa
chọn R.

Thứ nhất, với tư cách là một công cụ cho nghiên cứu thống kê – kinh tế lượng, năng lực phân tích của
R là không thua kém bất kì phần mềm thống kê nào hiện có, thậm chí trong nhiều tình huống còn làm
tốt hơn. Chẳng hạn, nếu phân tích dữ liệu mảng (Panel Data) thì chúng ta sẽ cân nhắc giữa Stata và
Eviews vì Stata có năng lực phân tích đa dạng và linh động hơn so với Eviews. Còn nếu bạn thực hiện
các phân tích thống kê đa biến như phân tích EFA, CFA thì bạn sẽ có xu hướng chọn Stata hoặc SPSS
– AMOS do chúng linh hoạt và tiện lợi hơn. Tuy nhiên, nếu dùng R thì bạn chẳng cần phải đắn đo về
vấn đề này: nó có thể thực hiện tất cả những phân tích mà các phần mềm thống kê thương mại trên
có thể làm và làm tốt hơn.

Thứ hai, R còn là một ngôn ngữ lập trình hoàn thiện định hướng cho tính toán thống kê, phân tích dữ
liệu. Nó cho phép bạn xây dựng những hàm, những câu lệnh chỉ để giải quyết một nhóm các nhiệm vụ
phân tích đặc thù nào đó và chia sẻ chúng trên mạng. Chẳng hạn, nếu có một kiểm định mới, một mô
hình mới về phương diện lý thuyết và được đăng trên một tạp chí chuyên nghành nào đó, bạn hoàn
toàn có thể viết một chương trình nhằm biến kiểm định mới, những mô hình mới chỉ ở dạng lý thuyết
kia thành một hàm cụ thể trong R. Nếu được kiểm tra bởi cộng đồng những người sử dụng rằng đúng
và không có lỗi, hàm mà bạn viết sẽ được thừa nhận và sử dụng rộng rãi.

Thứ ba, với tư cách là một công cụ phân tích dữ liệu nói chung, R còn là một công cụ cho Data Mining,
Big Data, Data Visualization và Machine Learning. Tôi lấy một ví dụ của Data Visualization bằng hình
ảnh ấn tượng dưới đây:

Hình ảnh này được vẽ trong R dựa trên các số liệu thu thập được về các chuyến bay của 7 hãng hàng
không lớn nhất thế giới. Dựa vào hình ảnh này các bạn có thể thấy trung tâm của cái mạng nhện này
là ở Bắc Mĩ và Châu Âu – những đầu mối nhộn nhịp nhất của vận tải hàng không. Nếu căn cứ vào màu
sắc (mỗi hãng hàng không một màu) thì bạn cũng thấy rõ ngay các thị trường chính của những hàng
không này. Suy rộng ra là, với tư cách là một nhà nghiên cứu thị trường, các xu hướng xã hội, hay buộc

Nguyễn Chí Dũng http://rpubs.com/chidungkt


4

dữ liệu phải lên tiếng, phải cung cấp cho ta một thông tin đáng giá nào đó thì R hoàn toàn là một công
cụ thích hợp cho bạn lựa chọn.

Một ví dụ nữa là sử dụng dữ liệu từ Google Scholar, chúng ta có thể hình ảnh hóa (Data Visualization)
về thị phần của R từ năm 1995 đến 2011 dựa trên các truy vấn tìm kiếm như sau:

Dữ liệu cần thiết đễ vẽ đồ thị trên tôi cũng gửi kèm với tài liệu này.

Thứ tư, sử dụng R trong nghiên cứu và phân tích dữ liệu là một xu hướng và ngày càng phổ biến, ít
nhất là trong nghiên cứu thống kê – kinh tế lượng. Hiện R được giảng dạy và sử dụng như một công
cụ phân tích dữ liệu ở nhiều trường đại học lớn, có uy tín trong lĩnh vực này ở Mĩ và Châu Âu. Đây
cũng là lý đo xứng đáng để bạn chọn R.

Cuối cùng, các trường đại học sớm hay muộn thì cũng không thể dùng phần mềm chùa như hiện nay
và sẽ sớm chuyển sang sử dụng các phần mềm miễn phí. Hiện nay đã có một số trường đại học sử
dụng R cho việc giảng dạy thống kê và kinh tế lượng.

Đối tượng bạn đọc của tài liệu này là ai?

Đây chắc chắn là câu hỏi mà tôi phải trả lời trước ki viết tài liệu này. Đối tượng bạn đọc mà tôi hướng
đến trước hết là các bạn học khối nghành kinh tế nói chung có nhu cầu sử dụng R như là một công cụ
nghiên cứu – thực hành thống kê cũng như kinh tế lượng. Tất nhiên bạn đọc không thuộc khối kinh
tế cũng có thể thu được nhiều lợi ích khi sử dụng tài liệu này.

Ngoài ra, nếu bạn là người phóng khoáng, ưa thích cái đẹp và sự chính xác thì chắc chắn R sẽ trở thành
người bạn đồng hành lâu dài của bạn ngay cả khi bạn chọn cho mình một nghề nghiệp mà buộc dữ
liệu phải nói điều gì đó có ích. Ví dụ, không giống như một số phần mềm thương mại khô cứng khác
(và bạn chẳng biến nó tính toán ra sao) khi thực hiện hồi quy OLS bạn cứ làm mãi mỗi một thao tác.
R thì không như vậy, cũng là hồi quy OLS nhưng bạn có thể có hàng chục cách thức khác nhau. Về sự
chính xác, theo tôi được biết thì cho đến tận phiên bản mới nhất của Stata mà tôi đang dùng (Version
14) thì khi tính R2 với dữ liệu mảng, Stata vẫn báo kết quả sai. Với R thì điều này không có. Vì bạn biết
từng bước trong tính toán nếu muốn bằng cách xem trực tiếp những dòng mã lệnh.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


5

Bạn cần có gì để sử R với tài liệu này?

Trước hết cần nói rằng đây không phải là một tài liệu về kinh tế lượng. Nó là một cuốn hướng dẫn sử
dụng R với các áp dụng cho kinh tế lượng, do vậy sẽ không đề cập nhiều đến lý thuyết (mặc dù có một
số tình huống tôi cũng có nhắc lại lý thuyết). Tôi mặc định là các bạn đã có kiến thức nền tảng về thống
kê và kinh tế lượng. Ngoài ra tôi cũng khuyến cáo bạn nên sử dụng tài liệu này kèm với cuốn Giáo
Trình Kinh Tế Lượng in năm 2012 của tác giả Nguyễn Quang Dong và Nguyễn Thị Minh của Đại Học
Kinh Tế Quốc Dân (NEU) hoặc cuốn Kinh tế lượng của tác giả Nguyễn Thành Cả và Nguyễn Thị Ngọc
Miên thuộc đại học Kinh Tế Thành Phố Hồ Chí Minh (UEH).

Ngoài ra, từ chương 8 trở đi của cuốn giáo trình của NEU sử dụng nhiều dữ liệu từ cuốn sách
Introductory Econometrics: A Modern Approach của Wooldridge (2013) nên tôi cũng gửi kèm các
bạn cuốn sách này để tham khảo và đối chiếu.

Sử dụng R có khó không?

Câu trả lời rất dứt khoát: không . Và tôi tin chắc là nếu bạn thành thạo R ở mức tối thiểu, bạn có xu
hướng không sử dụng các phần mềm thống kê thương mại khác. Vì sao? Vì bạn hiểu bạn đang làm gì.
Tuy nhiên là một người tự học nên tôi có một lời khuyên: R không phải là một kiểu “mì ăn liền” như
Eviews, SPSS, hay Stata – những phần mềm mà các bạn chủ yếu là kích chuột, kích chuột là có kết quả.
R có chút khắt khe hơn khi nó yêu cầu bạn hai thứ: (1) sự thận trọng trong việc gõ các câu lệnh, và (2)
tuần tự từng bước. Theo kinh nghiệm của tôi cũng như nhiều người khác, là một người mới sử dụng
R, bạn không thể nào học theo lối nhảy cóc được.

Là một tài liệu định hướng thực hành nên khía cạnh lý thuyết (nhất là các công thức, các chứng minh)
sẽ không phải là trọng tâm của tài liệu này. Trong tình huống cần tham chiếu lại lý thuyết một cách rõ
ràng tôi sẽ chỉ rõ tại số trang bao nhiêu, của cuốn sách hay nghiên cứu nào. Tất nhiên, nếu là sách
trong nước thì tôi sẽ chỉ sử để cập đến hai cuốn giáo trình kinh tế lượng của đại học Kinh Tế Quốc
Dân và Kinh Tế Thành Phố Hồ Chí Minh. Ngoài ra tôi mặc định rằng người sử dụng đã có những kiến
thức cơ bản về kinh tế lượng cũng như thống kê.

Kết cấu của tài liệu này

Dự kiến tôi sẽ viết tài liệu này thành hai tập. Tập một tương ứng với học phần kinh tế lượng 1 được
giảng ở NEU cũng như UEH. Tuy nhiên phần này có thêm một số nội dung mà chương trình học của
EUH không có là hồi quy phân vị, Logistic, Probit, Poisson, các mô hình có biến kiểm duyệt, mô hình
hồi quy với biến công cụ, phân tích dữ liệu bảng (hay dữ liệu tổng hợp). Tập hai tương ứng với nội
dung phân tích chuỗi dữ liệu thời gian cũng một số mô hình quen thuộc như ARCH, GARCH, VAR,
BVAR.

Dữ liệu sử dụng cho tài liệu

Một trong những nguyên tắc chủ đạo của tôi khi viết tài liệu này là sử dụng data có nguồn gốc rõ ràng
và đáng tin cậy. Điều này đảm bảo rằng các bạn có thể kiểm tra, đối chiếu các kết quả phân tích thu
được nếu cần. Một lí do nữa tôi tin rằng không thể học tốt kinh tế lượng nếu như không am hiểu ở
mức độ tối thiểu về dữ liệu mà mình đang sử dụng. Tất cả số liệu được sử dụng trong tài liệu này

Nguyễn Chí Dũng http://rpubs.com/chidungkt


6

các bạn có thể dễ dàng lấy trên Internet. Tuy nhiên để thuận tiện tôi gửi toàn bộ chúng cùng tài liệu
này. Cụ thể, các số liệu được sử dụng trong tài liệu này đến từ 7 nguồn chủ yếu dưới đây:

1. Các số liệu từ cuốn Giáo Trình Kinh Tế Lượng của tác giả Nguyễn Quang Dong và Nguyễn Thị
Minh của NEU ở dạng file Eviews (gửi kèm tài liệu này).
2. Các số liệu từ cuốn sách Kinh tế lượng của tác giả Nguyễn Thành Cả và Nguyễn Thị Ngọc Miên
của UEH được cung cấp tại: https://sites.google.com/site/kinhteluongttkueh/home.
3. Bộ số liệu CPS 1988 đi kèm với gói AER. Bộ số liệu engel đi kèm gói quantreg. Ngoài ra còn
có một số bộ dữ liệu khác được sử dụng và được tích hợp (có sẵn) trong một số gói phân tích
của R.
4. Một số bộ số liệu (file Stata) lấy từ cuốn Econometrics by Example in năm 2011 của Gujarati.
5. Bộ số liệu panel1.dta (file Stata) sử dụng ở chương 10 cho phân tích dữ liệu mảng lấy từ cuốn
Econometric Analysis of Panel Data in năm 2005 của Baltagi.
6. Một số bộ dữ liệu lấy từ một số giáo trình điển hình khác về kinh tế lượng như cuốn
Introductory Econometrics: A Modern Approach ấn bản năm 2013 của Wooldridge, cuốn
Applied Logistic Regression ấn bản năm 2013 của Hosmer và Lemeshow và một số sách
khác. Các dữ liệu này ở dạng file Stata.
7. Một số bộ dữ liệu từng được sử dụng trong một số nghiên cứu của nước ngoài và được sử
dụng lại bởi nhiều cuốn giáo trình kinh tế lượng trên thế giới.

Về văn phong của tài liệu này

Trước khi công bố tài liệu này tôi cũng gửi cho nhiều bạn đọc thẩm định trước. Ý kiến phản hồi về tài
liệu chủ yếu là ở hai khía cạnh sau.

Một là, văn phong bình dân với bằng chứng từ việc sử dụng nhiều đại từ “chúng ta”, “các bạn”. Việc
này tôi cũng có cân nhắc trước khi viết. Sự thực là thay vì viết “Chúng ta có thể tính kiểm định F trực
tiếp như sau..” bằng “Tính trực tiếp kiểm định F như sau..” là việc tôi có thể làm được. Nhưng tôi thấy
viết kiểu đó tài liệu trở nên “kém thân thiện”. Tôi hoàn toàn có thể viết tài liệu theo xung hướng trang
trọng điển hình của các sách giáo trình. Tuy nhiên, tôi thích kiểu “thân thiện” hơn nên sẽ vẫn để
nguyên phong cách ngôn ngữ như vậy. Có lẽ tôi bị ảnh hưởng từ A. Field – một trong số các tác giả
yêu thích. Chẳng hạn, một trong các cuốn sách thống kê của tác giả này có tên Discovering statistics
using SPSS: (and sex and drugs and rock 'n' roll) – dịch ra là : Khám phá thống kê sử dụng SPSS: (và
tình dục, ma túy, nhạc Rock – Roll).

Hai là, giải thích chi tiết quá. Về điểm này tôi cần giải thích như sau. Đối tượng bạn đọc của tài liệu này
có thể có mức độ học và hiểu thống kê – kinh tế lượng ở các mức độ khác nhau: từ những người được
đào tạo bài bản về thống kê – kinh tế lượng như ở khoa Toán của đại học Kinh Tế Quốc Dân cho đến
những bạn đọc không chuyên về thống kê như tôi. Nên viết chi tiết, nhất là ở khía cạnh thực hành, là
điều tôi muốn hướng tới. Điều này còn dựa trên kinh nghiệm của chính bản thân tôi khi học cách sử
dụng R: một lỗi rất nhỏ trong thao tác có thể làm cho một câu lệnh hay toàn bộ một chương trình
không vận hành. Mà có thể tìm mãi cũng không ra. Bạn đọc có thể thấy điều này về cuốn sách về R
vừa được tái bản ở Việt Nam của T.S Nguyễn Văn Tuấn (in cuối năm 2015). Rõ ràng ông có thể viết
cuốn sách ngắn cô đọng hơn. Nhưng ông không làm thế.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


7

Các sai sót

Dù đã rất cẩn thận và cố gắng, tôi tin chắc tài liệu này còn có thiếu sót. Do vậy tôi rất mong nhận được
bất kì phản hồi nào của các bạn về tài liệu. Dựa trên những phản hồi ấy tôi sẽ hiệu chỉnh và hoàn thiện
hơn tài liệu cho những lần đánh máy sau.

Trợ giúp từ người viết tài liệu này

Trong tình huống các bạn gặp trục trặc (như thiếu data chẳng hạn) hay có bất kì phê phán nào đối với
tài liệu, các bạn có thể nhận được hỗ trợ và phản hồi một cách nhanh chóng nhất có thể từ tôi qua ba
cách thức sau (theo thứ tự ưu tiên và cập nhật giảm dần):

1. Website gồm các bài viết về phân tích dữ liệu nói chung và kinh tế lượng nói riêng tại:
http://rpubs.com/chidungkt. Các bài viết ở mục này sẽ có nhãn KTLR và các bạn có thể phản
hồi ngay lập tức. Tôi sẽ cố gắng cập nhật, trả lời phản hồi nhanh nhất có thể.
2. Gửi câu hỏi đến địa chỉ: https://phantichdinhluong.wordpress.com/. Đây là Blog của tôi được
thành lập để chúng ta trao đổi mọi thắc mắc về R. Do tôi chưa có kinh nghiệm dùng Blog nên
giao diện của nó còn chưa tiện dụng và xấu. Tuy nhiên cái đó không quan trọng vì chắc chắn
nó sẽ được cải thiện. Cách này được khuyến khích.
3. Tài liệu này luôn được làm mới và cập nhật cứ 2 tháng mỗi lần tại:
http://www.mediafire.com/download/3lg8bsfbu6csq8d/KinhTeLuongUngDungVoiR.rar

Lời cảm ơn

Tất nhiên, mọi thứ không thể được xây dựng từ chân không. Người viết tài liệu này được hưởng lợi
từ sự động viên, định hướng, công sức và sự nhiệt tình của nhiều người và do vậy tôi muốn nói lời
cảm ơn chân thành tới họ. Trước hết, đó là Thầy Lê Đức Hoàng (Viện Ngân Hàng – Tài Chính, đại học
Kinh Tế Quốc Dân) – người đã giúp đỡ tôi nhiều mặt (và cũng là một người bạn). Thầy đã tạo cho tôi
sự chú ý đối với R thông qua cuốn sách tuyệt vời Analysis of Financial Time Series của Ruey S. Tsay.

Ngoài ra, tôi cũng gián tiếp được hưởng lợi từ: (1) T.S Nguyễn Văn Tuấn ở viện nghiên cứu Garvan
(Australia) – người nhiệt thành cổ vũ cho việc sử dụng R trong các nghiên cứu và phân tích bằng việc
công bố tài liệu tiếng Việt đầu tiên về R qua Blog của mình vào những năm 2004, (2) T.S Daniel
Zelterman (Yale University) – người đã gửi cho tôi rất nhiều dữ liệu từ các nghiên cứu của ông cũng
như cho cuốn Applied Multivariate Statistics with R, (3) T.S Hadley Wickham (Rice University) –
người đã hào phóng gửi cho tôi bản mềm cuốn sách ggplot2 - Elegant Graphics for Data Analysis còn
đang trong quá trình in ấn của mình mà không suy nghĩ gì về vấn đề bản quyền. Nhiều kiến thức thu
được về sử dụng gói ggplot2 từ cuốn sách này được sử dụng để viết một phần chương 3 của tài liệu.

Tôi cũng muốn nói lời cảm ơn đến bố - mẹ, những bạn bè thân hữu đã cũng tạo điều kiện và giúp đỡ
tôi hoàn thành tài liệu này mặc dù họ có thể không ý thức được điều đó.

Cuối cùng, tôi cũng muốn nói lời cảm ơn đến tất cả các bạn – những người quan tâm và sử dụng tập
tài liệu này.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


8

Nguyễn Chí Dũng http://rpubs.com/chidungkt


9

Mục Lục

Chương 1: R với tư cách một công cụ nghiên cứu kinh tế lượng ...................................................... 18
1.1 Tổng quan về R ............................................................................................................................................. 18
1.2 Cài đặt R, Rstudio và các Packages cần thiết ...................................................................................... 19
1.2.1 Cài đặt R cho cho Windows ...................................................................................................... 19
1.2.2 Cài đặt Rstudio ........................................................................................................................... 20
1.2.3 Cài đặt các packages.................................................................................................................. 21
1.2.4 Yêu cầu một Package cụ thể trình diện ................................................................................. 22
1.2.5 Sử dụng Rmarkdown để trao đổi, công bố kết quả trên Internet với Rpub .................. 23
1.2.6 Cập nhật các phiên bản mới hơn của R ................................................................................. 26
1.3 Trợ giúp từ R ................................................................................................................................................. 26
1.4 Xem danh sách các gói đã cài đặt cũng như số lượng các gói của R .......................................... 29
1.5 Các quy ước khi sử R cho phân tích ...................................................................................................... 29
1.6 Tổng kết chương mở đầu ......................................................................................................................... 30
Chương 2: Môi trường làm việc trong R .................................................................................................... 30
2.1 Nhập dữ liệu trực tiếp vào R.................................................................................................................... 31
2.2 Hiệu chỉnh dữ liệu ....................................................................................................................................... 31
2.3 Đọc dữ liệu từ file sẵn có ở các định dạng khác nhau, từ các nguồn bên ngoài vào R ........ 32
2.3.1 Đọc dữ liệu từ file Eviews ........................................................................................................ 33
2.3.2 Đọc dữ liệu từ Stata................................................................................................................... 34
2.3.3 Đọc dữ liệu từ SPSS ................................................................................................................... 35
2.3.4 Đọc dữ liệu của phần mềm SAS ............................................................................................... 37
2.3.5 Đọc dữ liệu từ Excel .................................................................................................................. 37
2.3.6 Đọc dữ liệu định dạng txt ......................................................................................................... 37
2.3.7 Đọc dữ liệu định dạng csv ........................................................................................................ 38
2.3.8 Đọc nhiều file dữ liệu cùng một lúc ....................................................................................... 38
2.3.9 Đọc dữ liệu được cung cấp bởi World Bank với gói WDI .................................................. 40
2.3.9.1 Giới thiệu về các số liệu được cung cấp bởi WB ............................................................. 40
2.3.9.2 Lấy các dữ liệu cung cấp bởi WB vào R với gói WDI ...................................................... 41
2.3.10 Đọc dữ liệu tài chính từ Internet với gói quantmod ........................................................ 47
2.3.11 Đọc dữ liệu kích thước lớn ................................................................................................... 52
2.4 Quản lý dữ liệu, đổi tên, hiệu chỉnh dữ liệu bằng các hàm của gói base .................................. 54

Nguyễn Chí Dũng http://rpubs.com/chidungkt


10

2.4.1 Tạo một data frame ................................................................................................................... 54


2.4.2 Dán lại nhãn cho các quan sát thuộc bộ số liệu từ dạng số thành ki tự hoặc factor ..... 56
2.4.3 Dán lại nhãn cho các quan sát từ dạng kí tự thành dạng số .............................................. 58
2.4.4 Ghép dữ liệu vào một data frame sẵn có............................................................................... 58
2.4.5 Trích dữ liệu từ một data frame có sẵn với dấu [] ............................................................. 60
2.4.5.1 Trích xuất dữ liệu theo cột ................................................................................................. 60
2.4.5.2 Trích xuất dữ liệu theo hàng ............................................................................................. 60
2.4.5.3 Trích xuất dữ liệu đồng thời theo hàng và cột ............................................................... 61
2.4.6 Trích dữ liệu từ một data frame có sẵn bằng lệnh subset() ............................................ 61
2.4.7 Lấy mẫu ngẫu nhiên.................................................................................................................. 61
2.5 Quản lý dữ liệu, hiệu chỉnh dữ liệu bằng các hàm của gói tidyverse ....................................... 62
2.5.1 Tổ chức dữ liệu ở dạng tibble ................................................................................................. 63
2.5.2 Lọc dữ liệu với lệnh filter ........................................................................................................ 66
2.5.3 Chọn cột biến với lệnh select .................................................................................................. 66
2.5.4 Đổi tên biến với lệnh rename ................................................................................................. 67
2.5.5 Sắp xếp lại theo giá trị tăng dần hay giảm dần với lệnh arrange ..................................... 67
2.5.6 Tạo biến mới với lệnh mutate và transmute ....................................................................... 67
2.5.7 Lấy ra ngẫu nhiên một số quan sát với lệnh sample_n và sample_frac ........................... 67
2.5.8 Lấy ra không ngẫu nhiên một số quan sát với lệnh slice ................................................... 68
2.5.9 Loại các dòng trùng nhau bằng lệnh distinct ....................................................................... 68
2.5.10 Hợp nhất dữ liệu bằng lệnh bind_rows và bind_cols ....................................................... 69
2.5.11 Dán lại nhãn cho các quan sát với hàm recode() hoặc recode_factor() ....................... 70
2.5.12 Dán lại nhãn cho các quan sát với hàm if_else hoặc case_when..................................... 72
2.5.13 Chuyển từ dạng wide sang long cho các nghiên cứu dữ liệu bảng với lệnh gather . 73
2.5.14 Hợp nhất có điều kiện theo cột cho các bộ dữ liệu .......................................................... 75
2.6 Toán tử tẩu thuốc pipe (%>%)............................................................................................................... 78
2.7 Tính các thống kê cơ bản với bộ số liệu PISA sử dụng gói dplyr ................................................ 80
2.8 Lưu các dữ liệu đã có trong R thành file Excel, Stata ..................................................................... 83
2.9 Lưu các kết quả, các lệnh đã thực hiện cũng như các Objects để sử dụng cho lần sau ..... 84
2.10 Thực hiện các tính toán thông thường, đại số tuyến tính .......................................................... 85
2.11 Mô phỏng dữ liệu ...................................................................................................................................... 90
2.12 Viết và trình bày R code đúng cách ..................................................................................................... 93
2.13 Lưu ý về sử dụng dấu = thay cho <- và lệnh attach ...................................................................... 95

Nguyễn Chí Dũng http://rpubs.com/chidungkt


11

2.14 Lưu ý khi gặp tình huống cùng một tên hàm tồn tại ở hai hay nhiều gói ............................. 96
Chương 3: Các thống kê mô tả và hình hóa dữ liệu với R ..................................................................... 97
3.1 Thực hiện các thống kê mô tả trong R.................................................................................................. 97
3.1.1 Thống kê mô tả với các hàm sẵn có trong R ......................................................................... 97
3.1.2 Thống kê mô tả chi tiết với gói pastecs ................................................................................. 99
3.1.3 Thống kê mô tả chi tiết với gói stargazer ........................................................................... 100
3.1.4 Thống kê mô tả chi tiết với gói fBasics ................................................................................ 101
3.2 Tìm các giá trị thống kê và mức xác suất của phân phối N, t, F,và χ2 ...................................... 102
3.2.1 Phân phối chuẩn N .................................................................................................................. 102
3.2.2 Phân phối Student t ................................................................................................................. 104
3.2.3 Phân phối F ............................................................................................................................... 106
3.2.4 Phân phối χ2 ............................................................................................................................. 107
3.3 Vẽ các Graph và đồ thị trong R .............................................................................................................. 108
3.3.1 Các Graphs với gói mặc định graphics của R ...................................................................... 108
3.3.1.1 Vẽ Scatter Plot .................................................................................................................... 108
3.3.1.2 Histogram ........................................................................................................................... 110
3.3.1.3 Hàm mật độ xác suất Density .......................................................................................... 112
3.3.1.4 Boxplots .............................................................................................................................. 113
3.3.1.5 Biểu đồ cột .......................................................................................................................... 118
3.3.1.6 Pie Chart ............................................................................................................................. 120
3.3.1.7 Biểu đồ đường ................................................................................................................... 122
3.3.1.8 Trình bày nhiều Graphs trên cùng một cửa sổ hiển thị trong R ................................ 123
3.3.2 Các Graphs với gói ggplot2 .................................................................................................... 123
3.3.2.1 Vẽ Scatter Plot .................................................................................................................... 124
3.3.2.2 Vẽ đường hồi quy .............................................................................................................. 125
3.3.2.3 Vẽ Histogram ..................................................................................................................... 127
3.3.3.4 Boxplots .............................................................................................................................. 128
3.3.2.5 Biểu đồ cột .......................................................................................................................... 130
3.3.2.6 Vẽ các đường cong hồi quy bặc hai ................................................................................ 130
3.3.2.7 Hàm mật độ xác suất Density .......................................................................................... 138
3.3.2.8 Biểu đồ đường ................................................................................................................... 140
3.3.2.9 Pie Chart ............................................................................................................................. 142
3.3.3 Hình ảnh hóa dữ liệu (Data Visualiztion) nâng cao .......................................................... 143

Nguyễn Chí Dũng http://rpubs.com/chidungkt


12

3.3.3.1 Trình bày nhiều Graphs trên cùng một cửa sổ hiển thị trong R với gói grid .......... 143
3.3.3.2 Vẽ thêm Histogram cho đường hồi quy với gói ggExtra ............................................. 144
3.3.3.3 Vẽ thêm hàm mật độ xác suất cho đường hồi quy với gói gridExtra ........................ 145
3.3.3.4 Vẽ thêm Boxplot cho đường hồi quy với gói gridExtra ............................................... 146
3.3.3.5 Vẽ đồ thị thị phần của R giai đoạn 1995 - 2011 ............................................................ 147
3.3.3.6 Sử dụng gói plotly tạo ra các hình ảnh tương tác ....................................................... 148
3.3.3.7 Sử dụng gói googleVis tạo ra các hình ảnh tương tác ................................................ 152
3.4 Môt số nguyên tắc của hình ảnh hóa dữ liệu của Edward Tufte ............................................... 157
3.5 Lưu các Graphs ........................................................................................................................................... 159
3.6 Mini Projects: Hình ảnh hóa dữ liệu trong thực tế ........................................................................ 160
Chương 4: Mô hình hồi quy tuyến tính hai biến số ............................................................................... 169
4.1 Một số thống kê cơ bản về bộ dữ liệu ................................................................................................. 169
4.2 Thực hiện hồi quy và một số kiểm định thường gặp .................................................................... 171
4.2.1 Hồi quy đơn, khoảng tin cậy cho các hệ số và bảng ANOVA ............................................ 171
4.2.2 Tìm các quan sát bất thường và chẩn đoán lỗi mô hình bằng hình ảnh ....................... 175
4.2.3 Thực hiện một số kiểm định thường gặp cho mô hình hồi quy ..................................... 176
4.2.3.1 Kiểm định tính phân phối chuẩn của phần dư ............................................................. 176
4.2.3.2 Kiểm định Durbin - Watson ............................................................................................. 179
4.2.3.3 Kiểm định Wald về một giá trị cụ thể của một hệ số hồi quy ...................................... 179
4.2.3.4 Kiểm định Wald đồng thời cho nhiều hệ số hồi quy ..................................................... 180
4.3 Mô phỏng Monte Carlo kiểm tra các giả thuyết CLMR .................................................................. 180
4.4 Sử dụng kết quả hồi quy cho ước lượng ........................................................................................... 183
4.5 Một số tiêu chí thường sử dụng để đánh giá chất lượng mô hình ........................................... 186
4.5.1 Tiêu chí R2 và tương quan giữa Y và Ŷ ................................................................................ 187
4.5.2 Các tiêu chí đánh giá theo phần dư ...................................................................................... 187
4.5.3 Các tiêu chuẩn thông tin AIC, SIC, và Cp của Mallow ........................................................... 187
4.5.4 Tỉ lệ sai sót huấn luyện, sai sót kiểm định và hiện tượng quá khớp ............................. 188
4.6 Đánh giá chất lượng của mô hình bằng các phương pháp tái chọn mẫu ............................... 193
4.6.1 Phương pháp Bootstrap......................................................................................................... 194
4.6.2 Phương pháp kiểm tra chéo .................................................................................................. 200
4.6.2.1 Kiểm tra chéo LOOCV....................................................................................................... 200
4.6.2.2 Kiểm tra chéo k lớp.......................................................................................................... 202
4.6.2.3 Sự đánh đổi Bias – Variance ........................................................................................... 203

Nguyễn Chí Dũng http://rpubs.com/chidungkt


13

4.6.3 Giới thiệu về các phương pháp tái chọn mẫu bằng gói caret .......................................... 204
4.7 Dữ liệu thiếu và xử lý dữ liệu thiếu trong phân tích kinh tế lượng ........................................ 210
Chương 5: Mở rộng mô hình hồi quy hai biến số ................................................................................. 217
5.1 Hồi quy qua gốc tọa độ - mô hình CAPM ............................................................................................ 217
5.2 Vấn đề thay đổi đơn vị của biến ........................................................................................................... 220
5.3 Hồi quy chuẩn hóa ..................................................................................................................................... 222
5.4 Dạng hàm của mô hình hồi quy ............................................................................................................ 223
5.4.1 Mô hình logarit tuyến tính ..................................................................................................... 223
5.4.2 Mô hình bán logarit ................................................................................................................. 226
5.4.3 Mô hình xu hướng tuyến tính ............................................................................................... 229
5.4.4 Mô hình tuyến tính – logarit .................................................................................................. 230
5.4.5 Mô hình nghịch đảo ................................................................................................................. 232
5.4.6 Mô hình đa thức ....................................................................................................................... 233
Chương 6: Mô hình hồi quy bội................................................................................................................... 235
6.1 Thực hiện hồi quy bội trong R và khoảng tin cậy cho các hệ số ................................................ 235
6.2 Khoảng tin cậy cho một biểu thức của hệ số hồi quy .................................................................... 236
6.3 Kiểm định Wald về sự ràng buộc của các hệ số hồi quy............................................................... 237
6.4 Kiểm định F về việc đồng thời bằng không của nhiều hệ số hồi quy....................................... 238
6.5 Mối liên hệ hình chữ U ngược giữa giáo dục và mức lương....................................................... 240
6.6 hồi quy chuẩn hóa và vấn đề so sánh tác động của các biến độc lập ....................................... 241
6.7 Kiểm định LM, LR trong trường hợp kích cỡ mẫu là lớn ............................................................ 242
6.8 Gợi ý trả lời một sô bài tập chương 2 thuộc cuốn giáo trình của NEU.................................... 245
Chương 7: Các mô hình hồi quy biến giả ................................................................................................. 253
7.1 Bản chất của biến giả và các mô hình hồi quy ANOVA .................................................................. 253
7.1.1 mô hình ANOVA với chỉ một biến giải thích là biến giả duy nhất................................... 253
7.1.2 mô hình ANOVA với hai biến giả trở lên ............................................................................. 256
7.1.3 mô hình ANOVA có sự tương tác của các biến giả ............................................................. 257
7.2. Mô hình có chứa cả biến giả lẫn biến định lượng – mô hình ANCOVA................................... 258
7.2.1 Mô hình ANCOVA không có sự tương tác giữa các biến ..................................................... 258
7.2.2 Mô hình ANCOVA có sự tương tác giữa các biến ............................................................... 259
7.2.3 Vai trò của biến định tính và kiểm định Chow ................................................................... 259
7.2.4 Sử dụng biến định tính thay thế cho kiểm định Chow ..................................................... 260
7.3. Biến định tính có nhiều phạm trù ....................................................................................................... 263
7.4. Hồi quy riêng lẻ cho từng nhóm .......................................................................................................... 265

Nguyễn Chí Dũng http://rpubs.com/chidungkt


14

7.5 Vấn đề gán giá trị cho biến giả .............................................................................................................. 268
7.6 Sử dụng biến định tính cho hồi quy từng khúc và phân tích mùa vụ ...................................... 270
7.2.1 Hồi quy từng khúc .................................................................................................................... 270
6.7.1 Tính chất mùa vụ trong phân tích kinh tế sử dụng biến định tính................................... 272
Chương 8: Hiện tượng đa cộng tuyến và cách xử lý đa cộng tuyến ............................................... 275
8.1 Hiện tượng đa cộng tuyến ...................................................................................................................... 275
8.2 Một ví dụ minh họa hiện tượng đa cộng tuyến ............................................................................... 277
8.3 Xử lý hiện tượng đa cộng tuyến bằng bỏ biến số căn cứ vào tiêu chí Cp của Mallows...... 282
8.4 Xử lý hiện tượng đa cộng tuyến bằng phân tích thành phần chính PCA ................................ 289
8.5 Lựa chọn số lượng biến căn cứ vào các tiêu chuẩn thông tin BIC ........................................... 292
Chương 9: Phương sai sai số thay đổi trong mô hình hồi quy.......................................................... 296
9.1 Phương sai sai số thay đổi và hậu quả ............................................................................................... 296
9.2 Chẩn đoán phương sai sai số thay đổi................................................................................................ 297
9.2.1 Các phương pháp không chính thức.................................................................................... 297
9.2.1.1 Căn cứ vào bản chất của các biến số kinh tế ................................................................. 297
9.2.1.2 Căn cứ vào đồ thị phần dư ............................................................................................... 297
9.2.2 Căn cứ vào các bằng chứng thống kê chính thức .............................................................. 298
9.2.2.1 Kiểm định Park .................................................................................................................. 298
9.2.2.2 Kiểm định Glejser .............................................................................................................. 301
9.2.2.3 Kiểm định Goldfeld - Quandt ........................................................................................... 302
9.2.2.4 Kiểm định do Breusch – Pagan đề xuất dựa trên kiểm định F ................................... 303
9.2.2.5 Kiểm định White ................................................................................................................ 306
9.2.2.6 Kiểm định Koenker - Basett ............................................................................................. 307
9.3 Một số cách khác phục phương sai sai số thay đổi ........................................................................ 308
9.3.1 Phương pháp bình phương nhỏ nhất có trọng số và đổi biến số ................................... 308
9.3.2 Sử dụng biến đổi Box – Cox và Yeo-Johnson....................................................................... 311
Chương 10: Lỗi định dạng và lựa chọn mô hình .................................................................................... 315
10.1 Các tiêu chuẩn lựa chọn mô hình ...................................................................................................... 315
10.2 Các loại lỗi mô hình ................................................................................................................................ 315
10.3 Bỏ sót biến quan trọng .......................................................................................................................... 316
10.3.1 Các hậu quả của việc bỏ sót biến quan trọng ................................................................... 316
10.3.2 Kiểm định Wald ..................................................................................................................... 316
10.3.3 Kiểm định F ............................................................................................................................ 319
10.3.4 Kiểm định Ramsey RESET ................................................................................................... 319

Nguyễn Chí Dũng http://rpubs.com/chidungkt


15

10.3.5 Kiểm định Lagrange Multiplier .......................................................................................... 321


10.4 Thêm biến không cần thiết .................................................................................................................. 323
10.4.1 Các hậu quả của thêm biến không cần thiết..................................................................... 323
10.4.2 Các kiểm định......................................................................................................................... 323
10.5 Dạng hàm sai ............................................................................................................................................ 323
10.5.1 Kiểm định Koop ..................................................................................................................... 323
10.5.2 Ramsey Test ........................................................................................................................... 325
10.5.3 Davidson – MacKinnon Test ................................................................................................ 327
10.6 Lỗi đo lường .............................................................................................................................................. 329
10.7 Lỗi do các quan sát bất thường, đòn bẩy cao, quan sát gây ảnh hưởng .............................. 329
Chương 11: Hồi quy với biến công cụ và hồi quy hai giai đoạn 2SLS ............................................. 335
11.1 Nguyên nhân của việc sử dụng biến công cụ cho mô hình hồi quy ....................................... 335
11.2 Sử dụng đồng thời nhiều biến công cụ cho một biến số............................................................ 338
11.3 Kiểm định biến công cụ yếu, kiểm định Wu-Hausman và Sargan ......................................... 339
11.4 Hậu quả của việc sử dụng biến công cụ yếu .................................................................................. 340
11.5 Ước lượng bình phương nhỏ nhất hai giai đoạn 2SLS .............................................................. 342
Chương 12: Phân tích dữ liệu bảng (Panel Data).................................................................................. 345
12.1 Giới thiệu về dữ liệu bảng.................................................................................................................... 345
12.2 Giới thiệu bộ số liệu sử dụng và package cần thiết cho phân tích ......................................... 346
12.3 Phân tích dữ liệu mảng cho mô hình nghiên cứu ........................................................................ 348
12.3.1 Hồi quy gộp (Pooled OLS) .................................................................................................... 348
12.3.2 Mô hình tác động cố định biến giả SLDV và kiểm định gộp ........................................... 350
12.3.3 Mô hình tác động cố định không có biến giả .................................................................... 354
12.3.4 Mô hình tác động ngẫu nhiên một chiều ........................................................................... 356
10.3.5 Mô hình tác động ngẫu nhiên hai chiều ............................................................................ 360
12.4 Một số kiểm định lựa chọn và chẩn đoán lỗi của mô hình ....................................................... 361
12.4.1 Kiểm định lựa chọn giữa FEM , Pooled OLS và REM ....................................................... 361
12.4.2 Kiểm định Breusch-Pagan cho lựa chọn giữa REM và Pooled OLS .............................. 363
12.4.3 Một số kiểm định khác chẩn đoán lỗi mô hình sử dụng dữ liệu mảng ....................... 364
12.4.3.1 Kiểm định tương quan phần dư giữa các cá thể ....................................................... 364
12.4.3.2 Kiểm định tương quan chuỗi cho FEM, REM ............................................................... 364
12.4.3.3 Kiểm định phương sai sai số thay đổi cho FEM .......................................................... 365
12.5 Một số phân tích hình ảnh – đồ thị cho dữ liệu bảng .................................................................. 366
12.6 Một số lưu ý về định dạng dữ liệu và công thức cho mô hình ................................................. 368

Nguyễn Chí Dũng http://rpubs.com/chidungkt


16

12.7 Một số mô hình nâng cao cho phân tích dữ liệu mảng ............................................................... 370
12.7.1 Sử dụng biến công cụ ............................................................................................................ 370
12.7.2 Ước lượng Hausman – Taylor ............................................................................................ 375
12.7.3 Phương pháp moment tổng quát GMM............................................................................. 377
12.7.4 Ước lượng FGLS.................................................................................................................... 378
12.8 Vài kết luận cuối cùng về phân tích dữ liệu mảng ....................................................................... 379
Chương 13: Các mô hình với biến phụ thuộc là rời rạc ...................................................................... 380
13.1 Mô hình xác suất tuyến tính LPM ...................................................................................................... 380
13.2 Mô hình Logistic và một số tiêu chí đánh giá ................................................................................ 381
13.2.1 Mô hình Logistic ..................................................................................................................... 381
13.2.2 Một số tiêu chí đánh giá chất lượng của mô hình Logistic .............................................. 393
13.2.2.1 Kiểm định Hosmer-Lemeshow ...................................................................................... 393
13.2.2.2 Các tiêu chí khác đo lường khả năng phân loại của mô hình .................................. 394
13.3 Mô hình Logistic đa cấp độ .................................................................................................................. 398
13.4 Mô hình Probit ......................................................................................................................................... 402
13.5 So sánh Probit và Logistic theo tiêu chí AUC ................................................................................. 405
13.6 Một vài nhận xét về chương 10 sách giáo trình ........................................................................... 407
13.7 Ứng dụng trong nghiên cứu của mô hình Logit và Probit và một số mô hình phân loại
khác cho xếp hạng tín dụng........................................................................................................................... 409
13.8 Lựa chọn mô hình phù hợp cho bài toán phân loại – xếp hạng hồ sơ tín dụng............... 417
13.9 Mô hình cây phân loại và so sánh với mô hình Logistic ............................................................ 419
13.9.1 Giới thiệu về mô hình cây phân loại .................................................................................... 419
13.9.2 So sánh mô hình cây phân loại và Logistic dựa trên hậu quả kinh tế của việc sử dụng
.............................................................................................................................................................. 422
Chương 14: Mô hình có biến bị kiểm duyệt: Tobit và hồi quy Poisson ......................................... 431
14.1 Mô hình Tobit ........................................................................................................................................... 431
14.2 Hồi quy Poisson ....................................................................................................................................... 433
Chương 15: Phân tích nhân tố khám phá EFA ........................................................................................ 436
15.1 Mô tả số liệu và các gói cần thiết cho phân tích ............................................................................ 436
15.2 Các phân tích sơ bộ cần thiết .............................................................................................................. 437
15.2.1 Phân tích tương quan ........................................................................................................... 437
15.2.2 Phân tích một số thống kê khác về các câu hỏi .................................................................. 438
15.3 Kiểm định KMO và Bartlett.................................................................................................................. 439
15.3.1 Kiểm định KMO ....................................................................................................................... 439

Nguyễn Chí Dũng http://rpubs.com/chidungkt


17

15.3.2 Kiểm định Bartlett ................................................................................................................. 440


15.4 Số lượng các nhân tố chính rút ra ..................................................................................................... 440
15.5 Các biến cấu thành nhân tố, đặt tên cho nhân tố và kiểm định Cronbach Alpha ............. 442
15.6 Mini Project: Hình ảnh hóa dữ liệu sử dụng thang đo Likert ................................................. 446
15.7 Về xu hướng sử dụng phân tích EFA trong nghiên cứu hiện nay........................................... 454

Nguyễn Chí Dũng http://rpubs.com/chidungkt


18

Chương 1: R với tư cách một công cụ nghiên cứu kinh tế lượng

Chương này chúng ta sẽ tìm hiểu về R với tư cách là một phần mềm tính toán thống kê – kinh tế lượng
kiêm ngôn ngữ lập trình cũng như cách cài đặt R và một số Packages (gói) cần thiết cho nghiên cứu
thống kê – kinh tế lượng.

1.1 Tổng quan về R


Động lực ra đời của R khá đơn giản. Vào khoảng năm 1993 Ross Ihaka và Robert Gentleman ở
University of Auckland (New Zealand) nhận thấy rằng các phần mềm thống kê thương mại sử dụng
cho các tính toán thống kê vào thời điểm ấy là còn đắt đỏ và quan trọng hơn là không phù hợp và chưa
linh hoạt cho cả mục đích giảng dạy thống kê cũng như một số tình huống công việc. Hai ông đã quyết
định lựa chọn ngôn ngữ S được phát triển bởi Bell Laboratories với nỗ lực viết một phần mềm thống
kê mới. Lí do lựa chọn S có lẽ là do sự thành công của S-PLUS – một phần mềm thống kê cũng dựa
trên ngôn ngữ S được phát triển những năm 80 và đến thời điểm đó đã được sử dụng phổ biến. Tuy
nhiên người nhìn thấy tiềm năng và sức mạnh của R nếu như mã nguồn (R code) của nó được công
khai với tư cách là một phần mềm miễn phí chính là Martin Maechler. Được thuyết phục bởi Maechler,
Ross Ihaka và Robert Gentleman đã quyết định rằng R là miễn phí cho tất cả người sử dụng vào năm
1995. Kể từ thời điểm đó, R được đón nhận và ngày càng trở nên mạnh mẽ vì nó được phát triển bởi
một cộng đồng rộng lớn những chuyên gia về phân tích dữ liệu mà trước tiên là các nhà thống kê và
kinh tế lượng. Đến thời điểm hiện tại thì R đã là một công cụ phân tích dữ liệu đa năng không chỉ sử
dụng cho thống kê mà còn là công cụ của Data Mining, Machine Learning, và Big Data. Với tư cách là
một công cụ cho nghiên cứu thống kê – kinh tế lượng, R ngày càng trở nên phổ biến và được giảng
dạy ở hầu hết các trường đại học lớn Princeton, Yale, University of California at Berkeley, University
of California at Los Angeles, Stanford, Havard, MIT.. ở Hoa Kì và Cambridge ở Anh.

Khoảng năm 2004, TS Nguyễn Văn Tuấn có lẽ là người Việt Nam đầu tiên viết về R khi giới thiệu tập
tài liệu về R (hồi đó là hơn 100 trang) qua blog của mình. Hiện tài liệu này đã trở thành một cuốn sách
dày hơn 500 trang được in bởi nhà xuất bản thành phố Hồ Chính Minh (cuối năm 2015). Tuy nhiên,
tác giả là một nhà nghiên cứu Y Học nên cuốn sách này là thuộc Biostatistics (thống kê Y – Sinh) nên
có thể chưa phù hợp lắm nhu cầu của người học và nghiên cứu các vấn đề kinh tế.

Với mục đích nghiên cứu thống kê – kinh tế lượng, R có thể thực hiện được tất cả các phân tích mà
các phần mềm thống kê thương mại như Eviews, SPSS – AMOS, STATA, SAS có thể làm. Và trong nhiều
tình huống còn làm tốt hơn. Chẳng hạn, nếu phân tích dữ liệu mảng thì Eviews có khả năng hạn chế
và kém hơn so với Stata. Nhưng nếu là nghiên cứu dùng đến thống kê đa biến, thống kê nhiều chiều
như phân tích nhân tố khám phá EFA, CFA, phân tích đường dẫn (Path Analysis)… thì bạn có xu hướng
dùng SPSS – AMOS hay Stata vì nó phù hợp hơn. Nhưng với R bạn chẳng cần lựa chọn gì cả. Nó thực
hiện được tất cả các phân tích đó, kể các các phân tích phức tạp cho dữ liệu chéo, dữ liệu mảng, đến
dữ liệu chuỗi thời gian và dữ liệu tần số cao (High Frequency Data) vốn phổ biến trong nghiên cứu
tài chính.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


19

Ngoài ra, với tư cách là một ngôn ngữ lập trình hoàn thiện, R cho phép bạn xử lý những phân tích một
cách linh hoạt hoặc thiết kê những hàm, những chương trình cho phép bạn xử lí một vấn đề phân tích
cụ thể nào đó và có thể chia sẻ với người khác.

Việc học và làm chủ được một công cụ phân tích số liệu mạnh như R cho thống kê – kinh tế lượng là
một công việc không hề khó. Điều này tôi có thể khẳng định chắc chắn. Thứ bạn cần là sự đều đặn
trong thực hành (thường không quá 1 tháng với mỗi ngày học 60 phút). Một khi đã thành thao R ở
một mức độ tối thiểu nào đó chắc chắn bạn chỉ muốn học thêm nhiều về R.

1.2 Cài đặt R, Rstudio và các Packages cần thiết


Phần này giới thiệu cách thức cài đặt R, Rstudio cho Windown, Mac cũng như một số khía cạnh liên
quan khác.

1.2.1 Cài đặt R cho cho Windows


Để sử dụng R cho các máy dùng hệ điều hành Windows, trước hết các bạn cần cài đặt nó. Tôi kiến
nghị rằng các bạn nên cài đặt phiên bản mới nhất R 3.3.2 (biệt danh của nó là Sincere Pumpkin Patch)
từ địa chỉ sau:

https://cran.r-project.org/bin/windows/base/R-3.3.2-win.exe

Sau khi cài đặt (cả cài và download chưa đến 10 phút), R có giao diện như sau (trích một phần):

Nếu dùng Mac bạn cần cài đặt R cho phiên bản Mac ở mục Download R for (Mac) OS X tại:

https://cran.r-project.org/

Đến đây chúng ta có thể sử dụng trực tiếp R. Chẳng hạn chúng ta thực hiện phép tính 2+2 rồi enter
kết quả là (trích một phần):

Nguyễn Chí Dũng http://rpubs.com/chidungkt


20

Tuy nhiên cách thực thực hiện các phân tích, tính toán trực tiếp trong R như trên là không khuyến
khích. Thay vì sử dụng R trực tiếp chúng ta sẽ sử dụng R thông qua Rstudio – một giao diện thân thiện
và có nhiều hỗ trợ hơn. Chúng ta tìm hiểu vấn đề này ở mục ngay sau đây.

1.2.2 Cài đặt Rstudio


Nếu bạn nào từng sử dụng các phần mềm thống kê có môi trường làm việc dạng giao diện cửa sổ
(SPSS là một điển hình) thì khi làm việc với R bạn sẽ cảm thấy khá khó chịu. Thay vì di chuyển và kích
chuột bạn cần phải nhớ các dòng lệnh khi làm việc với R. Chưa hết, nếu bạn gõ sai R cũng không báo
cho bạn biết. Rstudio được ra đời với nhiều mục đích trợ giúp (hay chí ít là làm cho R “gần hơn” với
giao diện cửa sổ - vốn rất dễ sử dụng) khi làm việc với R. Hiện nay Hadley Wickham là Chief Scientist
của Rstudio.

Rstudio có hai phiên bản, trong đó có một phiên bản miễn phí dành cho các máy tính cá nhân. Tuy
thuộc vào dòng máy (dùng Windows hay máy Mac) mà bạn cần cài Rstudio tại:

https://www.rstudio.com/products/rstudio/download/

Khi kích vào link trên bạn nhớ chọn cho mình phiên bản Rstudio phù hợp dưới đây:

Sau khi load và cài đặt (tầm 5 phút) khởi động Rstudio chúng ta có giao diện như sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


21

Giao diện của nó được chia thành 4 phần và phần dưới cùng bên trái chính là nơi chúng ta sẽ gõ các
dòng lệnh. Đến đây bạn có thể trải nghiệm những khả năng của Rstudio. Lúc này các dòng lệnh sẽ là
màu xanh và kết quả hiện lên có chữ màu đen. Hình ảnh (nếu có) sẽ được hiện ở khu vực phía dưới
bên phải của màn hình. Chẳng hạn để tính 2+2 tại cửa sổ lệnh của Rstudio (bên dưới góc trái màn
hình) các bạn gõ 2+2 rồi enter.

Tất nhiên các bạn gõ lệnh trong R và Rstudio thì kết quả luôn luôn như nhau. Nhớ rằng Rstudio là thư
hỗ trợ chúng ta sử dụng R thuận tiện hơn. Ngoài ra Rstudio còn có thể “biến” các phân tích của bạn
thành một bài trên web site. Ví dụ:

http://rpubs.com/chidungkt/185954

Như đã nói, Rstudio là một kiểu môi trường, một kiểu giao diện giúp chúng ta thuận tiện hơn trong
việc sử dụng R. Do vậy, tất cả các phân tích mà chúng ta thực hiện trong tài liệu này sẽ được thực hiện
trong Rstudio. Tất nhiên nếu bạn muốn, bạn có thể sử dụng trực tiếp R. Các bạn cũng cần chú ý rằng
trong tài liệu này, cụm từ “tại cửa sổ lệnh của R” thì hoàn toàn tương đương với cụm từ “tại cửa sổ
lệnh của Rstudio”.

1.2.3 Cài đặt các packages


Ban đầu được phát triển như là một công cụ cho tính toán Thống Kê - Kinh Tế Lượng nhưng theo thời
gian R đã trở thành một công cụ phân tích dữ liệu đa năng. Từ đào mỏ dữ liệu (Data Mining), dữ liệu
lớn (Big Data) trong nhiều lĩnh vực khác nhau (Marketing, Kinh Tế, Tài Chính, Thống kê Y - Sinh,
nghiên cứu Ngôn Ngữ Học) đến cả vẽ bản đồ. Điều này ngụ ý rằng chúng ta không cần đến mọi chức
năng phân tích của nó. Mỗi khi cài đặt R thì chỉ có một số hàm, chẳng hạn hàm mean() để tính trung
bình, là luôn thường trực để chúng ta sử dụng. Tuy nhiên nếu chúng ta cần một phân tích đặc biệt
nào đó như phân tích dữ liệu bảng thì chúng ta cần phải cài đặt một hoặc một số gói (Packages) cần
thiết tương ứng.

Cho đến thời điểm tài liệu này được viết đã có hơn 9000 gói được viết cho R bởi một cộng đồng rộng
lớn thuộc giới phân tích dữ liệu – bao gồm cả các nhà thống kê, kinh tế lượng và giới phân tích dữ liệu
chuyên nghiệp. Chúng ta tạm hiểu một Package của R là một tập hợp các chương trình, hàm được viết
sẵn để xử lý một nhóm các phân tích hay một nhóm các bài toán nào đó. Trong nhiều trường hợp, các
Packages này có thể bao gồm cả dữ liệu đi kèm. Ví dụ gói AER – một gói trong số các gói mà chúng sử
dụng trong tập tài liệu này có chứa bộ dữ liệu CPS1988 – một bộ dữ liệu tương tự như VHLSS của Việt
Nam.

Đối với nghiên cứu thống kê – kinh tế lượng, dưới đây là một số gói quan trọng mà chúng ta cần đến:

Tên gói Công dụng

xlsx Đọc data đuôi .xlsx (file Excel)

gdata Đọc data đuôi .xls (file Excel)

foreign Đọc data đuôi .sav (file SPSS), .dta (file Stata)

hexView Đọc data đuôi .wf1 và .WF1(file Eviews)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


22

AER Gói thực hiện nhiều phân tích kinh tế lượng cơ bản

ggplot2 Vẽ Graph với chất lượng hình ảnh cao.

Để cài đặt một gói nào đó, ví dụ gói gdata chẳng hạn, các bạn làm như sau. Tại cửa sổ lệnh của R các
bạn gõ:

install.packages("gdata")

Tuy nhiên cách cài đặt như các bạn vừa thực hiện ở trên là không khuyến khích. Nguyên nhân là một
số gói của R để sử dụng được còn phụ thuộc vào một hoặc một số gói khác. Do vậy an toàn nhất là cài
đặt với lựa chọn dependencies = TRUE với hàm ý rằng chúng ta sẽ cài đặt luôn tất cả các gói phụ
thuộc:

install.packages("gdata", dependencies = TRUE)

Kể từ đây, khi cài đặt bất kì gói nào chúng ta đều nên có lựa chọn thêm là dependencies = TRUE dù
rằng có thể có gói nào đó không phụ thuộc vào bất kì gói nào. Nghĩa là chúng ta đang thực hiện một
chiến thuật kiểu “Giết nhầm còn hơn bỏ sót”.

Khi nó rằng “một số gói quan trọng” nghĩa là vẫn còn một số gói “râu ria” nữa. Đương nhiên sau một
thời gian thực hành các bạn sẽ thành thạo việc xác định gói nào cần và tự biết cách tự cài đặt cũng
như sử dụng chúng. Trước mắt, các bạn nên cài đặt tất cả các gói mà tôi liệt kê ở trên.

Cách thức cài đặt một gói như trên chỉ áp dụng cho những gói có trên CRAN – tạm hiểu là một “kho
chứa” các gói của R và được lưu ở một máy chủ nào đó. Có một số gói đang được phát triển hoặc đã
viết xong rồi nhưng tác giả chưa “công bố” chính thức trên CRAN mà lại lưu tại tài khoản của cá nhân
họ trên github (một loại tài khoản lưu trữ tài liệu và chương trình) thì cách cài đặt sẽ khác bằng lệnh
install_github() như ở mục 8.4 mà chúng ta sẽ nghiên cứu cách cài đặt sau.

1.2.4 Yêu cầu một Package cụ thể trình diện


Yêu cầu một gói trình diện để sử dụng trong R quan trọng đến mức tôi phải để riêng một mục riêng.
Nếu có một công việc nào đó bạn yêu cầu R thực hiện lệnh ggplot() nhưng bạn quên không gọi
package tương ứng để thực hiện công việc ấy thì R sẽ báo lỗi kiểu như sau:

Lí do là vì ggplot là một hàm (lệnh) thuộc gói ggplot2 – một gói mà bạn đã cài đặt nhưng bạn quên
yêu cầu gói này trình diện. Để gọi gói này trình diện, bạn thực hiện theo câu lệnh sau:

library(ggplot2)

Các bạn thực hiện theo cú pháp này: tên gói bạn muốn gọi luôn để trong dấu ( ) của câu lệnh trên.
Điều này áp dụng cho mọi gói trong R. Do vậy khi yêu cầu một gói trình diện theo cú pháp trên mà
gặp thông báo kiểu như sau:

Error in library(XXX) : there is no package called ‘XXX’

Nguyễn Chí Dũng http://rpubs.com/chidungkt


23

Thì có nghĩa là bạn chưa cài đặt gói XXX này. Lúc đó, quay trở lại mục 1.2.3 để xem lại cách cài đặt gói
có tên XXX.

1.2.5 Sử dụng Rmarkdown để trao đổi, công bố kết quả trên Internet với Rpub
Rstudio hỗ trợ chúng ta công bố các phân tích trên mạng Internet. Đây là một ví dụ của việc công bố
các phân tích trên mạng: http://rpubs.com/chidungkt/215596 .

Việc công bố trên mạng như trên sẽ tạo thuận lợi cho việc trao đổi học hỏi lẫn nhau. Để sử dụng chức
năng này chúng ta sử dụng một ứng dụng của Rstudio thường gọi là Rmarkdown. Rmarkdown là một
hỗ trợ rất mạnh của R. Nó cho phép chúng ta xuất kết quả phân tích, code hoặc cả hai ra ít nhất 4 định
dạng: (1) website để công bố trên mạng Internet, (2) định dạng word, (3) định dạng pdf, và (4) mẫu
trình bày (template) của hầu hết các tạp chí có trên ScienceDirect.

Để sử dụng Rstudio chúng ta cài đặt hai gói là rmarkdown và knitr:

install.packages("rmarkdown", dependencies = TRUE)


install.packages("knitr", dependencies = TRUE)

Đây là hai gói đặc biệt vì khi cần sử dụng nó không cần phải gõ lệnh library() như thường thấy. Sau
khi cài đặt xong, để công bố code cũng như kết quả phân tích ta làm theo các bước sau:

Sau khi chọn R Markdown.. (khoanh vùng viền đỏ) chúng ta có giao diện kiểu như sau (chú ý rằng
giao diện của bạn có thể không hoàn toàn giống như vậy ở một số chi tiết phụ):

Nguyễn Chí Dũng http://rpubs.com/chidungkt


24

Đây là mẫu cơ bản. Chúng ta có thể hiệu chỉnh mẫu theo ý muốn của chúng ta dựa trên mẫu cơ bản
này. Chẳng hạn xóa hoàn toàn khu vực có chữ tiếng Anh và thay bằng câu “Rmarkdown là một ứng
dụng cho phép công bố phân tích trên mạng.” .Hãy quan sát thật kĩ sự khác biệt giữa mẫu cơ bản và
hiệu chỉnh (do chúng ta xóa một số lệnh cũng như tùy chỉnh, gõ mới một số lệnh) dưới đây:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


25

Ở đây khu vực A là khu vực bạn có thể chính sửa. Các khu vực C và D gọi là code chunk – nơi chúng
ta gõ các lệnh của R. Cụ thể ở code chunk C chúng ta đã gõ hai lệnh và data(iris) và summary(iris) còn
code chunk D chỉ có một lệnh là hist(iris$Sepal.Length).

Như vậy phân tích của bạn chỉ có 3 câu lệnh mà thôi. Để xuất kết quả của ba câu lệnh này lên mạng
chúng ta kích vào Knit HTML ↦ Knit to HTML như dưới đây:

Đến bước này R sẽ hỏi lưu một cái gì đó. Bạn cứ lưu đi. Lưu và ấn OK được sản phẩm trung gian như
sau:

Đến đây bạn muốn công bố kết quả phân tích lên mạng Internet thì kích vào cửa sổ Publish ở góc trên
bên phải. Rstudio có thể yêu cầu bạn đăng kí một tài khoản ở bước cuối cùng này. Nếu bạn làm đúng
(có thể cần một chút thời gian thử - sai ) thì bạn sẽ có sản phẩm tương tự như sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


26

http://rpubs.com/chidungkt/228157

Thay vì kích Knit to HTML, nếu bạn muốn xuất ra file word thì kích vào Knit to Word. Thực tế tài
liệu này được viết gần như hoàn toàn trong Rmarkdown.

1.2.6 Cập nhật các phiên bản mới hơn của R


R thường cập nhật và cải tiến nhanh chóng (khoảng 1 quý hay nửa năm một lần). Ví dụ những phân
tích trong tài liệu này là sử dụng R 3.3.2 Muốn cài đặt những phiên bản mới hơn của R, trước hết
chúng ta cài đặt gói installr bằng lệnh install.packages(“installr”). Kế tiếp tại cửa sổ lệnh của
Rstudio thực hiện các lệnh sau để cài đặt các phiên bản mới nhất (nếu có) của R:

library(installr)
setInternet2(TRUE) # Câu lệnh này dành cho mục đích cài các biên bản thấp hơn
3.3.0 của R.Cao hơn thì không cần
installr::updateR() # Cập nhật (cài đặt) phiên bản mới nhất của R.

Trước khi cài đặt (cập nhật) mới các bạn cũng nên xem R bạn đang sử dụng thuộc phiên bản gì bằng
cách gõ version tại cửa sổ của Rstudio. Cá nhân tôi không hứng thú việc cập nhật mới vì nguyên nhân
sau: có nhiều gói vốn sử dụng được ở phiên bản cũ nhưng sẽ không tương thích với phiên bản mới và
do đó bạn cần cài đặt lại – một việc rất tốn thời gian còn hơn cả cài đặt R.

1.3 Trợ giúp từ R


Mục này bạn nên biết để tự trả lời một số tình huống chưa hiểu, thậm chí là khó khăn nếu có khi sử
dụng R với sự trợ giúp của Google dịch (nếu bạn đọc tiếng Anh chưa thạo). Giả sử bạn đã cài đạt gói
lmtest và muốn biết sơ bộ các hàm, lệnh (và mọi thứ cơ bản khác) thuộc một gói này, trong R bạn gõ
đồng thời hai lệnh:

library(lmtest)
help(package = lmtest)

Lúc này chúng ta nhận được các mô tả về các hàm của gói này (trích) xuất hiện góc phải phía dưới
giao diện của Rstudio :

Các gói thường luôn đi kèm với một số bộ dữ liệu nào đó để minh họa các lệnh (hay các hàm của gói).
Để xác định một gói cụ thể, chẳng hạn lmtest, có đi kèm với những bộ số liệu nào các bạn gõ:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


27

data(package = "lmtest")

Sau khi thực hiện câu lệnh này các bạn sẽ thấy góc trái phía trên của Rstudio báo cáo như sau (trích
một phần):

Với vốn tiếng Anh cơ bản các bạn có thể đoán bộ dữ liệu có tên bondyield (thứ 4 từ trên xuống) có
thể là lãi suất của trái phiếu. Để biết nhiều thông tin hơn nữa về bộ dữ liệu này các bạn gõ:

help("bondyield", package = lmtest)

Lúc này góc phải phía dưới của Rstudio hiển thị các thông tin về bộ dữ liệu này như sau (trích một
phần):

Các bạn có thể thấy đây là một chuỗi thời gian đa biến (nhiều biến số) từ quý 1 năm 1961 tới quý 4
năm 1975. Mô tả chi tiết về các biến cũng đi kèm.

Trở lại báo lỗi của R ở mục 1.2.3:

Bất kể khi nào bạn gặp thông báo như trên thì có nghĩa là hầu hết các bạn quên gọi một gói tương ứng
để thực hiện một lệnh (hàm) nào đó. Nếu chúng ta biết rằng lệnh ggplot này thuộc gói ggplot2 thì đến
đây bạn có thể xử một số trở ngại điển hình (chỉ dành cho người học R giai đoạn đầu) thường gặp
bằng cách cài đặt gói ggplot2 như sau (nếu bạn chưa cài đặt):

library(ggplot2)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


28

Khi sử dụng một lệnh nếu chúng ta chưa hiểu rõ lệnh đó có tác dụng gì và áp dụng ra sao, ví dụ với
lệnh tính trung bình cộng (lệnh mean()) chúng ta làm như sau:

?mean()

Lúc này chúng ta sẽ biết rất nhiều thông tin về hàm này kể cả cách sử dụng cũng như ví dụ:

Trong tình huống chúng ta không nhớ cụ thể một hàm nào đó và chỉ biết rằng, chẳng hạn, hàm đó có
cụm kí tự test. Lúc này chúng ta có thể liệt kê tất cả các hàm có cụm kí tự này (trích một phần):

apropos("test")

## [1] ".valueClassTest" "ansari.test"


## [3] "bartlett.test" "binom.test"

Tình huống nếu chúng ta muốn tra cứ chi tiết hơn nữa cách sử dụng, thậm chí là một bài báo nào đó
về sử dụng một hàm cụ thể, chẳng hạn, với lệnh ggplot():

help.search("ggplot")
?mean()

Lúc này bạn sẽ có thông báo kiểu như sau:

Lúc này bạn có thể: (1) xem mã nguồn của nó, (2) tải bản PDF về sử dụng lệnh này – cụ thể là hướng
dẫn vẽ biểu đồ Venn, hoặc (3) vào một số link trên Internet có bài viết về sử dụng lệnh này.

Một tình huống khác bạn hay gặp (thường là các sách..dày cả ngàn trang về R): bạn gõ chính xác tất
cả các câu lệnh nhưng R lại không cho ra kết quả như kì vọng. Trong tình huống này bạn nên rà soát
xem có gói nào bạn chưa cài đặt và yêu cầu R sử dụng hay không.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


29

1.4 Xem danh sách các gói đã cài đặt cũng như số lượng các gói của R
Trong nhiều tình huống số lượng các gói mà chúng ta cài đặt là rất nhiều. Lệnh dưới đây cho biết
những gói nào được chúng ta cài đặt (user-installed R packages) – tức là không tính các gói mặc định
được cài đặt kèm khi cài đặt R lần đầu. Trong R chúng ta gõ các lệnh sau (với chú ý chữ viết sau dấu
# là lời giải thích cho lệnh được gõ vào) :

trang <- as.data.frame(installed.packages()[, c(1, 3:4)])


rownames(trang) <- NULL
trang <- trang[is.na(trang$Priority), 1:2, drop = FALSE]
dim(trang) # Lệnh này cho biết tại thời điểm tôi viết tài liệu này, có 261 gó
i được cài đặt.
head(trang) # Liệt kê tên cùng phiên bản của 6 gói đầu tiên.

Để biết hiện có bao nhiêu gói mà chúng ta có thể cài đặt trực tiếp từ CRAN:

trangyeu <- available.packages()


dim(trangyeu) # Cho biết số gói. Tại thời điểm tôi viết tài liệu này là có 93
34 gói – một con số khổng lồ.
head(trangyeu[, c(1, 2)]) Liệt kê tên cùng phiên bản của 6 gói đầu tiên.

Như vậy hiện có 9334 gói mà chúng ta có thể cài đặt. Tất nhiên KHÔNG MỘT AI thành thạo và cần
phải sử dụng đến 9334 gói này. Lưu ý rằng con số này chưa dừng lại và sẽ tăng hàng ngày chứ không
phải hàng tuần. Nên lúc bạn thực hiện các lệnh trên, con số thu được sẽ khác.

1.5 Các quy ước khi sử R cho phân tích


Để thuận lợi trong việc sử dụng tài liệu này chúng ta có một vài quy ước với nhau như sau:

1. Để tất các file dữ liệu vào thư mục KTLR (xem kĩ mục 2.3 của chương 2 về cách tạo thư mục
này).
2. Luôn gõ lệnh setwd("D:/KTLR") sau khi khởi động R để chỉ thị cho R làm việc với thư mục
KTLR.
3. Giải thích cho ý nghĩa dòng lệnh (nếu có) được đặt sau dấu #. Dòng giải thích có thể được đặt
trước hoặc sau một dòng lệnh cụ thể. Dưới đây là một ví dụ về dòng giải thích đặt sau dòng
lệnh:
.
Ở đây head(dung) là lệnh của R còn giải thích cho dòng lệnh này đặt sau dấu # và là “Xem 6
quan sát đầu tiên”.
4. Các bạn có bản mềm của tài liệu này trong tay và điều này có nghĩa là về cơ bản, các bạn có
thể copy lệnh từ tài liệu rồi paste vào R. Trong hầu hết các tình huống R sẽ cho ra kết quả như
mong muốn. Tuy nhiên tôi khuyến cáo không làm thế vì ít nhất hai lí do: (1) một số tình huống,
thao tác copy – paste này không có tác dụng vì phạm một lỗi gọi là typos, và (2) các bạn chẳng
học sử dụng R một cách hiệu quả bằng cách copy – paste như vậy.
5. Các câu lệnh (hay hàm), tên các gói nếu xuất hiện lần đầu sẽ được in đậm. Ví dụ: lệnh library(),
gói ggplot2. Các cụm từ, khái niệm quan trọng, tên các nghiên cứu được in đậm và nghiêng.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


30

1.6 Tổng kết chương mở đầu


Với những người chưa sử dụng R bao giờ thì chương mở đầu này vừa gây cho bạn tò mò, cảm giác bị
thử thách. Đây là chương quan trọng vì nó tạo những cơ sở đầu tiên để bạn học cách sử dụng R một
cách chuyên nghiệp. Chung quy lại, chương này có hai nội dung quan trọng.

Thứ nhất là cài đặt R/Rstudio và các hỗ trợ cần thiết, đặc biệt là cài đặt các gói (packages) cũng như
chỉ thị cho R gọi một gói cụ thể nào đó để sử dụng bằng lệnh library().

Thứ hai là sử dụng Rpub để trao đổi cũng như công bố các phân tích lên Internet.

Cuối cùng, những địa chỉ sau đây được sử dụng để trợ giúp các bạn bằng cách trả lời những thắc mắc
và lỗi (nếu có) của tài liệu:

1. https://www.facebook.com/Econometrics-and-Quantitative-Analysis-
1429972370648696/
2. http://rpubs.com/chidungkt
3. Cứ 6 tháng một lần tài liệu được cập nhật tại địa chỉ:
http://www.mediafire.com/file/3lg8bsfbu6csq8d/KinhTeLuongUngDungVoiR.rar

Chương 2: Môi trường làm việc trong R

Đây là chương mở đầu và là chương tạo những nền tảng đầu tiên cơ bản cho bạn sử dụng R một cách
thành thạo không chỉ cho nghiên cứu kinh tế lượng nói riêng mà còn phân tích dữ liệu nói chung.
Chương này giới thiệu những kĩ năng cốt lõi nhất của việc đọc dữ liệu từ các định dạng khác nhau

Nguyễn Chí Dũng http://rpubs.com/chidungkt


31

(Eviews, SPSS, Stata, Excel), nhập dữ liệu trực tiếp vào R cũng như các cấu trúc dữ liệu data frame và
data_frame. Những kĩ năng biến đổi và quản lí số liệu (gọi chung là Data Manipulation) là trọng tâm
của chương này. Là một chuơng khá dài và bạn nên đầu tư một cách thích đáng.

2.1 Nhập dữ liệu trực tiếp vào R


Để phân tích dữ liệu thứ đầu tiên bạn cần làm là nhập dữ liệu vào R. Bạn có thể nhập dữ liệu trực tiếp
vào R. Để mình họa chúng ta xét bảng số liệu sau:

X2 X3 Y
STT
(Lương) (TN khác) (Chi tiêu)

1 20 16 24.4
2 30 10 31.2
3 28 2 29.2
4 24 0 23.6
5 32 18 36.0
6 36 10 31.4
7 32 16 32.6
8 34 24 36.8
9 24 28 32.8
10 22 20 29.8
11 28 8 30.2
12 30 4 26.8

Để nhập bảng dữ liệu trên gõ các lệnh sau:

luong <- c(20, 30, 28, 24, 32, 36, 32, 34, 24, 22, 28, 30)
thunhapkhac <- c(16, 10, 2, 0, 18, 10, 16, 24, 28, 20, 8, 4)
chitieu <- c(24.4, 31.2, 29.2, 23.6, 36, 31.4, 32.6, 36.8, 32.8, 29.8, 30.2,
26.8)

Ở trên, dấu <- được gọi là dấu gán. Trong Rstudio, để có dấu này gõ tổ hợp phím Alt và – (phím có
dấu trừ). Sau khi nhập bộ dữ liệu này các bạn có thể xem lại, chẳng hạn biến có tên luong trong R:

luong

## [1] 20 30 28 24 42 36 32 34 24 22 28 30

2.2 Hiệu chỉnh dữ liệu


Trong tình huống bạn nhập sai một quan sát nào đó, chẳng hạn với biến luong, quan sát cuối cùng
thực tế là 32 nhưng bạn nhập sai thành 30. Để hiệu chỉnh giá trị này các bạn làm như sau trong R:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


32

luong <- edit(luong)

R sẽ ra cửa sổ sau:

Lúc này bạn có thể di chuyển con trỏ đến vị trí 30 cuối cùng và chỉnh thành 32.

Một điểm cần chú ý là các dấu = như các bạn đã sử dụng ở trên có thể thay bằng dấu <- quen thuộc.
Ví dụ, thay vì gõ luong = edit(luong) như trên các bạn có thể thay bằng luong <- edit(luong). Tuy
nhiên dùng đấu = có thể gây một số lỗi khi thực hiện một số lệnh và hàm nên dù tiết kiệm thời gian
thì chúng ta cũng không nên sử dụng kí hiệu này. Trong tài liệu này các bạn sẽ thấy dấu = xuất hiện
khá nhiều. Đây là một thói quen xấu của tôi và do vậy không khuyến khích các bạn học theo.

2.3 Đọc dữ liệu từ file sẵn có ở các định dạng khác nhau, từ các nguồn bên ngoài vào R
R cũng cho phép bạn đọc dữ liệu ở một loạt các định dạng khác nhau từ dữ liệu dạng số đến dữ liệu
văn bản (text) hay thậm chí dữ liệu hình ảnh, từ Internet. Với phạm vi hẹp là nghiên cứu kinh tế lượng,
chúng ta chỉ xem xét cách thực hành để R đọc dữ liệu từ một file sẵn có ở một số định dạng phổ biến
là Excel, Stata, Eviews, SPSS. Mục này cũng trình bày cách thu thập dữ liệu kinh tế vĩ mô cung cấp bởi
World Bank và dữ liệu tài chính trực tiếp trên Internet.

Tại mỗi thời điểm R mặc định chỉ làm việc với một thư mục và luôn mặc định là thư mục Documents.
Chúng ta có thể kiểm tra lại như sau:

getwd()

## [1] "C:/Users/admin/Documents"

Ở đây lệnh getwd() chỉ ra đường dẫn của thư mục hiện thời (là Documents) mà R đang làm việc. Để
thuận lợi trong quản lí và tạo sự thống nhất, chúng ta sẽ chỉ định cho R làm việc với thư mục có tên là
KTLR ở ổ D của máy tính và chúng ta sẽ để toàn bộ các số liệu được sử dụng trong tài liệu này ở thư
mục trên. Có hai cách để tạo ra thư mục này. Một là vào ổ D, dùng con chuột kích chuột phải rồi chọn
New ↦ Folder rồi đặt tên cho thư mục là KTLR. Cách thứ hai (chúng ta sẽ sử dụng cách này trong tài
liệu này) là chúng ta tạo ra thư mục này từ R như sau:

dir.create("D:/KTLR")

Với lệnh này các bạn tạo một folder có tên KTLR ở ổ D. Kế tiếp, bạn chỉ thị cho R làm việc chỉ với foder
này bằng lệnh:

setwd("D:/KTLR")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


33

Chú ý rằng cách thức thiết lập đường dẫn có thể khác so với những gì được trình bày nếu bạn sử dụng
Mac.

2.3.1 Đọc dữ liệu từ file Eviews


Giả sử chúng ta cần đọc dữ liệu có tên ch2vd5.WF1 với tên gọi mới là dung trong R:

setwd("D:/KTLR") # Đặt đường dẫn vì ch2vd5.WF1 ở folder có tên KTLR.


library(hexView) # Gọi gói hexView chuyên dụng đọc file Eviews.
dung <- readEViews("ch2vd5.WF1", as.data.frame = TRUE) # Đọc dữ liệu

R sẽ thông báo một số cảnh báo (warnings) nhưng chúng ta chưa cần quan tâm và tìm hiểu về các
cảnh báo này. Sau khi thực hiện chính xác ba câu lệnh trên, bạn có thể xem qua số liệu này (10 quan
sát đầu tiên):

dung

## CT HHSIZE INTEREST STOCKDIVIDEND TN TNP TS


## 1 944.654 49.7 -10.351 14.91 1035.2 538.9108 5166.8
## 2 966.354 50.4 -4.720 15.12 1090.0 550.9414 5280.8
## 3 993.554 51.3 1.044 15.39 1095.6 584.4252 5607.4
## 4 1059.154 52.2 0.407 15.66 1192.7 600.4736 5759.5
## 5 1075.354 52.3 -5.283 15.69 1227.0 633.2276 6086.1
## 6 1110.654 52.6 -0.277 15.78 1266.8 649.2908 6243.9
## 7 1165.454 53.0 0.561 15.90 1327.5 660.8410 6355.6
## 8 1190.154 54.4 -0.138 16.32 1344.0 706.3342 6797.0
## 9 1278.654 56.7 0.262 17.01 1433.8 746.1540 7172.2
## 10 1317.054 59.2 -0.736 17.76 1502.3 769.0618 7375.2

Đối với dữ liệu hàng chục ngàn (thậm chí hàng trăm ngàn) quan sát với hàng chục biến số thì bạn nên
sử dụng một trong bốn câu lệnh sau:

dim(dung) # Xem số lượng quan sát và số lượng biến số

## [1] 33 7

head(dung) # Xem 6 quan sát đầu tiên

## CT HHSIZE INTEREST STOCKDIVIDEND TN TNP TS


## 1 944.654 49.7 -10.351 14.91 1035.2 538.9108 5166.8
## 2 966.354 50.4 -4.720 15.12 1090.0 550.9414 5280.8
## 3 993.554 51.3 1.044 15.39 1095.6 584.4252 5607.4
## 4 1059.154 52.2 0.407 15.66 1192.7 600.4736 5759.5
## 5 1075.354 52.3 -5.283 15.69 1227.0 633.2276 6086.1
## 6 1110.654 52.6 -0.277 15.78 1266.8 649.2908 6243.9

tail(dung) # Xem 6 quan sát cuối cùng

Nguyễn Chí Dũng http://rpubs.com/chidungkt


34

## CT HHSIZE INTEREST STOCKDIVIDEND TN TNP TS


## 28 2621.954 139.3 -1.043 41.79 3051.9 1361.5204 11868.8
## 29 2679.154 142.3 -3.534 42.69 3108.5 1445.6836 12634.4
b## 30 1068.354 52.3 -5.283 15.69 1225.0 650.2908 6086.1
## 31 1108.654 52.6 -0.277 15.78 1265.8 662.8410 6243.9
## 32 1158.454 53.0 0.561 15.90 1325.5 705.3342 6355.6
## 33 1194.154 54.4 -0.138 16.32 1340.0 740.1540 6797.0

str(dung) # Mô tả chi tiết kiểu biến số của data frame

## 'data.frame': 33 obs. of 7 variables:


## $ CT : num 945 966 994 1059 1075 ...
## $ HHSIZE : num 49.7 50.4 51.3 52.2 52.3 52.6 53 54.4 56.7 59.2 ...
## $ INTEREST : num -10.351 -4.72 1.044 0.407 -5.283 ...
## $ STOCKDIVIDEND: num 14.9 15.1 15.4 15.7 15.7 ...
## $ TN : num 1035 1090 1096 1193 1227 ...
## $ TNP : num 539 551 584 600 633 ...
## $ TS : num 5167 5281 5607 5760 6086 ...

Với lệnh đầu tiên bạn thấy có 33 quan sát và 7 biến số trong bộ dữ liệu này. Còn lệnh thứ hai liệt kê
chỉ một số quan sát đầu tiên. Lệnh thứ ba miêu tả chi tiết hơn các biến số có trong bộ số liệu.

Chúng ta cũng có thể xem chi tiết các biến số theo cách thức tương tự như của Excel:

View(dung)

Chú ý rằng câu lệnh đọc file dữ liệu vào R có thể được gõ dài dòng như sau:

dung <- readEViews("D:/KTLR/ch2vd5.WF1", as.data.frame = TRUE)

Tất nhiên cách gõ lệnh dài dòng như vậy là không cần thiết vì chúng ta đã chỉ định cho R làm việc với
thư mục KTLR rồi nên câu lệnh có thể gõ ngắn lại như bạn có thể thấy.

2.3.2 Đọc dữ liệu từ Stata


Đọc file dữ liệu panel1.dta (đây là file của phần mềm Stata) vào R với tên gọi mới là aoe chúng ta sử
dụng gói foreign:

library(foreign)
aoe <- read.dta("Panel1.dta")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


35

Chú ý rằng không cần dùng lệnh setwd("D:/KTLR") nữa vì đã làm điều này ở mục 2.3.1 (mà nếu có
dùng lại cũng không sao). Các bạn có thể kiểm tra file dữ liệu này:

aoe[1:6, ] # Xem 6 quan sát đầu tiên

## i t C Q PF LF
## 1 1 1 1140640 0.952757 106650 0.534487
## 2 1 2 1215690 0.986757 110307 0.532328
## 3 1 3 1309570 1.091980 110574 0.547736
## 4 1 4 1511530 1.175780 121974 0.540846
## 5 1 5 1676730 1.160170 196606 0.591167
## 6 1 6 1823740 1.173760 265609 0.575417

Với gói foreign, R cũng có thể đọc dữ liệu nếu nó lưu ở một website nào đó. Chẳng hạn, bộ dữ liệu có
tên crime.dta của trung tâm tính toán thống kê IDRE thuộc UCLA (University of California, Los
Angeles) có thể được đọc vào R ở dạng data.frame với tên gọi greek:

greek <- read.dta("http://www.ats.ucla.edu/stat/data/crime.dta")

Lệnh read.dta() ở trên chỉ đọc được các file của Stata từ phiên bản 12 trở xuống. Muốn đọc được các
file Stata phiên bản 13 hoặc 14 (khi tài liệu này được viết thì Stata mới dừng ở phiên bản 14) cần sử
dụng một gói khác là readstata13 (mặc định là bạn đã cài đặt gói này). Dưới đây là R code để đọc bộ
dữ liệu của Stata 13 có tên dung_stata13.dta với lệnh read.stata13():

library(readstata13)
doc_stata13 <- read.dta13("dung_stata13.dta")

Để đọc dữ liệu Stata cũng có thể sử dụng gói haven:

library(haven)
dung_haven <- read_stata("dung_stata13.dta")

Điểm khác biệt ở đây chính là tốc độ. Gói have có tốc độ đọc dữ liệu nhanh và nó hỗ trợ các tính toán
hiệu tốc độ cao. Điều này thực sự ý nghĩa nếu dữ liệu nguyên thủy cần đọc có kích thước lớn.

2.3.3 Đọc dữ liệu từ SPSS


Để đọc dữ liệu của SPSS chúng ta có hai cách: (1) sử dụng gói foreign, hoặc (2) haven. Ví dụ, cần đọc
một file của SPSS có tên chicken.sav vào R với tên gọi lần lượt là aoe1 và aoe2:

# cách 1 (dùng gói foreign)


aoe1 <- read.spss("chicken.sav", to.data.frame = TRUE)
# Cách 2 (dùng gói haven). Có hai hàm của gói này có thể đọc SPSS
aoe2 <- read_spss("chicken.sav")
aoe2 <- read_sav("chicken.sav")

Điểm khác biệt đáng chú ý ở đây là nếu dùng lệnh read.sps() thì các biến định tính (GROUP) được giữ
nguyên dạng kí tự (thuật ngữ của R gọi là factor):

Nguyễn Chí Dũng http://rpubs.com/chidungkt


36

aoe1

## GROUP QUALITY QUANTITY


## 1 Manic Psychosis 5 4
## 2 Manic Psychosis 5 9
## 3 Manic Psychosis 6 10
## 4 Manic Psychosis 7 11
## 5 Manic Psychosis 7 12
## 6 Manic Psychosis 7 13
## 7 Manic Psychosis 7 13
## 8 Manic Psychosis 7 13
## 9 Manic Psychosis 8 16
## 10 Manic Psychosis 8 20
## 11 Sussex Lecturers 2 2
## 12 Sussex Lecturers 4 7
## 13 Sussex Lecturers 5 8
## 14 Sussex Lecturers 7 9
## 15 Sussex Lecturers 8 10
## 16 Sussex Lecturers 10 13
## 17 Sussex Lecturers 10 13
## 18 Sussex Lecturers 10 14
## 19 Sussex Lecturers 10 14
## 20 Sussex Lecturers 10 17

Trong khi đó, nếu dùng gói haven thì biến có bản chất định tính được chuyển thành số. Cụ thể 1 ứng
với Manic Psychosis còn 2 ứng với Sussex Lecturers:

aoe2

## # A tibble: 20 × 3
## GROUP QUALITY QUANTITY
## <dbl+lbl> <dbl> <dbl>
## 1 1 5 4
## 2 1 5 9
## 3 1 6 10
## 4 1 7 11
## 5 1 7 12
## 6 1 7 13
## 7 1 7 13
## 8 1 7 13
## 9 1 8 16
## 10 1 8 20
## 11 2 2 2
## 12 2 4 7
## 13 2 5 8
## 14 2 7 9
## 15 2 8 10
## 16 2 10 13
## 17 2 10 13
## 18 2 10 14

Nguyễn Chí Dũng http://rpubs.com/chidungkt


37

## 19 2 10 14
## 20 2 10 17

Cần lưu ý sự khác biệt này khi thực hiện phân tích.

2.3.4 Đọc dữ liệu của phần mềm SAS


Với file dữ liệu của phần mềm SAS chúng ta sử dụng, ví dụ, hàm read_sas() của gói này để đọc dữ
liệu:

# Đọc dữ liệu của SAS vào R:


credit <- read_sas("hmeq.sas7bdat")
# Xem 6 quan sát đầu:
head(credit)

## # A tibble: 6 x 13
## BAD LOAN MORTDUE VALUE REASON JOB YOJ DEROG DELINQ CLAGE
## <dbl> <dbl> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 1 1100 25860 39025 HomeImp Other 10.5 0 0 94.36667
## 2 1 1300 70053 68400 HomeImp Other 7.0 0 2 121.83333
## 3 1 1500 13500 16700 HomeImp Other 4.0 0 0 149.46667
## 4 1 1500 NA NA NA NA NA NA
## 5 0 1700 97800 112000 HomeImp Office 3.0 0 0 93.33333
## 6 1 1700 30548 40320 HomeImp Other 9.0 0 0 101.46600
## # ... with 3 more variables: NINQ <dbl>, CLNO <dbl>, DEBTINC <dbl>

2.3.5 Đọc dữ liệu từ Excel


File dữ liệu của Excel thường có hai định dạng là .xlsx và .xls. Để đọc các file dữ liệu dạng này vào R
chúng ta có thể sử dụng các hàm của một trong hai gói là readxl hoặc gdata. Một số ví dụ:

library(gdata)
doc_file_xls <- read.xls("Table2_8.xls") # Đọc dữ liệu có tên Table2_8.xls.

Riêng gói readxl có thể đọc cả định dạng xlsx lẫn xls:

library(readxl)
# Đọc xls
doc_xls <- read_excel("Table2_8.xls")
# Đọc xlsx
doc_xlsx <- read_excel("luong.xlsx", sheet = 1)

Lợi thế của sử dụng gói readxl là tốc độ đọc dữ liệu nhanh gấp 10 lần. Các file xlsx có thể có nhiều
bảng (sheet) và do đó muốn chỉ thị R đọc chính xác sheet nào thì cần chỉ thị rõ. Trong trường hợp
trên, sheet = 1 có nghĩa là sheet 1 thuộc file có tên luong.xlsx.

2.3.6 Đọc dữ liệu định dạng txt


Đọc dữ liệu từ file có đuôi .txt vốn là một chức năng ban đầu của R khi nó được xây dựng nên chúng
ta không cần cài đặt gói nào cả. Giả sử ta có dữ liệu tên là luong.txt ở màn hình rồi thì chỉ thị cho R
đọc file này và gán nó với cái tên mới persian bằng câu lệnh:

persian <- read.table("luong.txt", header = TRUE, row.names = 1)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


38

2.3.7 Đọc dữ liệu định dạng csv


Với file dữ liệu có đuôi csv có tên scholarly_impact_2012.4.9.csv chúng ta có thể yêu cầu R đọc file
này với tên mới là hello (dữ liệu này sẽ được sử dụng lần nữa ở chương 3):

hello <- read.csv("scholarly_impact_2012.4.9.csv", header = TRUE)

Nếu file đuôi csv có kích thước lớn, sử dụng lệnh read_csv() của gói readr có thể tăng tốc độ đọc dữ
liệu lên chừng 10 lần:

library(readr)
hello <- read_csv("scholarly_impact_2012.4.9.csv")

Chú ý rằng nếu sử dụng lệnh read_csv thì ta không cần sử dụng lựa chọn header=TRUE. Với các dữ
liệu có kích thước rất lớn chúng ta nên sử dụng lệnh fread() như được trình bày ở mục 2.3.11.

2.3.8 Đọc nhiều file dữ liệu cùng một lúc


Trong nhiều tình huống chúng ta cần đọc nhiều file dữ liệu cùng một lúc, chẳng hạn, chừng 360 file
dữ liệu tài chính của 360 công ti niêm yết trên sàn HOSE. Rõ ràng chỉ thị cho R đọc từng file là một
cách làm nhàm chán. Với mục đích minh họa, giả sử cần đọc dữ liệu tài chính của hai mã AAA và AAM
vào R (là các file csv), trước hết lấy dữ liệu này tại địa chỉ http://www.cophieu68.vn/export.php. Khi
kích vào địa chỉ trên chúng ta có:

Download hai file dữ liệu về AAA và AAM và để chúng vào một folder có tên cophieu chứa trong folder
KTLR mà chúng ta đã biết. Dưới đây là R code để đọc hai file dữ liệu tài chính về AAA và AAM đồng
thời:

path <- dir("D:/KTLR/cophieu", full.names = TRUE) # Đặt đường dẫn.


path # Xem chi tiết đường dẫn.

## [1] "D:/KTLR/cophieu/excel_aaa.csv" "D:/KTLR/cophieu/excel_aam.csv"

data <- lapply(path, read.csv) # Đọc tất cả dữ liệu cùng lúc.


str(data) # Xem dữ liệu được đọc thuộc loại gì.

## List of 2
## $ :'data.frame': 1569 obs. of 14 variables:
## ..$ X.Ticker. : Factor w/ 1 level "AAA": 1 1 1 1 1 1 1 1 1 1 ...

Nguyễn Chí Dũng http://rpubs.com/chidungkt


39

Ở đây có một điểm cần chú ý là lúc này data không phải data frame quen thuộc mà nó là một list (thể
hiện bằng dòng chữ List of 2 ) chứa cả hai data frame. Data frame thứ nhất ứng với AAA còn data
frame thứ hai ứng với AAM. Nếu cần phân tích riêng cho từng mã cổ phiếu có thể tách các data frame
này ra như sau:

aaa <- data[[1]] # Data frame này ứng với mã AAA


aam <- data[[2]] # Data frame này ứng với mã AAB

Đương nhiên hai data frame này có biến số trùng nhau (hiển thị một phần):

names(aaa)

## [1] "X.Ticker." "X.DTYYYYMMDD." "X.OpenFixed." "X.HighFixed."


names(aam)

## [1] "X.Ticker." "X.DTYYYYMMDD." "X.OpenFixed." "X.HighFixed."


head(aaa)

## X.Ticker. X.DTYYYYMMDD. X.OpenFixed. X.HighFixed. X.LowFixed.


## 1 AAA 20161028 29.6 29.8 29.3
## 2 AAA 20161027 29.7 30.0 29.2
## 3 AAA 20161026 29.3 29.7 29.0

Nếu muốn hợp nhất hai data frame ứng với hai cổ phiếu ở trên thành một data frame duy nhất với
tên là love3 nhưng đồng thời chỉ chọn ra các biến là mã cổ phiếu, giá mở cửa và giá cao nhất:

love <- lapply(data, function(df) df[,c("X.Ticker.", "X.Open.", "X.High.")])


love3 <- do.call("rbind", love)
dim(love3)

## [1] 3265 3

Có 3265 quan sát ở love3 và chúng chính là tổng của 1569 và 1696 – số lượng các quan sát ứng với
mã AAA và AAM tính đến thời điểm tài liệu này được viết:

table(love3$X.Ticker.)

##
## AAA AAM
## 1569 1696

Tên biến nên được đổi lại cho dễ hiểu với người đọc phổ thông như sau:

names(love3) <- c("Ma_CK", "Gia_mocua", "Gia_caonhat")


head(love3)

## Ma_CK Gia_mocua Gia_caonhat


## 1 AAA 29.6 29.8
## 2 AAA 29.7 30.0
## 3 AAA 29.3 29.7

Nguyễn Chí Dũng http://rpubs.com/chidungkt


40

Có thể áp dụng cách thức tương tự cho việc đọc nhiều file dữ liệu cùng một lúc thuộc các đinh dạng
khác. Ví dụ, nếu chúng ta có 1000 file Stata 13 và tất cả có đuôi là .dta thì trước hết chúng ta cần gọi
gói readsata13 bằng lệnh library(readstata13) đồng thời thay read.csv bằng read.dta13 ở câu lệnh
data <- lapply(path, read.csv).

Trong trường hợp chúng ta muốn lấy tất cả các cột biến thì làm như sau:

love4 <- do.call("rbind", data)


dim(love4)

## [1] 3265 3

Có thể thực hiện việc đổi tên cho cột biến tương tự như trên cho data frame có tên love4 hoặc theo
một số cách khác được trình bày ở mục 2.4 hoặc 2.4.

2.3.9 Đọc dữ liệu được cung cấp bởi World Bank với gói WDI
R có một lợi thế nữa là nó có thể trực tiếp thu thập dữ liệu được cung cấp bởi nhiều tổ chức, các cơ
quan thống kê hay các tổ chức chuyên cung cấp số liệu từ Internet. Mục này chỉ giới thiệu một trong
số các khả năng đó của R là thu thập dữ liệu kinh tế - xã hội từ ngân hàng thế giới WB (World Bank).

2.3.9.1 Giới thiệu về các số liệu được cung cấp bởi WB


Trong nhiều nghiên cứu , nhất là các nghiên cứu Vĩ Mô thì việc lấy được các dữ liệu vĩ mô về nền kinh
tế là rất quan trọng. Một trong các nguồn tin cậy mà chúng ta có thể khai thác là bộ gồm 7145 chuỗi
số liệu theo thời gian – thường được gọi là bộ Chỉ Số Phát Triển Thế Giới WDI (viết tắt của cụm từ
World Development Indicator) - được Ngân Hàng Thế Giới (WB) cung cấp cho 200 quốc gia và vùng
lãnh thổ. Các chuỗi dữ liệu này được phân thành 20 nhóm (gọi là Topics) như sau:

(Nguồn: http://datacatalog.worldbank.org )

Sở dĩ có 20 nhóm dữ liệu này nhưng lại có tới 16000 chuỗi dữ liệu khác nhau là bởi vì mỗi một nhóm
này lại được phân thành các nhóm nhỏ hơn (gọi là SubTopic). Ví dụ, chúng ta xét 7 chuỗi dầu tiên:

(Nguồn: http://data.worldbank.org/sites/default/files/WDI_April2013_CETS.xls)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


41

Ở đây các bạn cần chú ý đến mã của chuỗi dữ liệu ở cột có tên Series Code. Ví dụ mã AG.AGR.TRAC.NO
có nghĩa là số đầu máy kéo nông nghiệp. Các bạn cũng có thể thấy rằng 7 chuỗi chỉ số này đều thuộc
nhóm Environment nên nó có cùng cụm kí tự AG ở đầu. Việc tìm hiểu chi tiết các thức WB kí hiệu cho
các chuỗi chỉ số các bạn có thể tham khảo tại:

https://datahelpdesk.worldbank.org/knowledgebase/articles/201175-how-does-the-world-bank-
code-its-indicators

Để lấy chính xác các dữ liệu cho các nghiên cứu vĩ mô chúng ta trước hết cần lấy chính xác các mã số
liệu. Ngoài ra chúng ta cũng cần biết chính xác mã ISO-2 của các quốc gia được cung cấp ở cột A2 dưới
đây (trích):

(Nguồn: http://www.vas.com/Tnotes/Country%20Codes.htm)

Để lấy được một (hay một nhóm) các chỉ số cho một (hay một nhóm) các quốc gia thì chúng ta cần
hiểu rõ cách tra chỉ số cần lấy cũng như mã ISO-2 của từng nước. Với R chúng ta có thể dễ dàng lấy
những số liệu từ WB cũng như thực hiện nhiều phân tích khác nhau với sự trợ giúp của gói WDI được
viết bởi Vincent Arel-Bundock (University of Michigan).

2.3.9.2 Lấy các dữ liệu cung cấp bởi WB vào R với gói WDI
Chúng ta cần tìm hiểu các chỉ số (kí hiệu cũng như miêu tả) có thể lấy bằng lệnh WDIcache():

# Gọi gói WDI:


library(WDI)
d <- WDIcache()
d1 <- data.frame(d$series)
d2 <- data.frame(d$country)

Ở đây d1 là danh sách (mà thực chất là một data frame – một khái niệm mà chúng ta sẽ biết rõ hơn ở
các mục sau) các chỉ số có thể lấy và có hai cột chúng ta cần chú ý. Cột thứ nhất là kí hiệu các chỉ số
(cột indicator). Cột thứ hai là miêu tả ngắn về chỉ số đó (cột name). Chúng ta có thể thấy điều này
bằng xem 6 quan sát đầu tiên trong danh sách (trích một phần):
head(d1)

## indicator
## 1 ZINC
## 2 XGDP.56.FSGOV.FDINSTADM.FFD
## 3 XGDP.23.FSGOV.FDINSTADM.FFD
## 4 WP15187.1
## 5 WP15186.1
## 6 WP15185.1

Nguyễn Chí Dũng http://rpubs.com/chidungkt


42

Ví dụ, chỉ số có kí hiệu XGDP.56.FSGOV.FDINSTADM.FFD được miêu tả là “Government expenditure in


tertiary institutions as % of GDP (%)” và do đó chúng ta hiểu chỉ số này là chi tiêu của chính phủ
(%GDP) cho giáo dục đại học.
Có thể xem chi tiết hơn (và cũng thuận lợi hơn) danh sách này bằng lệnh View():
View(d1)

Số lượng các chỉ số có thể lấy từ WB là hơn 16000:


dim(d1)

## [1] 16038 5

nrow(d1)

## [1] 16038

Danh sách d2 là các thông tin về những quốc gia mà chúng ta có thể lấy số liệu cho nó. Có ba cột thông
tin đáng quan tâm là: (1) country - tên của quốc gia, (2) iso2c - mã quốc gia, và (3) income - nhóm thu
nhập của quốc gia theo cách phân loại của WB:
# Số lượng các quốc gia có trong kho dữ liệu của ngân hàng thế giới:
dim(d2)

## [1] 304 9

# Xem 6 quan sát đầu:


head(d2)

## iso3c iso2c country region capital


## 1 ABW AW Aruba Latin America & Caribbean Oranjestad
## 2 AFG AF Afghanistan South Asia Kabul
## 3 AFR A9 Africa Aggregates
## 4 AGO AO Angola Sub-Saharan Africa Luanda
## 5 ALB AL Albania Europe & Central Asia Tirane
## 6 AND AD Andorra Europe & Central Asia Andorra la Vella

Tất nhiên chúng ta có thể xem qua phân bố các quốc gia theo nhóm thu nhập:
# Số lượng các quốc gia theo từng nhóm thu nhập:
table(d2$income)

##
## Aggregates High income Low income
## 86 79 31

Nguyễn Chí Dũng http://rpubs.com/chidungkt


43

## Lower middle income Upper middle income


## 52 56

Với 304 quốc gia và vùng lãnh thổ thì tìm mã iso2c cho, chẳng hạn, cho Việt Nam là một công việc khá
chán nếu dò từng dòng bằng mắt. Chúng ta nên sử dụng lệnh filter() của gói dplyr thuộc hệ sinh thái
tidyverse để tìm:
library(tidyverse)
filter(d2, country == "Vietnam")

## iso3c iso2c country region capital longitude latitude


## 1 VNM VN Vietnam East Asia & Pacific Hanoi 105.825 21.0069
## income lending
## 1 Lower middle income Blend

Mã quốc gia của Việt Nam là VN thuộc khu vực Đông Á - Thái Bình Dương với thủ đô là Hà Nội có kinh
độ 105.825 và vĩ độ là 21.0069 và nằm trong nhóm thu nhập Lower middle income.
Ở bước này tôi tin là nhiều bạn khi gõ lệnh library(tidyverse)sẽ thấy báo lỗi và 90% trong số
này có nguyên nhân từ việc chưa cài đặt tidyverse. Hãy xem lại mục 1.2.3 về cài đặt các gói.

Với hơn 16000 chỉ số tì tìm kiếm một chỉ số nào đó trong kho là một việc rất mất thời gian nếu chúng
ta cứ tra từng dòng một. Dưới đây là cách tìm kiếm một chỉ số nhanh chóng hơn với lệnh
WDIsearch(). Chẳng hạn chúng ta cần tìm các chỉ số có chữ GDP (chú ý không phân biệt chữ hoa –
chữ thường) trong phần miêu tả về chỉ số đó ở cột name:
# Các chỉ số có chữ gdp:
df1 <- WDIsearch("gdp", cache = d)
dim(df1) # Có 369 chỉ số có chữ gdp

## [1] 369 2

head(df1) # Xem 6 chỉ số đầu.

## indicator
## [1,] "XGDP.56.FSGOV.FDINSTADM.FFD"
## [2,] "XGDP.23.FSGOV.FDINSTADM.FFD"
## [3,] "UIS.XUNIT.GDPCAP.4.FSGOV"
## [4,] "UIS.XUNIT.GDPCAP.3.FSGOV"
## [5,] "UIS.XUNIT.GDPCAP.2.FSGOV"
## [6,] "UIS.XGDP.FSGOV.FDINSTADM.FFD"

Có thể xem các chỉ số có ba kí tự GDP (không hiển thị kết quả):
View(df1)

Chúng ta có thể thu hẹp phạm vi tìm kiếm hơn nữa với điều kiện là chỉ số đó có: (1) có cụm gdp, (2)
capita, và (3) current:
# Các chỉ số có ba nhóm chữ gdp, capita và current:
df2 <- WDIsearch("gdp.*capita.*current", cache = d)
dim(df2)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


44

## [1] 3 2

df2

## indicator name
## [1,] "NY.GDP.PCAP.PP.CD" "GDP per capita, PPP (current international $)"
## [2,] "NY.GDP.PCAP.CN" "GDP per capita (current LCU)"
## [3,] "NY.GDP.PCAP.CD" "GDP per capita (current US$)"

Như vậy có 3 chỉ số thỏa mãn các điều kiện tìm kiếm ở trên.
Khi đã biết rõ mã của chỉ số tương tứng với quốc gia cần lấy chúng ta có thể sử dụng lệnh WDI() để
thu thập dữ liệu. Dưới đây minh họa cho việc thu thập dữ liệu về tăng trưởng của GDP đầu người của
Việt Nam (mã là NY.GDP.PCAP.KD.ZG và được mô tả bằng tiếng Anh là “GDP per capita growth (annual
%)” từ năm 1980 đến 2015:
dat <- WDI(indicator = c("NY.GDP.PCAP.KD.ZG"),
country = c("VN"),
start = 1980,
end = 2015)

Chú ý rằng không phải quốc gia nào cũng có số liệu từ năm 1980. Việt Nam có lẽ cũng không ngoại
lệ. Có thể tìm số lượng những năm không có số liệu về chỉ số này như sau:
sum(is.na(dat$NY.GDP.PCAP.KD.ZG))

## [1] 5

Như vậy có 5 năm trong khoảng thời gian trên Việt Nam không có số liệu. Chúng ta có thể thấy rõ
điều này:
dat

## iso2c country NY.GDP.PCAP.KD.ZG year


## 1 VN Vietnam 5.5451849 2015
## 2 VN Vietnam 4.8512640 2014
## 3 VN Vietnam 4.3057625 2013
## 4 VN Vietnam 4.1228302 2012
## 5 VN Vietnam 5.1184109 2011
## 6 VN Vietnam 5.3122718 2010
## 7 VN Vietnam 4.2874981 2009
## 8 VN Vietnam 4.5443114 2008
## 9 VN Vietnam 5.9753804 2007
## 10 VN Vietnam 5.7977601 2006
## 11 VN Vietnam 6.2997628 2005
## 12 VN Vietnam 6.2568503 2004
## 13 VN Vietnam 5.6639787 2003
## 14 VN Vietnam 5.0947677 2002
## 15 VN Vietnam 4.8562383 2001
## 16 VN Vietnam 5.3646942 2000
## 17 VN Vietnam 3.2136790 1999
## 18 VN Vietnam 4.1533817 1998
## 19 VN Vietnam 6.4779929 1997

Nguyễn Chí Dũng http://rpubs.com/chidungkt


45

## 20 VN Vietnam 7.6044878 1996


## 21 VN Vietnam 7.7588146 1995
## 22 VN Vietnam 7.0256254 1994
## 23 VN Vietnam 6.2192883 1993
## 24 VN Vietnam 6.7291499 1992
## 25 VN Vietnam 4.0293809 1991
## 26 VN Vietnam 3.1224958 1990
## 27 VN Vietnam 4.8599929 1989
## 28 VN Vietnam 2.6205993 1988
## 29 VN Vietnam 1.0655945 1987
## 30 VN Vietnam 0.4332025 1986
## 31 VN Vietnam 1.7321367 1985
## 32 VN Vietnam NA 1984
## 33 VN Vietnam NA 1983
## 34 VN Vietnam NA 1982
## 35 VN Vietnam NA 1981
## 36 VN Vietnam NA 1980

Các dữ liệu trống có lẽ không cần thiết nên ta có thể bỏ bằng lệnh na.omit() – tức là chỉ lấy dữ liệu từ
1985. Có ít nhất ba cách khác nhau để làm việc này:
# Cách 1:
c1 <- na.omit(dat)
c1

## iso2c country NY.GDP.PCAP.KD.ZG year


## 1 VN Vietnam 5.5451849 2015
## 2 VN Vietnam 4.8512640 2014
## 3 VN Vietnam 4.3057625 2013
## 4 VN Vietnam 4.1228302 2012
## 5 VN Vietnam 5.1184109 2011
## 6 VN Vietnam 5.3122718 2010
# Cách 2:
c2 <- dat[dat$year >= 1985, ]

# Cách 3:
c3 <- filter(dat, year >= 1985)

Có thể hình ảnh hóa dữ liệu (Data Visualization) nhằm mô tả tăng trưởng GDP đầu người của Việt
Nam bằng hình ảnh sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


46

R codes để tạo ra hình ảnh này là:

library(ggplot2)
library(ggthemes)
k <- ggplot(c3, aes(year, NY.GDP.PCAP.KD.ZG)) +
geom_line() +
geom_point(col = "red") +
labs(x = NULL,
y = NULL,
title = "Vietnam's Economic Growth: 1985 - 2015",
subtitle = "Unit: Percentage",
caption = "Data Source: The World Bank") +
theme_economist()
k

Chúng ta sẽ tìm hiểu kĩ hơn về Data Visualization ở chương 3. Sau khi học xong chương 3 các bạn có
thể trở lại để tìm hiểu những dòng lệnh trên.

Chúng ta cũng có thể lấy nhiều chỉ số cùng một lúc cho nhiều quốc gia. Dưới đây là minh họa việc lấy
cả NY.GDP.PCAP.KD.ZG và SP.DYN.LE00.IN (tuổi thọ bình quân) cho 6 nước là Lào, Campuchia, Việt
Nam, Miến Điện, Philippine và Indonesia:
dung <- WDI(country = c("LA","KH","VN","MY","PH","ID"),
indicator = c("NY.GDP.PCAP.KD.ZG","SP.DYN.LE00.IN"),
start = 1986,
end = 2014,
extra = TRUE,
cache = NULL)

Giả sử chúng ta chỉ quan tâm đến xu hướng về tuổi thọ của các quốc gia mà thôi thì chúng ta có thể
tách từ ra biến SP.DYN.LE00.IN và year mà thôi:
trang <- select(dung, country, year, SP.DYN.LE00.IN)

Sau đó đổi tên biến cho dễ hiểu hơn:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


47

trang <- rename(trang, Country = country,


Year = year,
Longevity = SP.DYN.LE00.IN)

Rồi hình ảnh hóa dữ liệu:

a <- ggplot(data = trang, aes(Year, Longevity, color = Country)) +


geom_line(size=0.7) +
geom_point()

a + labs(x = NULL,
y = NULL,
title = "The average life expectancy in some countries: 1986 - 2014",
subtitle = "Unit: Year",
caption = "Data Source: The World Bank")

Tất nhiên chúng ta có thể khai thác những dữ liệu thu được từ WB cho nhiều mục đích khác nhau.
Chẳng hạn như thực hiện các mô hình phân tích thống kê – kinh tế lượng hay kết hợp với các nguồn
dữ liệu khác để thực hiện nghiên cứu.

2.3.10 Đọc dữ liệu tài chính từ Internet với gói quantmod


Chuỗi thời gian (Time Series) là dữ liệu về một hay nhiều biến số được lấy ở những khoảng thời gian
khác nhau. Ví dụ điển hình nhất là khối lượng cung tiền M1. Đây là chuỗi số liệu chủ yếu được tính
theo tháng ở Hoa Kì. Một ví dụ khác về dữ liệu thời gian là GDP – thường được thu thập và tính toán
theo quý hoặc theo năm.

Trong lĩnh vực tài chính, các chuỗi dữ liệu thời gian thường là giá của các tài sản như kim loại quý,
các hàng hóa chiến lược như dầu thô, giá của các chứng khoán phái sinh hay một chỉ số chứng khoán
như S&P 500 hoặc VNDIRECT và thường được gọi tắt là dữ liệu tài chính (Financial Data) hay gọi theo
tên đầy đủ là chuỗi dữ liệu tài chính theo thời gian FTS (Financial Time Series). Trong tài liệu này, các
thuật ngữ này được sử dụng thay thế cho nhau mà không có khác biệt nào về ý nghĩa.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


48

Để phân tích dữ liệu tài chính tất nhiên thứ đầu tiên cần có là dữ liệu. Với vai trò là công cụ thu thập
dữ liệu thì chắc chắn R tỏ ra vượt trội so với các phần mềm khác: nó có thể thu thập các dữ liệu tài
chính một cách trực tiếp từ từ Internet ở nhiều định dạng khác nhau.

Gói quantmod của R có thể download tầm 40.000 chuỗi dữ liệu thời gian từ nhiều nguồn khác nhau
(Yahoo Finance, Google, FRED - Federal Reserve Economic Data). Dưới đây là một minh họa đơn giản
sử dụng gói này với điều kiện máy của bạn được kết nối với mạng Internet.

Dưới đây là R code để lấy dữ liệu tài chính của công ti Apple (mã AAPL) từ 2007-01-03 đến thời điểm
mà tài liệu này đang được đánh máy (ngày 05/08/2016) được cung cấp bởi Yahoo Finance:

library(quantmod) # Tải gói quantmod để R sử dụng.


?getSymbols() # Xem chi tiết cách lấy dữ liệu.
getSymbols(Symbols = "AAPL", src = "yahoo") # Lấy dữ liệu tài chính của Apple
từ Yahoo Finance tính từ thời điểm mã AAPL niêm yết đến hiện tại.

## [1] "AAPL"

Sys.Date() # Xem ngày hiện tại là bao nhiêu.

## [1] "2016-05-18"

str(AAPL) # Kiểm tra sơ bộ dữ liệu (trích).

## An 'xts' object on 2007-01-03/2016-05-17 containing:


## Data: num [1:2360, 1:6] 86.3 84.1 85.8 86 86.5 ...
tail(AAPL) # Xem 6 quan sát cuối cùng (trích).

## AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume


## 2016-05-10 93.33 93.57 92.11 93.42 33592500
## 2016-05-11 93.48 93.57 92.46 92.51 28539900
## 2016-05-12 92.72 92.78 89.47 90.34 76109800

Lệnh trên nếu không có lựa chọn src = "yahoo" thì R vẫn sẽ mặc định nguồn lấy là Yahoo Finance.
Với data trên có thể thực hiện một số phân tích kĩ thuật dựa trên hình ảnh:

chartSeries(AAPL, theme = "white") # Vẽ Biểu đồ giá và khối lượng giao dịch


với nền trắng.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


49

Nếu không có lựa chọn theme="white" thì chúng ta có đồ thị trên nền đen. Cũng có thể lựa chọn
khoảng thời gian khác cho đồ thị:

chartSeries(AAPL, theme = "white", subset = "2015-12-31::2016-02-26") # Chúng


ta cũng có thể vẽ biểu đồ trên với khoảng thời gian khác.

Dưới đây là R code để thu thập dữ liệu tài chính của AAPL với một khoảng thời gian nhất định và tạo
ra các hình ảnh cần thiết cho phân tích kĩ thuật:

getSymbols(Symbols = "AAPL", src = "yahoo",


from = "2016-01-01",
to = "2016-05-28")
barChart(AAPL, theme = "white")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


50

Tạo biểu đồ hình nến trong phân tích kĩ thuật:

candleChart(AAPL, multi.col = TRUE, theme = "white") # Biểu đồ nến.

Thêm chỉ số MACD (Moving Average Convergence Divergence indicator) cho đồ thị:

addMACD()

Nguyễn Chí Dũng http://rpubs.com/chidungkt


51

Vẽ thêm Bollinger Bands:

addBBands()

Tất nhiên khả năng của quantmod không chỉ đơn giản là lấy dữ liệu mà chức năng chính của nó là
phân tích kĩ thuật và thực hiện nhiều phân tích khác. Tuy nhiên các chủ đề này vượt qua giới hạn của
tài liệu này nên chúng không được trình bày ở đây.

Chúng ta cũng có thể lấy dữ liệu một cách đồng thời cho nhiều mã cổ phiếu, tài sản tài chính cũng như
tài sản thực (kim loại quý, các hàng hóa chiến lược như dầu thô) từ nhiều nguồn khác nhau:

getSymbols(c("YHOO", "GOOG")) # Lấy dữ liệu tài chính cho Yahoo và Google.

## [1] "YHOO" "GOOG"

getSymbols("YHOO", src = "google") # Từ nguồn là Google Finance

Nguyễn Chí Dũng http://rpubs.com/chidungkt


52

## [1] "YHOO"

getFX("EUR/USD", from = "2005-01-01") # Tỉ giá EUR/USD từ 2005/01/01.

## [1] "EURUSD"

getMetals(Metals = "gold", base.currency = "USD", from = "2013-10-10") # Giá


của vàng với giá niêm yết là đồng USD.

## [1] "XAUUSD"

Thậm chí chúng ta cũng có thể lấy các báo cáo tài chính của, chẳng hạn, Apple trong 3 năm liên tiếp
(mặc định):

getFinancials("AAPL")

## [1] "AAPL.f"

viewFinancials(AAPL.f, type = "BS", period = "A")

## 2016-09-24 2015-09-26
## Cash & Equivalents 11883.00 9731.00
## Short Term Investments 46671.00 20481.00
## Cash and Short Term Investments 67155.00 41601.00
## Accounts Receivable - Trade, Net 15754.00 16849.00
## Receivables - Other NA NA
## Total Receivables, Net 29299.00 30343.00
## Total Inventory 2132.00 2349.00

Trong câu lệnh trên thì lựa chọn type = "BS" có nghĩa là xem bảng cân đối kế toán (viết tắt của
Balance Sheet) còn period = "A" nghĩa là xem theo năm (Annual). Có thể thay BS bằng CF để xem
dòng tiền, hay IS để xem báo cáo doanh thu (Income Statement). Thay A bằng Q để xem các thông tin
báo cáo tài chính theo quý. Tất nhiên gói quantmod cũng được sử dụng để phân tích các báo cáo tài
chính (Financial Statement Analysis).

Mục này chỉ trình bày một cách giản lược và cơ bản về sử dụng gói quantmod như là một công cụ thu
thập dữ liệu. Chi tiết hơn có thể xem ở nhiều tài liệu khác nhau. Ví dụ:

http://www.quantmod.com/download/

Các dữ liệu tài chính được cung cấp bởi các nguồn từ Việt Nam thường không tuân theo một số định
dạng tiêu chuẩn nên để sử dụng được tất cả các tính năng của gói quantmod, trước hết cần thực hiện
một số điều chỉnh nhỏ. Vấn đề này sẽ đươc trình bày trong môt tài liệu chuyên khảo khác.

2.3.11 Đọc dữ liệu kích thước lớn


Trong thực tế thường chúng ta gặp những bộ dữ liệu lên đến hàng triệu quan sát với hàng trăm, thậm
chí hàng ngàn biến. Kích thước của những bộ dữ liệu này lớn đến nỗi các phần mềm thống kê thông
dụng như Excel, SPSS, Stata hay Eviews cũng không thể xử lý được. R có thể xử lý những bộ dữ liệu
với kích thướng lớn như vậy (và lớn hơn nữa) một cách dễ dàng. Nhưng đọc các bộ dữ liệu như thế
có thể rất tốn thời gian. Trong tình huống đó, chúng ta nên sử dụng một số gói đặc biệt để đọc dữ liệu
kích thước lớn. Một trong những gói rất mạnh là data.table . Chúng ta hãy minh họa với bộ dữ liệu

Nguyễn Chí Dũng http://rpubs.com/chidungkt


53

flights.csv với 227496 quan sát và 21 biến số (thực tế tôi từng gặp bộ số liệu lớn hơn nhiều: xấp xỉ
200 biến số và gần 2 triệu quan sát). Trước hết chúng ta so sánh thời gian đọc dữ liệu bằng lệnh
read.csv() mặc định của R và fread() của gói này:

setwd("D:/KTLR")
system.time(trang <- read.csv("flights.csv"))

Mất 3.01 giây để đọc bộ dữ liệu này. Tất nhiên máy của bạn có thể ra con số khác tùy vào cấu hình
máy và mỗi lần thực hiện, các con số cũng có thể khác nhau trên cùng một máy tính. Chúng ta sử dụng
lệnh fread() để đọc dữ liệu:

library(data.table)
system.time(trangyeu <- fread("flights.csv"))

Có thể thấy thời gian đọc dữ liệu của lệnh này nhanh gấp 8 lần so với lệnh read.csv(). Chúng ta có thể
kiểm chứng rằng có sự khác biệt về thời gian đọc dữ liệu giữa hai lệnh với sự trợ giúp của gói
microbenchmark. Dưới đây chúng ta sẽ viết lần lượt hai hàm đọc bộ dữ liệu flights.csv (có tên là
love và you) sau đó sử dụng hàm microbenchmark để chỉ thị đọc bộ dữ liệu 100 lần rồi tính toán các
thống kê về thời gian đọc. Kế đến sử dụng các thông tin có được thực hiện kiểm định t để chỉ ra rằng
có sự khác biệt về thời gian đọc dữ liệu ứng với hai lệnh:

love <- function() read.csv("flights.csv")


you <- function() fread("flights.csv")
library(microbenchmark)
loveyou <- microbenchmark(love(), you(), times = 100L)
loveyou

Thời gian trung bình (đơn vị là Miliseconds – mili giây) của hai lệnh này là chênh lệch nhau cỡ 8 lần
(3019 so với 414). Chúng ta có thể sử dụng kiểm định t để chỉ ra rằng khác biệt này có ý nghĩa thống
kê. Trước hết chúng ta chuyển loveyou về dạng data frame như sau:

loveyou <- data.frame(loveyou)


head(loveyou)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


54

# Thực hiện kiểm định t.


t.test(loveyou$time ~ loveyou$expr)

Do giá trị p-value là bằng 0 nên chúng ta có thể kết luận rằng sự khác biệt về thời gian để đọc bộ dữ
liệu là có ý nghĩa thống kê.

R có thể đọc dữ liệu với kích thước rất lớn nhưng để đảm bảo máy tính không bị đơ, chỉ nên đọc vào
R bộ dữ liệu tối đa chỉ chừng 50% đến 60% dung lượng của RAM. Do vậy, nếu máy tính của bạn có 4
Gi RAM thì chỉ nên đọc những bộ dữ liệu tối đa là 2.4 Gi. Chúng ta có thể đo kích thước của bộ dữ liệu
được đọc vào R như sau với hàm object_size() của gói pryr:

library(pryr)
object_size(trang)

## 20.2 MB

Trong tình huống nếu bộ dữ liệu cần xử lí mà lớn hơn RAM của máy tính thì chúng ta cần đến một số
giải pháp chuyên cho dữ liệu lớn (Big Data). Đây là chủ đề nằm ngoài phạm vi của tài liệu này nên sẽ
không được trình bày ở đây.

2.4 Quản lý dữ liệu, đổi tên, hiệu chỉnh dữ liệu bằng các hàm của gói base
Mục này chúng ta sẽ thực hành một số hàm quản lí dữ liệu, đổi tên và hiệu chỉnh dữ liệu (thuật ngữ
tiếng Anh là Data Manipulation hay Data Wrangling) với gói base – vốn là một gói cơ sở của R và sẽ
tự động xuất hiện khi khởi động R. Đây là những kĩ năng cần thành thạo.

2.4.1 Tạo một data frame


Các file dữ liệu dung và aoe như bạn thấy ở mục 2.2.1 và 2.2.2 được R quản lý dưới dạng một
data.frame (hay data frame theo cách gọi của một số tài liệu). Đây chính là cách thức quản lý dữ liệu
linh hoạt và tiện lợi cho rất nhiều phân tích sau này. Với dữ liệu có được ở mục 2.1 bạn cũng nên “hợp
nhất” các biến số thành một data.frame trong R với tên gọi trangxinh như sau:

trangxinh <- data.frame(luong, thunhapkhac, chitieu)


trangxinh

Nguyễn Chí Dũng http://rpubs.com/chidungkt


55

## luong thunhapkhac chitieu


## 1 20 16 24.4
## 2 30 10 31.2
## 3 28 2 29.2

Tất nhiên có data.frame này chúng ta thực tế là làm qua hai bước như đã biết. Bước 1 là khởi tạc các
biến luong, thunhapkkhac và chitieu. Bước 2 là sử dụng lệnh data.frame() để hợp nhất các biến này.
Chúng ta có thể nhập trực tiếp một bảng số liệu vào R thành một data.frame theo cách thức khác.

Xét bộ số liệu sau:

X2 X3 X4
10 50 52
15 75 75
18 90 97
24 120 129
30 150 152

Chúng ta có thể nhập bộ dữ liệu này vào R dưới dạng một data.frame với tên gọi ct:

ct <- data.frame(x2 = c(10, 15, 18, 24, 30),


x3 = c(50, 75, 90, 120, 150),
x4 = c(52, 75, 97, 129, 152))

ct

## x2 x3 x4
## 1 10 50 52
## 2 15 75 75
## 3 18 90 97
## 4 24 120 129
## 5 30 150 152

Chúng ta cũng có thể nhập bảng dữ liệu trên ở dạng một data.frame với tên gọi khác là yamato theo
một cách thức mà bạn rất quen thuộc:

yamato <- edit(data.frame())

Nguyễn Chí Dũng http://rpubs.com/chidungkt


56

Nếu file có tên yamato trong R mà bạn nhập sai một quan sát nào đó, bạn có thể sửa lại trong R như
sau:

yamato <- edit(yamato)

Chúng ta cũng có thể sử dụng lệnh edit để thay đổi cả giá trị ở các cột (nếu chúng ta nhập sai dữ liệu)
cũng như tên của các cột đối với data frame có tên ct ở trên bằng cách gõ:

ct <- edit(ct)

Chúng ta cũng có thể thực hiện, chẳng hạn, việc đổi tên cho cột thứ 3 từ x4 thành y theo một cách khác
mà không dùng lệnh edit:

colnames(ct)[3] <- "y"

Đổi tên biến là một công việc hữu ích trong nhiều trường hợp. Chẳng hạn, các dữ liệu thu thập từ
World Bank ở các phần sau có các kí hiệu rất lạ, dài, và khó hiểu với đa số công chúng phổ thông. Để
trình bày các kết quả của phân tích số liệu thì rõ ràng việc mà chúng ta nên làm là đổi tên gọi cho
chúng.

2.4.2 Dán lại nhãn cho các quan sát thuộc bộ số liệu từ dạng số thành ki tự hoặc factor
Để minh họa, chúng ta đọc bộ dữ liệu ch4bt8.wf1 vào R với tên gọi mới là hello. Trong bộ dữ liệu này
có biến URBAN có hai giá trị 0 và 1 với ý nghĩa URBAN = 1 cho quan sát thuộc khu vực thành thị, = 0
nếu thuộc khu vực nông thôn. Thực chất biến URBAN là biến định tính (hay còn gọi là biến giả) và do
đó sẽ tiện lợi hơn nếu ta thay cách kí hiệu để làm nổi bật rằng URBAN là biến định tính trong đó
URBAN = 1 tương ứng với Dothi và URBAN = 0 ứng với Nongthon:

library(hexView)
hello <- readEViews("ch4bt8.wf1", as.data.frame = TRUE)
hello$khuvuc[hello$URBAN == 1] <- "Dothi"
hello$khuvuc[hello$URBAN == 0] <- "Nongthon"

Kết quả là data.frame có tên hello sẽ được thêm một cột biến mới như sau (trích một số quan sát):

hello[1:6, ]

## AGE BLACK EDUC EXPER FEDUC GT IQ MALE MARRIED MEDUC


## 1 33 0 17 8 1.2e+01 4.504779e+257 132 1 1 8.0e+00
## 2 32 0 10 11 5.0e+00 7.436740e+221 103 0 1 1.2e+01
## 3 37 0 12 18 1.0e-37 7.691624e+218 101 0 1 1.0e-37
## SOUTH SSIBS URBAN WAGE khuvuc
## 1 1 3 1 3942 Dothi
## 2 1 3 1 2700 Dothi
## 3 0 1 1 2765 Dothi

Lúc này biến số mới khuvuc được tạo ra và nó mang ý nghĩa hoàn toàn trùng khớp với ý nghĩa của
biến URBAN. Điều này cũng có nghĩa là, việc tạo thêm một cột biến cũ URBAN là không cần thiết nên
ta có thể xóa cột biến này:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


57

# Xóa cột biến URBAN


hello$URBAN <- NULL

Việc dán lại nhãn theo cách thức vừa thực hiện thực chất là chúng ta tạo ra một cột biến mới có tên
Khuvuc có cùng ý nghĩa (tức mang nội dung thông tin) không khác so với URBAN do đó chúng ta cần
xóa đi cột biến cũ URBAN. Trong tình huống chúng ta muốn vẫn giữ lại cột biến URBAN với nội dung
thông tin như cũ nhưng chỉ khác biệt ở cách dán nhãn cho quan sát thì:

hello$URBAN[hello$URBAN == 1] <- "Dothi"


hello$URBAN[hello$URBAN == 0] <- "Nongthon"

Cách thức này không tạo ra cột biến mới Khuvuc và do vậy chúng ta không cần phải xóa đi một cột
biến có nội dung thông tin trùng nhau như ở trên.

Cách dán lại nhãn cho các quan sát như trên thì cột biến khuvuc sẽ có dạng kí tự (string) và có bản
chất là biến định tính. Trong nhiều tình huống chúng ta muốn nhấn mạnh “chất” định tính này của
những biến số bằng một định dạng khác mà thuật ngữ của những người sử dụng R gọi kiểu định dạng
này là factor. Ví dụ, với bốn biến có bản chất định tính của bộ số liệu chúng ta có thể dán lại nhãn ở
dạng factor theo cách thức như sau:

hello$MALE <- factor(hello$MALE, levels = c("1", "0"),


labels = c("Male", "Female"))
hello$MARRIED <- factor(hello$MARRIED, levels = c("1", "0"),
labels = c("Yes", "No"))

hello$BLACK <- factor(hello$BLACK, levels = c("1", "0"),


labels = c("Black", "White"))
hello$SOUTH <- factor(hello$SOUTH, levels = c("1", "0"),
labels = c("South", "North"))

head(hello)

## AGE BLACK EDUC EXPER FEDUC GT IQ MALE MARRIED MEDUC


## 1 33 White 17 8 1.2e+01 4.504779e+257 132 Male Yes 8.0e+00
## 2 32 White 10 11 5.0e+00 7.436740e+221 103 Female Yes 1.2e+01
## 3 37 White 12 18 1.0e-37 7.691624e+218 101 Female Yes 1.0e-37
## SOUTH SSIBS URBAN WAGE
## 1 South 3 Dothi 3942
## 2 South 3 Dothi 2700
## 3 North 1 Dothi 2765

Một cách thức dán nhãn khác cho các quan sát được sử dụng thường xuyên là, chẳng hạn, phân loại
nhóm thu nhập (theo một tiêu chuẩn nào đó) cho các quan sát. Giả sử tiêu chuẩn đó là ngưỡng thu
nhập thấp hơn hoặc bằng 3200 thì thuộc nhóm thu nhập thấp, từ 3200 đến nhỏ hơn hoặc bằng 3500
là nhóm thu nhập trung bình còn lớn hơn 3500 là nhóm thu nhập khá. Để thực hiện dán nhãn nhóm
thu nhập chúng ta sử dụng lệnh ifelse():
hello$Class <- ifelse(hello$WAGE <= 3200, "Thap",
ifelse(hello$WAGE > 3200 & hello$WAGE <= 3500, "Trungbi
nh",

Nguyễn Chí Dũng http://rpubs.com/chidungkt


58

ifelse(hello$WAGE > 3500, "Kha", "Thap")))


table(hello$Class)

##
## Kha Thap Trungbinh
## 352 269 314

2.4.3 Dán lại nhãn cho các quan sát từ dạng kí tự thành dạng số
Đây là cách thức biến đổi ngược so vơí cách biến đổi ở mục 2.4.2. Nếu muốn trở lại cách biểu diễn cũ
cho biến URBAN trong đó quan sát có nhãn Dothi ứng với 1 và Nongthon ứng với 0 thì:

hello$URBAN[hello$URBAN == "Dothi"] <- 1


hello$URBAN[hello$URBAN == "Nongthon"] <- 0

Cách dán nhãn lại cho các quan sát kiểu này vốn là cách làm truyền thống kể từ khi có R và bất tiện,
khó nhớ. Ở các mục sau chúng ta sẽ nghiên cứu một cách tiếp cận mới với gói tidyverse trong đó cac
câu lệnh được thiết kế linh hoạt và dễ nhớ (vì nó gần với ngôn ngữ người) đồng thời tăng tốc độ xử
lí và tính toán.

2.4.4 Ghép dữ liệu vào một data frame sẵn có


Ghép một chuỗi dữ liệu vào một data.frame sẵn có là một kĩ năng bạn phải thành thạo. Chẳng hạn,
sau khi chúng ta thực hiện hồi quy, chúng ta cần gép, chẳng hạn phần dư vào data.frame đã có với một
tên gọi bất kì mà bạn chọn. Thực chất, các câu lệnh vừa thực hiện ở mục 2.5.2 chính là một thao tác
gép thêm biến có tên khuvuc vào data frame sẵn có hello. Trong mục này chúng ta sẽ nghiên cứu ba
lệnh thường sử dụng nhất là cbind(), rbind() và merge().

Trở lại với data frame có tên trangxinh ở mục 2.4. Giả sử chúng ta có thêm hai quan sát nữa và cần
nhập số liệu cho 2 quan sát này với trangxinh đã có. Trước hết:

love <- data.frame(luong = c(31, 30),


thunhapkhac = c(7, 10),
chitieu = c(23, 28))
love

## luong thunhapkhac chitieu


## 1 31 7 23
## 2 30 10 28

Sau đó ghép bộ dữ liệu này vào trangxinh đã có bằng lệnh rbind() :

trangxinh <- rbind(trangxinh, love)


trangxinh

## luong thunhapkhac chitieu


## 1 20 16 24.4
## 2 30 10 31.2
## 11 28 8 30.2
## 12 30 4 26.8

Nguyễn Chí Dũng http://rpubs.com/chidungkt


59

## 13 31 7 23.0
## 14 30 10 28.0

Như vậy với lệnh rbind() chúng ta đã nghép hai bộ dữ liệu này theo “chiều thẳng đứng”. Chú ý rằng
để nghép hai bộ dữ liệu theo cách này, thì love phải có cùng tên biến như trangxinh.

Nếu 14 quan sát ở trên có 8 quan sát đầu thuộc khu vực thành thị (kí hiệu TT) và 6 quan sát sau thuộc
khu vực nông thôn (kí hiệu NT). Tạo một cột biến định tính mới với tên gọi khuvuc rồi gán biến này
vào trangxinh bằng lệnh cbind() như sau:

khuvuc <- c(rep("TT", 8), rep("NT", 6))


trangxinh <- cbind(trangxinh, khuvuc)
trangxinh

## luong thunhapkhac chitieu khuvuc


## 1 20 16 24.4 TT
## 2 30 10 31.2 TT
## 3 28 2 29.2 TT
## 4 24 0 23.6 TT
## 5 42 18 36.0 TT
## 6 36 10 31.4 TT
## 7 32 16 32.6 TT
## 8 34 24 36.8 TT
## 9 24 28 32.8 NT
## 10 22 20 29.8 NT
## 11 28 8 30.2 NT
## 12 30 4 26.8 NT
## 13 31 7 23.0 NT
## 14 30 10 28.0 NT

Như vậy với lệnh cbind() chúng ta đã cộng thêm một cột biến mới vào bộ dữ liệu sẵn có. Đây là kiểu
ghép dữ liệu “theo chiều ngang”. Chú ý rằng cột dữ liệu mới này phải có cùng số quan sát là 14 như
bộ dữ liệu ban đầu.

Ở đây lệnh rep(“TT”, 8) có nghĩa là lặp lại nhãn TT 8 lần cho biến định tính khuvuc.

Một cách thức nghép các data frame lại với nhau thường sử dụng là lệnh merge(). Để mình họa, hãy
xem xét hai bộ dữ liệu được tạo ra như sau:

df1 <- data.frame(Name = c("Hoa", "Linh", "Nam"),


Age = c(18, 21, 20))
df2 <- data.frame(Name = c("Hoa", "Linh", "Nam"),
Score = c(19, 26, 24),
Gender = c("F", "F", "M"))

Hai bộ dữ liệu này có cùng: (1) cột biến tên là Name, và (2) thứ tự các quan sát ở cột biến này (thực
chất đây là hai data frame lưu các thông tin về một lớp học giả định có ba học sinh). Có thể hợp nhất
hai data frame trên thành một bộ dữ liệu duy nhất:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


60

total <- merge(df1, df2, by.x = "Name")


total

## Name Age Score Gender


## 1 Hoa 18 19 F
## 2 Linh 21 26 F
## 3 Nam 20 24 M

R cũng mặc định sẽ gép các data frame lại căn cứ vào cột biến chung (miễn là các quan sát có cùng
thứ tự) do đó co thể làm ngắn gọn hơn như sau:

total <- merge(df1, df2)

2.4.5 Trích dữ liệu từ một data frame có sẵn với dấu []


Dưới đây chúng ta xét ba kĩ năng cơ bản là trích xuất (hay tách) dữ liệu từ một data frame có sẵn theo:
(1) cột biến, (2) theo dòng, và (3) cả theo dòng và cột.

2.4.5.1 Trích xuất dữ liệu theo cột


Trong nhiều tình huống các bạn chỉ quan tâm đến một số biến chứ không phải toàn bộ biến số ở một
data frame sẵn có. Chẳng hạn, với dữ liệu hello ở trên chúng ta chỉ quan tâm đến hai biến là EDUC và
EXPER và muốn tách (lọc) hai biến này thành một data frame khác có tên gọi là hello2 với dấu [] –
thực chất là một lệnh của R như sau:

hello2 <- hello[, c(4, 5)]


head(hello2) # Xem 6 quan sát đầu tiên của hello2.

## EXPER FEDUC
## 1 8 1.2e+01
## 2 11 5.0e+00
## 3 18 1.0e-37
## 4 9 1.1e+01
## 5 11 1.3e+01
## 6 10 1.0e-37

Cũng có thể lấy ra hello2 bằng cách chỉ thị cụ thể tên biến:

hello2 <- hello[, c("EXPER", "FEDUC")]

Hai cách thức tách dữ liệu này là tương đương nhau.

2.4.5.2 Trích xuất dữ liệu theo hàng


Có thể trích xuất ra một data frame con bằng cách chỉ định cụ thể quan sát nào muốn lấy theo vị trí
của hàng. Dưới đây là một số ví dụ:

df1 <- hello[c(1, 99, 200), ] # lấy quan sát ở dòng 1, 99 và 200
df2 <- hello[c(1:3, 100, 500), ] # lấy quan sát từ 1 đến 3, 100 và 500

Cách thức trích dữ liệu con (hay lấy mẫu theo dòng) như trên thường chỉ có tác dụng kiểm tra một số
quan sát cụ thể nào đó và do vậy nó không hữu ích bằng việc lấy mẫu ngẫu nhiên mà ta sẽ nghiên cứu
ở mục sau.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


61

2.4.5.3 Trích xuất dữ liệu đồng thời theo hàng và cột


Để trích xuất dữ liệu đồng thời theo hàng và cột:

df3 <- hello[c(1, 3, 5), c(4, 5)]


df3

## EXPER FEDUC
## 1 8 1.2e+01
## 3 18 1.0e-37
## 5 11 1.3e+01

Ở đây df3 (là một data frame) được trích xuất ra từ hello bằng cách lấy các quan sát ở dòng 1, 3 và 5
nhưng chỉ lấy các biến ở cột 4 và 5 từ data frame gốc hello ban đầu.

2.4.6 Trích dữ liệu từ một data frame có sẵn bằng lệnh subset()
Trong nhiều tình huống, các bạn cần tách dữ liệu cho các quan sát theo một tiêu chí nào đó. Chẳng
hạn, các từ hello các bạn muốn lọc ra tất cả các quan sát ứng với URBAN = 1 mà thôi với tên gọi là
dothi chẳng hạn:

dothi <- subset(hello, URBAN == 1)

Lúc này, 671 quan sát khu vực thành thị sẽ được tách ra như các bạn có thể thấy:

dim(dothi)

## [1] 671 16

Bạn cũng có thể tách từ data.frame có tên hello các quan sát mà: (1) ứng với URBAN =1, và (2) có IQ
≥ 110 với tên gọi là thongminh:

thongminh <- subset(hello, URBAN == 1 & IQ >= 110)

Với câu lệnh này, sẽ có 216 quan sát thỏa mãn hai tính chất trên. Chú ý rằng data.frame dothi ở trên
có thể được tách theo một cách thức khác như sau:

dothi <- subset(hello, khuvuc == "Dothi")

2.4.7 Lấy mẫu ngẫu nhiên


Giả sử một lớp lớp học có 4 người với tên và tuổi như sau:

myclass <- data.frame(Name = c("Nam", "Linh", "An", "Trang"),


Age = c(19, 22, 21, 23))
myclass

## Name Age
## 1 Nam 19
## 2 Linh 22
## 3 An 21
## 4 Trang 23

Để chọn ra ngẫu nhiên 2 người trong số 4 người này làm cán bộ lớp:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


62

df1 <- myclass[sample(nrow(myclass), 2), ]


df1

## Name Age
## 4 Trang 23
## 2 Linh 22

Ở đây (nrow(myclass) là số học sinh của lớp và chính là 4. Chú ý rằng mỗi lần các bạn thực hiện
câu lệnh trên thì chúng ta sẽ có một df1 khác nhau và kết quả của bạn có thể khác kết quả trên. Vì số
lượng các df1 khác nhau có thể lấy chính là tổ hợp chập 2 của 4 nên để cố định kết quả chúng ta cần
có một thao tác gọi là “gieo hạt” bằng lệnh set.seed() trước khi lấy ngẫu nhiên 2 trong số 4 quan sát:

set.seed(29)
df1 <- myclass[sample(nrow(myclass), 2), ]
df1

## Name Age
## 1 Nam 19
## 4 Trang 23

Con số 29 tôi chọn là ngày sinh nhật của tôi 02/ 09. Tất nhiên các bạn có thể chọn một con số bất kì
khác. Nếu chọn một con số khác 29 thì đương nhiên các bạn lại có một df1 khác.

Các thức chọn mẫu như trên là chọn mẫu không hoàn lại. Tức là nếu một bạn đã được chọn làm lớp
trưởng rồi thì sẽ không được chọn làm lớp phó nữa. Nói cách khác, cách thức chọn mẫu này sẽ không
bao giờ xẩy ra tình huống một quan sát được chọn hai lần. Ngược lại chúng ta có kiểu chọn mẫu có
hoàn lại – tức là một quan sát có thể được lấy nhiều hơn một lần như sau:

df2 <- myclass[sample(nrow(myclass), 2, replace = TRUE), ]

2.5 Quản lý dữ liệu, hiệu chỉnh dữ liệu bằng các hàm của gói tidyverse
Các hàm của gói base mà chúng ta sử dụng ở mục 2.4 cho Data Manipulation xuất hiện vào khoảng
thời điểm khi R xuất hiện vào năm 1995 nhưng cú phát của nhiều hàm thuộc gói base là không nhất
quán và khó nhớ, đặc biệt là cho một nhóm công việc đặc biệt tốn thời gian đó là biến đổi số liệu (Data
Manipulation). Gói tidyverse ra đời nhằm đáp ứng các nhu cầu ngày càng tăng của việc biến đổi và
làm sạch dữ liệu (Data Cleaning). Gói tidyverse (nói cho đúng là hệ sinh thái tidyverse vì nó là tập hợp
của những gói mạnh nhất chuyên cho công việc làm sạch và biến đổi số liệu) được khuyến khích sử
dụng vì ít nhất các lí do sau:

1. Dễ hiểu và có cú pháp nhất quán.


2. Hợp nhất và hỗ trợ ggplot2 - một gói chuyên cho data visualization.
3. Có thể phân tích, quản lí cơ sở dữ liệu ngoài (external databases) mà không cần biết sâu các
chi tiết và kiến thức của các ngôn ngữ truy vấn cơ sở dữ liệu (database query languages) khác
như SQL.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


63

Trước hết chúng ta xem xét một dạng tổ chức dữ liệu gọi là tibble (còn gọi là data_frame) – một dạng
tổ chức dữ liệu thay thế cho data frame truyền thống.

2.5.1 Tổ chức dữ liệu ở dạng tibble


Trước hết chúng ta hãy xem lại cách tạo ra một data frame truyền thống với lệnh data.frame:

# Tạo data frame


df <- data.frame(a = 1:3, b = c(2, 3, 4.1), c = c(3, 5, 7.1))
# Xem qua dữ liệu
df

## a b c
## 1 1 2.0 3.0
## 2 2 3.0 5.0
## 3 3 4.1 7.1

# Xem cấu trúc dữ liệu


str(df)

## 'data.frame': 3 obs. of 3 variables:


## $ a: int 1 2 3
## $ b: num 2 3 4.1
## $ c: num 3 5 7.1

Với lệnh str (viết tắt của structure) chúng ta biết những thông tin cơ bản sau:

 Số nguyên được có kí hiệu là int.


 Số nói chung có kí hiệu là num.
 Dữ liệu có được tổ chức ở dạng data frame với dòng kí tự 'data.frame'.

Đây chính là kiểu cấu trúc dữ liệu truyền thống có từ khi R xuất hiện. Nhưng nhược điểm của kiểu cấu
trúc dữ liệu này là các tính toán sẽ trở nên chậm (đặc biệt là với dữ liệu kích thước lên đến hàng Gi)
và không hỗ trợ nhiều cho Data Manipulation.

Nhằm đáp ứng các nhu cầu về tốc độ tính toán cũng như xử lí dữ liệu kích thước lớn, một kiểu cấu
trúc dữ liệu khác được tạo ra trong R là tibble (hay còn gọi là data_frame) bằng gói tidyverse. Cấu
trúc dữ liệu dạng tibble và data frame chính là một ngoại trừ một số khác biệt nhỏ về trình bày hiển
thị. Chúng ta có thể tạo một tibble theo hai cách thức sau:

# Gọi gói tidyverse


library(tidyverse)

## Loading tidyverse: ggplot2


## Loading tidyverse: tibble
## Loading tidyverse: tidyr
## Loading tidyverse: readr
## Loading tidyverse: purrr
## Loading tidyverse: dplyr

## Conflicts with tidy packages ---------------------------------------------


-

Nguyễn Chí Dũng http://rpubs.com/chidungkt


64

## filter(): dplyr, stats


## lag(): dplyr, stats

# Cách 1
df_tb_c1 <- data_frame(a = 1:3, b = c(2, 3, 4.1), c = c(3, 5, 7.1))
df_tb_c1

## # A tibble: 3 × 3
## a b c
## <int> <dbl> <dbl>
## 1 1 2.0 3.0
## 2 2 3.0 5.0
## 3 3 4.1 7.1

str(df_tb_c1)

## Classes 'tbl_df', 'tbl' and 'data.frame': 3 obs. of 3 variables:


## $ a: int 1 2 3
## $ b: num 2 3 4.1
## $ c: num 3 5 7.1

# Cách 2
df_tb_c2 <- tibble(a = 1:3, b = c(2, 3, 4.1), c = c(3, 5, 7.1))
df_tb_c2

## # A tibble: 3 × 3
## a b c
## <int> <dbl> <dbl>
## 1 1 2.0 3.0
## 2 2 3.0 5.0
## 3 3 4.1 7.1

str(df_tb_c2)

## Classes 'tbl_df', 'tbl' and 'data.frame': 3 obs. of 3 variables:


## $ a: int 1 2 3
## $ b: num 2 3 4.1
## $ c: num 3 5 7.1

Khi gọi gói tidyverse thì bạn nhận được một loạt thông báo theo đó, gói đầu tiên được gọi là ggplot2
và cuối cùng là dplyr. Như đã nói, một tibble chính là một data frame nhưng: (1) hỗ trợ tính toán và
biến đổi số liệu, (2) có một số khác biệt về trình bày và hiển thị. Cụ thể là:

 Khi gõ df_tb_c1 thì ngoài các thông tin như đã thấy còn có các chữ int và dbl để trong dấu
< > với hàm ý chỉ số nguyên và số thông thường (dbl là viết tắt của double và int là viết tắt
của interger).
 Cấu trúc của dữ liệu được hiển thị ở dòng Classes 'tbl_df', 'tbl' and 'data.frame'
khi sử dụng lệnh str(df_tb_c2) .

Đương nhiên, chúng ta cũng có thể chuyển hóa một bộ dữ liệu ở dạng data frame về tibble. Lấy ví dụ
với bộ dữ liệu df ở trên:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


65

# Cách 1
df_c1 <- as_tibble(df)
# Cách 2
df_c2 <- tbl_df(df)
# Xem kết quả của chuyển đổi từ data frame sang tibble
df_c1

## # A tibble: 3 × 3
## a b c
## <int> <dbl> <dbl>
## 1 1 2.0 3.0
## 2 2 3.0 5.0
## 3 3 4.1 7.1

df_c2

## # A tibble: 3 × 3
## a b c
## <int> <dbl> <dbl>
## 1 1 2.0 3.0
## 2 2 3.0 5.0
## 3 3 4.1 7.1

Chuyển hóa một tibble sang data frame:

df_dang_dataframe <- as.data.frame(df_c1)

Hoặc theo một cách thức khác:

df_dang_dataframe <- data.frame(df_c1)

Đến đây các bạn đã hiểu cách tạo ra một tibble và chuyển hóa từ data frame sang tibble và ngược lại.
Các bạn nên chuyển hóa cấu trúc dữ liệu từ data frame sang tibble, đặc biệt là trong các tình huống
bộ dữ liệu rất lớn. Nói như thế không có nghĩa là kiểu dữ liệu truyền thống kiểu data frame không
còn được sử dụng trong tài liệu này.

Với mục đích minh họa, các mục kế tiếp chúng ta sẽ thực hành bộ dữ liệu CPS1988 có trong gói AER.
Bộ dữ liệu này là thông tin về mức lương (wage), trình độ học vấn (education), kinh nghiệm
(experience) cũng như một số biến định tính khác (ví dụ: parttime – làm thêm hay không) của 28.155
cá nhân được thu thập bởi bộ thống kê Hoa Kì (US Census Bureau) vào năm 1988 và sau đó được sử
dụng trong một loạt các nghiên cứu khác nhau.

Để sử dụng bộ dữ liệu này các bạn làm như sau:

library(AER)
data("CPS1988")

Để có mô tả chi tiết về các biến số:

help("CPS1988")

Để biêt bộ dữ liệu có bao nhiêu quan sát cũng như số lượng các biến:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


66

dim(CPS1988)

Để biết các biến số thuộc kiểu gì (định lượng hay định tính chẳng hạn) chúng ta gõ:

str(CPS1988)

Như đã biết, những biến là số nguyên sẽ có kí hiệu int (chẳng hạn education), những biến là số thực
thì có kí hiệu num (chẳng hạn wage) và cấu trúc dữ liệu của nó là ở dạng data frame. Các biến còn lại
là biến định tính với kí hiệu factor. Cụ thể hơn nữa, biến định tính parttime chỉ có hai nhóm là yes
hoặc no nên sẽ được hiển thị chi tiết hơn thành factor w/2 levels “no”, “yes”.

2.5.2 Lọc dữ liệu với lệnh filter


Lệnh filter cho phép lọc – trích các quan sát từ bộ dữ liệu gốc ban đầu dựa trên các giá trị hay điều
kiện nào đó.

Lọc ra các quan sát có education lớn hơn 12 và biến định tính smsa nhận giá trị “no”:

df1 <- filter(CPS1988, education > 12 & smsa == "no")

Lọc ra các quan sát đến khu vực miền nam và tây. Có ba cách thức:

# Cách 1
df2 <- filter(CPS1988, region == "south" | region == "west")
# Cách 2
df3 <- filter(CPS1988, region %in% c("south", "west"))
# Cách 3
df4 <- filter(CPS1988, region != "northeast" & region != "midwest")

Chú ý rằng lệnh filter , nếu gặp dữ liệu trống, nó sẽ tự động loại bỏ những dữ liệu này.

2.5.3 Chọn cột biến với lệnh select


Nếu chúng ta chỉ quan tâm đến hai cột biến là wage và education và muốn tách ra thành một tibble
riêng:

df5 <- select(CPS1988, wage, education)

Nếu muốn chuyển hai biến là smsa và region lên vị trí thứ nhất và hai những giữ nguyên các biến còn
lại:

df6 <- select(CPS1988, smsa, region, everything())

Một số cách thức khác sử dụng lệnh select khác:

# Loại biến smsa


df7 <- select(CPS1988, -smsa)
# Lấy các biến từ education đến smsa
df8 <- select(CPS1988, education:smsa)
# Lấy các biến bất đầu bằng chữ e. Có hai cách vì lệnh này không phân biệt
chữ hoa - chữ thường:
df9 <- select(CPS1988, starts_with("e"))
df10 <- select(CPS1988, starts_with("E"))
# Lấy các biến có kết thúc là chứ n

Nguyễn Chí Dũng http://rpubs.com/chidungkt


67

df11 <- select(CPS1988, ends_with("n"))


# Lấy các biến mà có ba chữ uca (và theo thứ tự đó):
df21 <- select(CPS1988, contains("uca"))
# Lấy các biến mà tên là một trong ba cái tên smsa, wage và parttime:
df22 <- select(CPS1988, one_of("smsa", "wage", "parttime"))

Lệnh select cũng có thể được sử dụng để đổi tên biến nhưng nó sẽ xóa tất cả các biến không được
chọn còn lại:

df12 <- select(CPS1988, luong = wage, giaoduc = education)

Chính vì lí do này, chúng ta nên sử dụng lệnh rename nếu muốn giữ lại các biến khác.

2.5.4 Đổi tên biến với lệnh rename


Chúng ta có thể đổi tên biến theo cách thức như sau:

df14 <- rename(CPS1988, luong = wage, giaoduc = education)

Theo cách thức này, các biến khác không được lựa chọn để đổi tên vẫn được giữ lại.

2.5.5 Sắp xếp lại theo giá trị tăng dần hay giảm dần với lệnh arrange
Nếu muốn sắp xếp lại bộ số liệu theo thứ tự giảm dần của mức lương:

df15 <- arrange(CPS1988, desc(wage))

Nếu có dữ liệu trống thì các giá trị trống sẽ được xếp ở dưới cùng. Nếu không có desc(wage)thì bộ
số liệu được sắp xếp theo chiều tăng của wage.

2.5.6 Tạo biến mới với lệnh mutate và transmute


Biến wage trong bộ số liệu gốc đo mức lương tuần theo đơn vị USD. Nếu muốn tạo biến mới với tên
wage_1000 đo mức lương tuần theo đơn vị là 1000 USD thì:

df16 <- mutate(CPS1988, wage_1000 = wage / 1000)

Bằng cách này chúng ta tạo ra biến mới có tên wage_100 và sẽ được thêm vào cột cuối cùng của bộ số
liệu gốc.

Tương tự, chúng ta có thể cho rằng tuổi của người lao động bằng năm đi học cộng với năm kinh nghiệp
và cộng thêm 6 (giả thiết dân Mĩ đi học lớp 1 từ lúc 6 tuổi) :

df17 <- mutate(CPS1988, age = education + experience + 6)

Nếu chúng ta muốn tạo biến mới dựa trên các biến cũ nhưng muốn tách hẳn chúng ra để thành tibble
mới thì sử dụng lệnh transmute:

df18 <- transmute(CPS1988, luong = wage / 1000, age = education + experience


+ 6, khuvuc = region)

2.5.7 Lấy ra ngẫu nhiên một số quan sát với lệnh sample_n và sample_frac
Để lấy ra 5 quan sát ngẫu nhiên từ bộ dữ liệu gốc:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


68

# Cố định kết quả


set.seed(29)
# Lấy ra 5 quan sát một cách ngẫu nhiên
df19 <- sample_n(CPS1988, 5)

Hoặc theo một cách thức khác – lấy theo tỉ lệ so với bộ dữ liệu gốc:

set.seed(222)
# Lấy ra ngẫu nhiên 1% các quan sát từ bộ số liệu gốc
df20 <- sample_frac(CPS1988, 0.01)

2.5.8 Lấy ra không ngẫu nhiên một số quan sát với lệnh slice
Nếu muốn lấy một cách không ngẫu nhiên các quan sát theo vị trí của dòng trong bộ dữ liệu gốc
chúng ta sử dụng lệnh slice:

# Lấy các quan sát nằm ở dòng 1, 2, và 3


df21 <- slice(CPS1988, 1:3)
# Lấy các quan sát nằm ở dòng 1, 2, 3 và 100
df22 <- slice(CPS1988, c(1:3, 100))

Cũng có thể sử dụng lệnh slice để loại bỏ một số quan sát theo vị trí dòng:

# Từ bộ dữ liệu gốc, bỏ các quan sát nằm ở dòng 1, 2, 3 và 100


df22 <- slice(CPS1988, -c(1:3, 100))

2.5.9 Loại các dòng trùng nhau bằng lệnh distinct


Trước hết tạo ra một bộ dữ liệu có tên dung như sau:

dung <- tibble(x = c(1, 2, 5, 1, 1, 2),


y = c(3, 2, 7, 3, 6, 2),
z = c(4, 2, 3, 5, 2, 2))

Có thể thấy quan sát ở dòng 2 và 6 là trùng nhau và chúng ta muốn loại bỏ các quan sát trùng theo
dòng:

df1 <- distinct(dung)


df1

## # A tibble: 5 × 3
## x y z
## <dbl> <dbl> <dbl>
## 1 1 3 4
## 2 2 2 2
## 3 5 7 3
## 4 1 3 5
## 5 1 6 2

Kể từ đây, để không cần gõ df1 mà vẫn muốn hiển thị được hiệu ứng của một lệnh, ta dùng dấu () như
sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


69

(df1 <- distinct(dung))

## # A tibble: 5 × 3
## x y z
## <dbl> <dbl> <dbl>
## 1 1 3 4
## 2 2 2 2
## 3 5 7 3
## 4 1 3 5
## 5 1 6 2

Nếu muốn, xóa các dòng trùng căn cứ theo, chẳng hạn, biến y thì:

(df2 <- distinct(dung, y, .keep_all = TRUE))

## # A tibble: 4 × 3
## x y z
## <dbl> <dbl> <dbl>
## 1 1 3 4
## 2 2 2 2
## 3 5 7 3
## 4 1 6 2

2.5.10 Hợp nhất dữ liệu bằng lệnh bind_rows và bind_cols


Trước hết tạo ra ba tibbles từ cùng một bộ dữ liệu gốc CPS1988:

a <- slice(CPS1988, 1:3)


b <- slice(CPS1988, 5:7)
c <- slice(CPS1988, c(100, 200))

Rõ ràng cả ba tibbles này có : (1) cùng số biến số, (2) cùng tên biến số, và (3) cùng thứ tự biến số. Hợp
nhất cả ba tibbles này như sau:

(all <- bind_rows(a, b, c))

## wage education experience ethnicity smsa region parttime


## 1 354.94 7 45 cauc yes northeast no
## 2 123.46 12 1 cauc yes northeast yes
## 3 370.37 9 9 cauc yes northeast no
## 4 593.54 12 36 cauc yes northeast no
## 5 377.23 16 22 cauc yes northeast no
## 6 284.90 8 51 cauc yes northeast no
## 7 688.51 18 16 cauc no northeast no
## 8 518.52 14 17 cauc no northeast yes

Lệnh bind_rows() ở trên tương đương với lệnh rbind() mà chúng ta đã biết.

Giả sử chúng ta có tibble tên là d chứa hai biến là uni (biến định tính cho biết có bằng đại học hay
không) và biến child (cho biết số con của người lao động):

Nguyễn Chí Dũng http://rpubs.com/chidungkt


70

d <- tibble(uni = c("yes", "no", "no"),


chil = c(1, 2, 4))

Rõ ràng a và d có cùng số quan sát và giả sử chúng ta muốn ghép hai bộ dữ liệu trên thành một bộ duy
nhất thì có hai cách làm, hoặc là a trước d sau, hoặc là ngược lại:

(ad <- bind_cols(a, d))

## wage education experience ethnicity smsa region parttime uni chil


## 1 354.94 7 45 cauc yes northeast no yes 1
## 2 123.46 12 1 cauc yes northeast yes no 2
## 3 370.37 9 9 cauc yes northeast no no 4

(da <- bind_cols(d, a))

## # A tibble: 3 × 9
## uni chil wage education experience ethnicity smsa region
## <chr> <dbl> <dbl> <int> <int> <fctr> <fctr> <fctr>
## 1 yes 1 354.94 7 45 cauc yes northeast
## 2 no 2 123.46 12 1 cauc yes northeast
## 3 no 4 370.37 9 9 cauc yes northeast
## # ... with 1 more variables: parttime <fctr>

Lệnh bind_cols() tương đương với lệnh merge() của gói base.

Có thể coi hai bộ dữ liệu này là mang cùng một thông tin. Nhưng với R chúng sẽ hiểu đây là hai tibbles
khác nhau vì thứ tự của các biến là khác.

Tất nhiên chức năng quản trị dữ liệu (Data Manupulation) của hệ sinh thái tidyverse rất phong phú
và rộng lớn chứ không chỉ giới hạn ở một số hàm cơ bản trên (lưu ý rằng các hàm này mới chỉ là các
hàm thuộc gói dplyr – một trong 6 gói của hệ sinh thái tidyverse). Chúng ta sẽ thấy sức mạnh của việc
sử dụng hệ sinh thái này (thực ra, nói cho đúng là mới chỉ sử dụng dplyr) cho Data Manipulation nói
chung và phân tích thống kê nói riêng ở mục 2.7. Tuy nhiên, để tiến đến mục 2.7 chúng ta cần hiểu rõ
vai trò của toán tử pipe ở mục 2.6 trước.

2.5.11 Dán lại nhãn cho các quan sát với hàm recode() hoặc recode_factor()
Trở lại với bộ dữ liệu ch4bt8.wf1 đã biết ở mục trước:

library(hexView)
hello <- readEViews("ch4bt8.wf1", as.data.frame = TRUE)

Có thể dán lại nhãn cho các quan sát theo một cách thức khác với hàm recode() của gói dplyr:

hello$BLACK <- dplyr::recode(hello$BLACK,


"1"= "Black",
"0" = "White")

str(hello)

## 'data.frame': 935 obs. of 14 variables:


## $ AGE : num 33 32 37 30 29 33 37 38 29 30 ...

Nguyễn Chí Dũng http://rpubs.com/chidungkt


71

## $ BLACK : chr "White" "White" "White" "White" ...


## $ EDUC : num 17 10 12 12 12 14 16 16 12 16 ...

Sử dụng lệnh recode() nhưng lại phải gõ thêm dplyr::là bởi vì hàm có tên recode() cũng là một hàm
của gói car nên để tránh tình trạng nhầm lẫn và gây ra lỗi, chúng ta cần chỉ định đính danh là sử dụng
hàm của gói dplyr (là một gói thuộc hệ sinh thái tidyverse) chứ không phải của gói car. Tổng quát là
trong những tình huống mà có nhiều hơn hai gói có cùng một tên hàm, thì để tránh tình huông mắc
lỗi (do R không biết cần phải sử dụng hàm nào) chúng ta cần chỉ thị rõ cho R biêt như trên.

Cách thức dán lại nhãn như trên thì biến BLACK lúc này sẽ là biến kí tự (character). Muốn dán nhãn
lại cho quan sát nhưng chuyển hóa luôn về dạng factor thì làm như sau (lấy biến URBAN làm ví dụ):

hello$URBAN <- dplyr::recode_factor(hello$URBAN,


"1"= "Dothi",
"0" = "Nongthon")
str(hello)

## 'data.frame': 935 obs. of 14 variables:


## $ SOUTH : num 1 1 0 0 1 1 0 0 0 0 ...
## $ SSIBS : num 3 3 1 2 1 1 1 7 5 3 ...
## $ URBAN : Factor w/ 2 levels "Dothi","Nongthon": 1 1 1 1 2 1 1 1 1 2 ...
## $ WAGE : num 3942 2700 2765 2789 2825 ...

Cần cẩn trọng khi dán lại nhãn cho quan sát. Ví dụ, với bộ data có tên all ở mục 2.5.10 thì thực hiện
lệnh như sau:

all$smsa <- recode(all$smsa,


"yes" = "Dothi",
"no" = "Nongthon")

Thì R sẽ báo lỗi. Nguyên nhân là bởi vì biến smsa của all là biến factor chứ không phải character như
hello:

str(all)

## 'data.frame': 8 obs. of 7 variables:


## $ wage : num 355 123 370 594 377 ...
## $ education : int 7 12 9 12 16 8 18 14
## $ experience: int 45 1 9 36 22 51 16 17
## $ ethnicity : Factor w/ 2 levels "cauc","afam": 1 1 1 1 1 1 1 1
## $ smsa : Factor w/ 2 levels "no","yes": 2 2 2 2 2 2 1 1
## $ region : Factor w/ 4 levels "northeast","midwest",..: 1 1 1 1 1 1 1
1
## $ parttime : Factor w/ 2 levels "no","yes": 1 2 1 1 1 1 1 2

Do vậy, để dán lại nhãn cần thực hiện như sau:

all$smsa <- recode_factor(all$smsa,


"yes" = "Dothi",
"no" = "Nongthon")
str(all)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


72

## 'data.frame': 8 obs. of 7 variables:


## $ wage : num 355 123 370 594 377 ...
## $ education : int 7 12 9 12 16 8 18 14
## $ experience: int 45 1 9 36 22 51 16 17
## $ ethnicity : Factor w/ 2 levels "cauc","afam": 1 1 1 1 1 1 1 1
## $ smsa : Factor w/ 2 levels "Dothi","Nongthon": 1 1 1 1 1 1 2 2
## $ region : Factor w/ 4 levels "northeast","midwest",..: 1 1 1 1 1 1 1
1
## $ parttime : Factor w/ 2 levels "no","yes": 1 2 1 1 1 1 1 2

2.5.12 Dán lại nhãn cho các quan sát với hàm if_else hoặc case_when
Trở lại với bài toán dán lại nhãn cho các quan sát thành các nhóm thu nhập ở mục 2.4.2, chúng ta
cũng có thể sử dụng hàm if_else() hoặc case_when() kết hợp vói hàm mutate() đã biết để dán nhãn
thành các nhóm thu nhập cho các quan sát như sau:

d <- readEViews("ch4bt8.wf1", as.data.frame = TRUE)


# Cách 1:
d <- mutate(d, Class = if_else(WAGE <= 3200, "Thap",
if_else(WAGE > 3200 & WAGE <= 3500,"TB", "Kha")))
table(d$Class)

##
## Kha TB Thap
## 352 314 269

# Cách 2:
d <- mutate(d, Class = case_when(d$WAGE <= 3200 ~ "Thap",
d$WAGE > 3200 & d$WAGE <= 3500 ~ "TB",
d$WAGE > 3500 ~ "Kha"))
table(d$Class)

##
## Kha TB Thap
## 352 314 269

Đến đây cũng là cơ hội để các bạn so sánh tốc độ xử lí và tính toán khi sử dụng hệ sinh thái tidyverse
và các hàm của gói base. Trước hết chúng ta tạo ra một mẫu gồm 10 triệu quan sát có mức thu nhập
nằm trong khoảng từ 2615 đến 5578 (đúng bằng khoảng lương trong mẫu 935 quan sát) bằng hàm
runif() sau đó so sánh thời gian cần thiết để máy tính xử lí công việc được giao:

# Tạo ra một data_frame tên là dt chỉ có mỗi một cột biến với 10 triệu quan
sát:
dt <- data_frame(WAGE = c(runif(10000000, 2615, 5578)))

system.time(dt$Class <- ifelse(dt$WAGE <= 3200, "Thap",


ifelse(dt$WAGE > 3200 & dt$WAGE <= 3500, "TB",
ifelse(dt$WAGE > 3500, "Kha", "Thap"))))

## user system elapsed


## 11.03 1.08 12.17

Nguyễn Chí Dũng http://rpubs.com/chidungkt


73

system.time(d <- mutate(dt, Class = case_when(dt$WAGE <= 3200 ~ "Thap",


dt$WAGE > 3200 & dt$WAGE <= 3500 ~ "TB
",
dt$WAGE > 3500 ~ "Kha")))

## user system elapsed


## 0.95 0.28 1.23

Có thể thấy thời gian xử lí bài toán dán nhãn này là chênh nhau xấp xỉ 10 lần (12.7 so với 1.23). Lưu
ý rằng, dữ liệu của chúng ta chỉ mới có 1 cột biến và chưa thực hiện nhiều tính toán phức tạp. Việc sử
dụng hệ sinh thái tidyverse và cấu trúc dữ liệu kiểu data_frame ít nhất sẽ tạo ra hiệu quả về mặt tính
toán.

2.5.13 Chuyển từ dạng wide sang long cho các nghiên cứu dữ liệu bảng với lệnh gather
Trước hết chúng ta hãy xem xét một data frame chứa thông tin về giá trị của ba công ti A, B và C có
định dạng như sau:

wide <- data.frame(Year = c(2015, 2014, 2013),


A = c(300, 250, 270),
B = c(100, 120, 134),
C = c(46, 55, 43))
wide

## Year A B C
## 1 2015 300 100 46
## 2 2014 250 120 55
## 3 2013 270 134 43

Nhưng trong nhiều tình huống nghiên cứu (điển hình là những nghiên cứu về dữ liệu bảng – Panel
Data) thì định dạng dữ liệu này (gọi là wide form) là không thích hợp và ta cần biến đổi chúng về
long form như sau:

long1 <- gather(wide, Firm, Value, -Year)


long2 <- gather(wide, Firm, Value, -Year, factor_key = TRUE)

long1

## Year Firm Value


## 1 2015 A 300
## 2 2014 A 250
## 3 2013 A 270
## 4 2015 B 100
## 5 2014 B 120
## 6 2013 B 134
## 7 2015 C 46
## 8 2014 C 55
## 9 2013 C 43

long2

Nguyễn Chí Dũng http://rpubs.com/chidungkt


74

## Year Firm Value


## 1 2015 A 300
## 2 2014 A 250
## 3 2013 A 270
## 4 2015 B 100
## 5 2014 B 120
## 6 2013 B 134
## 7 2015 C 46
## 8 2014 C 55
## 9 2013 C 43

Cả long1 và long2 đều chứa các thông tin như nhau. Điểm khác biệt duy nhất giữa chúng đó là với
long2 thì cột biến Firm ở dạng factor chứ không phải character:

str(long1)

## 'data.frame': 9 obs. of 3 variables:


## $ Year : num 2015 2014 2013 2015 2014 ...
## $ Firm : chr "A" "A" "A" "B" ...
## $ Value: num 300 250 270 100 120 134 46 55 43

str(long2)

## 'data.frame': 9 obs. of 3 variables:


## $ Year : num 2015 2014 2013 2015 2014 ...
## $ Firm : Factor w/ 3 levels "A","B","C": 1 1 1 2 2 2 3 3 3
## $ Value: num 300 250 270 100 120 134 46 55 43

Đương nhiên chúng ta có thể biến đổi ngược lại từ long form về wide form:

wide1 <- spread(long1, Firm, Value)


wide2 <- spread(long2, Firm, Value)
wide1

## Year A B C
## 1 2013 270 134 43
## 2 2014 250 120 55
## 3 2015 300 100 46

wide2

## Year A B C
## 1 2013 270 134 43
## 2 2014 250 120 55
## 3 2015 300 100 46

Biến đổi dữ liệu kiểu này được gọi là tái định hình dữ liệu (Reshaping Data) và là một kĩ năng quan
trọng không chỉ cho phân tích dữ liệu bảng mà còn cho nhiều công việc khác, điển hình là Data
Visualization.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


75

2.5.14 Hợp nhất có điều kiện theo cột cho các bộ dữ liệu
Ở mục 2.5.10 chúng ta đã thực hiện hợp nhất các dữ liệu nhưng đó là kiểu hợp nhất không có điều
kiện. Để minh họa chúng ta xét một tình huống thường xuyên gặp trong thực tế dưới đây:

# Tạo ra hai bộ dữ liệu:


df1 <- data_frame(StudentCode = c(1:6),
Department = c(rep("Finance", 3), rep("Accounting", 3)))

df2 <- data_frame(StudentCode = c(2, 4, 6),


Origin = c(rep("Ha Noi", 2), rep("Nghe An", 1)))
# Xem hai bộ dữ liệu này:
df1

## # A tibble: 6 x 2
## StudentCode Department
## <int> <chr>
## 1 1 Finance
## 2 2 Finance
## 3 3 Finance
## 4 4 Accounting
## 5 5 Accounting
## 6 6 Accounting

df2

## # A tibble: 3 x 2
## StudentCode Origin
## <dbl> <chr>
## 1 2 Ha Noi
## 2 4 Ha Noi
## 3 6 Nghe An

Bộ dữ liệu df1 là thông tin về nghành học và mã sinh viên của 6 sinh viên. Còn df2 là thông tin về quê
quán của 3 trong số 6 sinh viên có ở danh sách df1. Giả sử chúng ta muốn ghép thêm cột chứa thông
tin về quê quán của các sinh viên này căn cứ vào mã sinh viên của họ. Nghĩa là điều kiện ở đây là
quét sự trùng hay không về mã sinh viên ở hai bộ số liệu. Hãy quan sát hiệu ứng của các lệnh sau:

# inner joint:
inner_join(df1, df2, by = "StudentCode")

## # A tibble: 3 x 3
## StudentCode Department Origin
## <dbl> <chr> <chr>
## 1 2 Finance Ha Noi
## 2 4 Accounting Ha Noi
## 3 6 Accounting Nghe An

inner_join(df2, df1, by = "StudentCode")

## # A tibble: 3 x 3
## StudentCode Origin Department

Nguyễn Chí Dũng http://rpubs.com/chidungkt


76

## <dbl> <chr> <chr>


## 1 2 Ha Noi Finance
## 2 4 Ha Noi Accounting
## 3 6 Nghe An Accounting

# left outer:
left_join(df1, df2, by = "StudentCode")

## # A tibble: 6 x 3
## StudentCode Department Origin
## <dbl> <chr> <chr>
## 1 1 Finance <NA>
## 2 2 Finance Ha Noi
## 3 3 Finance <NA>
## 4 4 Accounting Ha Noi
## 5 5 Accounting <NA>
## 6 6 Accounting Nghe An

left_join(df2, df1, by = "StudentCode")

## # A tibble: 3 x 3
## StudentCode Origin Department
## <dbl> <chr> <chr>
## 1 2 Ha Noi Finance
## 2 4 Ha Noi Accounting
## 3 6 Nghe An Accounting

# right outer:
right_join(df1, df2, by = "StudentCode")

## # A tibble: 3 x 3
## StudentCode Department Origin
## <dbl> <chr> <chr>
## 1 2 Finance Ha Noi
## 2 4 Accounting Ha Noi
## 3 6 Accounting Nghe An

right_join(df2, df1, by = "StudentCode")

## # A tibble: 6 x 3
## StudentCode Origin Department
## <dbl> <chr> <chr>
## 1 1 <NA> Finance
## 2 2 Ha Noi Finance
## 3 3 <NA> Finance
## 4 4 Ha Noi Accounting
## 5 5 <NA> Accounting
## 6 6 Nghe An Accounting

# full join:
full_join(df1, df2)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


77

## # A tibble: 6 x 3
## StudentCode Department Origin
## <dbl> <chr> <chr>
## 1 1 Finance <NA>
## 2 2 Finance Ha Noi
## 3 3 Finance <NA>
## 4 4 Accounting Ha Noi
## 5 5 Accounting <NA>
## 6 6 Accounting Nghe An

full_join(df2, df1)

## # A tibble: 6 x 3
## StudentCode Origin Department
## <dbl> <chr> <chr>
## 1 2 Ha Noi Finance
## 2 4 Ha Noi Accounting
## 3 6 Nghe An Accounting
## 4 1 <NA> Finance
## 5 3 <NA> Finance
## 6 5 <NA> Accounting

# semi join:
semi_join(df1, df2)

## # A tibble: 3 x 2
## StudentCode Department
## <int> <chr>
## 1 2 Finance
## 2 4 Accounting
## 3 6 Accounting

semi_join(df2, df1)

## # A tibble: 3 x 2
## StudentCode Origin
## <dbl> <chr>
## 1 2 Ha Noi
## 2 4 Ha Noi
## 3 6 Nghe An

# anti joint:
anti_join(df1, df2)

## # A tibble: 3 x 2
## StudentCode Department
## <int> <chr>
## 1 1 Finance
## 2 3 Finance
## 3 5 Accounting

anti_join(df2, df1)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


78

## # A tibble: 0 x 2
## # ... with 2 variables: StudentCode <dbl>, Origin <chr>

Gói base cũng có lệnh nhằm xử lí các tình huốn công việc tương tự là merge.

2.6 Toán tử tẩu thuốc pipe (%>%)


Để sử dụng toán tử này, trước hết các bạn cài đặt gói magrittr. Để hiểu ý nghĩa của toán tử pipe
(%>%) chúng ta xét tình huống rất thường gặp trong thực tế dưới đây.

Giả sử với bộ dữ liệu CPS1988, chúng ta cần chỉ ra 5 quan sát có mức lương lớn nhất và những quan
sát này phải thỏa mãn các điều kiện sau: (1) có năm kinh nghiệm lớn hơn 10, (2) đến từ miền tây
nước Mĩ. Thông thường chúng ta giải quyết bài toán này theo ba bước như sau:

# Bước 1
df1 <- filter(CPS1988, experience > 10 & region == "west")
# Bước 2
df2 <- arrange(df1, desc(wage))
# Bước 3
slice(df2, 1:5)

## wage education experience ethnicity smsa region parttime


## 1 10288.00 14 36 cauc yes west no
## 2 5143.98 18 26 cauc no west yes
## 3 5092.59 12 38 cauc no west no
## 4 4264.87 16 16 cauc yes west no
## 5 4115.23 18 31 cauc yes west yes

Nghĩa là để có kết quả cuối cùng, bạn phải gõ ba dòng lệnh khác nhau và tạo ra hai đối tượng (gọi là
object) trung gian là df1 và df2. Cụ thể, bằng lệnh filter bạn tạo ra df1 là một tibble gồm các quan sát
có nhiều hơn 10 năm kinh nghiệm và đến từ miền tây nước Mĩ. Kế tiếp, bạn sử dụng lệnh arrange để
“xử lí” df1 nhằm tạo ra df2 (cũng là một tibble) với các quan sát được sắp xếp theo mức lương giảm
dần. Cuối cùng, bạn sử dụng lệnh slice để “xử lí” df2 nhằm có câu trả lời cuối cùng cho bài toán.

Có hai object trung gian được tạo ra theo cách làm này. Bạn hãy nhớ kĩ điều này. Bạn có thể đo kích
thước của, chẳng hạn, object có tên df1 bằng lệnh object_size() như sau:

pryr::object_size(df1)

## 132 kB

Kích thước của df1 là 132 kB. Đây cũng là dung lượng mà bộ nhớ trong của máy tính phải phân bổ để
“chứa” object này.

Tất nhiên, trong tình huống của chúng ta, kích thước này là không lớn và để đạt kết quả cuối cùng các
bạn cũng chỉ tạo ra hai object trung gian mà thôi. Nhưng cách thức làm như trên sẽ thực sự tạo ra
một vấn đề nếu kích thước các object trung gian tạo ra là rất lớn và tạo ra nhiều object trung gian để
có kết quả cuối cùng. Để tránh tạo ra nhiều object trung gian chiếm bộ nhớ (mục đích chính) và làm
tiết kiệm thời gian gõ phím (mục đích phụ) chúng ta sử dụng toán tử %>% (còn gọi là pipe) để có
cùng kết quả trên như sau với chỉ một dòng lệnh:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


79

CPS1988 %>%
filter(experience > 10 & region == "west") %>%
arrange(desc(wage)) %>%
slice(1:5)

## wage education experience ethnicity smsa region parttime


## 1 10288.00 14 36 cauc yes west no
## 2 5143.98 18 26 cauc no west yes
## 3 5092.59 12 38 cauc no west no
## 4 4264.87 16 16 cauc yes west no
## 5 4115.23 18 31 cauc yes west yes

Kí kiệu %>% nên được dịch ra tiếng Việt thành “kế đến là”. Do đó, ý nghĩa của dòng lệnh trên được
diễn giải dễ hiểu như sau. Lấy CPS1988 làm nguyên liệu đầu vào, kế đến là dùng lệnh filter để lọc, kế
đến là dùng lệnh arrange để sắp xếp các quan sát, kế đến là dùng lệnh slice để chọn ra 5 quan sát có
mức lương lớn nhất.

Chú ý rằng hệ sinh thái tidyverse đã tích hợp toán tử pipe nên khi sử dụng toán tử này chúng ta không
cần phải gọi gói magrittr. Trong các tình huống khác, để sử dụng được toán tử pipe (coi như là một
hàm) thì chúng ta phải gọi gói magrittr trước với lệnh library(margrittr).

Không phải ngẫu nhiên mà toán tử %>% có tên là pipe – nghĩa là cái tẩu thuốc. Có lẽ, cách hay để các
bạn hiểu toán tử này là gắn nó với hình ảnh của một hệ thống đường ống xử lí nước, theo đó, CPS1988
là “nước” cần xử lí (nguyên liệu đầu vào) và cứ sau mỗi dấu %>% tương ứng với một lệnh của R là
một khâu xử lí nước.

Với Rstudio, để có kí hiệu %>% các bạn gõ tổ hợp ba phím là Ctrl + Shift + M.

Tất nhiên, để có kết quả như trên các bạn có thể sử dụng toán tử pipe theo cách thức đơn sơ như sau:

# Bước 1
df1 <- CPS1988 %>% filter(experience > 10 & region == "west")
# Bước 2
df2 <- df1 %>% arrange(desc(wage))
# Bước 3
df2 %>% slice(1:5)

## wage education experience ethnicity smsa region parttime


## 1 10288.00 14 36 cauc yes west no
## 2 5143.98 18 26 cauc no west yes
## 3 5092.59 12 38 cauc no west no
## 4 4264.87 16 16 cauc yes west no
## 5 4115.23 18 31 cauc yes west yes

Nếu đến đây các bạn thấy quá tải thì nên quay trở lại , nếu không là tất cả được, thì nên ứng dụng toán
tử này ở bất cứ dòng lệnh nào có thể được. Ví dụ, với df18 ở mục 2.5.6 có thể thay bằng:

df18 <- CPS1988 %>% transmute(luong = wage / 1000, age = education + experien
ce + 6, khuvuc = region)

Bằng cách này các bạn sẽ dần quen với toán tử pipe. Và chỉ có cách này mà thôi: thực hành đủ nhiều.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


80

2.7 Tính các thống kê cơ bản với bộ số liệu PISA sử dụng gói dplyr
Cuối năm 2016 tổ chức PISA (http://www.oecd.org/pisa/) công bố một kết quả gây sock và tạo ra
nhiều tranh luận nảy lửa về chất lượng giáo dục của Việt Nam. Theo đó, học sinh Việt Nam có thứ
hạng cao ở cả ba môn được khảo sát là Toán, Đọc Hiểu, và Khoa Học và có vị trí cao hơn cả Hoa Kì, Úc
– là những quốc gia có mức GDP và chất lượng giáo dục cao.

Bỏ qua vấn đề chọn mẫu khảo sách cho các thí sinh đến từ Việt Nam có hợp lí hay không, chúng ta có
thể sử dụng bộ số liệu PISA1.csv để tạo ra những kết quả mà tổ chức này công bố và được các báo
Việt Nam trích dẫn lại. Cụ thể các kết quả cần có, tính theo các quốc gia, là: (1) điểm trung bình, (2)
độ lệch chuẩn , (3) điểm nhỏ nhất – lớn nhất, và (4) số lượng học sinh được khảo sát.

Bộ số liệu này có rất nhiều biến, trong đó các biến mà chung ta quan tâm là CNT (tên các quốc gia),
MATH (điểm toán), SCIE (điểm khoa học) và READ (điểm đọc hiểu).

Những gì bạn sắp đối mặt có thể là một thử thách nhỏ và tôi hi vọng bạn có thể vượt qua. Các tính
toán dưới đây có sử dụng toán tử pipe với lưu ý rằng khi sử dụng hệ sinh thái tidyverse thì toán tử
này (vốn thuộc gói magrittr) sẽ tự động được triệu hồi và do đó chúng ta không cần thực hiện lệnh
library(magrittr) như thường thấy. Trước hết chúng ta tính các thống kê trên cho môn toán:

pisa <- read_csv("PISA1.CSV")


df1 <- pisa %>% group_by(CNT) %>%
summarise_each(funs(mean, max, min, sd, n()), MATH) %>%
arrange(desc(mean))
# Xem kết quả
df1

## # A tibble: 5 × 6
## CNT mean max min sd n
## <chr> <dbl> <dbl> <dbl> <dbl> <int>
## 1 Singapore 568.3597 910.742 191.0030 104.71272 5546
## 2 Viet Nam 510.5900 824.747 204.3230 83.52549 4959
## 3 Australia 492.8429 848.972 59.6744 98.53494 14481
## 4 USA 481.0325 822.021 174.0220 89.18490 4978
## 5 Thailand 441.1471 769.520 107.6570 91.86163 6606

Ý nghĩa các (thực sự chúng là một chuỗi dòng lệnh) ở đây là:

 group_by(CNT) ngụ ý rằng các tính toán sau đó được thực hiện theo từng quốc gia.
 summarise_each(funs(mean, max, min, sd, n()), MATH) lần lược áp dụng các hàm
tính trung bình (mean), lớn nhất (max), nhỏ nhất (min), độ lệch chuẩn (sd) và đếm (n()) cho
biến MATH.
 arrange(desc(mean)) sắp xếp kết quả theo thứ tự giảm dần của trung bình.

Nếu muốn chúng ta có thể đặt tên cho kết quả cuối cùng thu được (theo kiểu viết tắt cho bạn đọc
không biết tiếng Anh) như sau:

df2 <- pisa %>% group_by(CNT) %>%


summarise_each(funs(TB = mean, LN = max, NN = min, LC = sd, N = n()), MATH)
%>%

Nguyễn Chí Dũng http://rpubs.com/chidungkt


81

arrange(desc(TB))
# Xem kết quả
df2

## # A tibble: 5 × 6
## CNT TB LN NN LC N
## <chr> <dbl> <dbl> <dbl> <dbl> <int>
## 1 Singapore 568.3597 910.742 191.0030 104.71272 5546
## 2 Viet Nam 510.5900 824.747 204.3230 83.52549 4959
## 3 Australia 492.8429 848.972 59.6744 98.53494 14481
## 4 USA 481.0325 822.021 174.0220 89.18490 4978
## 5 Thailand 441.1471 769.520 107.6570 91.86163 6606

Có thể đổi tên biến CNT thành Country:

df3 <- pisa %>% rename(Country = CNT) %>%


group_by(Country) %>%
summarise_each(funs(TB = mean, LN = max, NN = min, LC = sd, N = n()), MATH)
%>%
arrange(desc(TB))
# Xem kết quả
df3

## # A tibble: 5 × 6
## Country TB LN NN LC N
## <chr> <dbl> <dbl> <dbl> <dbl> <int>
## 1 Singapore 568.3597 910.742 191.0030 104.71272 5546
## 2 Viet Nam 510.5900 824.747 204.3230 83.52549 4959
## 3 Australia 492.8429 848.972 59.6744 98.53494 14481
## 4 USA 481.0325 822.021 174.0220 89.18490 4978
## 5 Thailand 441.1471 769.520 107.6570 91.86163 6606

Dù sao kết quả trên cũng thực sự xấu. Chúng ta nên làm đẹp kết quả bằng làm tròn các kết quả thành
0 chữ số sau dấu chấm bằng hàm round(). Nhưng tibble df3 lại chứa biến định tính Country mà hàm
round() thì không áp dụng cho biến định tính. Nên chiến lược được chấp nhận ở đây là tách (hay xóa)
biến định tính Country ra, rồi gán lại cuối cùng là sắp xếp lại:

toan <- df3 %>% select(-Country) %>% round()


toan$Country <- df3$Country
(toan <- toan %>% select(Country, everything()))

## # A tibble: 5 × 6
## Country TB LN NN LC N
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Singapore 568 911 191 105 5546
## 2 Viet Nam 511 825 204 84 4959
## 3 Australia 493 849 60 99 14481
## 4 USA 481 822 174 89 4978
## 5 Thailand 441 770 108 92 6606

Nguyễn Chí Dũng http://rpubs.com/chidungkt


82

Còn một cách làm ngắn gọn, nhưng đòi hỏi các bạn cần biết viết hàm (hay lập trình hàm – funcional
programming) như sau:

(df3 <- df3 %>% mutate_if(is.numeric, function(x) round(x, 0)))

## # A tibble: 5 × 6
## Country TB LN NN LC N
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Singapore 568 911 191 105 5546
## 2 Viet Nam 511 825 204 84 4959
## 3 Australia 493 849 60 99 14481
## 4 USA 481 822 174 89 4978
## 5 Thailand 441 770 108 92 6606

Ví dụ này cũng cho thấy sức mạnh và sự linh hoạt của kĩ năng lập trình đối khi thực hiện công việc
phân tích dữ liệu.

Với tibble có tên toan (hoặc df3) ở trên chúng ta có thể tạo ra một báo cáo đẹp với gói DT:

library(DT)
datatable(toan, rownames = FALSE, colnames = c("Quốc Gia",
"Trung Bình",
"Nhỏ Nhất",
"Lớn Nhất",
"Độ Lệch Chuẩn",
"Số Lượng HS"),
caption = "Bảng 1: Kết quả khảo sát môn Toán")

Tất nhiên chúng ta có thể lặp lại quá trình trên cho điểm đọc hiểu và khoa học. Nhưng đó không phải
là một chiến lược hiệu quả. Nên làm như sau (không hiển thị kết quả):

all <- pisa %>% group_by(CNT) %>%


summarise_each(funs(mean, max, min, sd, n()), MATH, READ, SCIE)

Sau đó xem qua những gì thu được:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


83

names(all)
View(all)

Dựa trên những gì quan sát được chúng ta có cách thức tách ra từng bộ dữ liệu tính các thống kê cho
toán, đọc, và khoa học như sau với lệnh select nhưng có thêm lựa chọn contains:

(math <- all %>% select(CNT, contains("MATH")))


(read <- all %>% select(CNT, contains("READ")))
(scie <- all %>% select(CNT, contains("SCIE")))

Ở đây, ngoài chọn biến CNT với lựa chọn contains("MATH") chẳng hạn có nghĩa là chúng ta chọn
các biến có chứa kí tự MATH.

Với các tiêu chí thống kê cho môn toán chẳng hạn chúng ta có thể làm đẹp hơn:

(math <- all %>% select(CNT, contains("MATH")) %>% arrange(desc(MATH_mean)))

Thậm chí còn đẹp hơn nữa (không hiển thị kết quả):

math <- all %>% select(CNT, contains("MATH")) %>%


arrange(desc(MATH_mean)) %>% mutate_if(is.numeric, function(x) round(x, 0))

math

Ở trên các bạn đã sử dụng một hàm là summarise_each(). Hàm này áp dụng một , thậm chí một loạt
hàm cho một hoặc thậm chí nhiều biến số như các bạn đã thấy. Có tác dụng tương tự là hàm
summarise():

pisa %>% group_by(CNT) %>%


summarise(mean(MATH), sd(MATH), max(MATH), min(MATH), n())

Như các bạn có thể thấy trong tình huống bài toán của chúng ta thì lệnh này không hiệu quả bằng sử
dụng lệnh summarise_each().

Nhưng trong bất cứ trường hợp nào, nếu thực hiện những đòi hỏi tính toán như mô tả ở trên, nếu sử
dụng SPSS, STATA , Eviews, thậm chí là Excel thì chắc chắn không thể nhanh hơn sử dụng R (về thời
gian cần thao tác lẫn tốc độ). Nếu bộ dữ liệu mà hàng triệu hay hàng chục triệu quan sát thì bạn sẽ
thấy ngay lập tức hiệu ứng tốc độ và nhanh gọn khi sử dụng R cho những thống kê đơn giản này.

2.8 Lưu các dữ liệu đã có trong R thành file Excel, Stata


Với file dữ liệu (hay tibble) all ở trên , các bạn có thể lưu lại trong R:

save(all, file = "diem_ba_mon.rda")

Bằng cách này chúng ta đã lưu file dữ liệu với tên diem_ba_mon.rda. Đây là file dữ liệu mà R có thể
đọc trực tiếp. Để biết file được lưu ở đâu các bạn cần biết đường dẫn hiện thời của R bằng cách gõ:

getwd()

Nguyễn Chí Dũng http://rpubs.com/chidungkt


84

Trong tình huống này file diem_ba_mon.rda được lưu ở folder có tên KTLR ở ổ D với đường dẫn
miêu tả như trên. Giả sử bạn đã thoát khỏi R. Để R tải lại file dữ liệu này:

setwd("D:/KTLR")

load("trangxinh.rda")

Bằng lệnh này, bạn lại trở lại làm việc với tibble có tên diem_ba_mon.rda.

Câu lệnh mà bạn vừa thực hiện ở trên đã lưu file all thành file có tên diem_ba_mon.rda và chỉ sử
dụng được trong R. Trong nhiều tình huống chúng ta cần lưu file này ở các định dạng khác nhau. Một
nguyên tắc chung cần tuân thủ là: nếu bạn sử dụng gói xlsx để đọc một file ở dạng Excel vào R thì khi
muốn lưu một data.frame sẵn có trong R thành một file Excel, công việc đầu tiên là bạn phải gọi gói
xlsx. Trong tình huống của chúng ta, vì đã gọi gói xlsx rồi nên chúng ta không cần thiết phải thực hiện
lệnh gọi gói xlsx. Giả sử với data.frame có tên dung ở mục 2.2.1 chúng ta muốn lưu file này ở dạng
Excel hoặc Stata với tên mới bất kì nào đó chúng ta làm như sau.

Lưu ở dạng file Excel có đuôi .xlsx:

write.xlsx(dung, "adam.xlsx")

Lúc này sẽ có một file Excel có tên adam.xlsx lưu ở thư mục hiện thời mà R làm việc, tức KTLR.

Lưu ở dạng file Stata có đuôi .dta:

write.dta(dung, "hehe.dta")

Bằng cách này chúng ta lưu file dung thành file Stata có tên hehe.dta.

Tuy nhiên tôi khuyến cáo là lưu các dữ liệu ở dạng .csv – một định dạng mà R đọc nhanh hơn:

write.csv(dung, "trangyeu.csv")

Còn nhiều câu lệnh để lưu một data frame sẵn có thành nhiều đinh dạng khác nhau. Nhưng điều này
thực sự không cần thiết vì hầu hết các phần mềm thống kê đều đọc được lẫn nhau. Ví dụ SPSS có thể
đọc được file Stata (và ngược lại). Còn đối với file Excel thì tất cả các phần mềm thống kê thường sử
dụng như Eviews, SPSS, Stata.. đều có thể đọc được. Nên các câu lệnh kia là không cần thiết. Bạn chỉ
cần chuyển một data frame trong R ra một file Excel – một định dạng mà hầu hết các phần mềm khác
đều sử dụng được.

2.9 Lưu các kết quả, các lệnh đã thực hiện cũng như các Objects để sử dụng cho lần sau
R là một ngôn ngữ lập trình hướng đối tượng (Object-oriented programming). Vậy như thế nào là
một đối tượng (Object) trong R? Nói cho dễ hiểu, một đối tượng trong R là bất cứ thứ gì được tạo ra
bởi phép gán <- (hoặc dấu = ). Và đương nhiên đối tượng phải được đặt tên.

Trở lại với mục 2.1 để minh họa khái niệm này. Ở đây chúng ta tạo ra ba biến số - hay ba đối tượng có
tên luong, thunhapkhac và chitieu. Mặt khác, lệnh trangxinh <- data.frame(luong, thunhapkhac,
chitieu) tạo ta một đối tượng thứ cấp có tên là trangxinh (gọi là thứ cấp vì nó được tạo ra từ ba đối
tượng đã có).

Nguyễn Chí Dũng http://rpubs.com/chidungkt


85

Một đối tượng cũng có thế là kết quả của một phân tích phức tạp nào đó, chẳng hạn, của phân tích hồi
quy OLS. Ở mục 2.8 chúng ta đã biết các lưu data_frame có tên all (là một object có cấu trúc tibble)
thành file có tên diem_ba_mon.rda. Tuy nhiên trong nhiều tình huống, chúng ta muốn không chỉ lưu
lại data frame này mà còn là tất cả các objects khác như sau:

save(list=ls(), file = "tatcaobjects.RData")

Với lệnh này chúng ta sẽ lưu lại tất cả các objects vào file có tên tatcaobjects.Rdata. Tất nhiên file
này được lưu ở thư mục hiện thời là KTLR thuộc ổ D của máy tính. Nếu muốn sử dụng tất cả các
objects này cho các lần phân tích sau:

load("tatcaobjects.RData")

Để biết hiện R đang quản lý những object nào chúng ta dùng lệnh:

ls()

Trong một số tình huống, chúng ta cũng còn cần quét sạch (loại bỏ) tất cả các object như sau:

rm(list = ls())

Duới đây là hai câu lệnh hiển thị 25 dòng cũng như tất cả các câu lệnh lệnh vừa thực hiện:

history() # Hiển thị 25 dòng lệnh.


history(max.show = Inf) # Hiển thị tất cả dòng lệnh đã thực hiện.

Dưới đây là những lệnh để lưu lại tất cả dòng lệnh với một file có tên là caclenh.Rhistory cũng như
tải lại các dòng lệnh được lưu trong file này:

savehistory(file = "caclenh.Rhistory") # Lưu lại tất cả dòng lệnh.


loadhistory("caclenh.Rhistory")

Lưu lại tất cả các object cũng như lệnh là một lợi thế của R so với nhiều phần mềm thống kê – kinh tế
lượng khác. Điều này đặc biệt hữu ích nếu những phân tích của chúng ta kéo dài trong nhiều ngày,
thậm chí nhiều tuần.

2.10 Thực hiện các tính toán thông thường, đại số tuyến tính
R cũng có thể thực hiện mọi chức năng tính toán số học thông thường và cả các phép tính phức tạp
như tìm ma trận nghịch đảo, ma trận chuyển vị, nhân ma trận.. đến tính tích phân. Tuy nhiên, trong
mục này chúng ta chỉ xem xét những chức năng tính toán cơ bản nhất trong R. Dưới đây là một số câu
lệnh mà các bạn nên thực hiện để tự tìm hiểu các chức năng tính toán của R:

3 + 4

## [1] 7

3*4

## [1] 12

Nguyễn Chí Dũng http://rpubs.com/chidungkt


86

3 / 4

## [1] 0.75

2^3

## [1] 8

Các bạn cũng có thể thấy R là một ngôn ngữ hướng đối tượng. Ví dụ trong chuỗi câu lệnh dưới đây
tạo tạo một đối tượng (Object) có tên bankinh và gán cho nó giá trị 2 rồi thực hiện các tính toán bình
thường:

bankinh <- 2
chuvi=2*pi*bankinh
chuvi

## [1] 12.56637

abs(-2)

## [1] 2

sqrt(9)

## [1] 3

Với biến số luong chúng ta có thể thực hiện một số tính toán sau:

luong*luong

## [1] 400 900 784 576 1764 1296 1024 1156 576 484 784 900

1 / luong

## [1] 0.05000000 0.03333333 0.03571429 0.04166667 0.02380952 0.02777778


## [7] 0.03125000 0.02941176 0.04166667 0.04545455 0.03571429 0.03333333

mean(luong)

## [1] 29.16667

luong / 4

## [1] 5.0 7.5 7.0 6.0 10.5 9.0 8.0 8.5 6.0 5.5 7.0 7.5

Tất nhiên chức năng tính toán của R không chỉ giới hạn như như vậy. Chúng ta sẽ quen dần với các
tính toán phức tạp hơn của R trong các chương sau.

R cũng có thể thực hiện tất cả các tính toán của đại số tuyến tính. Giả sử chúng ta có ma trận A như
sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


87

2 5 2
𝐴=[ ]
6 1 4
Tạo ma trận này trong R:

A <- matrix(c(2, 5, 2, 6, 1, 4), nrow = 2, byrow = TRUE)


dim(A) # Xem số hàng và cột của ma trận A.

## [1] 2 3

## [,1] [,2] [,3]


## [1,] 2 5 2
## [2,] 6 1 4

Tạo ma trận chuyển vị AT của A:

At <- t(A)
At

## [,1] [,2]
## [1,] 2 6
## [2,] 5 1
## [3,] 2 4

Chú ý điểm khác biệt giữa các lệnh trong việc tạo ma trận mà chúng ta vừa sử dụng với:

B <- matrix(c(2, 5, 2, 6, 1, 4), nrow = 2, byrow = FALSE)


B

## [,1] [,2] [,3]


## [1,] 2 2 1
## [2,] 5 6 4

B <- matrix(c(2, 5, 2, 6, 1, 4), nrow = 2)


B

## [,1] [,2] [,3]


## [1,] 2 2 1
## [2,] 5 6 4

Với ma trận đơn vị I dưới đây:

1 0 0
𝐼 = [0 1 0 ]
0 0 1
I <- diag(3) # Tạo ma trận đơn vị kích thước 3
I

Nguyễn Chí Dũng http://rpubs.com/chidungkt


88

## [,1] [,2] [,3]


## [1,] 1 0 0
## [2,] 0 1 0
## [3,] 0 0 1

2*A # Nhân ma trận A với mộ số 2.

## [,1] [,2] [,3]


## [1,] 4 10 4
## [2,] 12 2 8

A*A # Chú ý kiểu nhân này vì nó khác với ma trận nhân ma trận.

## [,1] [,2] [,3]


## [1,] 4 25 4
## [2,] 36 1 16

Giả sử chúng ta cần thực hiện phép trừ hai ma trận sau:

2 6 −2 8.1
[5 1] − [ 3 8.2 ]
2 4 6 −9.8
m <- matrix(c(2, 5, 2, 6, 1, 4), nrow = 3)
m

## [,1] [,2]
## [1,] 2 6
## [2,] 5 1
## [3,] 2 4

n <- matrix(c(-2, 3, 6, 8.1, 8.2, -9.8), nrow = 3)


n

## [,1] [,2]
## [1,] -2 8.1
## [2,] 3 8.2
## [3,] 6 -9.8

m-n

## [,1] [,2]
## [1,] 4 -2.1
## [2,] 2 -7.2
## [3,] -4 13.8

Thực hiện phép nhân ma trận với ma trận dưới đây:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


89

3 −3
2 5 2
[ ] . [−1 1]
6 1 4
1 5
Thực hiện trong R:

A <- rbind(c(2, 5, 2), c(6, 1, 4))


A

## [,1] [,2] [,3]


## [1,] 2 5 2
## [2,] 6 1 4

B <- cbind(c(3, -1, 1), c(-3, 1, 5))


B

## [,1] [,2]
## [1,] 3 -3
## [2,] -1 1
## [3,] 1 5

C=A%*%B # Nhân hai ma trận


C

## [,1] [,2]
## [1,] 3 9
## [2,] 21 3

B%*%A # Kiểm tra tính chất của nhân ma trận: AB thường là khác BA.

## [,1] [,2] [,3]


## [1,] -12 12 -6
## [2,] 4 -4 2
## [3,] 32 10 22

Tìm ma trận nghịch đảo của:

3 1
[ ]
4 2
A <- matrix(c(3, 4, 1, 2), nrow = 2)
A

## [,1] [,2]
## [1,] 3 1
## [2,] 4 2

A.nd <- solve(A)


A.nd

Nguyễn Chí Dũng http://rpubs.com/chidungkt


90

## [,1] [,2]
## [1,] 1 -0.5
## [2,] -2 1.5

A%*%A.nd # Kiểm tra tính chất của ma trận nghịch đảo

## [,1] [,2]
## [1,] 1 0
## [2,] 0 1

Giải hệ phương trình sau:

𝑥1 + 𝑥2 = 2
−𝑥1 + 𝑥2 = 4
Hệ này được viết theo ngôn ngữ ma trận là:
1 1 𝑥1 2
( ) (𝑥 )=( )
−1 1 2 4
Giả hệ này trong R như sau:

a <- matrix(c(1, -1, 1, 1), nrow = 2, ncol = 2)


b <- matrix(c(2, 4), nrow = 2)
solve(a)%*%b # Cách 2

## [,1]
## [1,] -1
## [2,] 3

solve(a, b) # Cách 1

## [,1]
## [1,] -1
## [2,] 3

Kết quả này nghĩa là x1 = -1 và x2 = 3 như chúng ta đã biết trong quy ước của đại số tuyến tính.

R còn có thể thực hiện nhiều tính toán phức tạp khác không chỉ cho đại số tuyến tính mà còn là giải
tích, tối ưu hóa hay xây dựng các mô hình xác suất, các mô hình thống kê. Trên đây chỉ minh họa
những tính năng cơ bản (nhưng thiết yếu cho kinh tế lượng). Những tính toán phức tạp và chuyên
sâu hơn với R các bạn có thể tìm thấy ở nhiều tài liệu khác nhau.

2.11 Mô phỏng dữ liệu


Mô phỏng dữ liệu (Data Stimulation hay Random Number Generator như cách gọi của một số tài liệu)
chắc chắn là một trong những thế mạnh của R so với một số phần mềm khác. Nó có thể thực hiện một
loạt các mô phỏng từ đơn giản đến các mô phỏng phức tạp như Monte Carlo. Mô phỏng dữ liệu trong
nghiên cứu thống kê và kinh tế lượng là đặc biệt quan trọng trong việc kiểm tra, đánh giá các khía

Nguyễn Chí Dũng http://rpubs.com/chidungkt


91

cạnh lý thuyết của các mô hình cũng như các phương pháp thống kê. Đặc biệt quan trọng là mô phỏng
Monte Carlo – vốn phát sinh từ nỗ lực chế tạo quả bom nguyên tử đầu tiên thuộc dự án tối mật
Manhattan cuối những năm thế chiến thứ hai. Tuy nhiên, trong chương này chúng ta không đi sâu
vào các mô phỏng phức tạp mà chỉ chỉ quan tâm đến một số chức năng mô phỏng đơn giản của R cho
một số phân phối mà chúng ta hay sử dụng được cho ở bảng sau:

Phân phối Hàm trong R

Chuẩn/chuẩn hóa rnorm(n,mean=a,sd=b)

Student rt(n,df=m)

F rf(n,df1=a,df2=b)

Khi bình phương rchisq(n,df=m)

Ví dụ, chúng ta có thể tạo 100 quan sát ngẫu nhiên với trung bình là 50 và sai số chuẩn là 10:

rnorm(100, mean = 50, sd = 10)

## [1] 41.28354 55.34666 43.76292 24.53415 51.53372 53.74936 57.42527


## [8] 53.45937 53.77525 68.89104 52.47444 38.74406 63.39999 53.68108

Chú ý rằng các con số mà bạn thu được là không giống của tôi. Và mỗi khi thực hiện lại chính câu lệnh
trên thì kết quả lại khác. Ngoài ra mean và sd ứng với các quan sát thu được cũng không nhất thiết
bằng 50 và 10. Để cố định các kết quả trước khi thực hiện lệnh trên chúng ta thực hiện lệnh “gieo hạt”
như đã biết:

set.seed(29)

Để thuận tiện chúng ta nên gán 100 quan sát này thành một vector (hiểu như là một object, biến số
trong R) với tên là x chẳng hạn:

x <- rnorm(100, mean = 50, sd = 10)


mean(x)

## [1] 48.8063

sd(x)

## [1] 10.0689

Các bạn có thể thấy rằng trung bình là 48.86 và độ lệch chuẩn là 10.07 chứ không chính xác bằng 50
và 10. Nếu bạn thực hiện khoảng 1 tỉ lần tạo mẫu ngẫu nhiên và bạn có 1 tỉ cặp giá trị trung bình cũng
như độ lệch chuẩn rồi lấy trung bình cho chúng thì kết quả sẽ tiến sát đến 50, 10. Về lý thuyết, nếu
bạn thực hiện qúa trình này vô cùng lần thì các trung bình lần lượt chính xác bằng 50 và 10.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


92

Tương tự chúng ta cũng có thể tạo ra 100 quan sát với bậc tự do df = 3 có phân phối t:

y <- rt(100, df = 3)
y

## [1] 0.08525748 -5.27759225 0.41638373 -0.51700592 -1.34141205


## [6] 0.25089202 0.61853007 -0.30569410 1.19343507 -1.18899930
## [11] 0.79908437 1.37237856 0.88302365 -0.83954532 -0.26874577

Chúng ta có thể thực hiện các phân tích hình ảnh với mẫu ngẫu nhiên y:

par(mfrow = c(1, 2))


plot(density(y))
hist(y)

par(mfrow = c(1, 1)) # Trở lại chế độ hiển thị mặc định

Tất nhiên chúng ta có thể thực hiện nhiều phân tích với các dữ liệu mô phỏng thu được như phân tích
hồi quy y theo x:

summary(lm(y ~ x))
## Call:
## lm(formula = y ~ x)
##
## Residuals:
## Min 1Q Median 3Q Max
## -4.8723 -0.7264 0.0295 0.9023 3.5094
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.677736 0.706838 -0.959 0.340
## x 0.007291 0.014187 0.514 0.608
##
## Residual standard error: 1.421 on 98 degrees of freedom

Nguyễn Chí Dũng http://rpubs.com/chidungkt


93

## Multiple R-squared: 0.002688, Adjusted R-squared: -0.007488


## F-statistic: 0.2642 on 1 and 98 DF, p-value: 0.6084

Khả năng mô phỏng của R chúng ta sẽ dần tìm hiểu trong các chương sau của tài liệu.

2.12 Viết và trình bày R code đúng cách


R code ngoài viết đúng cú pháp còn phải thỏa mãn tiêu chí rằng chúng được trình bày đúng chuẩn.
Như Hadley Wickham một nhà khoa học dữ liệu ở Rstudio và R Core Team kiêm giáo sư thống kê ở
Rice University đã nói: “Good coding style is like using correct punctuation. You can manage
without it, but it sure makes things easier to read”.
Mục này sẽ trình bày một số nguyên tắc cơ bản của viết code đúng cách. Cụ thể là:
1. Tên của các object nên được đặt để có thể hiểu được ý nghĩa của nó và nên sử dụng dấu gạch
dưới như hoi_quy, phan_du. Theo quy ước này rõ ràng các bạn thấy tôi đã vi phạm khi sử
dụng một số tên riêng (thường là chỉ người) – cái tên chỉ có ý nghĩa với riêng tôi nên sẽ gây
chút khó khăn cho người đọc.
2. Tên biến nên được gán theo các danh từ còn tên hàm nên được gán bằng động từ (theo tiếng
Anh) để có thể dễ dàng phân biệt chức năng của chúng.
3. Không sử dụng các tên hàm sẵn có của R để đặt tên các biến. Ví dụ đặt tên (gán) cho một object
nào đó là mean là không được phép vì mean là một hàm (tính trung bình) của R.
4. Mỗi một dòng lệnh chỉ nên sử dụng tối đa 80 kí tự. Trong trường hợp mà một dòng lệnh có
số kí tự dài hơn 80 thì lệnh đó nên được viết theo cách thức sau:
df1 <- pisa %>% group_by(CNT) %>%
summarise_each(funs(mean, max, min, sd, n()), MATH) %>%
arrange(desc(mean))

Không nên viết dòng lệnh trên thành một dòng:


df1 <- pisa %>% group_by(CNT) %>% summarise_each(funs(mean, max, min,
sd, n()), MATH) %>% arrange(desc(mean))

5. Sau các phép toán cộng, trừ, nhân, chia, dấu gán, dấu phẩy thì dấu cách phải được sử dụng.
Chính vì thế mà cách thức viết code sau là sai:
x<-c(1, 2, 3)
y <- c(1,2,3)

Cách viết đúng phải là:


x <- c(1, 2, 3)
y <- c(1, 2, 3)

6. Ngoại lệ cho sử dụng dấu cách là trường hợp của dâu hai chấm. Cách viết đúng trong trường
hợp có sử dụng dấu hai chấm là:
z <- 1:10

7. Nếu một project được tiến hành qua nhiều công đoạn (block) nhỏ thì mỗi một block nên có
một tiêu đề để giải thích bằng sử dụng nhiều dấu # theo cách thức như sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


94

##########################################################
### Dưới đây là phân tích hình ảnh cho bộ dữ liệu iris ###
##########################################################

par(mfrow = c(2,2))
par(bg = "grey98")
for (i in 1:4) {
boxplot(iris[, i] ~ iris$Species,
main = names(iris)[i],
col = rainbow(3))
}

8. Dấu # cũng được sử dụng để giải thích cho các dòng lệnh theo một trong hai cách thức sau:
##--------------
## Cách 1
##--------------

# Cố định kết quả


set.seed(1)
# Tạo ra 10 quan sát ngẫu nhiên có phân phối chuẩn hóa
rnorm(10)

##-------------
## Cách 2
##-------------
set.seed(1) # Cố định kết quả.
rnorm(10) # Tạo ra 10 quan sát ngẫu nhiên có phân phối chuẩn hóa

Nguyễn Chí Dũng http://rpubs.com/chidungkt


95

9. Với các lệnh phức tạp có nhiều options thì chúng cũng nên được giải thích bằng cách sử dụng
hai dấu ## liên tiếp như sau (không hiển thị kết quả):
ggplot(data = mpg) +
geom_point(aes(x = displ, y = hwy, color = class)) +
## Đặt tiêu đề cho graph:
ggtitle("Vi du ve giai thich cho cau lenh")+
## Đặt tên cho trục X:
xlab("Day la truc X")

Các quy ước về cách viết code như trên là một quy ước được thừa nhận rộng rãi không chỉ trong giới
sử dụng R mà còn ở nhiều ngôn ngữ lập trình khác.
Trước đây tôi không được biết đến những nguyên tắc này (và việc không nên sử dụng dấu = thay cho
<- khi thực hiện phép gán) vì thế viết R code vô nguyên tắc và tạo thành một thói quen rất khó sửa.
Vì lí do này, các bạn có thể phát hiện ở đâu đó tôi vi phạm những nguyên tắc trên trong tài liệu này
dù đã rất cố gắng sửa một lỗi đã ăn vào máu.
Hi vọng các bạn không lặp lại sai lầm (và phải sửa sai) như tôi đã mắc.

2.13 Lưu ý về sử dụng dấu = thay cho <- và lệnh attach


Sử dụng lệnh attach() (như các phiên bản trước của tài liệu này cũng như một số tài liệu mà các bạn
gặp) có thể gây ra những lỗi làm gián đoạn toàn bộ các phân tích, đặc biệt là các dự án phân tích mà
bạn phải thao tác với nhiều dữ liệu cùng lúc, nhiều object cùng lúc. Là người bị ảnh hưởng bởi phong
cách viết R code của Hadley Wickham nên tôi tuân theo khẩu hiệu Never Attach. Dưới đây là giải
thích ngắn gọn trích từ cuốn Hands-on Programming with R tại trang 76 của Garrett Grolemund:

Giải thích kĩ nguyên nhân của việc không sử dụng lệnh attach có lẽ cần một chút kiến thức của
Computer Science và sẽ không được trình bày ở đây. Bạn nào quan tâm có thể tham khảo cuốn Hands-
on Programming with R đã đề cập ở trên.
Một số tài liệu các bạn có thể thấy dấu = có thể được sử dụng thay cho dấu <- khi thực hiện phép gán.
Nghĩa là, thay vì gõ:
y <- c(1, 2, 3)

Lại sử dụng dấu = như sau:


y = c(1, 2, 3)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


96

Tuy nhiên trong tài liệu này tôi sẽ không sử dụng dấu = thay cho <- khi thực hiện phép gán. Chi tiết
nhỏ này có thể làm hỏng một chương trình lớn hơn nhiều lần. Tôi đã từng viết một chương trình phân
tích rất dài (chừng 500 dòng lệnh) nhưng nó không hoạt động. Dù rằng cú pháp và mọi thứ khác đều
đúng. Tìm tòi hai ngày cũng không phát hiện ra lỗi nên đành phải gửi cho một chuyên gia về sử dụng
R thẩm định. Câu trả lời vô cùng đơn giản: tôi đã sử dụng không chỉ một, mà tới hai dấu = ở một khâu
then chốt của chương trình.
Một dự án phân tích có thể rất dài và việc viết sai lệnh là điều thường thấy và dễ dàng tìm ra sai ở
dòng lệnh nào. Tuy nhiên nếu sử dụng dấu = thì R sẽ không coi đây là một lỗi sai về cú pháp nhưng
chính dấu = này lại là nguyên nhân làm cho toàn bộ chương trình không hoạt động.
Vì lí do này, dấu = sẽ không được sử dụng để thực hiện phép gán trong tài liệu này.

2.14 Lưu ý khi gặp tình huống cùng một tên hàm tồn tại ở hai hay nhiều gói
Khi gọi nhiều gói khác nhau có thể xẩy ra tình huống sau: có hai gói cùng có một hàm trùng nhau về
tên (dù rằng hai hàm này có thể có thực hiện những công việc khác nhau hoàn toàn). Ví dụ, hàm
filter() là một hàm thuộc gói dplyr (thuộc hệ sinh thái tidyverse mà chúng ta đã biết) nhưng nó cũng
là một hàm của gói stats (luôn mặc định xuất hiện khi khởi động R). Trong tình huống này, chúng ta
nên chỉ thị cụ thể cho R hiểu là chúng ta muốn sử dụng hàm, chẳng hạn filter() của gói nào theo cách
thức đặc biệt sau:
library(tidyverse)
dplyr::filter(iris, Sepal.Length > 7.3)

## Sepal.Length Sepal.Width Petal.Length Petal.Width Species


## 1 7.6 3.0 6.6 2.1 virginica
## 2 7.7 3.8 6.7 2.2 virginica
## 3 7.7 2.6 6.9 2.3 virginica
## 4 7.7 2.8 6.7 2.0 virginica
## 5 7.4 2.8 6.1 1.9 virginica
## 6 7.9 3.8 6.4 2.0 virginica
## 7 7.7 3.0 6.1 2.3 virginica

Ở đây chúng ta sử dụng lệnh filter() để lọc ra các quan sát mà Sepal.Length lớn hơn 7.3 còn kí hiệu
dplyr:: xuất hiện ngay trước lệnh này có nghĩa là chỉ thị cụ thể cho R rằng sử dụng lệnh filter() của
gói dplyr chứ không phải của gói stats.
Một điểm nữa cần lưu ý là trong tình huống hai (hay nhiều) gói có chứa cùng một hàm thì hàm thuộc
về gói được gọi sau cùng sẽ được ưu tiên sử dụng nếu chúng ta không tuyên bố rõ ràng về gói được
sử dụng để thực thi hàm đó.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


97

Chương 3: Các thống kê mô tả và hình hóa dữ liệu với R

Chương này chúng ta sẽ thực hành tìm các thống kê mô tả cho các biến số cũng như tìm các giá trị thống
kê phổ biến thường sử dụng trong nghiên cứu thống kê – kinh tế lượng như phân phối chuẩn N, phân
phối Student t, phân phối F, và phân phối khi bình phương χ2. Chương này cũng trình bày môt số kĩ
thuật cũng như một số nguyên tắc cơ bản của hình ảnh hóa dữ liệu (Data Visualization).

3.1 Thực hiện các thống kê mô tả trong R


Mục này chúng ta sẽ thực hiện các thống kê mô tả cho bộ dữ liệu ch2_health.WF1 bằng cả bốn cách
là: (1) các hàm sẵn có trong R, (2) gói pastect cho các thống kê mô tả chi tiết, (3) gói stargazer, và (4)
gói fBasics.

3.1.1 Thống kê mô tả với các hàm sẵn có trong R


Bảng dưới đây liệt kê một số hàm cho các thống kê thường xuất hiện trong các báo cáo cũng như các
nghiên cứu:

Hàm/ Lệnh Chứng năng

mean() Kì vọng (hay trung bình) của biến/các biến

sd() Độ lệch chuẩn của biến/các biến

var() Phương sai của biến/các biến

cor() Ma trận hệ số tương quan của các biến

summary() Đưa ra 6 thống kê cơ bản cho biến/các biến số

max() Giá trị lớn nhất của các biến số

min() Giá trị nhỏ nhất của các biến số

quantile() Ngũ phân vị

Để minh họa ý nghĩa của các hàm này, lấy ví dụ với bộ số liệu ch2_health.WF1:

library(hexView)
dung <- readEViews("ch2_health.WF1", as.data.frame = TRUE)
summary(dung) # Xem các thống kê cơ bản của tất cả các biến

## HEALTH INCOME POP


## Min. : 1407 Min. : 11700 Min. : 480
## 1st Qu.: 5134 1st Qu.: 35800 1st Qu.: 1454
## Median : 13669 Median : 87300 Median : 3840
## Mean : 19929 Mean :144153 Mean : 5299
## 3rd Qu.: 22141 3rd Qu.:176650 3rd Qu.: 6026
## Max. :110057 Max. :920500 Max. :32683

Nguyễn Chí Dũng http://rpubs.com/chidungkt


98

Bảng ma trận hệ số tương quan giữa các biến số:

cor(dung)

## HEALTH INCOME POP


## HEALTH 1.0000000 0.9908936 0.9859726
## INCOME 0.9908936 1.0000000 0.9930022
## POP 0.9859726 0.9930022 1.0000000

Nếu chỉ quan tâm đến các thống kê cơ bản, hay một thống kê cụ thể nào đó cho biến INCOME mà thôi:

summary(dung$INCOME) # 6 thống kê cơ bản cho biến INCOME

## Min. 1st Qu. Median Mean 3rd Qu. Max.


## 11700 35800 87300 144200 176600 920500

quantile(dung$INCOME) # Ngũ phân vị cho biến INCOME

## 0% 25% 50% 75% 100%


## 11700 35800 87300 176650 920500

Ở đây lần đầu tiên các bạn sử dụng một kí hiệu đặc biệt: dấu $ (kí hiệu của đồng Dollar). Lưu ý rằng
dung (là một object trong R dạng data frame ) chứa các biến số HEALTH, INCOME, và POP. Do đó, để
chỉ thị R, chẳng hạn, áp dụng lệnh summary() cho biến INCOME thì chúng ta phải chỉ thị một cách rõ
ràng là summary(dung$INCOME) .

Còn một lí do phải sử dụng kí hiệu $. Giả sử còn một data frame nữa có tên là trang cũng chứa biến
INCOME. Lúc đó, nếu gõ lệnh summary(INCOME) thì R sẽ không hiểu là áp dụng hàm summary() cho
biến INCOME thuộc dung hay trang. Vì lí do này, nếu muốn chỉ thị cho R “làm việc” với INCOME thuộc
trang thì phải gõ summary(trang$INCOME).

Nếu muốn biết, chẳng hạn, ngũ phân vị cho tất cả các biến số:

sapply(dung, quantile)

## HEALTH INCOME POP


## 0% 1407.0 11700 480.0
## 25% 5134.5 35800 1454.5
## 50% 13669.0 87300 3840.0
## 75% 22141.0 176650 6026.0
## 100% 110057.0 920500 32683.0

Ở đây có thể nói chúng ta sử dụng “song song” hai lệnh cùng một lúc. Cụ thể, khi ta sử dụng lệnh
sapply() như trên thì R sẽ hiểu là áp dụng lệnh quantile() cho tất cả các côt biến có trong data frame
tên dung.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


99

Nếu sử dụng toán tử pipe thì tất cả những kết quả trên có thể thu được bằng những dòng lệnh sau
(theo thứ tự xuất hiện):

library(magrittr)
dung %>% summary()
dung %>% cor()
dung %>% summary(.$INCOME)
dung %>% quantile(.$INCOME, probs = seq(0, 1, 0.25))

Một ngoại lệ khi áp dụng toán tử pipe với hàm tính ngũ phân vị là ta phải tuyên bố rõ các mức xác
suất từ 0, 0.25, 0.50, 0.75 và 1.00 một cách rõ ràng:

dung %>% quantile(.$INCOME, probs = seq(0, 1, 0.25))

Đương nhiên câu lệnh này hoàn toàn tương đương với một trong hai câu lệnh sau:

quantile(dung$INCOME)
quantile(dung$INCOME, probs = seq(0, 1, 0.25))

Để biết ý nghĩa của lựa chọn probs = seq(0, 1, 0.25) thực hiện các lệnh sau:

probs = seq(0, 1, 0.25)


probs

Đây cũng chính là cách thức mà các bạn nên làm quen để sử dụng R thành thạo: tỉ mỉ xem xét từng
lựa chọn của một dòng lệnh rất dài có nhiều lựa chọn khác nhau.

3.1.2 Thống kê mô tả chi tiết với gói pastecs


Trong nhiều tình huống chúng ta có thể cần nhiều thống kê với mức độ chi tiết cao hơn. Trong tình
huống này chúng ta sử dụng các lệnh của gói pastecs:

# Hiển thị các kết quả chính xác đến 4 chữ số sau dấu phẩy
options(digits = 4)

# Hiển thị 10 chữ số, tính cả số trước dấu phẩy

options(digits = 10)
library(pastecs)
stat.desc(dung)

## HEALTH INCOME POP


## nbr.val 5.100000000e+01 5.100000000e+01 5.100000000e+01
## nbr.null 0.000000000e+00 0.000000000e+00 0.000000000e+00
## nbr.na 0.000000000e+00 0.000000000e+00 0.000000000e+00
## min 1.407000000e+03 1.170000000e+04 4.800000000e+02
## max 1.100570000e+05 9.205000000e+05 3.268300000e+04
## range 1.086500000e+05 9.088000000e+05 3.220300000e+04
## sum 1.016385000e+06 7.351800000e+06 2.702510000e+05
## median 1.366900000e+04 8.730000000e+04 3.840000000e+03
## mean 1.992911765e+04 1.441529412e+05 5.299039216e+03
## SE.mean 3.094921344e+03 2.368438674e+04 8.285198770e+02
## CI.mean.0.95 6.216332466e+03 4.757149080e+04 1.664131149e+03

Nguyễn Chí Dũng http://rpubs.com/chidungkt


100

## var 4.885054443e+08 2.860845894e+10 3.500870452e+07


## std.dev 2.210215927e+04 1.691403528e+05 5.916815403e+03
## coef.var 1.109038526e+00 1.173339589e+00 1.116582679e+00

Qua kết quả này các bạn có thể thấy ngoài các thống kê thông thường còn có các thống kê chi tiết hơn.
Ví dụ, quãng đáng tin 95% của HEALTH nằm trong khoảng từ 19929 – 6216 đến 19929 + 6216. Còn
giá trị coef.var = 1.109 chính là thương số của std.dev chia cho mean. Giá trị CI.mean.0.95 là khoảng
tin cậy 95% cho các biến số (CI là viết tắt của chữ Confidence Interval ). Có thể thu gọn kết quả trên
như sau:

stat.desc(dung, desc = F)

## HEALTH INCOME POP


## nbr.val 51 51 51
## nbr.null 0 0 0
## nbr.na 0 0 0
## min 1407 11700 480
## max 110057 920500 32683
## range 108650 908800 32203
## sum 1016385 7351800 270251

3.1.3 Thống kê mô tả chi tiết với gói stargazer


Nếu chúng ta không cần các thống kê quá chi tiết, chúng ta có thể thực hiện điều này với gói stargazer
với trình bày đẹp hơn:

library(stargazer)
stargazer(dung, type = "text", title = "Cac Thong Ke Mo Ta", digits = 3)
## Cac Thong Ke Mo Ta
## ===================================================
## Statistic N Mean St. Dev. Min Max
## ---------------------------------------------------
## HEALTH 51 19,929.000 22,102.000 1,407 110,057
## INCOME 51 144,153.000 169,140.000 11,700 920,500
## POP 51 5,299.000 5,917.000 480 32,683
## ---------------------------------------------------

Đây cũng là các thống kê tiêu chuẩn thường được trình bày trong các báo cáo và nghiên cứu khoa học.
Thực ra ứng dụng lớn nhất của gói này là trình bày các kết quả nghiên cứu ở dạng một cách đẹp mắt
tương tự như gói outreg2 trong Stata chứ không đơn giản là chụp lại màn hình để trình bày kết quả
(vì thực tế là, R đưa ra các trình bày kết quả không được đẹp mắt như một số phần mềm khác). Tất
nhiên việc sử dụng chi tiết gói này còn liên quan mật thiết với việc sử dụng LaTex. Điều này vượt quá
khuôn khổ của cuốn sách này nên tôi không trình bày ở đây.

Đây là một ví dụ về ứng dụng của gói này: các bạn có thể xuất ra một file dữ liệu ở dạng file Word với
tên ketqua.doc ở thư mục hiện thời của R:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


101

stargazer(dung, type = "text", title = "Cac Thong Ke Mo Ta", digits = 3, out


= "ketqua.doc")

Có thể suy luận trước rằng kết quả này được lưu ở thư mục KTLR thuộc ổ D của máy tính.

3.1.4 Thống kê mô tả chi tiết với gói fBasics


Tương tự như gói pastecs, gói fBasics cũng cho ta các thống kê chi tiết nhưng theo một cách linh hoạt
hơn:

library(fBasics)
basicStats(dung)

## HEALTH INCOME POP


## nobs 5.100000000e+01 5.100000000e+01 51.000000
## NAs 0.000000000e+00 0.000000000e+00 0.000000
## Minimum 1.407000000e+03 1.170000000e+04 480.000000
## Maximum 1.100570000e+05 9.205000000e+05 32683.000000
## 1. Quartile 5.134500000e+03 3.580000000e+04 1454.500000
## 3. Quartile 2.214100000e+04 1.766500000e+05 6026.000000
## Mean 1.992911765e+04 1.441529412e+05 5299.039216
## Median 1.366900000e+04 8.730000000e+04 3840.000000
## Sum 1.016385000e+06 7.351800000e+06 270251.000000
## SE Mean 3.094921344e+03 2.368438674e+04 828.519877
## LCL Mean 1.371278518e+04 9.658145037e+04 3634.908067
## UCL Mean 2.614545011e+04 1.917244320e+05 6963.170364
## Variance 4.885054443e+08 2.860845894e+10 35008704.518431
## Stdev 2.210215927e+04 1.691403528e+05 5916.815403
## Skewness 2.132019000e+00 2.456295000e+00 2.463944
## Kurtosis 4.846098000e+00 7.275747000e+00 7.454391

Hoặc chỉ quan tâm đến các thống kê cho biến INCOME mà thôi (không hiển thị kết quả):

basicStats(dung$INCOME)

So sánh cách thức R hiển thị kết quả với cặp dòng lệnh sau (không hiển thị kết quả):

options(digits = 3)
basicStats(dung)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


102

3.2 Tìm các giá trị thống kê và mức xác suất của phân phối N, t, F,và χ2
Khi nghiên cứu thống kê – kinh tế lượng thông thường chúng ta cần biết một số thống kê của các phân
phối chuẩn (N), thống kê Student (t), thống kê F, và thống kê khi bình phương (χ2). Truyền thống thì
chúng ta tra các bảng thống kê được in ở những trang cuối cùng của các sách về thống kê và kinh tế
lượng. Trong R (cũng như các phần mềm khác) cho phép chúng ta tìm các thống kê này mà không cần
tra bảng – một việc thường gây nhầm lẫn và nhàm chán.

3.2.1 Phân phối chuẩn N


Các biến tuân theo phân phối chuẩn N (Normal Distribution) có hàm mật độ xác suất như sau:

1 1 𝑥−𝜇 2
𝑒 2 𝜎 )
− (
𝑓(𝑥) = −∞<𝑥 < ∞
𝜎√2𝜋
Với phân phối chuẩn N chúng ta thường làm hai bài toán ngược nhau: (1) tìm xác suất – hay diện tích
giới hạn bởi hàm mật độ xác suất với các đường x1 = a, x2 = b, và (2) tìm giá trị ZA.

Giả sử chúng ta cần tính P(x ≤ 1100) với một phân phối chuẩn có trung bình 1000 và sai số chuẩn là
100. Trong R ta làm như sau:

pnorm(1100, 1000, 100)

## [1] 0.8413447

Từ đây ta cũng suy ra tìm P(x ≥ 1100) trong R như sau:

1 - pnorm(1100, 1000, 100)

## [1] 0.1586553

Hoặc chúng ta có thể gõ cách khác trong R để tra kết quả như trên:

pnorm(1100, 1000, 100, lower.tail = FALSE)

## [1] 0.1586553

Tất nhiên, với phân phối chuẩn hóa thì μ = 0 và σ = 1 nhưng cách thức thực hiện không khác. Chúng
ta xét ba ví dụ dưới đây (nhìn hình trang kế tiếp):

Nguyễn Chí Dũng http://rpubs.com/chidungkt


103

Chúng ta có thể tìm ra các kết quả như trên mà không cần tra bảng:

pnorm(-0.71, 0, 1)

## [1] 0.2388521

pnorm(0.92, 0, 1)

## [1] 0.8212136

pnorm(0.92, 0, 1) - pnorm(-0.71, 0, 1)

## [1] 0.5823616

Tuy nhiên, đã là phân phối chuẩn hóa thì R cho phép ta làm nhanh hơn như sau mà không cần gõ mãi
hai số 0 và 1:

pnorm(-0.71)

## [1] 0.2388521

pnorm(0.92)

## [1] 0.8212136

pnorm(0.92) - pnorm(-0.71)

## [1] 0.5823616

Nguyễn Chí Dũng http://rpubs.com/chidungkt


104

Ngược lại với bài toán tìm xác suất ở trên chúng ta có bài toán tìm giá trị ZA:

Bài toán ở đây là nếu biết diện tích A =0.025 chẳng hạn, thì ZA là bao nhiêu? Trong R hàm qnorm(1-A,
μ, σ) sẽ tìm ra giá trị ZA này. Ví dụ, nếu một phân phối chuẩn có trung bình là 1000, sai số chuẩn 100,
A = 0.1586 thì chúng ta có thể tính ZA trong R như sau:

qnorm(1 - 0.1586, 1000, 100)

## [1] 1100.023

Các sách thường cho các bảng tra ZA kiểu như sau:

Với phân phối chuẩn hóa, chúng ta không cần gõ 0,1 ở các câu lệnh mà chỉ cần gõ :

qnorm(0.95)

## [1] 1.644854

Nghĩa là chúng ta không cần tra bảng để tìm ra giá trị ZA =0.5(1.64+1.65) = 1.645 (nếu làm tròn tới 3
chữ số).

3.2.2 Phân phối Student t


Dưới đây là đồ thị hàm mật độ xác suất của phân phối t (còn gọi là phân phối student) ứng với các bậc
tự do v bằng 30, 10, và 2:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


105

Bậc tự do v càng lớn thì phân phối t càng tiến về phân phối chuẩn. Trong thực hành thì v ≥ 200 có thể
coi phân phối t là phân phối chuẩn. Với phân phối t chúng ta thường phải tìm tA,v sao cho P(t>tA,v) = A:

Trong cách sách về thống kê – kinh tế lượng người ta thường cho các giá trị tA,v dưới dạng bảng như
sau:

Chúng ta có thể tìm các giá trị này trong R theo cú pháp qt(1-A,df=v) mà không cần tra bảng:

qt(0.9, df = 3)

## [1] 1.637744

qt(0.975, df = 3)

## [1] 3.182446

qt(0.95, df = 35)

## [1] 1.689572

qt(0.99, df = 35)

## [1] 2.437723

Tất nhiên chúng ta cũng có thể giải bài toán ngược (tìm xác suất) như sau trong R:

pt(1.638, df = 3)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


106

## [1] 0.9000262

pt(1.689, df = 35)

## [1] 0.9499447

Trong nhiều tình huống chúng ta có thể phải thực hiện kiểm định hai phía. Các bạn thử suy nghĩ về ý
nghĩa của hai câu lệnh sau cho phân phối t và N:

qt(c(0.025, 0.975), df = 40)

## [1] -2.021075 2.021075

qnorm(c(0.025, 0.975))

## [1] -1.959964 1.959964

3.2.3 Phân phối F


Với phân phối F với bậc tự do v1, v2 chúng ta thường phải tìm các giá trị F1-A và FA :

Với A = 0.05, trong các sách thống kê – kinh tế lượng các giá trị của thống kê F thường được cho ở
dạng bảng như sau:

Chúng ta có thể tính một số giá trị này trong R mà không cần tra bảng:

qf(0.95, df1 = 2, df2 = 4)

## [1] 6.944272

qf(0.95, df1 = 9, df2 = 3)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


107

## [1] 8.8123

Với v1=9, v2=3 chúng ta có thể tìm đồng thời cả F0.05 và F0.95 như sau:

qf(c(0.05, 0.95), df1 = 9, df2 = 3)

## [1] 0.2588964 8.8122996

3.2.4 Phân phối χ2


Với phân phối χ2 có bậc tự do df chúng ta thường phải tìm các giá trị χ21-A và χ2A :

Trong các sách thống kê – kinh tế lượng các giá trị của thống kê χ2 thường được cho ở dạng bảng như
sau:

Chúng ta có thể tính một số giá trị này trong R mà không cần tra bảng:

qchisq(0.025, df = 3)

## [1] 0.2157953

qchisq(0.99, df = 2)

## [1] 9.21034

Các bạn thử suy nghĩ mối liên hệ giữa kết quả của ba câu lệnh sau:

qchisq(c(0.025, 0.975), df = 3)

## [1] 0.2157953 9.3484036

pchisq(0.2158, df = 3)

## [1] 0.02500078

Nguyễn Chí Dũng http://rpubs.com/chidungkt


108

pchisq(9.3483, df = 3)

## [1] 0.9749988

3.3 Vẽ các Graph và đồ thị trong R


Ngoài việc khai thác các thông tin ẩn chứa đằng sau bộ số liệu bằng các con số thống kê miêu tả thì
các hình ảnh là một cách thức khác để buộc dữ liệu truyền tải những thôn tin hữu ích. Chúng là một
phần không thể thiếu trong hầu hết các báo cáo khoa học hay các nghiên cứu. Các hình ảnh, đồ thị
không chỉ là phương tiện truyền tải những thông tin hữu ích ẩn dấu trong bộ dữ liệu mà nó còn có thể
được sử dụng như là một công cụ cho việc chẩn đoán các lỗi của mô hình hay manh mối để đưa ra các
mô hình phân tích phù hợp. Một ví dụ điển hình là phân tích hình ảnh của phần dư nhằm chẩn đoán
lỗi phương sai sai số thay đổi của mô hình hồi quy.

Vai trò của sử dụng hình ảnh hay hình ảnh hóa dữ liệu (Data Visualization) quan trọng đến mức mà
nhà thống kê học John Tukey đã phát biểu rằng “Hình ảnh, dù đơn giản, cũng mang lại nhiều thông
tin cho người phân tích (số liệu) hơn bất cứ phương tiện nào”.

Trong phần này chúng ta sẽ thực hành các vẽ các Graph, đồ thị thường gặp khi nghiên cứu thống kê
– kinh tế lượng với hai gói basic graphics và ggplot2 (dù rằng R còn nhiều gói khác hỗ trợ đồ họa).

Gói base graphics là gói mặc định xuất hiện trong trong R và do đó chúng ta không cần thực hiện lệnh
gọi gói này. Chất lượng hình ảnh tạo ra bởi gói này không tốt (nhưng thừa đủ để thực hiện tất cả các
chức năng vẽ như bất kì phần mềm nào khác). Gói ggplot2 được ra đời nhằm đáp ứng cho các yêu cầu
về chất lượng hình ảnh cũng như các Graphs có mức độ phức tạp cao. Tất nhiên sử dụng gói này cũng
phức tạp hơn. Dưới đây chúng ta chỉ thực hành một số lệnh đơn giản nhất (nhưng đủ dùng) cho mục
đích phân tích số liệu sơ bộ và cơ bản. Vì nếu nghiên cứu tính năng này của R một cách chi tiết có lẽ
cần một tài liệu rất dài.

Với mục đích minh họa, phần này chúng ta sẽ nghiên cứu bộ dữ liệu CPS1988 có trong gói AER mà
chúng ta đã biết ở chương 2

3.3.1 Các Graphs với gói mặc định graphics của R


Mục này chúng ta sẽ nghiên cứu cách thức tạo ra các graphs (Data Visualization) với gói graphics. Đây
là gói mặc định của R và thường được sử dụng để tạo ra các hình ảnh chất lượng không quá khắt khe.

3.3.1.1 Vẽ Scatter Plot


Chúng ta có thể vẽ Scatter Plot với education trên trục X và log(wage) trên trục Y:

plot(log(wage) ~ education, data = CPS1988, col = "blue")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


109

Bạn có thể thay "blue" bằng "pink" nếu thích màu hồng. Thậm chí là bỏ hẳn cả cụm col = "blue"
trong dòng lệnh trên.

3.3.1.2 Vẽ đường hồi quy

Giả sử chúng ta cần vẽ đường hồi quy cho mô hình ln(wage) = β + β2education trên cùng với Scatter
Plot ở trên:

abline(lm(data = CPS1988, log(wage) ~ education), col = "red")

Chúng ta có thể thay đổi: (1) hình dạng của điểm, (2) kích thước của đường, và (3) kiểu đường trong
R. Trước hết chúng ta chia màn hình hiển thị của R thành 1 hàng và 2 cột (tức có thể hiển thị 2 hình
ảnh cùng lúc) bằng lệnh par(mfrow = c(1,2)). Để minh họa chúng ta sử dụng bộ số liệu
ch2_health.wf1 về chi cho y tế (HEALTH) và thu ngân sách (INCOME) của 51 bang tại Mĩ:

setwd("D:/KTLR")
library(hexView)
dung<-readEViews("ch2_health.wf1",as.data.frame=TRUE)
head(dung)

## HEALTH INCOME POP


## 1 16056 96000 4351
## 2 2299 17100 615
## 3 14782 113000 4667
## 4 8463 53700 2538
## 5 110057 920500 32683
## 6 13669 119000 3969

par(mfrow = c(1, 2)) # Đặt cửa sổ hiển thị thành 1 hàng và 2 cột.
plot(HEALTH ~ INCOME, data = dung, col = "blue", pch = 17)
abline(lm(data = dung, HEALTH ~ INCOME), col = "red", lwd = 2, lty = 5)
plot(HEALTH ~ INCOME, data = dung, pch = 4)
abline(lm(data = dung, HEALTH ~ INCOME), col = "green", lty = 6)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


110

par(mfrow = c(1, 1)) # Đặt lại chế độ hiển thị mặc định.

Ở đây lwd = 2 là độ dày của đường (mặc định là 1) còn lty = 5 là kiểu đường thẳng được hiển thị, pch
= 17 là kiểu hình dạng của điểm. Cụ thể, kiểu hình dạng được cho ở bảng sau:

Còn kiểu đường được cho ở bảng sau:

3.3.1.2 Histogram
Chúng ta có thể vẽ Histogram cho ln(wage) theo 6 cách thức khác nhau (chú ý hiệu ứng của những
câu lệnh này):

par(mfrow = c(2, 3))


hist(log(CPS1988$wage), col = "pink")
# Không đặt tên cho graph:
hist(log(CPS1988$wage), col = "blue", main = "")
# Đặt tên cho Graph:
hist(log(CPS1988$wage), col = "green",

Nguyễn Chí Dũng http://rpubs.com/chidungkt


111

main = "Histogram cua log(wage)")


# Đặt tên cho trục X nhưng bỏ trống trục Y:
hist(log(CPS1988$wage), col = "yellow", main = " ",
xlab = "Truc X",
ylab = "")
# Đặt giới hạn cho trục X từ 3 đến 10, Y từ 0 đến 10000:
hist(log(CPS1988$wage), main = " ",
xlim = c(3, 10),
ylim=c(0, 10000),
density = 20)
# Không tô đường viền cho các class, hiển thị tần suất tương đối của mỗi lớp
đồng thời tô màu cho mỗi lớp mô phỏng màu cầu vồng.
hist(log(CPS1988$wage), col = rainbow(8),
main = "", border = F, prob = T)
# Trả lại chế độ hiển thị bình thường:
par(mfrow=c(1, 1))

Chúng ta cũng có thể tạo ra Histogram và tần suất tuyệt đối của mỗi class:

love <- hist(log(CPS1988$wage), col = rainbow(8),


main = "", border = F, ylim = c(1, 10000))
text(love$mids, love$counts+2, label = c(love$counts),cex = 0.7, pos = 3)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


112

Các câu lệnh trên sẽ tạo ra một histogram với số quãng (intervals) mặc định tính theo công thức sau
của Sturges:

R sẽ vẽ Histogram theo công thức này. Tuy nhiên nếu muốn, chúng ta có thể hiệu chỉnh số class nếu
muốn. Ngoài ra, chúng ta cũng có thể vẽ đường thẳng đứng biểu thị giá trị trung bình của log(wage):

par(mfrow=c(1, 2))
hist(log(CPS1988$wage), col = "pink", nclass = 35, main = "")
hist(log(CPS1988$wage), col = "pink", nclass = 35, main = "")
abline(v = mean(log(CPS1988$wage)), col = "blue", lwd = 2)
par(mfrow=c(1, 1))

3.3.1.3 Hàm mật độ xác suất Density


Hàm mật độ xác suất là hình ảnh mang lại những thông tin về các đặc điểm thống kê của bộ dữ liệu
tương tự như Histogram và Boxplot. Dưới đây chúng ta có thể vẽ hàm mật độ xác suất theo hai kiểu:

par(mfrow=c(1, 2))
d <- density(log(wage))
plot(d, main = "")
plot(d, main = "", frame = FALSE)
polygon(d, col = "steelblue")
par(mfrow = c(1, 1))

Nguyễn Chí Dũng http://rpubs.com/chidungkt


113

Chúng ta cũng có thể kết hợp vẽ hàm mật độ xác suất và histogram:

hist(log(CPS1988$wage), main="", density = 20, prob = T, ylim = c(0, 0.7))


lines(d, col = "blue")

3.3.1.4 Boxplots
Chúng ta có thể tạo các Boxplots cho ln(wage) đồng thời cho cả 4 vùng địa lý khác nhau:

boxplot(log(CPS1988$wage) ~ CPS1988$region)

Chúng ta cũng có thể tô màu cho các boxplot này:

boxplot(log(CPS1988$wage) ~ CPS1988$region,
col = c("blue", "sienna", "palevioletred1", "green"))

Nguyễn Chí Dũng http://rpubs.com/chidungkt


114

Boxplots cung cấp rất nhiều thông tin giá trị về mẫu nghiên cứu (đáng tiếc là các sách viết về chúng
chưa kĩ ở mức độ tối thiểu mà một người học thống kê – kinh tế lượng cần có). Ví dụ, chúng ta có thể
thấy rằng: (1) mức lương trung bình của lao động vùng northeast là cao nhất còn vùng south là thấp
nhất, (2) mức lương của cả 4 vùng bị méo về phía dương (positive skewness) và méo mạnh nhất là
vùng midwest, và (3) các điểm dữ liệu nằng ngoài phạm vi râu trên và râu dưới chính là các outliers
– những quan sát bất thường (Keller, 2004). Nhắc lại ý nghĩa của boxplot như sau:

Nghĩa là chúng ta sẽ có 50% số quan sát nằm trong khoảng từ phân vị thứ nhất Q1 đến phân vị thứ
ba Q3 . Còn Q2 chính là trung vị (median). Nếu Q2 – Q1 > Q3 – Q2 thì phân phối sẽ méo về phía dương
(positive skewness) và ngược lại. Nếu Q2 nằm chính giữa thì chúng ta có phân phối chuẩn. Ngoài ra,
bất kì giá trị nào thỏa mãn một trong hai điều kiện sau thì được gọi là các bất thường: (1) bé hơn [Q1
– 1.5⨉(Q3-Q1)] , hoặc (2) lớn hơn [Q3 + 1.5⨉(Q3-Q1)]. Nhìn chung, các thông tin mang lại từ boxplot
là tương tự như histogram nhưng cụ thể hơn. Để minh họa chúng ta nghiên cứu cụ thể boxplot cho
log(wage) cho toàn bộ mẫu nghiên cứu:

boxplot(log(CPS1988$wage))

Chúng ta có thể thấy rằng Q2 – Q1 > Q3 – Q2 nên phân phối của log(wage) là méo về phía dương
(chúng ta có thể thấy từ mục 3.3.1.3 hoặc 3.3.1.4). Chúng ta có thể xác nhận một lần nữa nhận định
của chúng ta như sau:

quantile(log(CPS1988$wage))

## 0% 25% 50% 75% 100%


## 3.913023 5.732176 6.258280 6.663746 9.840399

6.258280-5.732176

Nguyễn Chí Dũng http://rpubs.com/chidungkt


115

## [1] 0.526104

6.663746-6.258280

## [1] 0.405466

Chúng ta có thể thấy rằng Q2 – Q1 = 0.526 > Q3 – Q2 = 0.405 nên chúng ta có thể thấy phân phối của
log(wage) là méo về phía dương. Chúng ta cũng có thể tính cận trên và dưới cho râu:

cd <- 5.732176 - 1.5*(6.663746 - 5.732176)


ct <- 6.663746 + 1.5*(6.663746 - 5.732176)
cd

## [1] 4.334821

ct

## [1] 8.061101

Thay vì tính thủ công như trên chúng ta có thể làm nhanh hơn như sau:

boxplot(log(CPS1988$wage))$stats[c(1, 5), ]

## [1] 4.336375 8.059460

Chúng ta có thể nhận diện một số quan sát là outlier như sau (trích một số quan sát):
boxplot.stats(log(CPS1988$wage))$out

## [1] 3.976124 4.122770 4.305011 4.265914 4.154498 4.039360 8.188917


## [8] 4.004967 4.083452 4.083452 4.050393 4.205439 4.083452 4.039360
## [15] 4.310933 4.083452 4.305011 4.122770 4.231930 4.298645 4.017464

Để xác định chính xác số lượng các outlier:


length(boxplot.stats(log(CPS1988$wage))$out)

## [1] 439

Chúng ta cũng có thể tính số % các outlier này so với toàn bộ mẫu nghiên cứu:
length(boxplot.stats(log(CPS1988$wage))$out) / length(CPS1988$wage)

## [1] 0.01559226

Có nghĩa là có tầm 1.56% lao động hoặc là có thu nhập quá thấp, hoặc là quá cao.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


116

Ở trên các bạn tô màu cho bốn box plot bằng cách gõ tên của bốn màu. Rõ ràng cách tô màu này là kô
ng tiện dụng, đặc biệt là trong tình huống có nhiều boxplot. Để thuận lợi chúng ta có thể tô màu với s
ự trợ giúp của gói RcolorBrewer. Trước hết chúng ta liệt kê tất cả các màu cung cấp bởi gói này:
library(RColorBrewer)
display.brewer.all() # Hiển thị tất cả các màu sắc.

Hoặc chúng ta muốn hiển thị tất cả 8 màu của dải màu có tên Dark2:

display.brewer.pal(n = 8, name = "Dark2") # Hiển thị 8 màu của dải màu có tên
Dark2.

R quy định rằng mỗi một màu sắc có thể được chỉ định bằng một trong hai cách thức sau: (1) tên cụ
thể (như red, yellow), hoặc (2) mã màu. Chúng ta có thể hiển thị mã màu cho 8 màu sắc ứng với dải
màu Dark2:

kihieu <- brewer.pal(n = 8, name = "Dark2") # Kí hiệu (mã) của 8 màu.


kihieu # Hiển thị 8 mã này.

## [1] "#1B9E77" "#D95F02" "#7570B3" "#E7298A" "#66A61E" "#E6AB02" "#A6761D"


## [8] "#666666"

Điều này có nghĩa là, chẳng hạn, màu xanh đầu tiên trong dải có mã là #1B9E77. Chúng ta có thể tô
màu tự động mà không cần gõ tên màu một cách thủ công như vừa làm. Hãy so sánh kĩ hiệu ứng của
những dòng lệnh sau:

par(mfrow=c(1, 2))
# Dùng 4 màu đầu tiên của dải màu Dark2
boxplot(log(CPS1988$wage) ~ CPS1988$region, col = kihieu[1:4])
# Câu lệnh kiểu khác nhưng tương đương
boxplot(log(CPS1988$wage) ~ CPS1988$region, col = kihieu)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


117

par(mfrow=c(1, 1)) # Đưa về chế độ hiển thị bình thường

Dưới đây là câu lệnh vẽ bốn boxplot trên nhưng sử dụng 4 màu sắc cuối cùng của dải màu theo hai
cách khác nhau nhưng tạo ra cùng một hiệu ứng:

par(mfrow=c(1, 2))
boxplot(log(CPS1988$wage) ~ CPS1988$region,
col =c("#66A61E", "#E6AB02", "#A6761D", "#666666"))
boxplot(log(CPS1988$wage) ~ CPS1988$region,
col = c(kihieu[5:6],"#A6761D", "#666666"))

par(mfrow=c(1, 1)) # Đưa về chế độ hiển thị bình thường

Việc tô màu tự động cũng có thể được thực hiện theo một cách khác là sử dụng hàm rainbow() – mô
phỏng màu sắc của dải cầu vồng. Hãy chú ý sự khác biệt của hai câu lệnh sau:

par(mfrow=c(1, 2))
boxplot(log(CPS1988$wage) ~ CPS1988$region,
col = rainbow(4))
boxplot(log(CPS1988$wage) ~ CPS1988$region,
col = c(kihieu[5:6], "pink", "yellow"))

par(mfrow=c(1,1))

Ở đây các bạn có thể ở nhóm boxpot thứ hai chúng ta chọn 2 màu theo ý muốn (là pink và yellow)
cộng với với hai mã của màu thứ 5 và 6 trong dải màu Dark2.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


118

Tương tự, chúng ta cũng có thể sử dụng hàm qualiPalette() của gói fBasics để chọn màu tự động.
Đáng chú ý là hàm này sử dụng các dải màu được cung cấp bởi gói RcolorBrewer:

library(fBasics)
mausac <- qualiPalette(12, "Set3") # Chọn dải màu có tên Set3.
boxplot(log(CPS1988$wage) ~ CPS1988$region, col = mausac)

Với các thức tô màu tự động như trên chúng ta không cần phải tô màu bằng gõ tên của các màu.

3.3.1.5 Biểu đồ cột


Với cách lựa chọn màu tự động như đã làm ở mục 4.3.1.4 chúng ta có thể vẽ biểu đồ cột (Bar Plot)
cho, chẳng hạn, số quan sát theo khu vực địa lý:

dung <- table(CPS1988$region)


barplot(dung, col = mausac, main = "Phan bo dan so theo khu vuc")

Hoặc theo cả khu vực địa lý và sống ở khu vực đô thị hay phi đô thị:

trang <- table(CPS1988$smsa, CPS1988$region)


barplot(trang, col = mausac, main = "Ti le do thi hoa o cac vung")
legend("topright", legend = rownames(trang),
box.lty = 0, cex = 1, fill = mausac)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


119

Hoặc theo một cách thức khác:

mausac <- qualiPalette(2, "Set3") # Đặt lại màu tự động


barplot(trang, col = mausac, main = "Ti le do thi hoa o cac vung",
beside = TRUE, horiz = TRUE)
legend("topright", legend = rownames(trang),
box.lty = 0, cex = 1, fill = mausac)

Chú ý một lần nữa lệnh chọn màu tự động mausac <- qualiPalette(2,"Set3"). Nếu không có lệnh này,
bar plot của bạn sẽ có thể gây hiểu nhầm. Chúng ta có thể diễn giải với các con số:

addmargins(prop.table(trang, 2))

## region
## smsa northeast midwest south west Sum
## no 0.1535476 0.3022002 0.2837900 0.2748317 1.0143695
## yes 0.8464524 0.6977998 0.7162100 0.7251683 2.9856305
## Sum 1.0000000 1.0000000 1.0000000 1.0000000 4.0000000

Lệnh trên cho thấy ở vùng Northeast có 15.35 % dân cư ở khu vực phi đô thị và 84.64% còn lại ở khu
vực thành thị.

Chúng ta cũng có thể khai khác thông tin từ nhiều các khác bằng các lệnh hữu ích sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


120

addmargins(prop.table(trang, 1))

## region
## smsa northeast midwest south west Sum
## no 0.1369237 0.2871383 0.3441783 0.2317597 1.0000000
## yes 0.2604624 0.2287885 0.2997325 0.2110166 1.0000000
## Sum 0.3973862 0.5159268 0.6439108 0.4427763 2.0000000

addmargins(trang, 1)

## region
## smsa northeast midwest south west
## no 989 2074 2486 1674
## yes 5452 4789 6274 4417
## Sum 6441 6863 8760 6091

addmargins(trang, 2)

## region
## smsa northeast midwest south west Sum
## no 989 2074 2486 1674 7223
## yes 5452 4789 6274 4417 20932

3.3.1.6 Pie Chart


Chúng ta có thể vẽ đồ thị hình bánh (Pie Chart) cho 4 nhóm ứng với 4 khu vực địa lý:

pie(table(CPS1988$region), col = c("pink", "orange", "green", "blue"))

Tương tự chúng ta có thể vẽ Pie Chart cho 2 nhóm ứng với làm thêm hay không với tỉ lệ % tương ứng
cho mỗi nhóm. Trước hết chúng ta tìm số người không làm thêm và làm thêm:

table(CPS1988$parttime)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


121

## parttime
## no yes
## 25631 2524

Từ đây chúng ta xác định được cụ thể số người không làm thêm và làm thêm. Kế tiếp chúng ta thực
hiện các lệnh sau:

soluong <- c(25631, 2524)


lamthem <- c("no", "yes")
phantram <- round(soluong / sum(soluong)*100, 2)
lamthem <- paste(lamthem, phantram)
lamthem <- paste(lamthem, "%", sep="")
pie(soluong, labels = lamthem, col=c("green", "blue"))

Nếu Pie Chart không cần biểu thị tỉ lệ % tương ứng thì chỉ cần gõ:

pie(table(CPS1988$parttime), col = c("green", "blue"))

Trình bày các thông tin của dữ liệu bằng Pie Chart bị chỉ trích mạnh mẽ bởi giới phân tích số liệu và
thống kê. Theo Edward Tufte – một bậc thầy về hình ảnh hóa dữ liệu và cũng là một nhà thống kê ở
đại học Yale thì có ít nhất ba lí do không nên sử dụng Pie Chart: (1) kích thước tương đối của những
lát bánh là khó so sánh và diễn dịch, (2) chỉ cung cấp rất ít thông tin về dữ liệu nhưng lại chiếm rất
nhiều không gian trình bày, (3) có nhiều các thức hiệu quả hơn nhằm biểu diễn thông tin của dữ liệu,
chẳng hạn sử dụng biểu đồ hình cột.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


122

3.3.1.7 Biểu đồ đường


Biểu đồ đường (Line Graph) là một trong những biểu đồ thường được sử dụng phổ biến nhất. Chúng
thường được sử dụng để tìm hiểu xu hướng của một biến số theo thời gian. Để minh họa chúng ta sử
dụng bộ số liệu Table13_1.dta về tỉ giá hối đoái (biến ex) giữa đồng USD và EURO từ mùng 4 tháng
1 năm 2000 đến mùng 8 tháng 4 năm 2008 (có 2355 quan sát tất cả).

library(foreign)
dung <- read.dta("D:/KTLR/Table13_1.dta")
plot(dung$ex, type = "l", col = "blue", xlab = "",
ylab = "Ti Gia", main = "Ti Gia Hoi Doai USD/EUR")

Chúng ta có thể hiệu chính hình ảnh này đẹp hơn bằng cách đặt nền màu xám đồng thời vẽ những
đường thẳng thẳng đứng với giả thiết rằng một năm có 340 phiên giao dịch nhằm tìm hiểu xu hướng
biến động của tỉ giá theo từng năm một với giả sử 1 năm có 360 ngày:

par(bg = "grey90") # Đặt nền xám


plot(dung$ex, type = "l", col = "blue", xlab = "",
ylab = "Ti Gia", main = "Ti Gia Hoi Doai")
abline(v = c(seq(from = 1, to = 2355, by = 360)), col = "grey")

Từ đây chúng ta có thể thấy rõ hơn xu hướng biến động của tỉ giá theo từng khoảng thời gian nghiên
cứu.

Hiện tại hệ điều hành Window chưa hỗ trợ tiếng Việt cho R nên ở trên chúng ta gõ chữ không dấu.
Nếu máy tính của bạn là Mac hay sử dụng hệ điều hành Linux, Ubuntu thì có thể sử dụng tiếng Việt.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


123

3.3.1.8 Trình bày nhiều Graphs trên cùng một cửa sổ hiển thị trong R
Trong nhiều tình huống có thể chúng ta cần trình bày nhiều Graphs trên cùng một cửa sổ hiển thị.
Chẳng hạn để trình bày boxplots và pie chart trên cùng một cửa sổ hiển thị:

par(mfrow = c(2, 1))


hinh1 <- hist(log(CPS1988$wage), col = "pink", prob = TRUE)
hinh2 <- boxplot(log(CPS1988$wage) ~ CPS1988$region,
col = c("blue", "sienna", "palevioletred1", "green"))

Ở đây câu lệnh đầu tiên chi cửa sổ hiển thị của R thành 2 dòng và một cột. Các Graphs sẽ xuất hiện
theo thứ tự gõ các câu lệnh. Nếu thay mfrow = c(2, 1) bằng mfrow = c(2, 2) thì chúng ta có thể hiển
thị 2*2 = 4 Graphs trong cùng một cửa sổ lệnh. Sau khi thực hiện xong việc “ghép” 2 Graphs chúng ta
chỉ định cửa sổ đồ họa ở chế độ mặc định bằng cách gõ:

par(mfrow = c(1, 1))

3.3.2 Các Graphs với gói ggplot2


Gói này được sử dụng trong tình huống đòi hỏi những Graphs có chất lượng hình ảnh cao hay các
Graph phức tạp. Mục này chúng ta chỉ nghiên cứu một số câu lệnh đơn giản phục vụ cho nghiên cứu
kinh tế lượng – thống kê mà thôi. Để minh họa, chúng ta sử dụng lại bộ số liệu liệu ch4bt8.wf1 mà
chúng ta đã gán lại nhãn cho các biến định tính ở mục 2.4.2.

Về cơ bản, mỗi lệnh trong gói ggplot2 có ba thành phần chủ yếu sau:

 Dữ liệu đầu vào,


 Một bộ các aesthetic mappings (kí kiệu là aes) giữa các biến số của bộ dữ liệu và các đặc điểm
hình ảnh,
 Ít nhất một layer miêu tả dữ liệu. Các layer thường được tạo ra bằng hàm geom.

Chúng ta nghiên cứu một số ví dụ ngay sau đây để làm sáng tỏ dần cấu trúc cú pháp của gói ggplot2.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


124

3.3.2.1 Vẽ Scatter Plot


Vẽ Scatter Plot (biểu đồ phân tán) với EDUC trên trục X và WAGE trên trục Y:

library(ggplot2)
ggplot(hello, aes(x = EDUC, y = WAGE)) + geom_point()

Hiệu ứng hình ảnh này là tương đương với các câu lệnh sau:

ggplot(hello, aes(EDUC, WAGE)) + geom_point()

Hoặc:

p <- ggplot(hello, aes(EDUC, WAGE)) + geom_point()


p

Hoặc một kiểu khác:

m <- ggplot(hello, aes(EDUC, WAGE))


m + geom_point()

Nếu sử dụng toán tử pipe thì câu lệnh sẽ như sau:

library(magrittr) # gọi gói magrittr để sử dụng toán tử pipe


hello %>% ggplot(aes(EDUC, WAGE)) + geom_point()

Qua một loạt các câu lệnh “khác nhau” nhưng lại tạo ra hiệu ứng hình ảnh như nhau các đã có thể cảm
nhận được cách sử dụng gói ggplot cũng như sử dụng toán tử pipe. Dưới đây là những lệnh phức tạp
tăng dần.

Cho 2 nhóm lao động ứng với 2 nhóm giới tính:

ggplot(hello, aes(EDUC, WAGE, colour = MALE)) + geom_point(show.legend = F) +


facet_wrap(~ MALE)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


125

Hay “gộp” cả 2 Scatter Plot trên vào cùng một cửa sổ hiển thị:

ggplot(hello, aes(EDUC, WAGE, colour = MALE)) + geom_point()

Bổ sung thêm chỉ dẫn cho trục cũng như tiêu đề đồng thời đổi theme:

ggplot(hello, aes(x = EDUC, y = WAGE)) + geom_point() +


labs(x = "Education",
y = "Wage",
title = "The Relationship between Education and Wage",
subtile = "Unit of Wage: Dollar per month",
caption = "Data Source: U.S. Census Bureau") +
theme_light()

3.3.2.2 Vẽ đường hồi quy


Chúng ta có thể vẽ đường hồi quy cho toàn bộ mẫu nghiên cứu với biến độc lập là WAGE còn biến phụ
thuộc là EDUC:

ggplot(hello, aes(EDUC, WAGE)) + geom_point() +


geom_smooth(method = "lm", se = FALSE)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


126

Có thể vẽ đường hồi quy có quãng đáng tin 95% với câu lệnh sau (không hiển thị hình ảnh):

ggplot(hello, aes(EDUC, WAGE, colour = MALE)) +


geom_point() + geom_smooth(method = "lm", se = TRUE)

Do số lượng điểm dữ liệu là rất nhiều nên các bạn chưa thấy sự khác biệt và ý nghĩa của câu lệnh trên.
Các bạn nên thử với những file dữ liệu kích mẫu thước bé. Chú ý rằng nếu các bạn thay đổi thứ tự của
geom_poin() và geom_smooth(method = ”lm”) thì hiệu ứng hình ảnh sẽ khác.

Chúng ta cũng có thể vẽ 2 đường hồi quy ứng với 2 nhóm lao động riêng biệt và hiển thị ở cùng một
cửa sổ:

ggplot(hello, aes(EDUC, WAGE, colour = MALE)) +


geom_point() + geom_smooth(method = "lm")

Hoặc theo một cách khác:

ggplot(hello, aes(EDUC, WAGE)) +


geom_point() + geom_smooth(method = "lm") + facet_wrap(~MALE)

Nếu sử dụng cả màu sắc (không hiển thị hình ảnh):

Nguyễn Chí Dũng http://rpubs.com/chidungkt


127

ggplot(hello, aes(EDUC, WAGE, colour = MALE)) +


geom_point() + geom_smooth(method = "lm") +
facet_wrap(~ MALE)

Kĩ thuật vẽ đường hồi quy (hoặc các đường cong hồi quy) như vậy rất có ích trong việc nghiên cứu
các mô hình hồi quy có biến định tính (biến giả) như ta có thể thấy ở chương 7 sau này.

3.3.2.3 Vẽ Histogram
Vẽ Histogram cho biến IQ (chỉ số thông minh IQ) riêng biệt cho hai nhóm giới tính:

ggplot(hello, aes(IQ, fill = MALE)) +


geom_histogram(show.legend = F) + facet_wrap(~ MALE)

Điều chỉnh độ “đậm – nhạt” của màu sắc:

ggplot(hello, aes(IQ, fill = MALE)) +


geom_histogram(show.legend = F, alpha = 0.5) + facet_wrap(~ MALE)

Vẽ cho cả 2 nhóm trên cùng một cửa sổ hiển thị:

ggplot(hello, aes(IQ, fill = MALE)) +


geom_histogram(alpha = 0.6, binwidth = 5)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


128

Cho toàn bộ các quan sát trong mẫu và không sử dụng màu sắc (không hiển thị hình ảnh):

ggplot(hello, aes(IQ)) + geom_histogram(alpha = 0.7)

Nếu muốn chúng ta có thể làm cho histogram này đẹp hơn theo một cách thức khác:

ggplot(hello, aes(IQ)) + geom_histogram(binwidth = 5,


fill = "lightblue",
color = "darkblue")

3.3.3.4 Boxplots
Box plot cho IQ theo hai nhóm giới tính:

ggplot(hello, aes(MALE, IQ, colour = MALE)) + geom_boxplot(show.legend = F)

Hình ảnh này nói một câu chuyện thú vị (và cũng gây tranh cãi) về trí thông minh của hai giới. Hầu
hết các lý thuyết đều cho rằng không có sự khác biệt nào về trí thông minh giữa các giới tính (thậm
chí là chủng tộc) nhưng box plot này cho thấy nam giới có IQ cao hơn nữ rất rõ. Tất nhiên, chúng ta
có thể thực hiện kiểm định t về sự khác biệt này cho chỉ số IQ của hai giới để có kết luận chính thức.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


129

Hoặc có thể vẽ box plot cho IQ theo cả hai biến định tính là giới tính và chủng tộc:

ggplot(hello, aes(MALE:BLACK, IQ, colour = MALE:BLACK)) +


geom_boxplot(show.legend = F)

Nếu chúng ta không cần trình bày màu sắc (không hiển thị hình ảnh):

ggplot(hello, aes(MALE, IQ)) + geom_boxplot(show.legend = F)

Hoặc có thể đổi chiều cho các box plot và không sử dụng màu sắc:

ggplot(hello, aes(MALE, IQ)) + geom_boxplot(show.legend = F) + coord_flip()

Hoặc vẽ box plot cho tất cả các quan sát không phân biệt theo bất kì biến định tính nào:

ggplot(hello, aes(0, IQ)) + geom_boxplot(show.legend = F) + coord_flip() +


theme(axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank())

Nguyễn Chí Dũng http://rpubs.com/chidungkt


130

3.3.2.5 Biểu đồ cột


Biểu đồ cột (Bar Graph) là một trong những dạng biểu đồ được sử dụng phổ biến. Đáng chú ý là để
vẽ Bar Graph chúng ta có thể sử dụng một trong hai hàm là geom_bar() hoặc geom_col(). Trong
mục này chúng ta chỉ sử dụng geom_col() minh họa với bộ số liệu CPS1988 đã biết. Tuy nhiên do cần
thực hiện một số biến đổi số liệu nên chúng ta sẽ gọi gói tidyverse – khi gọi gói này thì ggplot2 cũng
luôn được tải cùng (và do đó không cần tải thêm ggplot2 nữa). Đồng thời để thành thạo toán tử pipe
sẽ được sử dụng liên tục.

library(AER)
data("CPS1988")
library(tidyverse)
#--------------------------------------
# Số lao động theo khu vực địa lí:
#--------------------------------------

# Kiểu 1:
k1 <- CPS1988 %>%
group_by(region) %>% count() %>%
ggplot(aes(region, n)) + geom_col() + theme_minimal()
k1

# Kiểu 2:
k2 <- CPS1988 %>%
group_by(region) %>% count() %>%
ggplot(aes(region, n, fill = region)) +
geom_col() + theme_minimal()
k2

Nguyễn Chí Dũng http://rpubs.com/chidungkt


131

# Cố định theme là theme_minimal chứ không phải là theme nền xám như thường t
hấy:
theme_set(theme_minimal())
# Kiểu 3:
k3 <- CPS1988 %>%
group_by(region) %>% count() %>%
ggplot(aes(reorder(region, n), n, fill = region)) +
geom_col(show.legend = FALSE)
k3

# Xoay lại và hiệu chỉnh:


k4 <- k3 + coord_flip() +
labs(x = NULL, y = NULL,
title = "Observations by Region",
caption = "Data Source: US Census Bureau")
k4

Nguyễn Chí Dũng http://rpubs.com/chidungkt


132

# Sử dụng theme của tạp chí The Economists:


library(ggthemes)
k5 <- k4 + theme_economist(horizontal = FALSE)
k5

# Vừa dùng theme và màu sắc kiểu The Economists:


k6 <- k5 + scale_fill_economist()
k6

# Vừa dùng theme và màu sắc kiểu Wall Street Journal:


j1 <- k3 + labs(x = NULL, y = NULL,
title = "Observations by Region",
caption = "Data Source: US Census Bureau") +
theme_wsj(base_size = 7) + scale_fill_wsj()
j1

Nguyễn Chí Dũng http://rpubs.com/chidungkt


133

# Nếu muốn hiện thêm số:


k7 <- k4 + geom_text(aes(label = n), color = "white", hjust = 1.2)
k7

#-----------------------------------------------
# Số lao động theo khu vực địa lí và chủng tộc:
#-----------------------------------------------

# Kiểu 1:
k8 <- CPS1988 %>% group_by(region, ethnicity) %>% count() %>%
ggplot(aes(region, n)) + geom_col() +
facet_wrap(~ ethnicity, scales = "free") +
geom_text(aes(label = n), color = "white", vjust = 1.2, size = 3) +
labs(x = NULL, y = NULL,
title = "Observations by Region and Ethnicity",
caption = "Data Source: US Census Bureau")

k8

Nguyễn Chí Dũng http://rpubs.com/chidungkt


134

# Kiểu 2 (không hiển thị hình):


k9 <- CPS1988 %>% group_by(region, ethnicity) %>% count() %>%
ggplot(aes(region, n, fill = ethnicity)) + geom_col(position = "stack") +
geom_text(aes(label = n), color = "white", vjust = 1.2, size = 3) +
labs(x = NULL, y = NULL,
title = "Observations by Region and Ethnicity",
caption = "Data Source: US Census Bureau")
k9

# Kiểu 3 (hiển thị hình):


k10 <- CPS1988 %>% group_by(region, ethnicity) %>% count() %>%
ggplot(aes(region, n, fill = ethnicity)) + geom_col(position = "stack") +
labs(x = NULL, y = NULL,
title = "Observations by Region and Ethnicity",
caption = "Data Source: US Census Bureau")
k10

# Kiểu 4 (không hiển thị hình):


k11 <- CPS1988 %>% group_by(region, ethnicity) %>% count() %>%
ggplot(aes(region, n, fill = ethnicity)) + geom_col(position = "fill") +
labs(x = NULL, y = NULL,
title = "Observations by Region and Ethnicity",

Nguyễn Chí Dũng http://rpubs.com/chidungkt


135

caption = "Data Source: US Census Bureau")


k11

# Kiểu 5 (sử dụng thêm hàm scale_y_percent() của gói hrbrthemes):


library(hrbrthemes)
k12 <- k11 + coord_flip() + scale_y_percent() +
labs(x = "US Region", y = "Ethnic Proportion",
title = "Observations by Region and Ethnicity",
caption = "Data Source: US Census Bureau")

k12

# Kiểu 6:
k13 <- CPS1988 %>% group_by(region, ethnicity) %>% count() %>%
ggplot(aes(region, n, fill = ethnicity)) + geom_col(position = "dodge") +
labs(x = NULL, y = NULL,
title = "Observations by Region and Ethnicity",
caption = "Data Source: US Census Bureau")
k13

#----------------------------------------------
# Biểu diễn cách khác cho lao động theo khu
# vực địa lí bằng một số cách khác:
#----------------------------------------------

# Cách 1 (không hiển thị):

Nguyễn Chí Dũng http://rpubs.com/chidungkt


136

p <- CPS1988 %>%


group_by(region) %>%
count() %>%
ggplot(aes(x = "", n, fill = region)) +
geom_col(width = 1)
p

# Cách 2:
u <- CPS1988 %>%
group_by(region) %>%
count() %>%
ggplot(aes(x = "", n, fill = region)) +
geom_col(width = 1, position = "fill") +
coord_flip() + theme(legend.position = "top") +
scale_y_percent() +
labs(x = NULL, y = NULL,
title = "Percentage of Observations by Region",
caption = "Data Source: US Census Bureau")
u

Tất nhiên còn nhiều cách thức vẽ bar graph khác và các bạn nên tìm tòi thực hành thêm dựa trên R
codes đã có ở trên. Một cách khác rất tốt để nâng cao khả năng sử dụng ggplot2 cho Data Visualization
là thực hiện các dự án nhỏ (ví dụ: http://rpubs.com/chidungkt/285385 ).

3.3.2.6 Vẽ các đường cong hồi quy bặc hai


Chúng ta cũng có thể vẽ các đường cong hồi quy bậc hai. Một ví dụ điển hình là từ kinh tế học lao động
mà theo đó, lợi ích của việc đi học (hay có thêm số năm kinh nghiệm) sẽ tuân theo quy luật lợi ích cận
biên giảm dần khi số năm đi học (hay kinh nghiệm) vượt qua một ngưỡng nào đó. Để minh họa chúng
ta sử dụng lại bộ số liệu CPS1988 đã biết. Nhưng vì bộ số liệu này quá lớn nên chúng ta chỉ lấy ngẫu
nhiên 200 quan sát từ bộ số liệu này mà thôi:

# Sử dụng lệnh này để cố định kết quả.


set.seed(29)
# Lấy 200 quan sát
con <- CPS1988[sample(nrow(CPS1988), 200), ]
ggplot(con, aes(x = experience, y = log(wage))) +
geom_point() +

Nguyễn Chí Dũng http://rpubs.com/chidungkt


137

stat_smooth(method = "lm", formula = y ~ x + I(x^2), size = 1) +


facet_wrap(~region)

Nếu sử dụng toán tử pipe (khuyến khích sử dụng) và tô màu cho từng đường cong thì chúng ta không
cần phải tạo ra object trung gian là con:

set.seed(29)
CPS1988 %>%
sample_n(200) %>%
ggplot(aes(experience, log(wage), color = region, fill = region)) +
geom_point(show.legend = FALSE) +
stat_smooth(method = "lm",
formula = y ~ x + I(x^2),
size = 1, show.legend = FALSE) +
facet_wrap(~region)

Hoặc trên cùng một cửa sổ hiển thị đồng thời không lấy khoảng tin cậy 95%:

set.seed(29)
con <- CPS1988 %>% sample_n(200)
con %>% ggplot(aes(experience, log(wage), colour = region)) +
geom_point(alpha = 0.3) +
stat_smooth(method = "lm", formula = y ~ x + I(x^2), se = FALSE) +
theme_bw()

Nguyễn Chí Dũng http://rpubs.com/chidungkt


138

Hoặc không phân biệt theo từng khu vực địa lý:

con %>% ggplot(aes(experience, log(wage))) +


geom_point() +
stat_smooth(method = "lm", formula = y ~ x + I(x^2))

Các ví dụ trên cũng cho thấy rằng để có cùng một sản phẩm là graph (và tổng quát là các phân tích)
trong R có thể rất linh hoạt, nhiều cách thức khác nhau. Sức mạnh của R và đồng thời cũng là điểm
yếu của nó, theo như cách nói vui của Bob Rudis – một chuyên gia về phân tích dữ liệu là “..có 12 cách
làm cho một thứ công việc..”. Điều này có thể làm bạn rất khó nhớ và bạn muốn thành thạo R thì chỉ
còn cách là thực hành đủ nhiều để nắm được cái “hồn” của ngôn ngữ này.

3.3.2.7 Hàm mật độ xác suất Density


Sử dụng bộ số liệu CPS1988 chúng ta có thể vẽ hàm mật độ xác suất cho log(wage) ứng với bốn nhóm
lao động đến từ 4 khu vực địa lý:

ggplot(CPS1988, aes(log(wage), colour = region)) + geom_density()

Nguyễn Chí Dũng http://rpubs.com/chidungkt


139

Chúng ta có thể vẽ hàm mật độ xác suất ứng với 4 nhóm lao động theo một cách khác:

ggplot(CPS1988, aes(log(wage), fill = region)) + geom_density(alpha = 0.3)

Chúng ta cũng thể vẽ hàm mật độ xác suất của log(wage) với toàn bộ quan sát bằng lệnh:

ggplot(CPS1988, aes(log(wage))) +
geom_density(color = "darkblue", fill = "lightblue")

Chúng ta cũng có thể hiện thị đồng thời cả Histogram và Density:

CPS1988 %>% ggplot(aes(log(wage))) +


geom_density(alpha = 0.3, fill = "blue", color = "blue") +
geom_histogram(aes(y = ..density..), fill = "red", color = "red", alpha = 0
.3) +
theme_bw()

Nguyễn Chí Dũng http://rpubs.com/chidungkt


140

Hoặc cho từng nhóm làm thêm hay không làm thêm:

CPS1988 %>% ggplot(aes(log(wage))) +


geom_density(alpha = 0.3, fill = "blue", color = "blue") +
geom_histogram(aes(y = ..density..), fill = "red", color = "red", alpha = 0
.3) +
theme_bw() +
facet_wrap(~ parttime)

3.3.2.8 Biểu đồ đường


Trở lại với bộ số liệu mà chúng ta đã sử dụng ở mục 3.3.1.7:

ggplot(dung, aes(time, ex)) + geom_line(col = "blue")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


141

Chú ý rằng bộ số liệu này thì biến time không phải mang ý nghĩa thời gian thực. Để vẽ đồ thị đường
với thời gian thực chúng ta trở lại với bộ số liệu các cổ phiếu ở mục 2.3.8:

path <- dir("E:/KTLR/cophieu", full.names = TRUE)


data <- lapply(path, read.csv)
data <- do.call("rbind", data)
# Xem qua số liệu:
head(data[, 1:5])

## X.Ticker. X.DTYYYYMMDD. X.OpenFixed. X.HighFixed. X.LowFixed.


## 1 AAA 20161028 29.6 29.8 29.3
## 2 AAA 20161027 29.7 30.0 29.2
## 3 AAA 20161026 29.3 29.7 29.0
## 4 AAA 20161025 29.0 29.9 29.0
## 5 AAA 20161024 30.0 30.6 29.7
## 6 AAA 20161021 30.8 31.0 30.0

# Chuyển biến X.DTYYYYMMDD. theo đúng bản chất thời gian và vẽ:
library(lubridate)
# Kiểu 1:
data %>% mutate(Date = ymd(X.DTYYYYMMDD.)) %>%
ggplot(aes(Date, X.Open.)) + geom_line(color = "blue") +
facet_wrap(~ X.Ticker., drop = TRUE, scales = "free") +
theme_bw()

Hoặc theo một số cách thức khác:

# Kiểu 2:
data %>% mutate(Date = ymd(X.DTYYYYMMDD.)) %>%
ggplot(aes(Date, X.Open., color = X.Ticker.)) + geom_line() +
theme_bw()

Nguyễn Chí Dũng http://rpubs.com/chidungkt


142

# Kiểu 3:
data %>% mutate(Date = ymd(X.DTYYYYMMDD.)) %>%
rename(Price = X.Open., Symbol = X.Ticker.) %>%
ggplot(aes(Date, Price, color = Symbol)) + geom_line() +
theme_bw()

Ở trên chúng ta đã sử dụng hàm ymd() của gói lubridate để tạo biến thời gian có tên Date dựa trên
biến X.DTYYYYMMDD. (vốn có thứ tự là năm, tháng, ngày – tương ứng với ba chữ ymd của hàm
ymd()). Ngoài ra với cách vẽ 3 chúng ta cũng đổi tên một số biến số cho graph đẹp và dễ hiểu với
lệnh rename() của gói dplyr trước khi vẽ.

3.3.2.9 Pie Chart


Vẽ biểu đồ hình bánh với gói ggplot2 là tương đối phức tạp. Việc đầu tiên là tạo ra một biểu đồ cột rồi
sau đó chuyển hóa biểu đồ cột này thành biểu đồ hình bánh:

# Trước hết tạo ra bar graph:


p <- CPS1988 %>%
group_by(region) %>%
count() %>%
ggplot(aes(x = "", n, fill = region)) +
geom_col(width = 1, stat = "identity")
p

Nguyễn Chí Dũng http://rpubs.com/chidungkt


143

# Rồi mới tạo pie graph:


p + coord_polar("y", start = 0) + labs(x = NULL, y = NULL)

Có thể thấy hai loại biểu đồ này mang ý nghĩa thông tin như nhau nhưng biểu đồ bánh chiếm không
gian trình bày nhiều lại thiết kế phức tạp nên trừ khi không còn cách nào khác (như thông lệ ở Việt
Nam vẫn có xu hướng lạm dụng biêu đồ bánh) thì ta nên kể một câu chuyện về số liệu bằng biểu đồ
cột chứ không phải biểu đồ hình bánh. Lí do như đã được trình bày ở mục trước.

3.3.3 Hình ảnh hóa dữ liệu (Data Visualiztion) nâng cao


Phần này chúng ta sẽ nghiên cứu cách tạo ra các hình ảnh thương tác (interactive graphs) thường
được sử dụng cho mục đích thuyết trình hay viết các báo cáo.

3.3.3.1 Trình bày nhiều Graphs trên cùng một cửa sổ hiển thị trong R với gói grid
Một câu hỏi là các bạn có thể trình bay nhiều Graphs trên cùng một cửa sổ hiển thị nếu sử dụng gói
ggplot2 hay không? Câu trả lời là được. Chúng ta có thể thực hiện điều này với sự trợ giúp của gói
gridExtra. Dưới đây là một ví dụ về hiển thị đồng thời hai graphs trên một cửa sổ hiển thị:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


144

# Chọn ra 400 quan sát ngẫu nhiên từ CPS1988:


set.seed(1)
subData <- CPS1988[sample(nrow(CPS1988), 400), ]
# Vẽ đường hồi quy và catter plot:
g1 <- ggplot(subData, aes(education, log(wage), colour = region)) +
geom_point(show.legend = FALSE) + facet_wrap(~ region) +
geom_smooth(method = "lm", show.legend = FALSE)
# Vẽ hàm mật độ xác suất cho log(wage):
g2 <- ggplot(subData, aes(log(wage), fill = region)) +
geom_density(alpha = 0.3, show.legend = FALSE) +
facet_wrap(~ region)
# Gọi gói gridExtra:
library(gridExtra)
# Hiển thị g1, g2 theo hai hàng một cột:
grid.arrange(g1, g2, nrow = 2, ncol = 1)

Tất nhiên tất cả các đồ thị - hình vẽ mà gói Basic Graphics có thể làm được thì ggplot2 cũng có thể làm
được (và với chất lượng tốt hơn) như các bạn đã thấy. Trên đây chúng ta mới chỉ nghiên cứu các chức
năng của ggplot2 kiểu “cưỡi ngựa xem hoa”. Bạn nào quan tâm đến gói này có thể đọc các sách chuyên
biệt về ggplot2. Một trong những cuốn cơ bản nhất là “ggplot2 Essentials” của Donato Teutonico.

3.3.3.2 Vẽ thêm Histogram cho đường hồi quy với gói ggExtra
Chúng ta có thể đồng thời vẽ cả đường hồi quy với khoảng tin cậy 95% với Histogram cho các biến số
trên cùng một đồ thị với sự trợ giúp của gói ggExtra (các bạn cài đặt gói này bằng cách gõ
install.packages(“ggExtra”) trong cửa sổ lệnh của R). Để minh họa, phần này tôi sử dụng lại bộ dữ
liệu dung ở mục 3.1. Các câu lệnh thực hiện là:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


145

library(ggExtra)
aoe <- ggplot(dung, aes(INCOME, HEALTH)) + geom_point() +
geom_smooth(method = "lm")
ggMarginal(aoe, type = "histogram")

3.3.3.3 Vẽ thêm hàm mật độ xác suất cho đường hồi quy với gói gridExtra
Chúng ta có thể đồng thời vẽ cả đường hồi quy với quãng đáng tin 95% và hàm mật độ xác suất các
biến số trên cùng một cửa sổ hiển thị với sự trợ giúp của gói gridExtra (trước hết cài đặt gói này bằng
cách gõ install.packages(“gridExtra”). Đầu tiên chúng ta thực hiện các dòng lệnh sau:

yeu <- ggplot(dung, aes(INCOME)) +theme(legend.position = "none") +


geom_density(alpha =0.5, color = "darkblue", fill="lightblue")
em <- ggplot(dung, aes(HEALTH)) + theme(legend.position="none") +
geom_density(alpha=0.5,color="darkblue", fill="lightblue") +
coord_flip()
aoe <- ggplot(dung, aes(INCOME, HEALTH)) + geom_point() +
geom_smooth(method = "lm")

Kế tiếp chúng ta cần tạo một khoảng trống (blank) như sau:

trong <- ggplot()+geom_blank(aes(1,1))+


theme(
plot.background = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
panel.background = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.text.x = element_blank(),

Nguyễn Chí Dũng http://rpubs.com/chidungkt


146

axis.text.y = element_blank(),
axis.ticks = element_blank(),
axis.line = element_blank())

Sau đó chúng ta sử dụng gridExtra để kết hợp tất cả lại:


library(gridExtra)
grid.arrange(yeu, trong, aoe, em,
ncol = 2,
nrow = 2,
widths = c(5, 3),
heights=c(2, 3))

3.3.3.4 Vẽ thêm Boxplot cho đường hồi quy với gói gridExtra
Chúng ta có thể đồng thời vẽ cả đường hồi quy với quãng đáng tin 95% và boxplot các biến số trên
cùng cửa sổ hiển thị:

greek <- ggplot(dung, aes(HEALTH, INCOME)) + coord_flip() +


geom_boxplot(color = "darkblue", fill = "lightblue")
choson <- ggplot(dung, aes(INCOME, HEALTH)) +
geom_boxplot(color = "darkblue", fill = "lightblue")
grid.arrange(greek, trong, aoe, choson,
ncol = 2,
nrow = 2,
widths = c(5, 3),
heights=c(2, 3))

Nguyễn Chí Dũng http://rpubs.com/chidungkt


147

3.3.3.5 Vẽ đồ thị thị phần của R giai đoạn 1995 - 2011


Ở đây tôi sẽ giới thiệu các câu lệnh (cũng như các gói cần thiết) để vẽ graph biểu thị thị phần của R so
với các phần mềm khác đã được trình bày trong phần mở đầu của tài liệu này. Do là một phần mềm
miễn phí nên chúng ta không thể có thông tin về doanh thu của R. Tuy vậy chúng ta có thể nghiên cứu
thị phần của R (cũng như của bất kì phần mềm nào khác) theo một cách khác: căn cứ vào mức độ sử
dụng R cho các nghiên cứu khoa học được đăng trên các tạp chí chuyên nghành chẳng hạn. Dữ liệu về
các truy vấn tìm kiếm các nghiên cứu khoa học sử dụng 6 phần mềm phổ biến giai đoạn 1995 – 2011
được thu thập từ cơ sở dữ liệu của Google Scholar và được lưu ở file scholarly_impact_2012.4.9.csv
mà các bạn đã gặp ở mục 2.3.5 của chương 2 (các câu lệnh sử dụng R để lấy dữ liệu từ Internet vượt
quá khuôn khổ của tài liệu này nên tôi sẽ không trình bày ở đây). Để vẽ graph này chúng ta sẽ sử dụng
lại data.frame dulieu ở mục 2.3.5 với sự trợ giúp của hai gói là reshape2 và scales (đến đây tôi giả
định là các bạn đã biết cách cài đặt các gói cần thiết trong R bất kể khi nào cần dùng đến chứ không
chỉ là reshape2 và scales ). Các câu lệnh thực hiện là như sau:
# Gọi gói tidyverse và thực hiện một số biến đổi dữ liệu về dạng thích hợp:
library(tidyverse)
con <- hello %>% select(JMP, Minitab, Stata, Statistica, Systat, R) %>%
mutate(Year = 1995:2011) %>% gather(PhanMem, MucDoTimKiem , -Year) %>%
mutate(PhanMem = as.factor(PhanMem))
# Vẽ thị phần của các phần mềm:
con %>% ggplot(aes(Year, MucDoTimKiem, group = PhanMem)) +
geom_smooth(aes(fill = PhanMem), position = "fill")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


148

Đây là một đồ thị rất quen thuộc với bạn nào chơi AOE – một game rất phổ biến. Các bạn có thể thấy
vào giai đoạn 1995 – 2000 thị phần của R gần như bằng 0 nhưng đến năm 2011 thì nó đã vươn lên vị
trí thứ nhất trong số 6 phần mềm khảo sát.

3.3.3.6 Sử dụng gói plotly tạo ra các hình ảnh tương tác
Các hình ảnh tương tác (Interactive Graphs) là một công cụ hình ảnh hóa dữ liệu rất ấn tượng và mang
lại nhiều thông tin. Điều này đặc biệt có giá trị nếu chúng ta sử dụng chúng cho các buổi thuyết trình
hay hỗ trợ cho các phân tích sâu hơn. Dưới đây chúng ta sẽ nghiên cứu cách tạo ra hình ảnh tương tác
với gói plotly. Trước hết các bạn hãy cài đặt gói này bằng install.packages(“plotly”).

Để minh họa chúng ta xé bộ số liệu iris (bộ số liệu này luôn đi kèm với R khi ta cài đặt). Đây là bộ số
liệu về chiều dài đài hoa, chiều rộng đài hoa .. của 150 quan sát thuộc 3 giống hoa là sesota, vericolor
và viginica. Dưới đây là R code cho việc tạo ra hình ảnh tương tác đơn giản nhất trong đó chúng ta
biểu diễn biểu đồ rời rạc (Scater Plot) với biến Petal.Length ở trục X và Petal.Width ở trục Y tương
ứng với 3 giống hoa:

library(plotly)
data(iris)
plot_ly(iris, x = ~ Petal.Length, y = ~Petal.Width,
type="scatter", mode = "markers" , color = ~Species)

Hình ảnh mà chúng ta thu được nếu bạn di con chuột vào thì chúng ta sẽ thấy hiện ra các con số.
Những hình ảnh kiểu như thế này được gọi là hình ảnh tương tác:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


149

Chúng ta cũng có thể công bố hình ảnh trên Internet bằng Rpub (khoanh vàng có chữ Puslish) hoặc
cửa sổ có hình histogram. Chẳng hạn chúng ta có thể công bố hình ảnh này với Rpub:

http://rpubs.com/chidungkt/228114

Chúng ta chú ý mối liên hệ thú vị sau giữa gói các hàm của gói ggplot và các hàm cùa gói plotly (không
hiển thị hình ảnh ở đây):

trang <- ggplot(iris, aes(Petal.Length,


Petal.Width,
colour = Species)) + geom_point()
trang
ggplotly(trang)

Có nghĩa là, để tạo ra một hiệu ứng hình ảnh tương tự, đầu tiên chúng ta tạo ra một object có tên m
(do hàm ggplot() tạo ra). Kế tiếp để tạo hiệu ứng hình ảnh tương tác thì áp dụng hàm ggplotly() cho
object tên trang này.

Tương tự, chúng ta có thể tạo các Boxplot cho 3 giống hoa này:

plot_ly(iris, x = ~Sepal.Length, color = ~Species, type = "box")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


150

Dưới đây là lệnh phức tạp hơn để tạo ra một hình ảnh ấn tượng: minh họa mối liên hệ giữa GDP và
tuổi thọ băng biểu đồ bong bóng. Sử dụng bộ số liệu bong1.csv chúng ta có hình ảnh sau:

Dưới đây là R code để tạo ra hình ảnh ấn tượng (nhưng cũng nhiều thông tin) này:

data <- read.csv("bong1.csv")


data_2007 <- data[which(data$year == 2007),]
data_2007 <- data_2007[order(data_2007$continent, data_2007$country),]
slope <- 2.666051223553066e-05
data_2007$size <- sqrt(data_2007$pop * slope)
colors <- c("#4AC6B7", "#1972A4", "#965F8A", "#FF7070", "#C61951")
p <- plot_ly(data_2007, x = ~gdpPercap, y = ~lifeExp, color = ~continent,
size = ~size,
colors = colors,
type = "scatter",

Nguyễn Chí Dũng http://rpubs.com/chidungkt


151

mode = "markers",
sizes = c(min(data_2007$size),
max(data_2007$size)),
marker = list(symbol = "circle",
sizemode = "diameter",
line = list(width = 2, color = "#FFFFFF")),
text = ~paste("Country:",
country,
"<br>Life Expectancy:",
lifeExp, "<br>GDP:",
gdpPercap,
"<br>Pop.:",
pop)) %>%
layout(title = 'Life Expectancy v. Per Capita GDP, 2007',
xaxis = list(title = 'GDP per capita (2000 dollars)',
gridcolor = 'rgb(255, 255, 255)',
range = c(2.003297660701705, 5.191505530708712),
type = 'log',
zerolinewidth = 1,
ticklen = 5,
gridwidth = 2),
yaxis = list(title = 'Life Expectancy (years)',
gridcolor = 'rgb(255, 255, 255)',
range = c(36.12621671352166, 91.72921793264332),
zerolinewidth = 1,
ticklen = 5,
gridwith = 2),
paper_bgcolor = 'rgb(243, 243, 243)',
plot_bgcolor = 'rgb(243, 243, 243)')
p

Cuối cùng, sử dụng gói quantmod để thu thập dữ liệu tài chính của Apple và Microsoft chúng ta có
thể minh họa giá của hai cổ phiếu này theo: (1) thời gian, và (2) theo từng năm (1 yr) hay tất cả (all).
Trước hết bạn cài đặt gói quantmod (chi tiết hơn về sử dụng gói này các bạn có thể xem tại chương
15) và thực hiện những dòng mã sau:

library(quantmod) # Tải gói quantmod


getSymbols(Symbols = c("AAPL", "MSFT")) # Lấy dữ liệu của Apple và Microsoft.
ds <- data.frame(Date = index(AAPL), AAPL[,6], MSFT[,6])
p <- plot_ly(ds, x = ~Date) %>%
add_lines(y = ~AAPL.Adjusted, name = "Apple") %>%
add_lines(y = ~MSFT.Adjusted, name = "Microsoft") %>%
layout(
title = "Stock Prices",
xaxis = list(
rangeselector = list(
buttons = list(
list(
count = 3,
label = "3 mo",

Nguyễn Chí Dũng http://rpubs.com/chidungkt


152

step = "month",
stepmode = "backward"),
list(
count = 6,
label = "6 mo",
step = "month",
stepmode = "backward"),
list(
count = 1,
label = "1 yr",
step = "year",
stepmode = "backward"),
list(
count = 1,
label = "YTD",
step = "year",
stepmode = "todate"),
list(step = "all"))),
rangeslider = list(type = "date")),
yaxis = list(title = "Price"))
p

Đến đây chúng ta di chuột vào các đường để biết giá của các cổ phiếu. Chúng ta cũng có thể kích vào
cửa sổ có tên 6 mo hay all để tìm hiểu xu hướng giá trong những khoảng thời gian khác nhau.

3.3.3.7 Sử dụng gói googleVis tạo ra các hình ảnh tương tác
Ngoài sử dụng gói plotly chúng ta cũng có thể dùng gói googleVis để tạo ra các hình ảnh tương tác
theo một cách thức khác. Trước hết chúng ta tìm hiểu về bộ số liệu có tên ginivsgdp1.csv về tăng

Nguyễn Chí Dũng http://rpubs.com/chidungkt


153

trưởng (đo bằng gdp_ann) và mức độ bất bình đẳng về thu nhập tại Hoa Kì (đo bằng hệ số Gini) từ
thời cầm quyền của Johnson cho đến Obama. Chúng ta hãy đánh giá một cách hình ảnh mức độ bất
bình đẳng về thu nhập quan các thời kì cầm quyền:

dung <- read.csv("ginivsgdp1.csv", header = TRUE)


plot(dung$gdp_ann,
dung$Gini,
pch = 20,
col = c(dung$Presidents),
type = "o",
xlab =" GDP ",
ylab = "He so Gini",
main = "Bat binh dang ung voi cac thoi ki",
xaxp = c(0, 18000, 8))
# Trang trí thêm
legend("bottomright", fill = c(6, 7, 4, 2, 9, 5, 3, 1, 8),
legend = c("Johnson",
"Nixon",
"Ford",
"Carter",
"Reagan",
"G.Bush",
"Clinton",
"Bush",
"Obama"), bty = "n", cex = 0.7)

Từ hình ảnh này chúng ta có thể thấy rằng thời kì cần quyền của G.Bush (Bush cha) thì mức độ bất
bình đẳng tăng cao nhất và đến thời của Clinton thì tốc độ bất bình đẳng giảm dần.

Giả sử mức độ bất bình đẳng và tăng trưởng có mối quan hệ tuyến tính và chúng ta thực hiện hồi quy
với biến độc lập là tăng trưởng, biến phụ thuộc là tăng trưởng (chúng ta sẽ nghiên cứu kĩ ở chương
4) đồng thời chúng ta muốn hiển thị cả các con số cũng như phương trình đường hồi quy. Để thực
hiện điều này trước hết bạn cần cài đặt gói googleVis. Dưới đây là các lệnh cho phép thực hiện điều
đó với điều kiện máy tính nối Internet:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


154

library(googleVis)
trang <- data.frame(gdp = c(dung$gdp_ann), gini= c(dung$Gini))
trangyeu <- gvisScatterChart(trang, option= list(width = 650,
height = 600, legend = "none", title = "Moi quan he giua bat binh dang - tang
truong tai Hoa Ki",
hAxis = "{title :'GDP'}",
vAxis = "{title :'Gini'}",
dataOpacity = 0.8,
trendlines="{0:{type : 'linear', visibleInLegend: true,
showR2: true}}"))
plot(trangyeu)

Lúc này nếu bạn di chuột dọc theo đường thẳng bạn sẽ thấy phương trình hồi quy được hiện thị cũng
như tọa độ của các điểm trên đồ thị.

Với gói googleVis chúng ta cũng có thể vẽ được bản đồ nợ công của một số nước châu Âu tương tự
như một bài viết đăng trên New York Times. Các bạn có thế tham khảo bài viết cùng hình ảnh tại đây:

http://www.nytimes.com/interactive/2010/04/06/business/global/european-debt-map.html

Khi kích vào bản đồ của từng nước, các bạn sẽ thấy hiện ra các thông tin về nợ công của quốc gia được
chọn.

Chúng ta hoàn toàn có thể vẽ bản đồ nợ công tương tự như trên. Sử dụng bộ số liệu debt.csv về nợ
công của một số nước châu Âu:

debt <- read.csv("debt.csv", header = TRUE, sep =",")


nghiyeu <- gvisGeoMap(debt, locationvar="Country",

Nguyễn Chí Dũng http://rpubs.com/chidungkt


155

numvar= "Debt_to_GDP_Ratio_2003",
hovervar="text",
options = list(width = "600px", height ="700px",
dataMode = "regions", region = '150',
colors= "[0xF8DFA7,
0x8D9569,
0xE9CC99,
0xE2AD5A,
0xCA7363]"))
plot(nghiyeu)

Sử dụng bộ số liệu có tên ghg.csv chúng ta có thể vẽ bản đồ hiển thị mức độ thải khí CO2 của 99 quốc
gia lớn nhất thế giới trong năm 2010:

dung <- read.csv("ghg.csv",sep =",", header = TRUE)


love <- gvisGeoChart(dung, locationvar = "Country",
sizevar = "Emission_in_2010",
options = list(displayMode = "markers",

Nguyễn Chí Dũng http://rpubs.com/chidungkt


156

width = 900,
height =500,
markerOpacity = 0.5,
sizeAxis = "{maxSize:'35'}",
colorAxis = "{colors:['green','red']}"))
plot(love)

Hình ảnh này cho thấy Trung Quốc là nước thải khí hiệu ứng nhà kính lớn nhất thế giới trong năm
2010. Tất nhiên chúng ta có thể lặp lại hình ảnh này với số liệu của năm khác.

Ngoài ra, chúng ta cũng có thể vẽ hình ảnh biểu diễn theo thời gian mức độ xả thải của một số quốc
gia từ năm 1990 cho đến năm 2030 (con số dự báo) :

Nguyễn Chí Dũng http://rpubs.com/chidungkt


157

Dưới đây là R code để tạo ra đồ thị tương tác trên:

dung <-read.csv("ghg1.csv")
love <- gvisLineChart(dung, xvar = "Year", yvar = c("Brazil", "China", "India
","Russia", "USA"), options = list( width = 500, height = 500,title = "Green
House Gas Emissions", vAxis="{title:'Million Metric tons of CO2'}",
hAxis="{title:'Year'}", gvis.editor ="Edit the Line Chart"))
plot(love)

Như vậy có thể thấy trong số những nước khảo sát, Nga là quốc gia duy nhất giảm lượng xả thải khí
gây hiệu ứng nhà kính.

3.4 Môt số nguyên tắc của hình ảnh hóa dữ liệu của Edward Tufte
Khi khai thác các thông tin hữu ích nhưng tiềm ẩn trong bộ số liệu bằng công cụ hình ảnh, chúng ta
không thể bỏ qua hai nguyên tắc cơ bản nhất của việc trình bày hình ảnh, đồ thị đã được giới thống
kê và phân tích số liêu thừa nhận của Edward Tufte – một bậc thầy về hình ảnh hóa dữ liệu đồng thời
là một giáo sư về thống kê, khoa học máy tính và chính trị học ở đại học Yale.

Nguyên tắc thứ nhất có thể được gọi là nguyên tắc tối giản theo đó việc hình ảnh hóa dữ liệu phải thỏa
mãn truyền tải tối đa các thông tin ẩn dấu trong bộ dữ liệu đồng thời các hình ảnh phải đơn giản nhất,
tiết kiệm mực in và không gian trình bày tối đa nhất có thể. Theo quan điểm này của Tufte thì biểu đồ
hình tròn (Pie Chart) không nên được sử dụng và có thể được thay thế bằng biểu đồ cột (Bar Chat).
Lí do là, chẳng hạn, để biểu diễn tỉ trọng % của nam và nữ trong một mẫu chẳng hạn, thì biểu đồ cột
hoàn toàn có thể thỏa mãn yêu cầu này đồng thời vẽ biểu đồ cột là rất đơn giản, linh hoạt và chiếm ít
không gian trình bày hơn so với biểu đồ hình bánh.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


158

Nguyên tắc thứ hai là rõ ràng, không gây nhầm lẫn và hiểu lầm cho người đọc trong việc nắm bắt, diễn
giải các thông tin ẩn chứa trong bộ dữ liệu. Để minh họa, xét bộ số liệu giả thuyết về xuất khẩu của
Việt Nam trong bốn quý của năm 2020:

Quy <- c("Q1", "Q2", "Q3", "Q4")


XuatKhau <- c(7, 7.1, 7.15, 6.95)
trang <- data.frame(Quy, XuatKhau)
head(trang)

## Quy XuatKhau
## 1 Q1 7.00
## 2 Q2 7.10
## 3 Q3 7.15
## 4 Q4 6.95

Giả sử chúng ta sử dụng công cụ hình ảnh để mô tả xu hướng về xuất khẩu của Việt Nam lần lượt bằng
ba biểu đồ cột dưới đây:

ggplot(data = trang, aes(x = Quy, y = XuatKhau, fill = Quy)) +


geom_bar(stat="identity")

ggplot(data = trang, aes(x = Quy, y = XuatKhau, fill = Quy)) +


geom_bar(stat = "identity", show.legend = F)

ggplot(data = trang, aes(x = Quy, y = XuatKhau)) +


geom_bar(stat = "identity", show.legend = F)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


159

Theo Tufte thì cả ba biểu đồ cột này đều vi phạm nguyên tắc thứ hai. Thực vậy, do các con số về xuất
khẩu là rất sát nhau nên người đọc có thể không phân biệt được, và do vậy không hề rút ra bất cứ
thông tin hữu ích nào về xu hướng xuất khẩu.

Riêng biểu đồ thứ nhất và thứ hai còn vi phạm thêm nguyên tắc thứ nhất: đó là sự tối giản trong trình
bày nhưng phải mang lại tối đa thông tin. Biểu đồ cột thứ nhất không cần thiếu phải sử dụng: (1) màu
sắc đại diện cho các quý, và (2) chú thích ở phía bên phải cho các quý. Vì rằng đã có 4 tên gọi từ Q1
đến Q4 đại diện cho các quý và như vậy, sử dụng thêm màu sắc là thừa.

Biểu đồ thứ 3 thỏa mãn nguyên tắc thứ nhất nhưng vi phạm rõ ràng nguyên tắc thứ hai vì nó không
thể hiện rõ xu hướng về xuất khẩu, hoặc rất khó để nhìn ra xu hướng ấy.

Trong tình huống này, biểu đồ đường sẽ thỏa mãn cả hai nguyên tắc của Tufte về hình ảnh hóa dữ liệu
như chúng ta có thể thấy:

ggplot(data = trang, aes(x = Quy, y = XuatKhau, group = 1)) +


geom_line() + geom_point()

Khi đọc đến những dòng này, có thể thấy một số graph trình bày trước đó đã vi phạm các nguyên tắc
của Tufte. Chẳng hạn việc sử dụng 4 màu sắc Box Plot ở mục 3.3.1.4 là thừa. Tuy nhiên tôi cần lưu ý
các bạn rằng những mục mục trước đó chỉ hướng vào minh họa và thực hành vẽ, tô màu chứ chưa
bám sát các nguyên tắc của Tufte. Bạn đọc quan tâm và muốn tìm hiểu sâu hơn có thể tham khảo một
trong số các sách của Tufte về hình ảnh hóa dữ liệu có tên “Visual Explanations: Images and
Quantities, Evidence and Narrative”.

3.5 Lưu các Graphs


R cho phép chúng ta cần lưu lại các Graphs ở nhiều định dạng khác nhau. Ở đây tôi chỉ giới thiệu cách
lưu các Graphs ở ba định dạng: (1) lưu ở file PDF, và (2) file JPG, và (3) PNG. Ví dụ, nếu chúng ta muốn
lưu lại hình ở mục 3.3.2.7 ở dạng file PDF với tên chidung ta làm như sau:

pdf("chidung.pdf")
ggplot(CPS1988, aes(log(wage), fill = region)) + geom_density(alpha = 0.3)
dev.off()

Lúc này, tại folder có tên KTLR sẽ có một file PDF có tên chidung.pdf. Trong tình huống các bạn muốn
lưu Graph này ở dạng file JPG hoặc PNG thì câu lện đầu tiên trong ba câu lện ở trên được thay lần lượt
bằng png("chidung.png") hoặc jpeg("chidung.jpeg").

Nguyễn Chí Dũng http://rpubs.com/chidungkt


160

Cách thức vừa trình bày ở trên là cách thức tổng quát cho việc lưu các graph. Riêng với trường hợp
sử dụng gói ggplot2 chúng ta có thể sử dụng hàm ggsave() của gói này để lưu lại các hình ảnh theo
một cách thức khác như sau:

ggplot(CPS1988, aes(log(wage), fill = region)) + geom_density(alpha = 0.3) +


ggsave("trang.pdf")

Ở đây chúng ta lưu lại graph với tên là trang.pdf.

3.6 Mini Projects: Hình ảnh hóa dữ liệu trong thực tế


Phần này chúng ta sẽ thực hiện một số dự án nhỏ (Mini Projects) hướng vào việc hoàn thiện những
kĩ năng về sử dụng R trong thực tế cho hình ảnh hóa dữ liệu (với tiêu chuẩn chất lượng là đăng được
ở các báo cáo, các tạp chí) từ dễ đến khó. Những dự án này đòi hỏi sử dụng và kết hợp các kĩ năng
khác nhau, bao gồm cả Data Manipulation.

Hình ảnh là cách thức hiệu quả truyền tải những thông tin hữu ích của dữ liệu như John Tukey – một
cây đại thụ của khoa học thống kê đã phát biểu:

“The simple graph has brought more information to the data analyst’s mind than any other
device.”

Trong dự án thứ nhất là hình ảnh hóa dữ liệu về đầu tư ròng của nước ngoài từ năm 1987 đến 2015
của Việt Nam theo phong cách trình bày hình ảnh của tạp chí The Econimists (có thể tìm hiểu thêm
bằng cách gõ cụm từ “the economist graph” vào Google) với dữ liệu cung cấp bởi Ngân Hàng Thế Giới
WB.

Trước hết thu thập những dữ liệu này trực tiếp từ R với gói WDI:

library(WDI)
df <- WDI(country = c("VN"),
indicator=c("BX.KLT.DINV.CD.WD"),
start = 1987,
end = 2015,
extra = TRUE,
cache = NULL)

Ở đây, VN là kí hiệu của Việt Nam và BX.KLT.DINV.CD.WD là kí hiệu bộ dữ liệu về dòng vốn đầu tư ở
Việt Nam. Dữ liệu thu thập được gồm nhiều biến số nhưng chúng ta chỉ quan tâm đến FDI ròng và
thời gian cho nên chúng ta chỉ cần giữ lại hai biến số đó. Ngoài ra để dễ hiểu chúng ta có thể đổi tên
cho biến số đồng thời tạo ra một biến mới là FDI_b với ngụ ý đơn vị của FDI ròng là tỉ Dollar:

library(tidyverse)
df <- rename(df, Year = year, FDI = BX.KLT.DINV.CD.WD)
df <- select(df, Year, FDI)
df <- mutate(df, FDI_b = FDI / 1000000000)

Kế tiếp chúng ta sử dụng gói ggplot2 (không cần phải gọi gói này vì hệ sinh thái tidyverse khi được
gọi thì gói ggplot2 cũng được gọi cùng) để hình ảnh hóa dòng FDI ròng trong khoảng thời gian trên
với nền (themes) theo phong cách của tạp chí The Economists:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


161

library(ggthemes)
ggplot(df, aes(x = Year, y = FDI_b)) +
geom_bar(stat="identity", position="identity",
show.legend = F, fill = c("#1874CD")) +
labs(x = NULL,
y = NULL,
title = "Vietnam's net FDI flows: 1987 - 2015",
subtitle = "Unit: Billion",
caption = "Source: The World Bank") +
theme_economist()

Nếu sử dụng toán tử pipe mà chúng ta đã biết thì tất cả các dòng lệnh (mỗi dòng lệnh đại diện cho
một công đoạn xử lí dữ liệu – data manipulation) dài dòng trên có thể thu gọn về chỉ còn một dòng
lệnh (không tính các dòng lệnh gọi các gói) như sau mà vẫn thu được kết quả cuối cùng:

library(WDI)
library(tidyverse)
library(ggthemes)
WDI(country = c("VN"),
indicator=c("BX.KLT.DINV.CD.WD"),
start = 1987,
end = 2015,
extra = TRUE,
cache = NULL) %>%
rename(Year = year, FDI = BX.KLT.DINV.CD.WD) %>%
select(Year, FDI) %>%
mutate(FDI_b = FDI / 1000000000) %>%
ggplot(aes(x = Year, y = FDI_b)) +
geom_bar(stat="identity",
position="identity",
show.legend = F,
fill = c("#1874CD")) +
labs(x = NULL,
y = NULL,
title = "Vietnam's net FDI flows: 1987 - 2015",
subtitle = "Unit: Billion",

Nguyễn Chí Dũng http://rpubs.com/chidungkt


162

caption = "Source: The World Bank") +


theme_economist()

Nếu có chỗ nào khó hiểu, các bạn có thể xem lại cách thức sử dụng toán tử pipe đã trình bày ở mục
2.6.

Dự án thứ hai chúng ta lấy dữ liệu trực tiếp từ Ủy Ban Người Tị Nạn của Liên Hợp Quốc (UNHCR) để
đưa ra các thông tin về: (1) 10 quốc gia có nhiều người tị nạn nhất từ năm 1951 đến năm 2014, và (2)
cơ cấu của người tị nạn trong khoảng thời gian trên. Ngoài ra, đây cũng là dự án mà lần đầu tiên
chúng ta tạo ra một đám mây từ (word cloud) – một công cụ hình ảnh hóa dữ liệu mà các tạp chí
thường làm.

Trước hết lấy dữ liệu trực tiếp từ Internet và thực hiện một số bước xử lí số liệu thô (nếu không có
Internet bạn có thể sử dụng bộ dữ liệu có tên unhcr_data.csv) :

# Lấy dữ liệu từ của UNHCR trực tiếp từ Internet:


link <- "http://popstats.unhcr.org/en/persons_of_concern.csv"
ref.d <- read.csv(link,
# Sử dụng header cho các cột biến số:
header = TRUE,
# Bỏ qua 3 dòng đầu của dữ liệu gốc:
skip = 2,
# Thay thế các kí tự trống, dấu _ và * thành NA:
na.strings = c("", "_", "*"))
# Xem qua dữ liệu (không hiển thị kết quả):
dim(ref.d)
names(ref.d)
# Đổi tên cho các cột biến. Sẽ là thuận lợi hơn trong tình huống
# này nếu chúng ta không sử dụng kiểu đổi tên bằng hàm rename:
new.names <- c("Year",
"Country",
"Country_Origin",
"Refugees",
"Asylum_Seekers",
"Returned_Refugees",
"IDPs",
"Returned_IDPs",
"Stateless_People",
"Others_of_Concern",
"Total")
names(ref.d) <- new.names
# Đổi Country và Country_Origin thành character:
ref.d <- ref.d %>% mutate_at(.cols = c("Country", "Country_Origin"),
.funs = as.character)
# Đổi các cột biến ở định dạng số nguyên về dạng số tổng quát:
ref.d <- ref.d %>% mutate_if(is.integer, as.numeric)
# Dán lại nhãn tên cho một số quốc gia:
old.countries <- c("Bolivia (Plurinational State of)",
"China, Hong Kong SAR",
"China, Macao SAR",

Nguyễn Chí Dũng http://rpubs.com/chidungkt


163

"Iran (Islamic Rep. of)",


"Micronesia (Federated States of)",
"Serbia and Kosovo (S/RES/1244 (1999))",
"Venezuela (Bolivarian Republic of)",
"Various/Unknown",
"Dem. Rep. of the Congo",
"Syrian Arab Rep.")

new.countries <- c("Bolivia",


"Hong Kong",
"Macao",
"Iran",
"Micronesia",
"Serbia & Kosovo",
"Venezuela",
"Unknown",
"Congo",
"Syria")

for (k in 1:length(old.countries)){
ref.d$Country_Origin[ref.d$Country_Origin == old.countries[k]] <- new.count
ries[k]
ref.d$Country[ref.d$Country == old.countries[k]] <- new.countries[k]
}

Kế tiếp thực hiện các tính toán cần thiết:

# Tính toán số người rời bỏ quê hương mình theo quốc gia:
or.count.tot2 <- ref.d %>%
group_by(Country_Origin) %>%
summarise_each(funs(sum(., na.rm = TRUE)), Total)

# 10 quốc gia có nhiều người bỏ quê hương nhất (không hiển thị):
u <- or.count.tot2 %>% arrange(desc(Total)) %>% slice(1:10)
u
# Loại ra nhóm chưa xác định đến từ đâu (Unknown) và vẽ Bar Plot:

library(ggthemes)
u %>% filter(Country_Origin != "Unknown") %>%
mutate(Total = Total/1000) %>%
ggplot(aes(x = reorder(Country_Origin, Total), y = Total, fill = Country_Or
igin)) +
geom_bar(stat = "identity", show.legend = FALSE) +
coord_flip() +
labs(x = NULL,
y = NULL,
title = "9 Countries With the Most Refugees",
subtitle = "Unit: Thousand",
caption = "Data Source: http://popstats.unhcr.org") +

Nguyễn Chí Dũng http://rpubs.com/chidungkt


164

theme_economist(horizontal = FALSE, base_size = 9) +


scale_fill_economist()

# Có thể lọc ra thông tin về người tị nạn Việt Nam để khai thác:
vn <- ref.d %>% filter(Country_Origin == "Viet Nam")

Thực hiện vẽ đám mây từ hiển thị tên của 100 quốc gia có nhiều người tị nạn nhất. Kích cỡ của từ
càng lớn thì có nghĩa là quốc gia đó càng có nhiều người tị nạn:

# Loại ra Unknown, có Total là 0, dữ liệu thiếu, Unknown và


# cuối cùng biến dữ liệu về data frame để vẽ word cloud:

or.count.tot2 <- na.omit(or.count.tot2) %>%


filter(Total != 0 & Country_Origin != "Unknown") %>%
as.data.frame()

# ----------------
# Vẽ word cloud
#----------------

# Gọi các gói cần thiết:


library(wordcloud); library(extrafont)
# Đặt nền đen:
par(bg = "black")
set.seed(1)
wordcloud(or.count.tot2[, 1],
or.count.tot2[, 2],
# Kích cỡ phông chữ:
scale = c(3, 1),
# Chỉ những quốc gia có trên 1.000.0000 người tị nạn:
min.freq = 1000000,
# Hiển thị tối đa 100 quốc gia:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


165

max.words = 100,
# Chọn phông chữ:
family = "Garamond",
font = 2,
random.order = F,
colors = brewer.pal(8, "Paired"))

#-----------------------------
# Hình ảnh hóa cơ cấu người
# tị nạn từ năm 1951
#-----------------------------

# Chọn các biến cần thiết và chuyển về dạng long:


mydf <- ref.d %>%
select(-Country, -Country_Origin, -Total) %>%
gather(variable, value, - Year)

# Tên của các cột biến được chọn:


ten <- names(ref.d %>% select(-Country, -Country_Origin, -Total, -Year))

# Chọn màu theo cách thức chúng ta muốn:


mycol <- c("#104E8B",
"#8B1A1A",
"#CD1076",
"#0000CD",
"#8B3A3A",
"#008B00",
"#EE0000")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


166

# Vẽ sơ bộ:
library(scales)
p1 <- ggplot(mydf, aes(Year, value)) +
geom_bar(aes(fill = variable), stat = "identity") +
labs(title = "Number of refugees from 1951 to 2014",
subtitle = "Unit: Millions",
caption = "Data Source: http://popstats.unhcr.org",
x = "",
y = "") +
theme_light() +
scale_fill_manual(labels = gsub("*_", " ", ten), values = mycol,
guide_legend(title = "Class"))

# Hiệu chỉnh trục y:


myfunc <- function(x) {x/1000000 }
p1 + scale_y_continuous(limits = c(0, 4.5e7),
breaks = seq(0, 4.5e7, by = 0.5e7),
labels = myfunc) +
scale_x_continuous(limits = c(1950, 2014),
breaks = seq(1950, 2015, by = 5),
expand = c(0.01, 0))

Dưới đây chúng ta sẽ thực hiện mini project thứ ba nhằm trả lời cho một câu hỏi là liệu hệ thống y
tế của Việt Nam có thực sự tệ đến mức mà bộ Y Tế (cũng như người đứng đầu bộ này) thường bị
chỉ trích gay gắt và có phần khắc nghiệt. Để trả lời câu hỏi này chung ta sẽ thu thập dữ liệu về tuổi thọ
bình quân, thu nhập đầu người tính theo tương đương sức mua, và quy mô dân số. Dưới đây là R
codes biểu diễn thu nhập bình quân trên trục X, tuổi thọ trên trục Y còn diện tích hình tròn biểu diễn
quy mô dân số của các quốc gia. Màu sắc thì biểu diễn nhóm thu nhập (có 4 nhóm thu nhập):

# Load các gói và lấy dữ liệu từ World Bank:


library(ggrepel)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


167

library(ggthemes)
mydf <- WDI(country = "all",
start = 2015,
end = 2016,
indicator = c("SP.POP.TOTL",
# Tuổi thọ bình quân:
"SP.DYN.LE00.IN",
# GDP đầu người:
"NY.GDP.PCAP.PP.CD"))
d <- WDIcache()
d2 <- data.frame(d[[2]])
# Chỉ lấy dữ liệu năm 2015:
nam2015 <- mydf %>% filter(year == 2015)

# Lấy thêm một cột biến về nhóm thu nhập cho các quốc gia:
chung <- intersect(d2$country, nam2015$country)

u <- d2 %>%
filter(country %in% chung) %>%
arrange(country) %>%
mutate(country = as.character(country))

nam2015 <- nam2015 %>%


filter(country %in% chung) %>%
arrange(country)

nam2015$Group <- u$income

# Không lấy các quốc gia không rõ nhóm thu nhập (loại Aggregates):
nam2015 <- nam2015 %>% filter(Group != "Aggregates")

# Hiển thị một số quốc gia được lựa chọn:


note <- c("Vietnam", "China", "India", "Japan", "Thailand", "Philippines",
"United States", "Indonesia", "Malaysia", "France", "Ukraine",
"Singapore", "Spain", "Australia", "Russian Federation")
# Mối quan hệ giữa thu nhập đầu người (trục X) và tuổi thọ (trục Y) đồng thờ
i
# biểu diễn quy mô dân số của từng quốc gia bằng diện tích của đường tròn:
p <- ggplot(nam2015, aes(NY.GDP.PCAP.PP.CD, SP.DYN.LE00.IN, size = SP.POP.TOT
L, colour = Group)) +
geom_point(alpha = 0.45, show.legend = FALSE) +
scale_size(range = c(0, 20)) +
scale_x_continuous(limits = c(500, 60000),
breaks = seq(5000, 60000, by = 5000)) +
geom_text_repel(size = 3, aes(label = country),
data = filter(nam2015, country %in% note),
colour = "black",
force = 10) +
labs(x = "GDP per capital",
y = "Life expectancy",

Nguyễn Chí Dũng http://rpubs.com/chidungkt


168

title = "The relationship between Life Expectancy and GDP per capit
al",
caption = "Data Source: The World Bank")
p + theme_economist()

Có thể thấy rằng Việt Nam là quốc gia có tuổi thọ trung bình cao nhất trong nhóm nước có thu nhập
trung bình (màu xanh) và cao hơn nhiều nước thuộc nhóm có thu nhập trung bình cao (màu tím),
ngang hàng với nhiều nước có thu nhập cao (màu đỏ) . Vào năm 2015, tuổi tọ trung bình của người
Việt Nam là 76 - một con số chỉ thua chút đỉnh so với Hoa Kì là 79 – quốc gia giàu và có tỉ trọng chi
cho Y Tế tính theo GDP cao nhất thế giới. Các bạn có thể tham khảo thêm một số cách trình bày hình
ảnh với bộ số liệu này tại: http://rpubs.com/chidungkt/271482 .

Các bạn cũng có thể thực hành thêm để nâng cao hai kĩ năng về data manipulation và data
visualization tại http://rpubs.com/chidungkt/245032 với số liệu từ ủy ban Nobel. Những thông tin
đáng chú ý thu được từ bộ số liệu này (trong rất nhiều) là: (1) Paris không phải là thành phố sinh ra
nhiều nhà khoa học nhất như New York nhưng lại là thành phố mà nhiều nhà khoa học nhất muốn
chết ở đó, (2) Berkerley chính là trường đại học sinh ra nhiều nhà khoa học nhất chứ không phải
Harvard, và (3) giai đoạn trước 1945 – thời kì hoàng kim của khoa học Đức thì số giải Nobel của nước
này gần gấp đôi hai quốc gia xếp sau là Hoa Kì và Anh.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


169

Chương 4: Mô hình hồi quy tuyến tính hai biến số

Mục tiêu của chương này là hướng dẫn các thực hành cho mô hình hồi quy hai biến số (còn gọi là hồi
quy đơn với ngụ ý rằng chỉ có một biến độc lập trong mô hình), kiểm định giả thuyết về các hệ số hồi
quy, ước lượng khoảng, ước lượng điểm, cũng như kiểm tra một số giả thuyết cơ bản về phần dư.

Trong chương này chúng ta sẽ thực hành với file dữ liệu có tên ch2_health.wf1 được cung cấp bởi khoa
Toán thuộc ĐH Kinh Tế Quốc Dân. File dữ liệu này gồm các thông tin về chi cho hệ thống chăm sóc y tế
(biến HEALTH), dân số (biến POP) và thu nhập từ các thuế và phí (biến INCOME) từ 50 bang và khu vực
hành chính Washington DC của Hoa Kì. Mục tiêu nghiên cứu là đánh giá xem chi cho hệ thống y tế có
liên hệ thế nào với nguồn thu nhập của các bang.

4.1 Một số thống kê cơ bản về bộ dữ liệu


Trước hết chúng ta yêu cầu R nhập bộ dữ liệu ch2_health.wf1 dưới dạng một data.frame tên mới là
dung đồng thời chỉ định R chỉ làm việc với file dữ liệu này như sau:

setwd("D:/KTLR")
library(hexView)
dung <- readEViews("ch2_health.wf1", as.data.frame = TRUE)

Thống kê mô tả sơ bộ cho các biến số trong bộ dữ liệu:

summary(dung)

## HEALTH INCOME POP


## Min. : 1407 Min. : 11700 Min. : 480
## 1st Qu.: 5134 1st Qu.: 35800 1st Qu.: 1454
## Median : 13669 Median : 87300 Median : 3840
## Mean : 19929 Mean :144153 Mean : 5299
## 3rd Qu.: 22141 3rd Qu.:176650 3rd Qu.: 6026
## Max. :110057 Max. :920500 Max. :32683

Chúng ta có kết quả hoàn toàn tương tự với toán tử pipe:

library(tidyverse)
dung %>% summary()

Nếu chúng ta quan tâm đến ngũ phân vị của biến INCOME:

with(dung, quantile(dung$INCOME))

## 0% 25% 50% 75% 100%


## 11700 35800 87300 176650 920500

Điều này có nghĩa là có (25%)⨉51 = 13 bang có INCOME bé hơn 35800. Chú ý rằng giá trị ứng với
50% là 87300 chính là trung vị (Median) – giá trị mà chúng ta đã thấy ở phần trước.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


170

Kết quả trên cũng có thể thu được theo một cách khác với toán tử pipe (không hiển thị kết quả):

dung %>% with(., quantile(.$INCOME))

Chú ý rằng khi đã sử dụng toán tử pipe thì dấu chấm (.) trong câu lệnh trên có nghĩa là chúng ta đang
“ám chỉ” đến data frame có tên dung.

Nếu chúng ta quan tâm đến các chi tiết thống kê chi tiết hơn cho bộ số liệu chúng ta có thể sử dụng
gói pastecs (xem lại chương 3):

options(scipen = 100)
options(digits = 8)
library(pastecs)
stat.desc(dung)

## HEALTH INCOME POP


## nbr.val 51.0000000 51.0000000 51.0000000
## nbr.null 0.0000000 0.0000000 0.0000000
## nbr.na 0.0000000 0.0000000 0.0000000
## min 1407.0000000 11700.0000000 480.0000000
## max 110057.0000000 920500.0000000 32683.0000000
## range 108650.0000000 908800.0000000 32203.0000000
## sum 1016385.0000000 7351800.0000000 270251.0000000
## median 13669.0000000 87300.0000000 3840.0000000
## mean 19929.1176471 144152.9411765 5299.0392157
## SE.mean 3094.9213438 23684.3867414 828.5198770
## CI.mean.0.95 6216.3324664 47571.4908040 1664.1311486
## var 488505444.3458824 28608458941.1764717 35008704.5184314
## std.dev 22102.1592689 169140.3527878 5916.8154034
## coef.var 1.1090385 1.1733396 1.1165827

Chúng ta có thể, chẳng hạn, tìm ra quãng đáng tin 95% của HEALTH nằm trong khoảng từ 19929 –
6216 đến 19929 + 6216. Còn giá trị coef.var = 1.109 chính là thương số của std.dev chia cho mean.
Giá trị CI.mean.0.95 là quãng đáng tin 95% cho các biến số (CI là viết tắt của chữ Confidence Interval
– quãng đáng tin).

Ma trận hệ số tương quan giữa các biến số:

cor(dung)

## HEALTH INCOME POP


## HEALTH 1.00000000 0.99089362 0.98597260
## INCOME 0.99089362 1.00000000 0.99300219
## POP 0.98597260 0.99300219 1.00000000

Nguyễn Chí Dũng http://rpubs.com/chidungkt


171

Hệ số tương quan giữa POP và INCOME gần bằng 1 (lớn hơn 0.8) nên nếu cả hai biến này xuất hiện
với tư cách là biến độc lập trong phương trình hồi quy thì mô hình có thể mắc lỗi đa cộng tuyến ở
mức độ nghiên trọng. Chúng ta sẽ xem xét vấn đề này ở chương 7.

4.2 Thực hiện hồi quy và một số kiểm định thường gặp
Mục này chúng ta xem xét việc thực hiện hồi quy đơn cũng như thực hiện các kiểm định thường gặp
với R.

4.2.1 Hồi quy đơn, khoảng tin cậy cho các hệ số và bảng ANOVA
Chúng ta xét mô hình hồi quy hai biến số sau:

HEALTH = β1 + β2INCOME. + ui (1)

Để ước lượng mô hình này trong R:

hoiquy <- lm(data = dung, HEALTH ~ INCOME)


options(scipen = 10)
summary(hoiquy)
## Call:
## lm(formula = HEALTH ~ INCOME, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -10396.27 -1272.71 -361.28 1087.98 9019.47
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1263.6871121 555.4167236 2.2752 0.0273 *
## INCOME 0.1294835 0.0025135 51.5143 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 3006.2 on 49 degrees of freedom
## Multiple R-squared: 0.98187, Adjusted R-squared: 0.9815
## F-statistic: 2653.7 on 1 and 49 DF, p-value: < 2.22e-16

Với toán tử pipe thì toàn bộ kết quả này có thể được thực hiện ngắn gọn như sau:

dung %>% lm(data = ., HEALTH ~ INCOME) %>% summary()

Các bạn có thể nâng độ chính xác của các kết quả bằng cách như sau:

options(digits = 10)
summary(hoiquy)
## Call:
## lm(formula = HEALTH ~ INCOME, data = dung)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


172

##
## Residuals:
## Min 1Q Median 3Q Max
## -10396.2691 -1272.7115 -361.2774 1087.9789 9019.4712
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1263.687112078 555.416723600 2.27521 0.027305 *
## INCOME 0.129483522 0.002513543 51.51434 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 3006.205 on 49 degrees of freedom
## Multiple R-squared: 0.9818702, Adjusted R-squared: 0.9815002
## F-statistic: 2653.727 on 1 and 49 DF, p-value: < 2.2204e-16

Lúc này, thống kê F được lấy tới 3 chữ số sau dấu phẩy. Rõ ràng, nếu căn cứ theo các tiêu chuẩn truyền
thống thì mô hình hồi quy của chúng ta là tốt thể hiện ở: (1) tất cả các hệ số hồi quy có ý nghĩa thống
kê ở mức 5%, (2) R2 rất cao, và (3) thống kê F có giá trị lớn.

Chúng ta cũng có thể biểu diễn đường hồi quy (Regression Line) với khoảng tin cậy 95%:

library(ggplot2)
ggplot(dung, aes(INCOME, HEALTH)) + geom_point() + geom_smooth(method = "lm")

Có thể vẽ đường hồi quy theo một cách khác (vừa xấu hơn và gõ cũng dài dòng):

plot(HEALTH ~ INCOME, data = dung)


abline(hoiquy)

Sau khi thực hiện hồi quy chúng ta có thể sử dụng một số hàm để khai thác thêm một số thông tin liên
quan đến mô hình. Dưới đây là một số hàm cơ bản:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


173

Tên hàm Chức năng

print() Hiển thị kết quả hồi quy ở dạng đơn giản

summary() Hiển thị kết quả hồi quy ở dạng chi tiết

coef() Hiện thị các hệ số hồi quy trong mô hình

residuals() Hiển thị phần dư

fitted() Hiển thị giá trị ước lượng (fitted values)

anova() Hiển thị bảng ANOVA

predict() Dự đoán

confint() Hiển thị khoảng tin cậy (mặc định 95%) cho các hệ số hồi quy

deviance() Hiển thị tổng bình phương phần dư (RSS)

vcov() Hiển thị ma trận variance-covariance.

df.residual() Hiển thị giá trị n – k (bậc tự do của mô hình hồi quy)

logLik() Hiển thị giá trị Log likehood

plot() Hiển thị 4 Graphs tiêu chuẩn dùng để tìm các quan sát bất thường

deviance() Tính tổng bình phương phần dư

Bên cạnh đó, nhằm hỗ trợ cho việc chẩn đoán các lỗi của mô hình (hiện tượng đa cộng tuyến, phương
sai sai số thay đổi, các quan sát bất thường) – một vấn đề mà chúng ta sẽ nghiên cứu kĩ hơn trong các
phần sau của tài liệu này. Sau khi thực hiện hồi quy chúng ta có thể sử sụng một số hàm mà gói car
cung cấp dưới đây:

vif() Tính các hệ số VIF cho các biến số

outlierTest() Tính giá trị Bonferoni p-Value cho quan sát bất thường

qqPlot() Vẽ biểu đồ Q-Q plot

leveragePlots() Đồ thị đòn bẩy

avPlot() Tính khoảng cách Cook

influencePlot() Chỉ ra các quan sát gây ảnh hưởng (Influences)

ncvTest() Kiểm định phương sai sai số thay đổi

spreadLevelPlot() Đồ thị chẩn đoán phương sai sai số thay đổi

Nguyễn Chí Dũng http://rpubs.com/chidungkt


174

crPlots() Đồ thị phần dư chẩn đoán hiện tượng phi cộng tuyến

ceresPlots() Đồ thị phần dư chẩn đoán hiện tượng phi cộng tuyến

durbinWatsonTest() Kiểm định Durbin – Watson cho hiện tượng tự tương quan

Phần trên chúng ta đã quen thuộc với hàm summary(). Chẳng hạn để tính khoảng tin cậy 95% cho
các hệ số hồi quy:

confint(hoiquy)

## 2.5 % 97.5 %
## (Intercept) 147.5354180444 2379.8388061115
## INCOME 0.1244323678 0.1345346762

Tính khoảng tin cậy 90% cho các hệ số hồi quy:

confint(hoiquy, level = 0.9)

## 5 % 95 %
## (Intercept) 332.5027083524 2194.8715158035
## INCOME 0.1252694389 0.1336976051

Vấn đề tính khoảng tin cậy cho một hệ thức của hai biến số , chẳng hạn cho mβ1+nβ2 chúng ta sẽ
nghiên cứu chi tiết ở chương 5.

Một trong những thông tin quan trọng khi thực hiện hồi quy là phân tích bảng ANOVA:

anova(hoiquy)

## Analysis of Variance Table


##
## Response: HEALTH
## Df Sum Sq Mean Sq F value Pr(>F)
## INCOME 1 23982446067 23982446067 2653.7273 < 2.22e-16 ***
## Residuals 49 442826151 9037268
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Ở đây RSS (với df2 = 51 – 2 = 49 bậc tự do) là 442826151 và ESS (với df1 = 1 bậc tự do) là
23982446067. Với chú ý rằng TSS = RSS + ESS chúng ta có thể kiểm tra lại là R2 =ESS/TSS = 0.982.
Bảng ANOVA này cũng hiển thị giá trị thống kê F là 2653.727 = (ESS/df1)/(RSS/df2) =
(23982446067/1)/( 442826151/49). Kết quả này chính là giá trị F được hiển thị ở kết quả phân tích
hồi quy.

Trong tình huống chúng ta muốn thực hiện ước lượng cho mô hình:

HEALTH = β1 + β2INCOME.22+ u

Nguyễn Chí Dũng http://rpubs.com/chidungkt


175

Do mỗi một phần mềm đều có một quy cách thực hiện nên trong R bạn phải gõ:

hoiquybac2 <- lm(data = dung, HEALTH ~ I(INCOME^2))

Chúng ta phải lưu tâm điều này: những phép đổi biến đơn giản thì phép đổi biến ấy nên đặt trong I()
như trên.

Một tình huống khác mà chúng ta có thể gặp là thực hiện hồi quy không có hệ số chặn (Regression
through the Origin). Đó là các mô hình hồi quy dạng:

HEALTH = β⨉INCOME + u

Thực hiện hồi quy không có hê số chặn cho mô hình trên trong R là:

hoiquykhonghesochan <- lm(data = dung, HEALTH ~ 0 + INCOME)

Chú ý rằng trong hồi quy không có hệ số chặn thì chỉ tiêu R2 được tính theo công thức truyền thống là
không áp dụng được và không có ý nghĩa trong việc đánh giá độ phù hợp của mô hình. Chúng ta sẽ
nghiên cứu kĩ hồi quy không có hệ số chặn trong chương sau.

4.2.2 Tìm các quan sát bất thường và chẩn đoán lỗi mô hình bằng hình ảnh
Chúng ta cũng có thể tìm ra các quan sát bất thường (outliers) – một vấn đề sẽ được nói kĩ hơn trong
chương 7. R cung cấp cùng một lúc 4 Graphs tiêu chuẩn phục vụ cho việc tìm ra các quan sát bất
thường chỉ bằng 2 dòng lệnh:

library("ggfortify")
autoplot(hoiquy, which = 1:4, ncol = 2, label.size = 3)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


176

Sự xuất hiện của các quan sát bất thường trong mô hình hồi quy sẽ có tác động rất mạnh lên các kết
quả thu được. Xử lý các quan sát bất thường sẽ được nghiên cứu kĩ hơn trong chương 10.

Cũng có thể có được hình vẽ và các thông tin tương tự theo một cách khác (không hiển thị graph):

par(mfrow = c(2, 2))


plot(hoiquy)

4.2.3 Thực hiện một số kiểm định thường gặp cho mô hình hồi quy
Dưới đây trình bày một số kiểm định thường gặp cho mô hình hồi quy. Các kiểm định này có thể phân
thành hai nhóm. Nhóm thứ nhất là các kiểm định nhằm đánh giá môt số giả thuyết của mô hình hồi
quy tuyến tính cổ điển, chẳng hạn, kiểm định tính phân phối chuẩn của phần dư. Nhóm thứ hai là các
kiểm định liên quan đến hệ số hồi quy của mô hình.

4.2.3.1 Kiểm định tính phân phối chuẩn của phần dư


Kiểm định tính phân phối chuẩn của phần dư (hay bất kì biến số này khác) có thể được thực hiện
bằng nhiều test khác khau. Chẳng hạn chúng ta có thể thực hiện kiểm định Jarque – Bera Test cho tính
phân phối chuẩn của phần dư theo công thức sau:

𝑆 2 (𝐾 − 3)2
JB = 𝑛 [ + ]
6 24

Thống kê JB này tuân theo phân phối khi bình phương (χ2) với hai bậc tự do. Nếu giá trị JB tính toán
ứng với p-value lớn hơn 5% thì chúng ta chưa thể bắc bỏ giả thiết rằng phân phối là chuẩn. Ngược lại,
ta chấp nhận giả thuyết phân phối là không chuẩn. Phân tích hình ảnh có thể chỉ cho ta thấy rằng phần
dư có thể là phân phối chuẩn hay không:

# Bổ sung thêm phần dư và thứ tự quan sát vào dung:


library(tidyverse)
dung <- dung %>%
mutate(phandu = hoiquy$residuals,
id = 1:nrow(dung))
# Có thể xem 6 giá trị đầu của phần dư:
dung$phandu %>% head()

## 1 2 3 4 5 6
## 2361.8948 -1178.8553 -1113.3251 246.0478 -10396.2691 -3003.2262

#Hình ảnh hóa phần dư bằng cả histogram và density:


theme_set(theme_minimal()) # Đặt cố định theme_minimal.
dung %>%
ggplot(aes(phandu)) +
geom_density(alpha = 0.3, fill = "blue", color = "blue") +
geom_histogram(aes(y = ..density..), fill = "red", color = "red", alpha = 0
.3)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


177

Hoặc có thể thể hiện bằng line graph như phần mềm Eviews thường thực hiện:

# Hình ảnh hóa phần dư bằng line graph:


dung %>%
ggplot(aes(id, phandu)) +
geom_line() +
geom_point() +
geom_hline(yintercept = 0, color = "blue")

Những hình ảnh trên không chỉ ra dấu hiệu chắc chắn nào cho thấy phần dư là phân phối chuẩn.
Chúng ta có thể sử dụng kiểm định Jarque – Bera để đưa ra bằng chứng thống kê về phân phối chuẩn:

# Kiểm định phân phối chuẩn bằng JB Test:


library(fBasics)
jarqueberaTest(dung$phandu)

##
## Title:
## Jarque - Bera Normalality Test
##
## Test Results:
## STATISTIC:
## X-squared: 24.9701
## P VALUE:
## Asymptotic p Value: 3.783e-06
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


178

Giá trị của Asymptotic p Value = 3.783*10-6 > 5% nên chúng ta có bằng chứng thống kê để chấp nhận
giả thuyết gốc rằng phần dư phân phối chuẩn.

Vì các thông tin về phần dư là rất quan trọng trong việc chẩn đoán các lỗi của mô hình hồi quy – một
vấn đề mà chúng ta sẽ nghiên cứu chi tiết từ chương 7 nên chúng ta nên lưu các giá trị phần dư này
để sử dụng và gán nó vào data frame tên dung như ở trên.

Chú ý rằng gói fBasics cung cấp nhiều kiểm định phân phối chuẩn khác nhau chứ không riêng gì
Jarque-Bera Test . Để biết chi tiết gói này cung cấp những kiểm định phân phối chuẩn gì các bạn gõ
?fBasics trong cửa sổ lệnh của R thì các bạn có thể thấy gói này cung cấp một số kiểm định phân
phối chuẩn như sau:

Các bạn có thể truy vấn trực tiếp về kiểm định Kolmogorov – Smirnov về tính phân phối chuẩn chẳng
hạn bằng cách gõ ?ksnormTest trong cửa sổ lệnh.

Chúng ta cũng có thể đánh giá chi tiết hơn về phần dư thu được:

# Thống kê chi tiết về phần dư:


basicStats(dung$phandu)

## X..dung.phandu
## nobs 5.100000e+01
## NAs 0.000000e+00
## Minimum -1.039627e+04
## Maximum 9.019471e+03
## 1. Quartile -1.272711e+03
## 3. Quartile 1.087979e+03
## Mean 0.000000e+00
## Median -3.612774e+02
## Sum 0.000000e+00
## SE Mean 4.167221e+02
## LCL Mean -8.370110e+02
## UCL Mean 8.370110e+02
## Variance 8.856523e+06
## Stdev 2.975991e+03
## Skewness 1.184680e-01
## Kurtosis 3.169952e+00

Nguyễn Chí Dũng http://rpubs.com/chidungkt


179

Chúng ta thấy rằng phần dư có Mean = 0, Skewness = 0.118 (độ méo), và Kurtosis = 3.169. Những
thông tin này ngụ ý rằng phần dư có thể không phân phối chuẩn. Và kiểm định Jarque-Bera mà chúng
ta thực hiện ở trên đã đưa ra bằng chứng thống kê cho nhận định trên.

4.2.3.2 Kiểm định Durbin - Watson


Trong Eviews mỗi khi chạy hồi quy thì mặc định xuất hiện giá trị của Durbin-Watson Test – một kiểm
định thường dùng đến khi đánh giá hiện tượng tự tương quan (Autocorrelation) – một vấn đề về lỗi
mô hình rất phổ biến với chuỗi dữ liệu thời gian với cặp giả thuyết sau:

H0: Phần dư của mô hình không có tự tương quan

H1: Phần dư của mô hình có tự tương quan

Nếu cần thiết, trong R cũng có thể thực hiện kiểm định này với gói lmtest bằng hàm dwtest():

library(lmtest)
hoiquy %>% dwtest()

##
## Durbin-Watson test
##
## data: .
## DW = 1.6995, p-value = 0.1432
## alternative hypothesis: true autocorrelation is greater than 0

Căn cứ vào giá trị p-value = 0.143 > 5% chúng ta có thể chấp nhận giả thuyết gốc rằng không tồn tại
tự tương quan trong mô hình.

Cũng cần phải lưu ý rằng kiểm định Durbin – Watson có khả năng áp dụng rất hạn chế vì kiểm định
này chỉ áp dụng cho tương quan bậc 1 và mô hình không có biến nội sinh. Chúng ta sẽ nghiên cứu kĩ
hơn kiểm định này trong những chương về tự tương quan và phân tích dữ liệu thời gian (Time Series
Analysis).

4.2.3.3 Kiểm định Wald về một giá trị cụ thể của một hệ số hồi quy
Giả sử chúng ta tin rằng số hồi quy β2 = 0.15. Chúng ta có thể kiểm định giả thuyết này với gói AER
như sau:

library(AER)
hoiquy <- lm(data = dung, HEALTH ~ INCOME)# Chạy lại mô hình hồi quy
linearHypothesis(hoiquy, "INCOME = 0.15")

## Linear hypothesis test


##
## Hypothesis:
## INCOME = 0.15
##
## Model 1: restricted model
## Model 2: HEALTH ~ INCOME
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


180

## Res.Df RSS Df Sum of Sq F Pr(>F)


## 1 50 1044928171
## 2 49 442826151 1 602102021 66.62434 0.00000000010799 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Cột giá trị Pr(>F) = 10.79⨉10-11 là rất bé nên ta bác bỏ giả thiết β2 = 0.15. bạn có thể thực hiện kiểm
định này bằng gõ linear.hypothesis(hoiquy,"INCOME=0.15"). Tất nhiên kết quả là không thay đổi.

4.2.3.4 Kiểm định Wald đồng thời cho nhiều hệ số hồi quy
Nếu chúng ta tin rằng β1 = 1300 và β2 = 0.15 chúng ta có thể thực hiện kiểm định Wald như sau:

linearHypothesis(hoiquy, c("(Intercept) = 1300", "INCOME = 0.13"))

## Linear hypothesis test


##
## Hypothesis:
## (Intercept) = 1300
## INCOME = 0.13
##
## Model 1: restricted model
## Model 2: HEALTH ~ INCOME
##
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 51 443833425
## 2 49 442826151 2 1007274.4 0.05573 0.94586

Cột giá trị Pr(>F) = 0.94 > 5% nên chúng ta có bằng chứng thống kê cho rằng β1 = 1300 và β2 = 0.15.
Ở đây các bạn cần chú ý rằng mặc dù chúng ta bắc bỏ giả thuyết β2 = 0.15 (mục 4.5) nhưng chúng ta
lại chấp nhận giả thuyết rằng β1 = 1300 và β2 = 0.15.

Kiểm định Wald về sự ràng buộc của các hệ số hồi quy áp dụng cho cặp giả thuyết H0: mβ2 + nβ3 = p;
H1: mβ2 + nβ3 # p. Kiểm định này áp dụng cho hồi quy bội và ta sẽ xét trong chương 5.

4.3 Mô phỏng Monte Carlo kiểm tra các giả thuyết CLMR
Chúng ta biết rằng nếu các điều kiện của mô hình hồi quy tuyến tính cổ điển (CLMR) được thỏa mãn
thì các ước lượng OLS thu được sẽ có tính chấtt BLUE. Nhưng trong thực tế bằng cách nào để chúng
ta có thể biết các ước lượng thu được, chẳng hạn, là không chệch. Chúng ta trở lại với mô hình được
xét ở mục 4.2:

HEALTH = β1 + β2INCOME. + ui (1)

Nhắc lại rằng các ước lượng OLS thu được từ sẽ là không chệch (unbiased – chữ U trong từ BLUE)
nếu:

E(β̂ 1) = β1 và E(β̂ 2) = β2

Nguyễn Chí Dũng http://rpubs.com/chidungkt


181

Ở đây β1 và β2 là các tham số thực nhưng chúng ta không-bao-giờ-biết những tham số thực này. Vậy
bằng cách nào chúng ta có thể đánh giá liệu rằng các ước lượng trên là không chệch hay không? Chúng
ta có thể trả lời câu hỏi này bằng thực hiện mô phỏng Monte Carlo. Quá trình này thực hiện mô phỏng
này thực hiện qua các bước sau:

1. Giả sử các tham số thực của mô hình (1) là β1 = 1300, β2 = 0.14.


2. Lựa chọn kích cỡ mẫu cố định. Để thuận lợi chúng ta chọn kích cỡ mẫu là 51 – đúng bằng kích
cỡ mẫu ở mục 4.2 mặc dù chúng ta có thể chọn kích cỡ mẫu tùy ý.
3. Chọn 51 giá trị cố định cho biến INCOME. Để thuận tiện, chúng ta có thể chọn luôn chính 51
giá trị của biến INCOME ở data frame có tên dung.
4. Chọn 51 giá trị ngẫu nhiên của sai số ngẫu nhiên ui . Chú ý rằng ui phải tuân theo quy luật
phân phối chuẩn hoặc chuẩn hóa.
5. Tính 51 giá trị tương ứng cho biến HEALTH theo công thức HEALTH = β1 + β2INCOME + ui .
6. Hồi quy biến HEALTH thu được ở bước 5 theo biến INCOME thu được các ước lượng OLS là
β̂ 1 và β̂ 2.
7. Lặp lại quá trình từ 1 đến 6 thêm n lần nữa. Nêu chọn n đủ lớn. Chẳng hạn, chúng ta chọn n =
499 thì chúng ta có tất cả 500 giá trị của β̂ 1 và β̂ 2.
8. Các giá trị trung bình E(β̂ 1) và E(β̂ 2) rồi so sánh nó với các giá trị β1 = 1300, β2 = 0.14. nếu các
giá trị này rất sát với trị β1 = 1300 và β2 = 0.14 thì chúng ta có thể nói các ước lượng thu được
là không chệch.

Dưới đây là mô phỏng Monte Carlo (không copy các dòng lệnh này) với vòng lặp 500 lần:

# Lấy ra 51 giá trị cố định của INCOME (Bước 3):


INCOME <- dung$INCOME
# Tạo một data frame trống để lưu kết quả của vòng lặp:
mydf <- data.frame()
# Tạo một vòng lặp chạy hồi quy 500 lần (Bước 6 và 7):
for (i in 1:500){
# Tạo ra 51 giá trị ngẫu nhiên của u với phân phối chuẩn (Bước 4):
set.seed(i)
u <- rnorm(51, 0, 1)
# Bước 5:
HEALTH = 1300 + 0.14*INCOME + u
# Tạo data frame với tên trang với 51 quan sát.
trang <- data.frame(HEALTH, INCOME)
ols <- lm(HEALTH ~ INCOME, data = trang)
mydf <- rbind(mydf, as.vector(ols$coefficients))
names(mydf) <- c("Beta1", "Beta2")
}

# Tách riêng ra các chuỗi beta:


Beta1 <- mydf$Beta1
Beta2 <- mydf$Beta2
# Và hình ảnh hóa:
par(mfrow = c(2, 2))

Nguyễn Chí Dũng http://rpubs.com/chidungkt


182

plot(Beta1, main = mean(Beta1), type = "b", xlab = "So vong lap", col = "blue
")
plot(Beta2, main = mean(Beta2), type = "b", xlab = "So vong lap", col = "red"
)
hist(Beta1, col = "blue", main = "Histogram cua Beta1")
hist(Beta2, col = "red", main = "Histogram cua Beta2")

Để R trở lại chế độ hiển thị hình ảnh bình thường chúng ta gõ:

par(mfrow = c(1, 1))

Kết quả này cho thấy E(β̂ 1) = 1299.99165 = β1 = 1300 và E(β̂ 2) = 0.14000 = β2 =0.14 do vậy cho thấy
rằng các ước lượng OLS thu được là không chệch. Có thể thấy điều này một lần nữa:

# Có thể xem các thông kê khác của các beta này:


head(mydf)

## Beta1 Beta2
## 1 1300.047 0.1400004
## 2 1299.958 0.1400006
## 3 1299.862 0.1400006
## 4 1300.215 0.1400000
## 5 1299.779 0.1400022
## 6 1300.240 0.1399989

summary(mydf)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


183

## Beta1 Beta2
## Min. :1299 Min. :0.14
## 1st Qu.:1300 1st Qu.:0.14
## Median :1300 Median :0.14
## Mean :1300 Mean :0.14
## 3rd Qu.:1300 3rd Qu.:0.14
## Max. :1301 Max. :0.14

Cũng có thể thực hiện kiểm định giả thiết rằng các hệ số hồi quy thu được phân phối chuẩn hay không
với kiểm định Jarque - Bera Normalality Test sử dụng gói fBasics:

# Kiểm tra giả thiết các beta phân phối chuẩn:


library(fBasics)
jarqueberaTest(mydf$Beta1)
## Title:
## Jarque - Bera Normalality Test
##
## Test Results:
## STATISTIC:
## X-squared: 1.5859
## P VALUE:
## Asymptotic p Value: 0.4525

jarqueberaTest(mydf$Beta2)
## Title:
## Jarque - Bera Normalality Test
##
## Test Results:
## STATISTIC:
## X-squared: 1.4243
## P VALUE:
## Asymptotic p Value: 0.4906

Các giá trị P-value đều lớn hơn 5% nên chúng ta có bằng chứng thống kê cho thấy phân phối của các
hệ số beta là chuẩn.

Trên đây chỉ mới trình bày mô phỏng Monte Carlo ở dạng đơn giản nhất. Tất nhiên còn nhiều khía
cạnh phức tạp hơn nhưng những vấn đề đó có phạm vi kiến thức nằm ngoài chương trình tiêu chuẩn
dành cho bạn đọc không chuyên kinh tế lượng và thống kê. Bạn đọc quan tâm có thể tìm hiểu sâu hơn
ở các tài liệu về mô phỏng ngẫu nhiên.

4.4 Sử dụng kết quả hồi quy cho ước lượng


Một trong những ứng dụng của các mô hình hồi quy là sử dụng cho các mục đích ước lượng. Chúng ta
trở lại với mô hình được nghiên cứu trước đó ở mục 4.2:

HEALTH = β1 + β2INCOME. + ui

Để thuận tiện và ngắn gọn khi đánh máy, đặt HEALT = Y và INCOME = X ta có:

Y = β1 + β2X + ui

Nguyễn Chí Dũng http://rpubs.com/chidungkt


184

Giả sử chúng ta muốn ước lượng:

Ŷ 0= E(Y|X0 =20.000) = β̂ 1 + β̂ 2X0

Trong đó X0 là một giá trị cụ thể nao đo. Vì Ŷ 0 là một ước lượng nên nó có thể khác giá trị thực và tuân
theo một phân phối nào đó. Khoa học thống kê đã chỉ ra rằng Ŷ 0 tuân theo phân phối chuẩn với phương
sai như sau:

1 (𝑋0 − 𝑋̅)2
var(𝑌̂0 ) = 𝜎 2 [ + ] (𝑎)
𝑛 ∑ 𝑥𝑖2
Hay:

𝑠𝑒(𝑌̂0 ) = √var(𝑌̂0 ) (𝑏)

Nhưng do σ2 là không biết nên chúng ta phải thay thế nó bằng σ̂ 2 là ước lượng của σ2 và do vậy chúng
ta thấy rằng biến:

𝑌̂0 − (𝛽1 + 𝛽2 𝑋0 )
𝑡= (𝑐)
𝑠𝑒(𝑌̂0 )
Tuân theo phân phối student t với n – 2 bậc tự do và khoảng tin cậy α là:

𝑃𝑟[𝛽̂1 + 𝛽̂2 𝑋0 − 𝑡𝛼/2 𝑠𝑒(𝑌̂0 ) ≤ 𝛽1 + 𝛽2 𝑋0 ≤ 𝛽̂1 + 𝛽̂2 𝑋0 + 𝑡𝛼/2 𝑠𝑒(𝑌̂0 )] = 1 − 𝛼 (𝑑)

Chú ý rằng ước lượng σ̂ 2 của σ2 ở công thức (2) được tính theo công thức sau:

2 ∑ û 𝑖 2
σ̂ = (𝑒)
𝑛−2
Với đó X0 = 20000 (chẳng hạn thu nhập của bang California) thì chi cho ý tế Ŷ 0 là:

1263.6871121 + 0.1294835*20000

## [1] 3853.357553

Con số 3853.687này gây ra nhiều nhầm lẫn trong diễn giải ý nghĩa của nó. Thực vậy, nhiều bạn hiểu
một cách sai trái rằng khi income của Carlifornia bằng 20000 thì chi cho y tế của bang này là 3853.687.
Nguyên nhân là chi cho y tế của bang California là một biến ngẫu nhiên và ta không biết chính xác
biến ngẫu nhiên này là bao nhiêu mà chỉ biết nó nằm trong một khoảng giá trị nào đó mà thôi. Giá trị
3853.687 ở trên được gọi là ước lượng điểm (Point Prediction, tên gọi khác là ước lượng trung
bình – Mean Prediction). Sử dụng các công thức từ (a) đến (e) chúng ta có thể tính ước lượng khoảng
tin cậy 95% cho ước lượng của Ŷ 0 khi X0 = 20000. Tuy nhiên tính toán thủ công như vậy rất lâu. R cho
phép ta tính con số ước lượng điểm 3853.687 cùng với khoảng tin cậy 95% một cách nhanh chóng
chỉ với một dòng lệnh:

khiINCOMEla20000 <- data.frame(INCOME = 20000)


predict(hoiquy, khiINCOMEla20000, interval = "confidence")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


185

## fit lwr upr


## 1 3853.357553 2800.322593 4906.392513

Ở đây giá trị fit chính là giá trị ước lượng điểm mà ta đã tính ở trên còn lwr và upr lần lượt là các cận
dưới và cận trên của ước lượng điểm theo công thức (d). Chú ý rằng hai câu lệnh trên có thể viết
thành một câu lệnh duy nhất như sau:

predict(hoiquy, newdata = data.frame(INCOME = 20000), interval ="confidence")

## fit lwr upr


## 1 3853.357553 2800.322593 4906.392513

Nếu muốn thực hiện ước lượng khoảng tin cậy 99% thì:

predict(hoiquy, newdata = data.frame(INCOME = 20000), interval="confidence",


level = 0.99)

## fit lwr upr


## 1 3853.358 2449.039 5257.676

Tương tự chúng ta có thể tính các ước lượng điểm cùng với khoảng tin cậy 95% cho 51 quan sát (lấy
kết quả cho 5 quan sát đầu tiên) như sau:

predict(hoiquy, interval = "confidence")

## fit lwr upr


## 1 13694.105227 12813.895925 14574.314529
## 2 3477.855339 2416.031617 4539.679061
## 3 15895.325102 15034.877412 16755.772792
## 4 8216.952245 7255.516515 9178.387975
## 5 120453.269144 116441.615058 124464.923230

Chúng ta cũng có thể ước lượng HEALTH khi INCOME lần lượt là 20000,21000, và 22000 cùng một
lúc như sau:

predict(hoiquy, newdata = data.frame(INCOME = c(20000, 21000, 22000)),


interval = "confidence")

## fit lwr upr


## 1 3853.357553 2800.322593 4906.392513
## 2 3982.841075 2932.806397 5032.875753
## 3 4112.324597 3065.274430 5159.374764

Nếu bạn muốn dự báo một chuỗi các ước lượng ứng với mức thu nhập từ 12000 cho đến 100000
nhưng các mức thu nhập cách nhau 1000. Tức là quan sát đầu tiên ứng với INCOME = 12000, quan
sát thứ hai ứng với INCOME = 13000 cho đến quan sát cuối cùng ứng với INCOME = 100000 thì chúng
ta làm như sau (lấy 10 kết quả đầu tiên) :

Nguyễn Chí Dũng http://rpubs.com/chidungkt


186

predict(hoiquy, newdata = data.frame(INCOME = seq(from = 12000, to = 100000,


by = 1000)), interval = "confidence")

## fit lwr upr


## 1 2817.489376 1739.900374 3895.078379
## 2 2946.972899 1872.505574 4021.440223
## 3 3076.456421 2005.096056 4147.816785
## 4 3205.939943 2137.671690 4274.208195
## 5 3335.423465 2270.232347 4400.614582
## 6 3464.906987 2402.777898 4527.036076
## 7 3594.390509 2535.308210 4653.472807
## 8 3723.874031 2667.823153 4779.924909
## 9 3853.357553 2800.322593 4906.392513
## 10 3982.841075 2932.806397 5032.875753

Tuy nhiên nếu chúng ta quan tâm đến các ước lượng cá nhân (Individual Prediction) của Y0 (Y0 chứ
không phải la Ŷ 0 ) tương ứng với X0 thì giá trị ước lượng Y0 có phương sai tính theo công thức sau:

2 1 (𝑋0 − 𝑋̅)2
var(𝑌0 − 𝑌̂0 ) = 𝐸[𝑌0 − 𝑌̂0 ] = 𝜎 2 [1 + + ] (𝑓)
𝑛 ∑ 𝑥𝑖2
Thay thế σ2 bằng σ̂ 2 thì có thể thấy rằng:

𝑌0 − 𝑌̂0
𝑡= (𝑔)
𝑠𝑒(𝑌0 − 𝑌̂0 )
Tuân theo phân phối t, có thể ước lượng khoảng tin cậy ở ngưỡng α (mặc định là 5%) cho Y0 khi X0 =
20000 một cách nhanh chóng với lựa chọn interval="prediction":

predict(hoiquy, newdata = data.frame(INCOME = 20000),interval = "prediction")

## fit lwr upr


## 1 3853.357553 -2278.928 9985.643

Giá trị fit (ước lượng) thì không thay đổi và vẫn là 3853.357553 nhưng có thể thấy khoảng tin cậy trở
nên rộng hơn.

4.5 Một số tiêu chí thường sử dụng để đánh giá chất lượng mô hình
Khi thực hiện các phân tích cũng như nghiên cứu, chúng ta có thể phải đưa ra quyết định lựa chọn mô
hình nào là phù hợp. Hoặc chúng ta cũng cần phải đánh giá phẩm chất, độ phù hợp của mô hình chẳng
hạn. Để làm điều này, trước hết chúng ta phải quyết định cần phải sử dụng những tiêu chí gì để đánh
giá một mô hình là tốt hơn những mô hình khác cũng như chất lượng của một mô hình cụ thể. Ví dụ,
để lựa chọn một mô hình trong số các mô hình cạnh tranh nhau chúng ta phải dựa vào một loạt các
yếu tố cũng như tiêu chí khác nhau. Trong mục này, chúng ta xem xét một số tiêu chí thống kê thường
sử dụng để đánh giá và so sánh các mô hình.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


187

4.5.1 Tiêu chí R2 và tương quan giữa Y và Ŷ


Đây là hai tiêu chí đo lường mức độ phù hợp của mô hình (Measures of Fit). Về cơ bản, trong hai mô
hình thì mô hình nào có R2 hoặc R2 hiệu chỉnh cao hơn là mô hình tốt hơn. Theo Gujarati & Porter
(2009), hạn chế của tiêu chí này là chúng ta chỉ so sánh và đánh giá được các mô hình có: (1) biến
phụ thuộc là giống nhau, và (2) có kích cỡ mẫu như nhau. Điều này có nghĩa là chúng ta không thể lấy
R2 làm tiêu chuẩn để đánh giá hai mô hình sau:

ln(Y) = β1 + β2X + u (mô hình a)

Y = ψ1 + ψ2X + u (mô hình b)

Với hồi quy đơn (là mô hình chỉ có 1 biến độc lập) như ở mô hình a thì R2 = [cor(Y,X)]2 hay là bình
phương tương quan giữa X và Y. Với hồi quy đa biến (mô hình có nhiều hơn 1 biến độc lập) thì R2 =
[cor(Y,Ŷ )]2 trong đo ,Ŷ la gia trị dự báo của của Y thu được từ mô hình.

Trong tình huống mà hai mô hình không có biến phụ thuộc như nhau như mô hình a và mô hình b thì
để đánh giá và so sánh chúng ta có thể so sanh cor(Y,Ŷ a) va cor(Y,Ŷ b) với Ŷ a va Ŷ b lần lượt là các giá trị
ước lượng thu được của Y từ mô hình a và b. Giá trị tương quan mà càng cao thì có nghĩa là ước lượng
của Y thu được càng gần với giá trị thực của nó, và do đó mô hình nào có giá trị tương quan này cao
hơn thì sẽ là mô hình tốt hơn.

4.5.2 Các tiêu chí đánh giá theo phần dư


Nhóm các tiêu chí sử dụng giá trị của phần dư là một trong những tiêu chí sử dụng phổ biến khi so
sánh, đánh giá mô hình. Trong số các tiêu chí thuộc nhóm này thì RMSE và MSE là hai tiêu chí sử dụng
phổ biến hơn. MSE được tính theo công thức sau:
𝑛
1 2
MSE = ∑(𝑌̂𝑖 − 𝑌𝑖 )
𝑛
𝑖=1

Còn RMSE được tính bằng căn bậc hai của MSE.

Một giá trị MSE (hoặc RMSE) càng bé thì có nghĩa là những giá trị ước lượng của Y sẽ càng sát với giá
trị thực và do đó, một mô hình có MSE (RMSE) bé hơn sẽ là một mô hình tốt hơn.

Ngoài ra một số tiêu chí thuộc nhóm này là MD, MAD, MPE và MAPE cũng có thể được sử dụng để
đánh giá mô hình.

4.5.3 Các tiêu chuẩn thông tin AIC, SIC, và Cp của Mallow
Đây là nhóm tiêu chí thường được sử dụng thay thế cho R2 trong nhiều tình huống và nó hạn chế được
các nhược điểm của tiêu chí R2.

Với các kí hiệu các bạn đã quen thuộc, tiêu chuẩn thông tin Akaike (AIC) được tình theo công thức:

∑ 𝑢̂𝑖2 RSS
AIC = 𝑒 2𝑘/𝑛 = 𝑒 2𝑘/𝑛
𝑛 n

Nguyễn Chí Dũng http://rpubs.com/chidungkt


188

Với chú ý rằng n là số quan sát, k là số biến số trong mô hình. Căn cứ vào tiêu chuẩn thông tin Akaike
AIC, mô hình có AIC thấp hơn sẽ được lựa chọn. Hầu hết các phần mềm thống kê, kể cả R đều báo cáo
tiêu chuẩn thông tin này. Với mô hình 1 như ở mục 4.2 để có tiêu chuẩn thông tin Akaike các bạn sử
dụng câu lệnh:

AIC(hoiquy)

Tương tự, tiêu chuẩn thông tin Schwarz (SIC) cũng được sử dụng để so sánh và đánh giá các mô hình
cạnh tranh. SIC được tính theo công thức sau:

∑ 𝑢̂2 RSS
SIC = 𝑛𝑘/𝑛 = 𝑛𝑘/𝑛
𝑛 n
Hiện tại, trong R chưa có sẵn hàm tính SIC nhưng các bạn có thể trực tiếp SIC trong R theo công thức
này.

Một tiêu chuẩn nữa là hệ số Cp của Mallow (Mallow’s Cp Criterion) được tính theo công thức:
RSS𝑝
𝐶𝑝 = − (𝑛 − 2𝑝)
𝜎̂ 2
Trong đó p là số biến độc lập (chú ý với mô hình k biến thì p = k – 1). Chúng ta cũng biết rằng E(σ̂ 2) là
ước lượng không chệch của phương sai sai số ngẫu nhiên σ2 – đại lượng mà chúng ta không bao giờ
biết chính xác. Do vậy, chúng ta có thể xấp xỉ E(Cp) như sau:

(𝑛 − 𝑝)𝜎 2
𝐸(𝐶𝑝 ) ≈ − (𝑛 − 2𝑝) ≈ 𝑝
𝜎2
Căn cứ theo tiêu chí Cp này, chúng ta sẽ ưu tiên lựa chọn mô hình có Cp thấp hơn và có hệ số R2 hoặc
R2 hiệu chỉnh càng cao càng tốt. Thường thì hai mục tiêu này mâu thuẫn với nhau và việc lựa chọn mô
hình cũng còn nên căn cứ vào, chẳng hạn, mối quan hệ của các biến số trong thực tế. Chúng ta sẽ
nghiên cứu kĩ hơn với tiêu chuẩn này ở mục 7.3 thuộc chương 7.

4.5.4 Tỉ lệ sai sót huấn luyện, sai sót kiểm định và hiện tượng quá khớp
Những gì các bạn sắp đọc chắc chắn là một thử thách. Không phải vì những gì được trình bày ở đây là
quá khó so với tư duy của các bạn mà vì một lí do khác rất đặc trưng của hầu hết chúng ta: chưa quen
với suy nghĩ một cách thống kê (Thinking Statistically) – điều mà hầu hết các giáo trình thống kê cũng
như kinh tế lượng bằng tiếng Việt không đề cập.

Thông thường việc so sánh chất lượng giữa hai mô hình hình cạnh tranh nhau hoặc đánh giá chất
lượng của một mô hình chúng ta thường dựa vào, chẳng hạn, tiêu chí R2 hoặc MSE. Nếu chọn MSE để
đánh giá thì mô hình nào có MSE bé hơn sẽ là mô hình tốt hơn. Trong tình huống đặc biệt, nếu MSE =
0 (tương đương với R2 =1) thì có nghĩa là chúng ta có một mô hình hoàn hảo với ngụ ý rằng các biến
số giải thích 100% biến động của biến phụ thuộc. Tương tự, khi đánh giá một mô hình chúng ta
thường căn cứ vào R2 – chỉ số này càng cao càng tốt. Hoặc chúng ta ta căn cứ vào MSE – chỉ số này
càng thấp càng tốt. Phải chăng, chẳng hạn, chỉ căn cứ vào MSE để đánh giá (hay so sánh) chất lượng
của các mô hình là đủ?

Nguyễn Chí Dũng http://rpubs.com/chidungkt


189

Câu trả lời là không. Để đánh giá chất lượng của một mô hình, theo James et al. (2013), chúng ta cần
căn cứ vào đồng thời cả hai tiêu chí: (1) sai số huấn luyện – training test error, và (2) sai số kiểm
định – testing test error. Để làm rõ hai khái niệm này chúng ta trở lại với bộ số liệu ở mục CPS1988
đã sử dụng ở chương 3 nhằm ước lượng mô hình sau:

wage = β1 + β2education + u (2)

Tuy nhiên thay vì ước lượng mô hình 2 với tất cả 28155 quan sát chúng ta chỉ ước lượng mô hình này
với 16.000 quan sát mà thôi. Rõ ràng là có đến K= 28155!/[16000!⨉(28155-16000)!] cách lấy ra
16000 quan sát từ 28155 quan sát và do vậy chúng ta cũng có chừng đó cặp giá trị ước lượng của β1
và β2 cũng như MSE. Dưới đây là 2 bộ số liệu rút ra từ K bộ số liệu có 16000 quan sát và do vậy có 2
bộ ước lượng β1 và β2 cũng như MSE:

data(CPS1988, package = "AER")


dim(CPS1988)

## [1] 28155 7

head(CPS1988)

## wage education experience ethnicity smsa region parttime


## 1 354.94 7 45 cauc yes northeast no
## 2 123.46 12 1 cauc yes northeast yes
## 3 370.37 9 9 cauc yes northeast no
## 4 754.94 11 46 cauc yes northeast no
## 5 593.54 12 36 cauc yes northeast no
## 6 377.23 16 22 cauc yes northeast no

set.seed(2611)
p <- 16000 / 28155
id1 <- sample(nrow(CPS1988), round(p*nrow(CPS1988)))
data1 <- CPS1988[id1, ] # Lấy bộ số liệu thứ nhất gồm 16000 quan sát.
data11 <- CPS1988[-id1, ] # Bộ số liệu còn lại sau khi loại ra tất cả các
quan sát đã có ở data1.
id2 <- sample(nrow(CPS1988), round(p*nrow(CPS1988)))
data2 <- CPS1988[id2, ] # Lấy bộ số liệu thứ hai gồm 16000 quan sát.
data22 <- CPS1988[-id2, ] # Lấy phần số liệu còn lại sau khi loại ra tất cả c
ác quan sát đã có ở data2.
head(data1)

## wage education experience ethnicity smsa region parttime


## 27187 1115.86 12 26 cauc yes west no
## 3590 325.68 14 3 cauc yes northeast no
## 5040 569.80 12 26 cauc yes northeast no
## 19729 550.09 12 16 cauc no south no

Nguyễn Chí Dũng http://rpubs.com/chidungkt


190

## 25187 474.83 18 0 cauc yes west no


## 18329 246.91 12 10 cauc no south no

head(data2)

## wage education experience ethnicity smsa region parttime


## 20135 74.07 5 56 cauc yes south yes
## 1967 1234.57 18 32 cauc yes northeast no
## 6773 427.35 12 15 cauc yes midwest no
## 17046 379.87 12 16 cauc yes south no
## 5639 469.14 11 47 cauc yes northeast no
## 10730 379.87 12 9 cauc yes midwest no

ols1 <- lm(wage ~ education, data = data1)


ols2 <- lm(wage ~ education, data = data2)
library(stargazer)
stargazer(ols1, ols2, type = "text")

##
## =============================================================
## Dependent variable:
## ----------------------------
## wage
## (1) (2)
## -------------------------------------------------------------
## education 48.268*** 46.491***
## (1.150) (1.246)
##
## Constant -24.752 -1.028
## (15.432) (16.696)
##
## -------------------------------------------------------------
## Observations 16,000 16,000
## R2 0.099 0.080
## Adjusted R2 0.099 0.080
## Residual Std. Error (df = 15998) 421.488 455.417
## F Statistic (df = 1; 15998) 1,760.477*** 1,393.024***
## =============================================================
## Note: *p<0.1; **p<0.05; ***p<0.01

library(Metrics)
MSE1 <- mse(data1$wage, predict(ols1, data1))
MSE2 <- mse(data2$wage, predict(ols2, data2))
print(paste(MSE1, MSE2))

Nguyễn Chí Dũng http://rpubs.com/chidungkt


191

## [1] "177630.272890156 207379.168767557"

Ở đây các bạn có thể thấy MSE1 thu được từ bộ dữ liệu data1 bé hơn MSE2 thu được từ data2. Phải
chăng các ước lượng từ data1 sẽ là đại diện hợp lí hơn so với các ước lượng từ data2 để mô tả mối
quan hệ thực giữa wage và education?.

Câu trả lời là chưa chắc. MSE1 và MSE2 mà chúng ta thu được ở trên chính là tỉ lệ sai sót huấn luyện
(training error rate). Nguyên nhân là ta thu được các ước lượng OLS từ data1 và data2 rồi ta sử dụng
chính hai mô hình thu được dựa trên hai bộ số liệu này để ước lượng wage thuộc chính data1 và
data2. Ở đây, bộ dữ liệu được sử dụng để xây dựng mô hình là data1 và data2 nên trong nghiên cứu
thống kê và kinh tế lượng, chúng có một tên gọi cụ thể hơn thể hiện bản chất và vài trò của bộ số liệu:
dữ liệu huấn luyện (training data, hoặc training set).

Tương tự khái niệm tỉ lệ sai sót huấn luyện, tỉ lệ sai sót kiểm định (testing error rate) được tính toán
dựa trên data11 và data22 – là hai bộ dữ liệu còn lại sau khi chúng ta lấy ra data1 và data2 – nhằm
đánh giá mô hình. Hai bộ dữ liệu data11 và data22 có tên gọi là dữ liệu kiểm định (testing data, hay
testing set). Tên gọi này có ngụ ý rằng, chẳng hạn, ols1 được xây dựng dựa trên bộ số liệu data1 và
sau đó bộ dữ liệu kiểm định tương ứng của data1 là data11 được sử dụng để đánh giá lại mô
hình. Chúng ta có thể tính toán tỉ lệ sai sót kiểm định ứng với hai bộ số liệu:

MSE11 <- mse(data11$wage, predict(ols1, data11))


MSE22 <- mse(data22$wage, predict(ols2, data22))
print(paste(MSE11, MSE22))

## [1] "199326.100766556 160158.933656659"

Như vậy, mặc dù tỉ lệ sai sót huấn luyện ứng với data1 là thấp hơn tỉ lệ sai sót huấn luyện ứng với
data2 nhưng tỉ lệ sai sót kiểm định ứng với data1 lại cao hơn tỉ lệ sai sót tỉ lệ sai sót kiểm định ứng
với data2.

Các khái niệm về tỉ lệ sai sót kiểm định và tỉ lệ sai sót huấn luyện là nền tảng của một khái niệm rất
quan trọng trong nghiên cứu thống kê nói chung và kinh tế lượng nói riêng, nhất là bài toán dự báo:
hiện tượng quá khớp (overfitting). Hiện tượng quá khớp được hiểu là một mô hình rất phù hợp với
bộ dữ liệu huấn luyện (MSE thấp và R2 cao chẳng hạn) nhưng lại không phù hợp với bộ dữ liệu kiểm
định (MSE cao và R2 thấp). Khi một mô hình xẩy ra hiện tượng quá khớp thì mặc dù nó có thể dự báo
rất tốt trên một tập quan sát nhưng nó lại thất bại trong việc dự báo khi chúng ta sử dụng bộ dữ liệu
khác. Nói cách khác, một mô hình quá khớp không có giá trị phổ quát vì nó chỉ phù hợp (fitting)
với một bộ dữ liệu cụ thể nào đó nhưng lại không phù hợp với những bộ dữ liệu khác và do vậy,
mô hình không có nhiều ý nghĩa trong bài toán dự báo cũng như mô tả.

Ngược lại với hiện tượng quá khớp là underfitting, theo đó, khả năng dự báo (hay khớp) với số liệu
của mô hình ở bộ số liệu huấn luyện là thấp hơn so với khả năng dự báo (hay khớp) của mô hình ở bộ
số liệu kiểm định.

Một mô hình tốt là một mô hình có cả hai thứ: tỉ lệ sai sót huấn luyện và tỉ lệ sai sót kiểm định đều
thấp. Thông thường khi đánh giá mô hình (hoặc so sánh các mô hình) thì chúng ta cần phải lưu tâm
đồng thời cả hai yếu tố này.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


192

Những khái niệm các bạn vừa nghiên cứu ở trên là nền tảng cho một nhánh của khoa học thống kê
gọi là các phương pháp tái chọn mẫu (Resampling Methods) được trình bày ở mục sau.

Cuối cùng để giúp các bạn hiểu rõ hơn về hai loại tỉ lệ sai sót, dưới đây là R code dưới đây thực hiện
hồi quy OLS cho mô hình 2 với bộ dữ liệu huấn luyện là 16000 quan sát và bộ dữ liệu kiểm định là
28155 – 16000 quan sát còn lại. Sau khi thực hiện OLS xong tính MSEtraining (tỉ lệ sai sót huấn luyện)
và MSEtesting (tỉ lệ sai sót kiểm định). Quá trình này lặp đi lặp lại 1000 lần và do đó có 1000 cặp giá
trị của MSEtesting và MSEtraining được lưu lại ở data frame tên trangyeu. Cuối cùng chúng ta so sánh
mean (trung bình) của các giá trị MSE này:

# Tạo ra hai vector trống:


MSEtraining <- c()
MSEtesting <- c()
p <- 16000 / 28155
set.seed(26111996)
for(i in 1:1000){
set.seed(i)
id <- sample(nrow(CPS1988), round(p*nrow(CPS1988)))
# Dữ liệu huấn luyện gồm 16000 quan sát:
training <- CPS1988[id, ]
# Dữ liệu kiểm định gồm 28155 quan sát còn lại:
testing <- CPS1988[-id, ]
ols <- lm(wage ~ education, data = training)
# Tính MSEtraining và MSEtesting:
MSEtraining <- c(MSEtraining, mse(training$wage, predict(ols,training)))
MSEtesting <- c(MSEtesting, mse(testing$wage, predict(ols,testing)))
# Tạo data frame gồm 1000 quan sát cho MSEtraining và MSEtesting:
trangyeu <- data.frame(MSEtraining, MSEtesting)
}

# Hình ảnh hóa:


trangyeu %>% gather(Sampling, Value) %>%
ggplot(aes(Sampling, Value, color = Sampling, fill = Sampling)) +
geom_boxplot(alpha = 0.3, show.legend = FALSE) + theme_bw()

Nguyễn Chí Dũng http://rpubs.com/chidungkt


193

# Các thống kê bằng số:


summary(trangyeu)

## MSEtraining MSEtesting
## Min. :149297 Min. :145566
## 1st Qu.:177345 1st Qu.:173207
## Median :188070 Median :185580
## Mean :187115 Mean :186834
## 3rd Qu.:197456 3rd Qu.:199717
## Max. :218484 Max. :236670

Kết quả chỉ ra rằng MSEtesting (tỉ lệ sai sót kiểm định) có trung bình là 186834 thấp hơn MSEtraining
(tỉ lệ sai sót huấn luyện) có trung bình 187115 khi cho mô hình chạy với 1000 bộ dữ liệu khác nhau
nên có có thể thấy mô hình (2) có dấu hiệu của hiện tượng underfitting (một hiện tượng ngược lại
overfitting).

4.6 Đánh giá chất lượng của mô hình bằng các phương pháp tái chọn mẫu
Các phương pháp tái chọn mẫu (Resampling Methods) là một cách tiếp cận đầy sức mạnh và tin cậy
để đánh giá chất lượng của một mô hình thống kê nói chung cũng như các mô hình kinh tế lượng
(James et al., 2013). Trước đây, trong một thời gian khá dài, do sức mạnh tính toán của máy tính còn
hạn chế nên các phương pháp tái chọn mẫu dù rất hoàn thiện về lý thuyết nhưng trong thực tế ít được
sử dụng. Tuy nhiên, những hạn chế này không còn là trở ngại lớn khi mà sức mạnh tính toán của máy
tính ngày càng mạnh và nhanh như hiện nay.

Đúng như tên gọi của nó, phương pháp này sử dụng việc tái chọn mẫu lặp đi lặp lại, sử dụng các thông
tin thu được từ mỗi lần chọn mẫu đó để đánh giá chất lượng của một mô hình. Chẳng hạn, việc tái
chọn mẫu 1000 lần để nghiên cứu chất lượng của mô hình thông qua tỉ lệ sai sót kiểm định và huấn
luyện như các bạn đã thực hiện ở mục 4.5.4 chính là một phương pháp tái chọn mẫu. Mục này chúng
ta sẽ nghiên cứu chi tiết hơn về hai nhóm phương pháp tái chọn mẫu là Bootstrap và Cross-validation.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


194

4.6.1 Phương pháp Bootstrap


Bootstrap là một phương pháp tái chọn mẫu do giáo sư Bradley Efron thuộc khoa Thống Kê của đại
học Stanford phát triển từ năm 1979 và đã làm nên một cuộc cách mạng vì nó giải quyết được nhiều
vấn đề mà các phương pháp cũ của thống kê không giải quyết được. Trước đây, phương pháp này chỉ
được sử dụng giới hạn trong các Lab của các trường đại học lớn nhưng hiện tại chúng ta có thể dễ
dàng thực hiện phương pháp tái chọn mẫu này một cách dễ dàng.

Mục này cũng giới thiệu phương pháp bootstrap thay thế cho sử dụng hồi quy tuyến tính OLS vốn
phụ thuộc nhiều vào các giả định chặt chẽ và do vậy các kết quả ước lượng thu được từ OLS là rất
nhậy với những giả định này. Vì lý do này, các ước lượng thu được từ phương pháp bootstrap sẽ là
tin cậy hơn.

Để minh họa cho phương pháp tiếp cận này, chúng ta nghiên cứu tình huống sau. Giả sử chúng ta có
một số tiền cố định và đầu tư số tiền này vào hai cổ phiếu A và B với lợi tức lần lượt là X và Y. Chú ý
rằng X và Y là những biến nghẫu nhiên. Nếu gọi α là tỉ trọng đầu tư vào cổ phiếu A thì (1- α) sẽ là tỉ
trọng đầu tư vào cổ phiếu B. Như vậy rủi ro của danh mục đầu tư này được đo bằng:

Var(𝛼𝑋 + (1 − 𝛼)𝑌)
Chúng ta đã biết rằng nhằm tối thiểu hóa rủi ro, tỉ trọng đầu tư vào cổ phiếu A phải thỏa mãn:

𝜎𝑌2 − 𝜎𝑋𝑌
𝛼=
𝜎𝑋2 + 𝜎𝑌2 − 2𝜎𝑋𝑌
Trong đó :

σ2X = Var(X), đó σ2Y = Var(Y), và σ2XY = Cov(X,Y).

Vấn đề ở đâu là trong thực tế chúng ta không biết ba đại lượng trên, do vậy chúng ta buộc phải ước
lượng các giá trị này để tính giá trị ước lượng của α la α̂ . Điều này được tiến hành như sau. Chúng ta
lấy 100 cặp quan sát của X và Y để tình α̂ 1. Lặp lại quá trình này 1000 lần và như vậy chúng ta có 1000
giá trị của α̂ . Lúc này trung bình của α̂ được tính như sau:
1,000
1
𝛼̅ = ∑ 𝛼̂𝑟
1,000
𝑟=1

Còn độ lệch chuẩn của α̂ được tính theo công thức sau:

1,000
1
√ ∑ (𝛼̂𝑟 − 𝛼̅)2
1,000 − 1
𝑟=1

Những bước mô tả như trên trong thực tế chúng ta khó có thể áp dụng được trong thực tế vì khó có
thể lấy ra 1000 mẫu khác nhau gồm 100 cặp giá trị X, Y từ mẫu nguyên thủy ban đầu.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


195

Tuy nhiên chúng ta có thể sử dụng phương pháp Bootstrap để thực hiện điều này bằng cách tái lấy
mẫu có hoàn lại. Nghĩa là các quan sát có thể được lấy một cách trùng lặp. Thủ tục này được mô tả
chi tiết ngay sau đây.

Giả sử mẫu nguyên thủy (Original Data) ban đầu Z của chúng ta có n = 3 quan sát . Chúng ta lấy ra
mẫu Z*1 cũng với ba quan sát – tức là đúng bằng số lượng quan sát ở mẫu nguyên thủy. Do một quan
sát bất kì có thể được chọn nhiều hơn 1 lần nên chúng ta thấy mẫu này có quan sát thứ ba (ở mẫu
nguyên thủy) xuất hiện hai lần. Quá trình này được lặp lại nhiều lần và cứ với một mẫu thứ cấp, chẳng
hạn, mẫu Z*1 chúng ta có một giá trị ước lượng α̂ *1. Lặp lại quá trình này B lần và do đó chúng ta có B
giá trị của α̂ * .

Khi đó độ lệch chuẩn của α từ phương pháp Bootstrap được tính theo công thức tổng quát sau:

𝐵
1
SE𝐵 (𝛼̂) = √ ∑(𝛼̂𝑟 − 𝛼̅)2
𝐵−1
𝑟=1

Chúng ta sẽ sử dụng bộ số liệu Portfolio tích hợp cùng gói ISLR (cài đặt gói này bằng lệnh
install.packages(“ISLR”)) để thực hiện phương pháp này với R. Bộ số liệu này là thông tin về lợi tức
X và Y của hai cổ phiếu trong 100 ngày. Trước hết chúng ta cần viết hàm tính α tối ưu theo công thức:

𝜎𝑌2 − 𝜎𝑋𝑌
𝛼=
𝜎𝑋2 + 𝜎𝑌2 − 2𝜎𝑋𝑌
# Tạo hàm có tên alpha để tính tỉ trọng đầu tư vào tài sản A.
alpha <- function(data, index){
X = data$X[index]

Nguyễn Chí Dũng http://rpubs.com/chidungkt


196

Y = data$Y[index]
return((var(Y) - cov(X,Y)) / (var(X) + var(Y) - 2*cov(X,Y)))
}

Chúng ta gọi bộ số liệu Portfolio của gói ISLR. Đây là bộ dữ liệu về lợi tức của hai cổ phiếu (chưa rõ
đơn vị đo) trong 100 ngày liên tiếp:
library(ISLR)
data(Portfolio)
head(Portfolio)

## X Y
## 1 -0.8952509 -0.2349235
## 2 -1.5624543 -0.8851760
## 3 -0.4170899 0.2718880
## 4 1.0443557 -0.7341975
## 5 -0.3155684 0.8419834
## 6 -1.7371238 -2.0371910

tail(Portfolio)

## X Y
## 95 2.2608577 0.6732248
## 96 0.4790909 1.4547745
## 97 -0.5350200 -0.3991748
## 98 -0.7731293 -0.9571748
## 99 0.4036343 1.3960382
## 100 -0.5884964 -0.4972851

Chúng ta có thể tính ước lượng của α (tức α̂ ) ứng với mẫu cụ thể này:

alpha(Portfolio)

## [1] 0.5758321

Chú ý rằng con số 0.5758 ở đây là ước lượng của α ứng với mẫu gốc. Dưới đây chúng ta tạo ra một
mẫu bằng phương pháp Bootstrap và tính ước lượng của α ứng với mẫu này:

m <- Portfolio[sample(nrow(Portfolio), 100, replace = T),] # Tạo một mẫu theo


phương pháp Bootstrap.
alpha(m) # Tính alpha.

## [1] 0.5220407

Tất nhiên kết quả của bạn sẽ không phải lf 0.5220407 như trên vì tính chất ngẫu nhiên của mẫu được
chọn. Và mỗi lần thực hiện thì sẽ ra một kết quả khác. Chúng ta có thể lặp lại quá trình này 1000 lần,
và do vậy có 1000 giá trị ước lượng của α. Chúng ta ghi lại 1000 giá trị này và tính mean cũng như độ

Nguyễn Chí Dũng http://rpubs.com/chidungkt


197

lệch chuẩn. Tuy nhiên R có gói boot có thể tự động làm việc này một cách nhanh chóng. Để tái tạo kết
quả, chúng ta sử dụng hàm set.seet() như sau:
library(boot)
set.seed(2611) # Để đảm bảo kết quả là trùng lặp.
trang <- boot(Portfolio, alpha, R = 1000)
trang

##
## ORDINARY NONPARAMETRIC BOOTSTRAP
##
##
## Call:
## boot(data = Portfolio, statistic = alpha, R = 1000)
##
##
## Bootstrap Statistics :
## original bias std. error
## t1* 0.5758321 0.002269671 0.09310941

0.1294835 2.513543e-03 51.514341 2.449579e-44

Chúng ta thấy giá trị ứng với cột original chính là ước lượng của alpha ứng với mẫu gốc. Một kết quả
mà ta đã có từ trước. Kết quả chỉ ra rằng sai số chuẩn ước lượng cho ước lượng của alpha là
0.09310941. Chúng ta có thể tính trung bình, tính lại giá trị của sai số chuẩn này:

head(trang$t) # Xem 6 quan sát đầu trong số 1000 ước lượng của alpha.

## [,1]
## [1,] 0.5081016
## [2,] 0.3961208
## [3,] 0.5432477
## [4,] 0.7088269
## [5,] 0.4465900
## [6,] 0.6602969

tail(trang$t) # Xem 6 quan sát cuối.

## [,1]
## [995,] 0.5278409
## [996,] 0.5216640
## [997,] 0.7314720
## [998,] 0.5328849
## [999,] 0.6543257
## [1000,] 0.5533597

sd(trang$t) # Tính sai số chuẩn

Nguyễn Chí Dũng http://rpubs.com/chidungkt


198

## [1] 0.09310941

mean(trang$t) # Trung bình các ước lượng ứng với 1000 mẫu Bootstrap.

## [1] 0.5781017

Chúng ta có thể hình ảnh hóa cho 1000 giá trị ước lượng của alpha:

par(mfrow = c(1, 2))


plot(trang$t, main=mean(trang$t), type="b",xlab="So lan chon mau",col="blue")
hist(trang$t, col="blue", main = "Histogram cua alpha tu 1000 mau bootstrap" )

par(mfrow = c(1, 1)) # Đặt chế độ hiển thị mặc định của R

Hoàn toàn tương tự chúng ta có thể sử dụng phương pháp Bootstrap để đánh giá chất lượng cũng
như các khía cạnh khác cho kết quả hồi quy thu được ở mục 4.2. Trước hết chúng ta viết hàm có tên
boot.hesohoiquy để hiển thị các hệ số hồi quy:

boot.hesohoiquy <- function(data, index) # Viết hàm


return(coef(lm(HEALTH ~ INCOME, data = dung, subset = index)))
boot.hesohoiquy(dung, 1:51)

## (Intercept) INCOME
## 1263.6871121 0.1294835

Kết quả trên là trùng khớp với kết quả thu được ở mục 4.2 khi chúng ta thực hiện hồi quy. Dưới đây
là các câu lệnh thực hiện bootstrap cho hai mẫu. Chú ý rằng những ước lượng thu được tương ứng là
khác nhau:

set.seed(123)
boot.hesohoiquy(dung, sample(51, 51, replace = T))

## (Intercept) INCOME
## 65.794685 0.139344

boot.hesohoiquy(dung, sample(51, 51, replace = T))

Nguyễn Chí Dũng http://rpubs.com/chidungkt


199

## (Intercept) INCOME
## 1720.8031663 0.1258176

Chúng ta có thể lặp lại quá trình này 1000 lần để nghiên cứu sự ổn định của mô hình hồi quy thu được
ở mục 4.2:

trangyeu <- boot(dung, boot.hesohoiquy, 1000)


trangyeu

##
## ORDINARY NONPARAMETRIC BOOTSTRAP
##
##
## Call:
## boot(data = dung, statistic = boot.hesohoiquy, R = 1000)
##
##
## Bootstrap Statistics :
## original bias std. error
## t1* 1263.6871121 -2.136956e+02 7.374884e+02
## t2* 0.1294835 1.849314e-03 6.860844e-03

Chúng ta có thể hiểu rõ hơn những kết quả trên như sau:

love <- trangyeu$t


head(love) # Xem 6 quan sát đầu trong số 1000 cặp giá trị ước lượng

## [,1] [,2]
## [1,] 1122.742 0.1311281
## [2,] 1433.357 0.1234588
## [3,] 1407.709 0.1262977
## [4,] 1565.651 0.1269054
## [5,] 1789.845 0.1278887
## [6,] 924.016 0.1332488

tail(love)

## [,1] [,2]
## [995,] 1305.4825 0.1295534
## [996,] -250.2552 0.1447241
## [997,] 1906.9541 0.1247074
## [998,] 1892.8701 0.1269881
## [999,] 1153.3988 0.1288668
## [1000,] 734.9050 0.1325789

summary(love)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


200

## V1 V2
## Min. :-850.5 Min. :0.1179
## 1st Qu.: 412.1 1st Qu.:0.1259
## Median :1199.1 Median :0.1300
## Mean :1050.0 Mean :0.1313
## 3rd Qu.:1612.8 3rd Qu.:0.1370
## Max. :2852.6 Max. :0.1490

So sánh, chẳng hạn sai số chuẩn của các ước lượng từ phương pháp Bootstrap với hồi quy ở mục 4.2:

summary(lm(HEALTH ∼ INCOME, data = dung))$coef

## Estimate Std. Error t value Pr(>|t|)


## (Intercept) 1263.6871121 5.554167e+02 2.275205 2.730473e-02
## INCOME 0.1294835 2.513543e-03 51.514341 2.449579e-44

Hệ số chặn và hệ số góc thu được từ phương pháp bootstrap lần lượt là 1050 và 0.1313. Những kết
quả này là khá sát với những kết quả khi sử dụng OLS. Tuy nhiên độ lệch chuẩn ứng với các ước lượng
có sai khác đáng kể hơn. Phải chăng các ước lượng thu được từ phương pháp bootstrap là có vấn đề?
Sự thực thì ngược lại. Thật vậy, các ước lượng cho sai số chuẩn ứng với các hệ số hồi quy OLS phụ
thuộc vào phương sai σ2 nhưng giá trị này là không bao giờ biết và do vậy buộc phải ước lượng giá trị
này bằng sử dụng RSS. Ngoài ra, OLS giả định rằng các giá trị của INCOME là cố định và do đó những
sai lệch (variation) được “nhóm” vào sai số ngẫu nhiên. Các ước lượng thu được từ bootstrap không
dựa vào các giả định này vào do vậy nó đưa ra những ước lượng hợp lí hơn (James et al., 2013;
Chernick, 2008) so với các ước lượng thu được từ OLS như chúng ta đã làm ở mục 4.2.

4.6.2 Phương pháp kiểm tra chéo


Tương tự Bootstrap, một cách tiếp cận khác thường được sử dụng để nghiên cứu tính ổn định cũng
như chất lượng của mô hình là sử dụng một trong hai phiên bản của một thủ tục thống kê gọi là kiểm
tra chéo (Cross-validation).

4.6.2.1 Kiểm tra chéo LOOCV


Kiểm tra chéo để lại một phần tử LOOCV (Leve-one-out cross-validation) sẽ chia bộ dữ liệu các quan
sát thành hai phần. Phần thứ nhất chỉ có một phần tử (x1, y1) – tức chỉ một quan sát và phần thứ hai
là toàn bộ các quan sát sau khi đã trừ ra quan sát (x1, y1) này. Nghĩa là bộ dữ liệu ban đầu nếu có n
quan sát thì bộ dữ liệu này còn n-1 quan sát. Một mô hình thống kê hay thủ tục thống kê nào đó, chẳng
hạn, hồi quy OLS sẽ được chạy trên bộ dữ liệu gồm n-1 quan sát này. Sau đó, một tiêu chí được lựa
chọn để đánh giá mô hình, chẳng hạn, là MSE1 sẽ được tính toán cho phần tử được trừ ra (x1, y1) theo
công thức:

MSE1 = (y - ŷ 1)2

Rõ ràng, bộ dữ liệu gồm n-1 phần tử được sử dụng để dựng mô hình OLS chính là dữ liệu huấn luyện
và phần tử duy nhất được trừ ra (x1, y1) đóng vai trò là bộ dữ liệu kiểm định. Như vậy, MSE1 sẽ là sai
số kiểm định và sẽ được sử dụng để đánh giá mô hình ứng với bộ dữ liệu huấn luyện gồm n-1 phần
tử này.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


201

Chúng ta sẽ lặp lại quá trình bằng trên bằng cách giữ lại phần tử (x2, y2), chạy mô hình OLS cho n-1
quan sát còn lại và tính MSE1 theo công thức MSE2 = (y - ŷ 2)2. Do bộ dữ liệu ban đầu có n phần tử nên
quá trình này được lặp lại n lần và trung bình của các MSE, kí hiệu là CV(n) được tính theo công thức
dưới đây sẽ là tiêu chí đánh giá sai sót kiểm định toàn cục của mô hình:
𝑛
1
CV(𝑛) = ∑ MSE𝑖
𝑛
𝑖=1

Chúng ta sẽ sử dụng bộ số liệu ở mục 4.2 để thực hành LOOCV. Dưới đây là R code thực hiện một vòng
lặp 51 lần cho bộ dữ liệu vì rằng chúng ta có 51 quan sát. Chú ý rằng, nếu bộ dữ liệu có 1 triệu quan
sát, thì chúng ta hoàn toàn có thể chạy một vòng lặp 1 triệu lần. Tuy nhiên, thực tế không nhất thiết
phải làm thế vì để đánh giá chất lượng và độ ổn định của mô hình ta chỉ cần một vòng lặp đủ lớn,
chẳng hạn, 10000 lần là đủ.
cacMSE <- c()
for (i in 1:51){
testing <- dung[i,]
training <- dung[-i,]
ols <- lm(HEALTH ~ INCOME, data = training)
mse <- mse(testing$HEALTH, predict(ols, testing))
cacMSE <- c(cacMSE, mse)
}
mean(cacMSE)

## [1] 14388750

# Tạo ra một data frame mới nhưng vẫn tên cũ là cacMSE


# rồi hình ảnh hóa. Cột biến PT hàm ý là phần tử được
# lấy riêng ra (LOOCV):
cacMSE <- data.frame(cacMSE, PT = 1:51)
cacMSE %>%
ggplot(aes(PT, cacMSE)) +
geom_line() + geom_point() + theme_minimal()

Chúng ta có thể thấy trong số 51 giá trị MSE, chỉ có 4 giá trị MSE là khác biệt so với nhóm còn lại.
Nghĩa là kết quả dự báo của mô hình cũng khá ổn định. Tính ổn định của mô hình cũng là một tiêu chí
quan trọng cần đánh giá nhất là với mục đích dự báo. Trong tình huống của chúng ta, hầu hết các

Nguyễn Chí Dũng http://rpubs.com/chidungkt


202

MSE đều có giá trị khá sát nhau, ngoại trừ có 4 tình huống các MSE mà chúng ta thấy trên graph, đặc
biệt là đối với phần tử thứ 5. Với mục đích dự báo, chúng ta sẽ tự tin hơn khi sử dụng một mô hình
mà tạo ra các kết quả dự báo là ổn định, không sai khác quá nhiều so với nhau trên các mẫu dữ liệu
khác nhau. Do vậy, sử dụng LOOCV cũng như các thủ tục tái chọn mẫu khác để đánh giá mô hình là
cần thiết.

4.6.2.2 Kiểm tra chéo k lớp


Kiểm định chéo k lớp (k-Fold Cross-Validation) liên quan đến việc chia dữ liệu ban đầu thành k lớp
bằng, hoặc xấp xỉ bằng nhau. Để minh họa, chúng ta xem xét mẫu ban đầu chỉ có 12 quán sát với k =3:

Theo cách tiếp cận này, bộ dữ liệu ban đầu sẽ được chia thành ba phần (gọi là 3 folds). Phần thứ nhất
được giữ lại và đóng vai trò là dữ liệu kiểm định (Testing Data 1), hai phần còn lại là dữ liệu huấn
luyện (Training Data 1). Mô hình sẽ được xây dựng trên bộ dữ liệu huấn luyện này. Sau đó, bộ dữ liệu
kiểm định tương ứng với nó (là Testing Data 1) sẽ được sử dụng để đánh giá lại mô hình căn cứ vào
một tiêu chí nào đó, chẳng hạn, là MSE. Với kiểm tra chéo 3 lớp thì quá trình này lặp lại 3 lần và chúng
ta sẽ có 3 giá trị MSE tương ứng. Sai sót kiểm định toàn cục của mô hình trong tình huống này được
tính theo công thức:
3
1
CV(3) = ∑ MSE𝑖
3
𝑖=1

Dễ dàng thấy rằng LOOCV là trường hợp đặc biệt của kiểm định chéo k lớp khi mà k = n. Tuy nhiên
trong thực tế chúng ta thường sử dụng kiểm định chéo k lớp với một trong hai giá trị tối ưu là k= 5
hoặc k = 10. Có ít nhất hai lý do để lựa chọn k như vậy. Thứ nhất là cái giá phải trả khi thực hiện tính
toán nếu chúng ta chọn k = n nếu số quan sát là rất lớn vì chúng ta sẽ phải chạy mô hình n lần, mỗi
lần cho n-1 quan sát còn lại. Thứ hai, và cũng là quan trọng nhất, theo Molinaro (2005) và Kim (2009),
đó là sự đánh đổi Bias – Variance (Bias-Variance Trade-off). Lí do thứ hai sẽ được giải thích chi tiết ở
mục sau.

Để minh họa, các bạn có thể sử dụng bộ số liệu ở mục 4.1 để thực hiện kiểm tra chéo với k = 3:

# Tính MSE1 cho lớp thứ nhất


testing1 <- dung[1:17, ]
training1 <- dung[-c(1:17), ]
ols1 <- lm(HEALTH ~ INCOME, data = training1)
MSE1 <- mse(testing1$HEALTH, predict(ols1, testing1))
# Tính MSE2 cho lớp thứ hai
testing2 <- dung[18:34, ]

Nguyễn Chí Dũng http://rpubs.com/chidungkt


203

training2 <- dung[-c(18:34), ]


ols2 <- lm(HEALTH ~ INCOME, data = training2)
MSE2 <- mse(testing2$HEALTH, predict(ols2, testing2))
# Tính MSE3 cho lớp thứ ba
testing3 <- dung[35:51, ]
training3 <- dung[-c(35:51), ]
ols3 <- lm(HEALTH ~ INCOME, data = training3)
MSE3 <- mse(testing3$HEALTH, predict(ols3, testing3))
# Tính trung bình các MSE
(1 / 3)*(MSE1 + MSE2 + MSE3)

## [1] 14948088

Chúng ta có thể viết một vòng lặp for loop cho ngắn gọn chứ không nên làm dài dòng như trên:

# Tạo một cột biến có tên là lop:


dung$lop <- c(rep("f1", 17), rep("f2", 17), rep("f3", 17))
fold <- unique(dung$lop)

# Vòng lặp for loop tính các MSE:


MSE <- c()
for (i in fold) {
testing <- dung %>% filter(lop == i)
training <- dung %>% filter(lop != i)
ols <- training %>% lm(HEALTH ~ INCOME, data = .)
MSE <- c(MSE, mse(testing$HEALTH, predict(ols, testing)))
}
# Kết quả là không có gì thay đổi:
mean(MSE)

## [1] 14948088

Tất nhiên trong thực tế, để kiểm định chất lượng cũng như tính ổn định của mô hình, quá trình này
có thể được lặp lại hàng trăm, thậm chí hàng ngàn lần. Tất nhiên chúng ta không thể thực hiện thủ
công như trên. R có một gói hỗ trợ cho việc thực hiện kiểm tra chéo k lớp một cách tự động rất thuận
tiện là caret. Chúng ta sẽ thực hành với gói caret ở mục 4.6.3.

4.6.2.3 Sự đánh đổi Bias – Variance


Giả sử chúng ta sử dụng ước lượng OLS và các giả thuyết của mô hình hồi quy tuyến tính cổ điển được
thỏa mãn, thì chúng ta dễ dàng thấy rằng các ước lượng thu được từ LOOCV cũng là không chệch
(unbiased) và các ước giá trị dự báo cũng sẽ gần hơn với các giá trị thực do kích cỡ của dữ liệu huấn
luyện là n – 1 gần như xấp xỉ kích cỡ mẫu ban đầu, nhất là với tình huống n lớn thì sai khác này không
đáng kể nếu xét theo tỉ số (n-1)/n (giới hạn của tỉ số này là 1 khi n tiến đến vô cùng). Còn khi thực
hiện kiểm định chéo k lớp (chẳng hạn k =5, hoặc k = 10) thì số quan sát trong bộ dữ liệu huấn luyện
là (k-1)n/k quan sát ít hơn so với cách tiếp cận LOOCV và do đó các ước lượng thu được sẽ bị chệch
ở một mức độ nào đó. Rõ ràng đứng trên quan điểm ưu tiên tính chất không chệch, thì LOOCV sẽ được
ưa thích hơn.

Tuy nhiên, tính không chệch chưa phản ánh toàn bộ câu chuyện. Vì chúng ta còn quan tâm đến sự ổn
định (hay Variance) của các ước lượng. Dễ dàng thấy rằng LOOCV có mức độ ổn định kém hơn kiểm

Nguyễn Chí Dũng http://rpubs.com/chidungkt


204

định chéo. Nguyên nhân là khi chúng ta thực hiện LOOCV, các mô hình được dựng trên bộ dữ liệu là
gần như không thay đổi so với nhau (chỉ khác duy nhất một quan sát) do đó các ước lượng (kết quả)
thu được là tương quan dương cao với nhau. Nhưng chúng ta thực hiện kiểm tra chéo k lớp thì
những ước lượng (kết quả) thu được từ k mô hình sẽ ít tương quan với nhau hơn do bộ dữ liệu huấn
luyện là khác biệt hơn. Điều này dẫn đến, chẳng hạn, các MSE thu được từ LOOCV có xu hướng biến
động hơn so với sử dụng kiểm tra chéo k lớp. Nếu chúng ta chọn MSE là tiêu chí đánh giá chất lương
của mô hình thì giá trị kì vọng của MSE có thể được phân thành ba bộ phận sau:

E[MSE]= σ2 + (Bias của mô hình)2 + (Variance của mô hình)

Ở đây bộ phận thứ nhất σ2 được gọi là nhiễu không thể loại trừ (irreducible noise) với ý nghĩa rằng
chúng ta không thể loại bỏ nhiễu này dù sử dụng mô hình nào đi chăng nữa. Bộ phận thứ hai phản
ánh mức độ chính xác về mối quan hệ giữa biến độc lập và biến phụ thuộc. Bộ phận cuối cùng phản
ánh mức độ sai lệch của mô hình ứng với các bộ dữ liệu khác nhau. Rõ ràng, để nâng cao chất lượng
của mô hình chúng ta sẽ tìm kiếm một mô hình, một phương pháp mà tối thiểu hóa cả hai bộ phận
của MSE của phương trình trên.

Với các phương pháp tái chọn mẫu, các nghiên cứu lý thuyết và thực nghiệm đã chỉ ra rằng k tối ưu
để cân bằng giữa tính không chệch và ổn định là 5 (với mẫu lớn) hoặc 10 (nếu mẫu là nhỏ). Thực tế,
các phần mềm thống kê – kinh tế lượng nếu có chức năng kiểm định chéo thì thường mặc định k là 5
hoặc 10, chẳng hạn gói caret của R mặc định giá trị k là 5.

4.6.3 Giới thiệu về các phương pháp tái chọn mẫu bằng gói caret
Như đã thấy, việc thực hiện tra chéo LOOCV hay k lớp theo cách thức thủ công là nhàm chán và mất
thời gian gõ lệnh. R có rất nhiều gói cho phép thực hiện những công việc này một các tự động. Một
trong những gói rất mạnh là caret của Kuhn (2013) . Gói này không chỉ được sử dụng cho hầu hết các
phân tích kinh tế lượng thường thấy mà còn sử dụng cho Machine Learning (thực tế gói này được
Kuhn thiết kế với mục đích xây dựng các mô hình Machine Learning).

Trước hết chúng ta so sánh việc thực hiện OLS với gói caret bằng hàm train() và so sánh với sử dụng
hàm lm() mà chúng ta đã biết. Dữ liệu được sử dụng, để minh họa, chúng ta chọn chỉ 10 quan sát đầu
của bộ dữ liệu CPS1988. Mô hình hồi quy nghiên cứu là wage = β1 + β2education. Đánh giá tác động
của số năm đi học (education) lên mức lương (wage):
library(AER)
data(CPS1988)
dung <- CPS1988 %>% slice(1:10)
ols1 <- dung %>% lm(wage ~ education, data = .)
ols1 %>% summary()

##
## Call:
## lm(formula = wage ~ education, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -449.05 -246.57 -21.75 54.60 957.97
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


205

## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -107.57 608.80 -0.177 0.864
## education 56.67 52.53 1.079 0.312
##
## Residual standard error: 427.1 on 8 degrees of freedom
## Multiple R-squared: 0.127, Adjusted R-squared: 0.01788
## F-statistic: 1.164 on 1 and 8 DF, p-value: 0.3121

So sánh với thực hiện OLS bằng hàm train() của gói caret. Ý nghĩa của một số dòng lệnh khác được
giải thích sau:
library(caret)
set.seed(1709)
ctrl <- trainControl(method = "repeatedcv", number = 2, repeats = 1)
ols2 <- dung %>%
train(wage ~ education, method = "lm", trControl = ctrl, data = .)
ols2 %>% summary()

##
## Call:
## lm(formula = .outcome ~ ., data = dat)
##
## Residuals:
## Min 1Q Median 3Q Max
## -449.05 -246.57 -21.75 54.60 957.97
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -107.57 608.80 -0.177 0.864
## education 56.67 52.53 1.079 0.312
##
## Residual standard error: 427.1 on 8 degrees of freedom
## Multiple R-squared: 0.127, Adjusted R-squared: 0.01788
## F-statistic: 1.164 on 1 and 8 DF, p-value: 0.3121

Có thể thấy các hệ số hồi quy (cũng như tất cả các kết quả khác) thu được từ hai cách thức thực hiện
OLS là như nhau.

Dưới đây là một số giải thích về sử dụng gói caret cho thực hiện OLS. Trước khi thực hiện OLS chúng
ta đã ngầm chỉ thị cho caret thực hiện OLS đồng thời với kiểm tra chéo 2 lớp với hàm trainControl()
và được giải thích ngay sau đây:

 method = "repeatedcv" : lựa chọn này để thực hiện kiểm tra chéo k lớp có lặp lại.
 number = 2 : chỉ rõ số lớp là 2 (tức là k=2).
 repeats = 1 : chỉ rõ số lần lặp là 1.

Để hiểu ý nghĩa của các lựa chọn này chúng ta hãy xem đối tượng ols2:

ols2

Nguyễn Chí Dũng http://rpubs.com/chidungkt


206

## Linear Regression
##
## 10 samples
## 1 predictor
##
## No pre-processing
## Resampling: Cross-Validated (2 fold, repeated 1 times)
## Summary of sample sizes: 6, 4
## Resampling results:
##
## RMSE Rsquared
## 449.4058 0.09213921
##
## Tuning parameter 'intercept' was held constant at a value of TRUE

Kết quả được giải thích dưới đây. Với lựa chọn như trên thì số liệu được sử dụng cho chạy mô hình
(10 quan sát) sẽ được chia làm 2 phần dữ liệu nhỏ xấp xỉ bằng nhau. Trong tình huống của chúng ta
hai phần này có số lượng lần lượt là 6 và 4 và có thể thấy ở dòng Summary of sample sizes: 6, 4.

Phần thứ nhất (gọi là training1) gồm 6 quan sát sẽ được sử dụng để chạy một mô hình OLS con thứ
nhất (gọi là tom) và mức độ phù hợp của mô hình này được đánh giá thông qua RMSE và R2 với phần
dữ liệu còn lại là 4 quan sát (gọi là testing 1). Tiếp tục, phần dữ liệu con thứ hai gồm 4 quan sát (gọi
là training2) sẽ được sử dụng để chạy một mô hình OLS con thứ hai (gọi là ca) và mô hình thu được
sẽ tiếp tục được đánh giá thông qua RMSE và R2 với phần dữ liệu còn lại là 6 quan sát (gọi là testing2).

Vì k = 2 nên các bạn có thể thấy rằng training1 chính là testing2 và training2 chính là testing1 (chú ý
rằng điều này chỉ đúng khi k =2 mà thôi). Như vậy sẽ có hai giá trị RMSE, hai giá trị R2 tương ứng với
hai mô hình con này. Cần nhắc lại rằng các cặp RMSE và R2 này chính là sai sót kiểm định. Con số R2
= 0.092139 và RMSE = 449.4058 mà chúng ta thấy là trung bình của hai cặp giá trị R2 và RMSE.

Vì phần dữ liệu thứ nhất (6 quan sát) được lấy ra từ 10 quan sát ban đầu nên cơ bản chúng ta sẽ có
tổ hợp chập 6 của 10 cách lấy khác nhau và do đó kết quả thu được ở trên nó chỉ là một tình huống
cá biệt. Nếu không có lệnh gieo hạt set.seed(1709) thì kết của của bạn sẽ khác vì tính chất ngẫu
nhiên của việc chọn mẫu.

Điều này cũng có nghĩa là con số R2 = 0.092139 sẽ có thể không trùng với R2 = 0.127 của mô hình sử
dụng cả 10 dữ liệu khi bạn sử dụng lệnh summary(ols2).

Từ phân tích trên chúng ta cũng có thể thấy ngay rằng, chẳng hạn, tổng của hai bộ dữ liệu testing1 và
training1 phải trùng hợp với bộ dữ liệu tên dung có 10 quan sát ban đầu. Có thể kiếm tra lại nhận
định này bằng một số lệnh sau (không hiển thị kết quả):
total <- rbind(training1, testing1)
summary(total)

summary(dung)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


207

Chúng ta trở lại với các kết quả R2 = 0.092139 và RMSE = 449.4058 và phân tích kĩ hơn những con
số này đến từ đâu và bằng cách nào:
ols2$results

## intercept RMSE Rsquared RMSESD RsquaredSD


## 1 TRUE 449.4058 0.09213921 210.7423 0.1264615
ols2$resample

## RMSE Rsquared Resample


## 1 598.4231 0.18156100 Fold1.Rep1
## 2 300.3885 0.00271741 Fold2.Rep1

Kết quả trên nghĩa là RMSE và R2 của mô hình con thứ nhất lần lượt là 598.4231 và 0.181561, còn đối
với mô hình con thứ hai sẽ là 300.3885 và 0.00271741. Chúng ta có thể kiểm tra lại để thấy rằng trung
bình của các RMSE và R2 chính là 449.4058 và 0.09213921:
(598.4231 + 300.3885) / 2

## [1] 449.4058
(0.18156100 + 0.00271741) / 2

## [1] 0.09213921

Chúng ta cũng có thể tính toán thủ công, ví dụ, là R2 cho mô hình con thứ nhất như sau:
d1 <- ols2$control$index$Fold1.Rep1
training1 <- dung[d1,] # Mẫu huấn luyện thứ nhất.
testing1 <- dung[-d1,] # Mẫu kiểm định thứ nhất.
tom <- training1 %>% lm(wage ~ education, data = .)
dubao1 <- predict(tom, testing1)
Rsquared1 <- cor(dubao1, testing1$wage)^2
Rsquared1

## [1] 0.181561

Tính toán trực tiếp R2 cho mô hình con thứ 2 theo cách hoàn toàn tương tự (dù cách làm hơi khác):
d2 <- ols2$control$index$Fold2.Rep1
training2 <- dung[d2,]
testing2 <- dplyr::setdiff(dung, training2)
ca <- training2 %>% lm(wage ~ education, data = .)
dubao2 <- predict(ca, testing2)
Rsquared2 <- cor(dubao2, testing2$wage)^2
Rsquared2

## [1] 0.00271741

Đến đây các bạn có thể tò mò rằng tại sao chúng ta lại dùng những lệnh kiểu như ols2$results hay
d2 <- ols2$control$index$Fold2.Rep1. Đây chính là cách thức để khai thác thông tin từ đối tượng
có tên là ols2. Nó là một list, tạm hiểu như sau: ols2 bao gồm nhiều “đối tượng con” được hiển thị sau
dấu $ bằng câu lệnh sau (hiển thị một phần kết quả trong một danh sách rất dài) :

Nguyễn Chí Dũng http://rpubs.com/chidungkt


208

str(ols2)

## List of 23
## $ method : chr "lm"
## $ modelInfo :List of 13
## ..$ label : chr "Linear Regression"
## ..$ library : NULL
## ..$ loop : NULL
## ..$ type : chr "Regression"
## ..$ parameters:'data.frame': 1 obs. of 3 variables:

Quan sát thì các bạn có suy đoán rằng nếu gõ lệnh ols2$modelInfo$type sẽ cho ra chữ “Regression”.

Trong thực tế, chúng ta thường thực hiện kiểm tra chéo 5 hoặc 10 lớp với số lần lập lại đủ nhiều để
chúng ta có thể đánh giá chính xác hơn mô hình. Sử dụng toàn bộ các quan sát của bộ dữ liệu CPS1988
chúng ta có thể đánh giá nhiều khía cạch về chất lượng của mô hình OLS chứ không chỉ căn cứ vào,
chẳng hạn, R2 không thôi. Dưới đây chúng ta thực hiện OLS đồng thời với thực hiện đánh giá mô hình
với kiểm tra 10 lớp, lặp lại 10 lần. Nghĩa là chúng ta thực hiện tất cả 10*10 + 1 bằng 101 mô hình tất
cả. Cụ thể có 100 mô hình con và một mô hình chính sử dụng toàn bộ các quan sát. Do số quan sát là
rất lớn nên chúng ta nên biết thêm cần bao nhiêu thời gian để chạy các mô hình:

set.seed(29) # Sử dụng lệnh này để tái lập kết quả.


love <- trainControl(method = "repeatedcv", number = 10, repeats = 10)
system.time(all <- train(wage ~ education, method = "lm",
trControl = love, data = CPS1988))

## user system elapsed


## 5.96 0.05 6.09

Mất chừng 6 giây để chạy 101 mô hình. Một số tình huống chúng ta có thể mất hàng giờ và thậm chí
hàng chục giờ để chạy mô hình.

Chúng ta có thể trích xuất ra data frame và đặt tên là k chứa các thông tin về RMSE , R2 của 100 mô
hình con:
k <- all$resample
summary(k)

## RMSE Rsquared Resample


## Min. :360.8 Min. :0.05090 Length:100
## 1st Qu.:393.9 1st Qu.:0.08063 Class :character
## Median :410.0 Median :0.09969 Mode :character
## Mean :429.4 Mean :0.09498
## 3rd Qu.:456.2 3rd Qu.:0.10876
## Max. :599.3 Max. :0.13540

Các giá trị trung bình lần lượt là 429.4 và 0.09498. Những giá trị trung bình này có thể thấy bằng hai
cách khác nhau:

all$results # Cách 1.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


209

## intercept RMSE Rsquared RMSESD RsquaredSD


## 1 TRUE 429.4022 0.09497748 51.44891 0.01952883

all # Cách 2.

## Linear Regression
##
## 28155 samples
## 1 predictor
##
## No pre-processing
## Resampling: Cross-Validated (10 fold, repeated 10 times)
## Summary of sample sizes: 25339, 25340, 25339, 25339, 25339, 25340, ...
## Resampling results:
##
## RMSE Rsquared
## 429.4022 0.09497748
##
## Tuning parameter 'intercept' was held constant at a value of TRUE
##

Ở đây các bạn có thể thấy 100 bộ dữ liệu huấn luyện có kích thước lần lượt là 25339, 25340, 25339,
25339, 25339, 25340… Con số này chính là xấp xỉ 90% của 28155 quan sát ban đầu:
28155*0.9

## [1] 25339.5

Chúng ta có thể đánh giá, chẳng hạn, mức độ ổn định của mô hình một cách hình ảnh:
k %>%
select(-Resample) %>%
gather(Metric, Value) %>%
ggplot(aes(Metric, Value, fill = Metric)) +
geom_boxplot(show.legend = FALSE) + theme_minimal() +
facet_wrap(~ Metric, scales = "free")

Hoặc vừa hiển thị Histogram và Density:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


210

k %>%
select(-Resample) %>%
gather(Metric, Value) %>%
ggplot(aes(Value)) +
geom_density(color = "red", fill = "red", alpha = 0.3) +
geom_histogram(aes(y = ..density..), color = "blue", fill = "blue", alpha = 0.3
) +
facet_wrap(~ Metric, scales = "free")

Có thể thấy rằng một tỉ lệ lớn các mô hình con có RMSE thấp (tin tốt) vì Histogram (Density) bị méo
về phía dương. Tất nhiên chúng ta còn đánh giá mức độ ổn định của mô hình này căn cứ vào độ méo
nữa. Một mô hình tốt, ngoài RMSE thấp thì cần tiêu chí ổn định. Nghĩa là phân phối của các RMSE
càng tiến về phân phối chuẩn càng tốt. Nếu nhìn vào Boxplot thì tiêu chí này có nghĩa là median Q2
gần như nằm chính giữa của hộp. Tất nhiên trong tình huống của chúng ta thì không phải vậy.

4.7 Dữ liệu thiếu và xử lý dữ liệu thiếu trong phân tích kinh tế lượng

Trong các giáo trình thống kê – kinh tế lượng tiêu chuẩn, chúng ta chỉ gặp duy nhất một trường hợp
sau: không có quan sát nào thiếu. Tuy nhiên, trong thực tế, dữ liệu thiếu mới là trường hợp chúng gặp
thường xuyên hơn. Giả sử rằng biến luong và thunhapkhac (ở mục 2.1 của chương 2) thiếu ở các quan
sát thứ hai và cuối cùng. Lúc đó trong R chúng ta sẽ nhập dữ liệu thiếu bằng kí tự NA (viết tắt của Not
Available) như sau:

luong <- c(20, NA, 28, 24, 32, 36, 32, 34, 24, 22, 28, 30)
thunhapkhac <- c(16, 10, 2, 0, 18, 10, 16, 24, 28, 20, 8, NA)

6 quan sát đầu của trangxinh sẽ như sau:

head(trangxinh)

## luong thunhapkhac chitieu


## 1 20 16 24.4
## 2 NA 10 31.2
## 3 28 2 29.2
## 4 24 0 23.6

Nguyễn Chí Dũng http://rpubs.com/chidungkt


211

## 5 32 18 36.0
## 6 36 10 31.4

R sẽ không thực hiện bất kì tính toán nào nếu có số liệu thiếu. Ví dụ:

mean(luong)

## [1] NA

Lúc này, để tính toán trung bình luong chúng ta phải làm như sau:

mean(luong, na.rm = T)

## [1] 28.18182

Nghĩa là lựa chọn na.rm = T chỉ thị cho R loại bất kì quan sát thiếu nào nếu có trước khi tính trung
bình. Điều này cũng có nghĩa là con số 28.18182 ở trên là trung bình của 11 quan sát chứ không phải
12.

Các xử lý thông thường là nếu tỉ lệ số liệu thiếu không quá lớn, chúng ta sẽ bỏ đi những quan sát thiếu.
Dưới đây là câu lệnh bỏ quan sát thiếu (là 2) từ trangxinh và tạo ra data frame mới với tên gọi là dung:

dung <- na.omit(trangxinh)

Lúc này, các bạn sẽ thấy dung chỉ còn lại 10 quan sát mà thôi so với 12 quan sát ban đầu:

head(dung)

## luong thunhapkhac chitieu


## 1 20 16 24.4
## 3 28 2 29.2
## 4 24 0 23.6
## 5 32 18 36.0
## 6 36 10 31.4
## 7 32 16 32.6

dim(trangxinh)

## [1] 12 3

dim(dung)

## [1] 10 3

Cách xử lý số liệu như trên là không phù hợp và không chuyên nghiệp ngay cả trong tình huống dữ
liệu thiếu là không nhiều. Dưới đây là một ví dụ trực quan. Giả sử chúng ta khảo sát thông tin về 5
biến số a, b, c, d, và e thể hiện trạng thái sức khỏe của 5 bệnh nhân và dữ liệu thiếu (tô màu vàng) lại
xuất hiện trên một đường chéo theo kiểu như sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


212

Lúc này, nếu xử lý số liệu thiếu theo cách thức trên thì bạn sẽ không còn dữ liệu nào để thực hiện
phân tích nữa.

Ví dụ trên chỉ ra rằng chúng ta cần một chiến lược xử lý số liệu thiếu khoa học hơn. Ví dụ, chúng ta có
thể thay số điểm số liệu trống bằng trung bình của biến số. Gói mice của R có thể thực hiện cách thức
chèn số liệu thiếu (Data Imputation) theo một phương pháp tương tự với mô tả ở trên với tên là
khớp trung bình dự báo (predictive mean matching - PMM).

Để mình họa, chúng ta lấy bộ số liệu pima.csv bao gồm 768 quan sát ứng với 768 bệnh nhân. Vì một
lý do nào đó, thông tin về hàm lượng insulin trong máu của bệnh nhân thứ nhất chẳng hạn là không
có. Bộ số liệu của chúng ta sẽ là bộ số liệu thiếu như chúng ta có thể thấy dưới đây:

setwd("D:/KTLR")
dung <- read.csv("pima.csv")
head(dung)

## X pregnant glucose diastolic triceps insulin bmi diabetes age test


## 1 1 6 148 72 35 NA 33.6 0.627 50 1
## 2 2 1 85 66 29 NA 26.6 0.351 31 0
## 3 3 8 183 64 NA NA 23.3 0.672 32 1

Trước hết, chúng ta có thể điều tra “mật độ” của dữ liệu thiếu bằng cả phương pháp hình ảnh và số
với sự trợ giúp của gói VIM như sau:

library(VIM)
trangyeu<- aggr(dung, col=c('navyblue','yellow'),
numbers = TRUE, sortVars = TRUE, labels = names(dung),
cex.axis = .7, gap = 3, ylab = c("Du Lieu Thieu","Pattern"))

Nguyễn Chí Dũng http://rpubs.com/chidungkt


213

##
## Variables sorted by number of missings:
## Variable Count
## insulin 0.486979167
## triceps 0.295572917
## diastolic 0.045572917
## bmi 0.014322917
## glucose 0.006510417
## X 0.000000000
## pregnant 0.000000000
## diabetes 0.000000000
## age 0.000000000
## test 0.000000000

Nếu bức tranh của chúng ta càng nhiều đốm màu vàng thì có nghĩa là dữ liệu của chúng ta thiếu càng
nhiều. Cụ thể hơn bằng số thì biến insulin thiếu 48.69% (nhiều nhất), còn biến glucose là 0.65%.

Dưới đây là câu lệnh cho phép chúng ta chèn dữ liệu thiếu theo phương pháp PMM bằng gói mice:

library(mice)
apple <- mice(dung, m=2, method = "pmm", seed = 100)

##
## iter imp variable
## 1 1 glucose diastolic triceps insulin bmi
## 1 2 glucose diastolic triceps insulin bmi
## 2 1 glucose diastolic triceps insulin bmi

Câu lệnh trên có nghĩa là chúng ta tạo ra hai bộ số liệu khác nhau (m=2) từ bộ số liệu trống nguyên
bản bằng phương pháp predictive mean matching (method = “pmm”). Chúng ta có thể xem qua, chẳng
hạn, hai trong số ba bộ dữ liệu này:

data1 <- complete(apple, 1) # Bộ thứ nhất.


data2 <- complete(apple, 2) # Bộ thứ hai.
summary(data1)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


214

## X pregnant glucose diastolic


## Min. : 1.0 Min. : 0.000 Min. : 44.0 Min. : 24.00
## 1st Qu.:192.8 1st Qu.: 1.000 1st Qu.: 99.0 1st Qu.: 64.00
## Median :384.5 Median : 3.000 Median :117.0 Median : 72.00
## Mean :384.5 Mean : 3.845 Mean :121.6 Mean : 72.29
## 3rd Qu.:576.2 3rd Qu.: 6.000 3rd Qu.:140.2 3rd Qu.: 80.00
## Max. :768.0 Max. :17.000 Max. :199.0 Max. :122.00

Chúng ta cũng có thể thực hiện hai mô hình hồi quy ứng với hai bộ số liệu này và so sánh chúng các
kết quả tương ứng với nhau với sự hỗ trợ của gói stargazer:

ols1 <- lm(diabetes ~ bmi, data = data1)


ols2 <- lm(diabetes ~ bmi, data = data2)
library(stargazer)
stargazer(ols1, ols2, title = "So sánh OLS1 và OLS2", type = "text")

##
## So sánh OLS1 và OLS2
## ===========================================================
## Dependent variable:
## ----------------------------
## diabetes
## (1) (2)
## -----------------------------------------------------------
## bmi 0.007*** 0.008***
## (0.002) (0.002)
##
## Constant 0.239*** 0.228***
## (0.057) (0.056)
##
## -----------------------------------------------------------
## Observations 768 768
## R2 0.022 0.025
## Adjusted R2 0.021 0.024
## Residual Std. Error (df = 766) 0.328 0.327
## F Statistic (df = 1; 766) 17.631*** 19.581***
## ===========================================================
## Note: *p<0.1; **p<0.05; ***p<0.01

Chúng ta có thể thấy rằng các ước lượng thu được có khác biệt nhỏ. Hai kết quả hồi quy ứng với hai
bộ số liệu khác nhau này có thể thu được theo một cách thức khác (không hiển thị kết quả) :

fit <- with(data = apple, exp = lm(diabetes ~ bmi))


summary(fit)

Rõ ràng, chúng ta cần một kết quả tổng hợp. Chúng ta có thể sử dụng hàm pool() để thu được kết quả
tổng hợp này:

tonghop <- pool(fit)


tonghop

Nguyễn Chí Dũng http://rpubs.com/chidungkt


215

## Call: pool(object = fit)


##
## Pooled coefficients:
## (Intercept) bmi
## 0.233344387 0.007357831
##
## Fraction of information about the coefficients missing due to nonresponse:
## (Intercept) bmi
## 0.03074234 0.03424035

Ở đây kết quả cuối cùng của được hiển thị ở dòng Pooled coefficients. Chúng ta có thể thấy rằng hệ số
chặn có giá trị là 0.23334487. Con số này chính bằng trung bình cộng các hệ số chặn thu được từ thực
hiện hồi quy hai bộ dữ liệu con:

(0.238760 + 0.227929) / 2

## [1] 0.2333445

Trên đây chúng ta vừa nghiên cứu việc xử lý số liệu thiếu theo một cách thức đơn giản nhất. Trong
thực tế, để xử lý số liệu thiếu người ta thường phải tìm hiểu kĩ nguyên nhân tại sao số liệu bị thiếu,
cũng như các đặc điểm thống kê của biến số bị thiếu để từ đó đưa ra phương pháp chèn số liệu thiếu
một cách phù hợp. Rõ ràng chúng ta không thể điền số 0 vào biến insulin cho bệnh nhân thứ nhất vì
không có cơ thể sống nào có hàm lượng insulin là 0 được. Chúng ta cũng nên, và trong nhiều trường
hợp là không thể loại chúng ra khỏi mẫu. Điền giá trị trống này bằng bao nhiêu hiện là một thách thức
của khoa học thống kê về cả khía cạnh lý thuyết cũng như thực hành.

Trong phạm vi của tài liệu này, thì trình bày cách thức xử lý số liệu thiếu một cách bài bản là không
thể, cũng như không thể bao tất cả những phương pháp phù hợp vốn rất nhạy cảm với từng tình
huống khác nhau. Bạn đọc quan tâm có thể tìm đọc cuốn sách cơ bản “Flexible Imputation of Missing
Data” của Stef van Buuren. Cuốn này sử dụng R nên các bạn sẽ không phải mất nhiều thời gian để
thực hành.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


216

Nguyễn Chí Dũng http://rpubs.com/chidungkt


217

Chương 5: Mở rộng mô hình hồi quy hai biến số

Chương này chúng ta sẽ nghiên cứu các những trường hợp mở rộng của hồi quy hai biến số. Những mô
hình được nghiên cứu là hồi quy qua gốc tọa độ (regression through the origin), các mô hình logarit
và (log-linear model ) bán logarit (semilog models) và một số mô hình khác. Bên cạnh đó chúng ta cũng
nghiên cứu hồi quy chuẩn hóa (reggression on standardized variables), sự thay đổi đơn vị đo của biến
số (units of measurement) cũng như dạng hàm (functional form) của mô hình tuyến tính.

5.1 Hồi quy qua gốc tọa độ - mô hình CAPM


Hồi quy qua gốc tọa độ còn gọi là hồi quy không có hệ số chặn là mô hình có dạng sau:

𝑌𝑖 = 𝛽2 𝑋𝑖 + 𝑢𝑖 (1)
Một ví dụ điển hình của hồi quy qua gốc tọa độ là mô hình định giá tài sản vốn CAPM (Capital Asset
Pricing Model) phổ biến trong nghiên cứu tài chính:

(ER 𝑖 − 𝑟𝑓 ) = 𝛽𝑖 (ER m − 𝑟𝑓 ) (2)


Ở đây ERi là lợi tức của một chứng khoán (một mã cổ phiếu), ERm là lợi tức của danh mục đầu tư thị
trường (thường là một chỉ số chứng khoán, chẳng hạn chỉ số VN Index) còn rf là lãi suất phi rủi ro, hệ
số β (đọc là beta) đo lường rủi ro hệ thống (systematic risk) của tài sản – là rủi ro mà không thể loại
bỏ bằng đa dạng hóa danh mục đầu tư. Nếu hệ số này lớn hơn một thì chứng khoán được nói là năng
động (aggressive), nếu hệ số này bé hơn một thì chứng khoán là thụ động (defensive).

Nếu thị trường tài chính là vận hành hiệu quả thì người ta nói rằng phần bù rủi ro kì vọng của chứng
khoán (expected risk premium) đo bằng (ERi - rf ) sẽ bằng tích của hệ số beta nhân với phần bù rủi
ro thị trường (ERm - rf ) và được gọi là lợi nhuận thị trường. Đường thẳng biểu diễn mối quan hệ này
được gọi là đường thị trường chứng khoán (security market line):

Nguyễn Chí Dũng http://rpubs.com/chidungkt


218

Với các nghiên cứu thực chứng trong tài chính, mô hình (2) thường được biểu diễn ở hai dạng sau:

𝑅𝑖 − 𝑟𝑓 = 𝛽𝑖 (𝑅𝑚 − 𝑟𝑓 ) + 𝑢𝑖 (3)

𝑅𝑖 − 𝑟𝑓 = 𝛼𝑖 + 𝛽𝑖 (𝑅𝑚 − 𝑟𝑓 ) + 𝑢𝑖 (4)

Mô hình (4) còn có tên gọi là mô hình thị trường (Market Model). Nếu CAPM là đúng thì αi được kì
vọng là bằng 0.

Cần lưu ý là hệ số R2 của hồi quy qua gốc tọa độ sẽ có thể là một con số âm và không có ý nghĩa trong
việc diễn giải sức mạnh giải thích của mô hình. Thay vì sử dụng công thức truyền thống, hệ số này của
hồi quy qua gốc tọa độ được gọi là r2 thô (raw r2) hay chỉ kí hiệu chỉ là r2 để phân biệt với R2 như ở
một số tài liệu và được tính theo công thức sau:

(∑ 𝑋𝑖 𝑌𝑖 )2
raw 𝑟 2 =
∑ 𝑋𝑖2 ∑ 𝑌𝑖2
Mặc dù r2 tính theo công thức này thỏa mãn 0 ≤ r2 ≤ 1 nhưng chúng ta cũng không thể so sánh một
cách trực tiếp r2 này với R2 được. Khi thực hiện hồi quy qua gốc tọa độ, hầu hết phần mềm (bao gồm
R) sẽ báo cáo r2 này.

Bởi vì những đặc điểm cá biệt này của mô hình chúng ta cần đặc biệt chú ý và thận trọng khi sử dụng
mô hình hồi quy không có hệ số chặn. Trừ khi chúng ta có kì vọng tiên nghiệm (priori expectation)
rất mạnh rằng hệ số chặn là bằng không, chúng ta nên đánh giá mô hình CAPM theo mô hình (4) chứ
không phải (3) và thực hiện các kiểm định cần thiết để chỉ ra rằng hệ số chặn là không có ý nghĩa
thống kê – tức là có thể bỏ hệ số chặn bằng 0 về mặt thống kê (statistically equal to zero).

Chúng ta xét bộ số liệu table6_1.xls trong đó biến X là phần bù rủi ro kì vọng (thể hiện lợi tức trội
hơn so với thị trường) của Afuture còn Y là phần bù rủi ro thị trường (hay lợi nhuận thị trường) từ
năm 1971 đến 1980:

setwd("D:/KTLR")
library(gdata)
dung <- read.xls("table6_1.xls")
head(dung)

## year Y X
## 1 1971 67.5 19.5
## 2 1972 19.2 8.5
## 3 1973 -35.2 -29.3
## 4 1974 -42.0 -26.5
## 5 1975 63.7 61.9
## 6 1976 19.3 45.5

Nếu chúng ta có kì vọng tiên nghiệm mạnh rằng hệ số chặn ở (4) là không tồn tại thì chúng ta có thể
thực hiện hồi quy qua gốc tọa độ:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


219

ols1 <- lm(Y ~ 0 + X, data = dung)


summary(ols1)

##
## Call:
## lm(formula = Y ~ 0 + X, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -30.291 -6.007 -0.720 4.484 46.247
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## X 1.0899 0.1916 5.69 0.000298 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 19.54 on 9 degrees of freedom
## Multiple R-squared: 0.7825, Adjusted R-squared: 0.7583
## F-statistic: 32.38 on 1 and 9 DF, p-value: 0.0002981

Có thể thấy hệ số beta β = 1.089 là lớn hơn 1, hay cổ phiếu của Afuture là năng động. Trong tài chính
kết quả này được diễn giải như sau: khi lợi nhuận thị trường tăng 1% thì lợi nhuận của Afuture sẽ
tăng 1.089%.

Nếu chúng ta không có bằng chứng tiên nghiệm trước rằng hệ số chặn bằng không, chúng ta nên sử
dụng (4) – tức là sử dụng mô hình thị trường để đánh giá mối liên hệ giữa lợi nhuận của Afuture và
lợi nhuận thị trường:

ols2 <- lm(Y ~ X, data = dung)


summary(ols2)

##
## Call:
## lm(formula = Y ~ X, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -30.623 -7.166 -1.237 3.585 45.373
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.2797 7.6886 0.166 0.87194
## X 1.0691 0.2383 4.486 0.00204 **
## ---

Nguyễn Chí Dũng http://rpubs.com/chidungkt


220

## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 20.69 on 8 degrees of freedom
## Multiple R-squared: 0.7155, Adjusted R-squared: 0.68
## F-statistic: 20.12 on 1 and 8 DF, p-value: 0.00204

Do p-value của hệ số chặn là 0.872 > 5% nên chúng ta chưa có bằng chứng thống kê để bắc bỏ giả
thiết rằng hệ số chặn bằng 0. Cần lưu ý là chúng ta không thể so sánh R2 = 71.55% ở đây với r2 =
78.25% ở trên với nhau được.

5.2 Vấn đề thay đổi đơn vị của biến


Việc thay đổi đơn vị đo của biến số phải chăng làm thay đổi ý nghĩa và bản chất kinh tế khi diễn giải
các kết quả thu được? Câu trả lời là không như chúng ta thấy ngay sau đây với bộ số liệu về tổng đầu
tư của khu vực tư GPD (gross private domestic investment) và tổng sản lượng GDP lưu ở
table6_2.xls. Chúng ta xét hai biến số này với cả hai đơn vị đo là tỉ (GDPB, GPDBL) và triệu (GDPM,
DPDIM):

trang <- read.xls("table6_2.xls")


View(trang)

Đánh giá sự phụ thuôc của GPD theo GDP theo những đơn vị đo khác nhau ta có:

summary(lm(GPDIBL ~ GDPB, data = trang)) # Đơn vị của GPD và GDP là tỉ.

##
## Call:
## lm(formula = GPDIBL ~ GDPB, data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -68.84 -31.82 -4.01 32.47 85.86

Nguyễn Chí Dũng http://rpubs.com/chidungkt


221

##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1026.4980 257.5874 -3.99 0.004 **
## GDPB 0.3016 0.0399 7.56 0.000066 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 54.5 on 8 degrees of freedom
## Multiple R-squared: 0.877, Adjusted R-squared: 0.862
## F-statistic: 57.1 on 1 and 8 DF, p-value: 0.0000656

summary(lm(GPDIM ~ GDPM, data = trang)) # Đơn vị của GPD và GDP là triệu.

##
## Call:
## lm(formula = GPDIM ~ GDPM, data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -68843 -31816 -4008 32471 85856
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1026497.9900 257587.4037 -3.99 0.004 **
## GDPM 0.3016 0.0399 7.56 0.000066 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 54500 on 8 degrees of freedom
## Multiple R-squared: 0.877, Adjusted R-squared: 0.862
## F-statistic: 57.1 on 1 and 8 DF, p-value: 0.0000656

Rõ ràng với các đơn vị đo khác nhau (cùng là tỉ hoặc cùng là triệu) thì các kết quả ước lượng là không
có gì thay đổi. Cụ thể, khi GDP tăng 1 (tỉ hoặc triệu) thì GPD tăng 0.3016 (tỉ hoặc triệu).

Nghĩa là, ý nghĩa và bản chất kinh tế về mối liên hệ giữa các biến số là không thay đổi. Và điều này còn
đúng trong những trường hợp chúng ta sử dụng đơn vị đo theo một kiểu khác như có thể thấy dưới
đây (không hiển thị kết quả):

# Đơn vị của GPD là triệu, của GDP là tỉ


summary(lm(GPDIM ~ GDPB, data = trang))
# Đơn vị của GPD là tỉ, của GDP là triệu
summary(lm(GPDIBL ~ GDPM, data = trang))

Nguyễn Chí Dũng http://rpubs.com/chidungkt


222

5.3 Hồi quy chuẩn hóa


Để thực hiện hồi quy chuẩn hóa, chẳng hạn, Y theo X trước hết chúng ta cần chuẩn hóa các biến số
này theo công thức sau:

𝑌𝑖 − 𝑌̅
𝑌𝑖∗ =
𝑆𝑌
𝑋𝑖 − 𝑋̅
𝑋𝑖∗ =
𝑆𝑋
Ở đây biến được chuẩn hóa có kí hiệu * ở trên đầu. Công thức này có nghĩa là để chuẩn hóa, ví dụ,
với biến Y thì chúng ta lấy các quan sát của Y trừ đo trung bình của nó được bao nhiêu chia cho độ
lệch chuẩn của Y (kí hiệu SY).

Trong R, với bộ số liệu được sử dụng ở mục 5.2, thực hiện hồi quy chuẩn hóa được thực hiện như
sau:

summary(lm(scale(GPDIBL) ~ scale(GDPB), data = trang))

##
## Call:
## lm(formula = scale(GPDIBL) ~ scale(GDPB), data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.4696 -0.2170 -0.0273 0.2215 0.5857
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.96e-16 1.18e-01 0.00 1
## scale(GDPB) 9.37e-01 1.24e-01 7.56 0.000066 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.372 on 8 degrees of freedom
## Multiple R-squared: 0.877, Adjusted R-squared: 0.862
## F-statistic: 57.1 on 1 and 8 DF, p-value: 0.0000656

Điểm đáng chú ý mà chúng ta có thể thấy ở đây là khi thực hiện hồi quy chuẩn hóa có hệ số chặn, thì
hệ số chặn luôn bằng 0 và p-value của nó luôn bằng 1. Nghĩa là hồi quy chuẩn hóa, dù ta tuyên bố rõ
ràng có sự xuất hiện của hệ số chặn thì kết quả luôn tương đương với hồi quy qua gốc tọa độ như
chúng ta có thể thấy dưới đây:

options(scipen = 10) # Định dạng cách kiểu hiển thị số.


options(digits = 6) # Định dạng hiểu thị số với 6 chữ số sau dấu phẩy.
summary(lm(scale(GPDIBL) ~ 0 + scale(GDPB), data = trang))

Nguyễn Chí Dũng http://rpubs.com/chidungkt


223

##
## Call:
## lm(formula = scale(GPDIBL) ~ 0 + scale(GDPB), data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.4696 -0.2170 -0.0273 0.2215 0.5857
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## scale(GDPB) 0.937 0.117 8.02 0.000022 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.35 on 9 degrees of freedom
## Multiple R-squared: 0.877, Adjusted R-squared: 0.864
## F-statistic: 64.3 on 1 and 9 DF, p-value: 0.0000218

5.4 Dạng hàm của mô hình hồi quy


Mục này chúng ta sẽ xét một số dạng hàm hay gặp trong phân tích kinh tế dưới đây:

 Mô hình logarit tuyến tính (log-linear model)


 Mô hình bán logarit (semilog model)
 Mô hình xu hướng tuyến tính (linear trend model)
 Mô hình tuyến tính – logarit (lin – log model)
 Mô hình nghịch đảo (reciprocal model)
 Mô hình đa thức (polyniminal model).

5.4.1 Mô hình logarit tuyến tính


Ví dụ điển hình cho mô hình dạng này là hàm sản xuất Cobb – Douglas trong đó sản lượng Q phụ
thuộc lao động L và vốn K theo phương trình:

Q = aLαKβ

Với a là một hằng số dương. Lấy ln (logarit tự nhiên) hai vế của phương trình trên ta có:

ln(Q) = ψ + αln(L) + βln(K)

Trong đó ψ = ln(a).

Trong kinh tế lượng, hàm sản xuất Cobb – Douglas sẽ được viết ở dạng:

ln(Qi) = ψ + αln(Li) + βln(Ki) + ui (5)

Nếu α + β = 1 thì chúng ta có hàm sản xuất có lợi tức không đổi theo quy mô. Nếu tổng này lớn hơn
1 thì chúng ta có hàm sản xuất có lợi tức giảm dần theo quy mô (và ngược lại) và thường được
đánh giá qua các mô hình kinh tế lượng thực nghiệm.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


224

Đặc điểm đáng chú ý của (5) là các hệ số ước lượng có thể thể coi như là những hệ số co giãn
(elasticities). Cụ thể, α là hệ số co giãn của sản lượng theo lao động còn β là hệ số co giãn của sản
lượng theo vốn khi tất cả cá yếu tố khác không đổi.

Để minh họa úng ta xét dữ liệu có tên Table2_1.xls gồm các thông tin về sản lượng (output), lao động
(labor) và vốn (capital) của 50 bang và khu vực hành chính đặc biệt Washington DC trong năm 2005
và thực hiện ước lượng mô hình (5):

dung <- read.xls("Table2_1.xls")


logatt <- lm(log(output) ~ log(labor) + log(capital), data = dung)
summary(logatt)

##
## Call:
## lm(formula = log(output) ~ log(labor) + log(capital), data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.4564 -0.1211 -0.0532 0.0452 1.2158
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.8876 0.3962 9.81 0.00000000000047 ***
## log(labor) 0.4683 0.0989 4.73 0.00001980879662 ***
## log(capital) 0.5213 0.0969 5.38 0.00000218315931 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.267 on 48 degrees of freedom
## Multiple R-squared: 0.964, Adjusted R-squared: 0.963
## F-statistic: 646 on 2 and 48 DF, p-value: <2e-16

Kết quả này chỉ ra rằng R2 = 96.4% - một con số cao bất thường đối với dữ liệu chéo. Các kết quả
khác còn lại được diễn giải như sau:

 Khi tăng lao động lên 1% thì sản lượng sẽ tăng 0.4683%.
 Khi tăng vốn lên 1% thì sản lượng tăng 0.5212%.
 Hàm sản xuất Dobb- Douglas thu từ mô hình thực nghiệm là Q = 48.79L0.4683K0.5212 .

Ở đây chúng ta thấy rằng α + β = 0.9896 ngụ ý rằng rất có thể hàm sản xuất là lợi tức không đổi theo
quy mô. Nếu α + β thực sự bằng 1 thì α = 1- β và phương trình (5) bằng biến đổi đại số sẽ trở thành:

ln(Qi/Li) = ψ + βln(Ki/Li) + ei (6)

Mô hình (6) gọi là mô hình bị giới hạn (Restricted Model) còn (5) gọi là mô hình không bị giới hạn
(Unrestricted Model). Chúng ta thực hiện ước lượng mô hình (6):

Nguyễn Chí Dũng http://rpubs.com/chidungkt


225

love <- lm(log(output / labor) ~ log(capital / labor), data = dung)


summary(love) # Table 2.4.
## Call:
## lm(formula = log(output/labor) ~ log(capital/labor), data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.4364 -0.1247 -0.0508 0.0436 1.2307
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.7562 0.1854 20.26 < 2e-16 ***
## log(capital/labor) 0.5238 0.0958 5.47 0.0000015 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.264 on 49 degrees of freedom
## Multiple R-squared: 0.379, Adjusted R-squared: 0.366
## F-statistic: 29.9 on 1 and 49 DF, p-value: 0.00000154

Mô hình này có nghĩa là nếu tỉ số vốn chia cho lao động tăng 1% thì sản lượng tăng 0.5238%. Chú ý
rằng R2 = 37.9% không thể so sánh được với R2 = 96.4% ở mô hình (5).

Để đánh giá xem α + β có bằng 1 hay không chúng ta sử dụng kiểm định F được tính theo công thức
sau:

(𝑅𝑆𝑆𝑅 − 𝑅𝑆𝑆𝑈𝑅 )/𝑚


𝐹= ~𝐹𝑚,(𝑛−𝑘) (7)
𝑅𝑆𝑆𝑈𝑅 /(𝑛 − 𝑘)
Trong đó RSSR và RSSUR lần lượt là tổng bình phương phần dư (RSS) của mô hình giới hạn và không
bị giới hạn, m là số biến độc lập mà mô hình bị giới hạn ít hơn mô hình giới hạn, k là số lượng biến
có ở mô hình không giới hạn (tính cả biến phụ thuộc) còn n là số quan sát.

Thống kê F tính theo công thức (7) sẽ tuân theo quy luật χ2 với số bật tự do lần lượt là m và n – k.
Nếu F tính theo công thức (7) mà lớn hơn giá trị tới hạn ở ngưỡng được chọn trước thì chúng ta bắc
bỏ giả thiết α + β = 1. Dưới đây chúng ta sẽ thực hiện kiểm định F đã mô tả:

RSS_u <- sum((logatt$fitted.values - log(dung$output))^2) # Tính RSSUR


RSS_r <- sum((love$fitted.values - log(dung$output / dung$labor))^2) # RSSR
Fqs=((RSS_r - RSS_u) / 1) / (RSS_u / (51 - 3))
f <- qf(0.95, df1 = 1, df2 = 51 - 3)
print(paste(Fqs,f))

## [1] "0.14140646378643 4.04265212856665"

Có thể thấy Fqs = 0.14 < 4.04 ở ngưỡng 5% nên chúng ta có chưa có bằng chứng để bắc bỏ giả thiết
rằng α + β = 1.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


226

Chúng ta có thể thực hiện kiểm định α + β = 1 theo cách khác sử dụng lệnh linearHypothesis() của
gói AER:

library(AER)
linearHypothesis(logatt, "log(labor) + log(capital) = 1") # Cách 1

## Linear hypothesis test


##
## Hypothesis:
## log(labor) + log(capital) = 1
##
## Model 1: restricted model
## Model 2: log(output) ~ log(labor) + log(capital)
##
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 49 3.426
## 2 48 3.416 1 0.01006 0.141 0.709

Do p-value = 0.709 > 5% nên chúng ta chưa có bằng chứng thống kê bắc bỏ giả thiết α + β = 1. Chúng
ta sẽ nghiên cứu kĩ hơn kiểm định sự ràng buộc giữa các hệ số hồi quy trong chương sau.

5.4.2 Mô hình bán logarit


Chúng ta xét mô hình tăng trưởng của GDP thực (kí hiệu là RGDP) của Mĩ từ năm 1960 đến 2007
như sau:

RGDPt = RGDP1960(1+r)t (8)

Trong đó r là tốc độ tăng trưởng, t là thời gian (trong 48 năm) từ năm 1960 đến 2007. Lấy ln hai vế
của (8) ta có:

ln(RGDP) = b1 + b2t (9)

Với b1 = ln(RGDP1960) và b2= ln(1+r).

Thực hiện ước lượng (9) với bộ số liệu Table2_5.xls trong R:

dung <- read.xls("Table2_5.xls")


ahi <- lm(log(rgdp)~time,data=dung)
summary(ahi)

##
## Call:
## lm(formula = log(rgdp) ~ time, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.09088 -0.01843 0.00526 0.02307 0.05946
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


227

## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 7.875662 0.009759 807.0 <2e-16 ***
## time 0.031490 0.000347 90.8 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.0333 on 46 degrees of freedom
## Multiple R-squared: 0.994, Adjusted R-squared: 0.994
## F-statistic: 8.25e+03 on 1 and 46 DF, p-value: <2e-16

Nghĩa là GDP của Mĩ tăng trưởng với tốc độ chừng 3.149% hàng năm. Chúng ta có thể minh họa tốc
độ tăng trưởng của ln(rgdp) theo thời gian:

library(ggplot2)
ggplot(dung, aes(time, log(rgdp))) + geom_line() + geom_point(col = "red")

Một vấn đề là vai trò của chọn trục thời gian t. Như ta thấy bộ số liệu gốc chọn time = 1 ứng với năm
1960, time = 48 ứng với 2007:

View(dung)

Tuy nhiên chúng ta có thể chọn lại các biểu diễn thời gian như sau mà không ảnh hưởng đến kết quả
ước ước lượng: chọn biến mới T từ 1960 đến 2007:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


228

dung$T = 1960:2007 # Tạo biến mới T từ 1960 đến 2007.


View(dung)

Kết quả hồi quy theo kiểu biến mới T:

loveyou <- lm(log(rgdp) ~ T, data = dung)


summary(loveyou)

##
## Call:
## lm(formula = log(rgdp) ~ T, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.090879 -0.018426 0.005258 0.023067 0.059459
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -5.381e+01 6.878e-01 -78.24 <2e-16 ***
## T 3.149e-02 3.467e-04 90.82 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.03328 on 46 degrees of freedom
## Multiple R-squared: 0.9945, Adjusted R-squared: 0.9943
## F-statistic: 8248 on 1 and 46 DF, p-value: < 2.2e-16

Ngoại trừ hệ số chặn, tất cả các kết quả khác là không khác nhau. Nguyên nhân là, chẳng hạn, ước
lượng rgdp cho năm 1960 ứng với hai kiểu biến khác nhau lần lượt sẽ là:

 exp(7.8756624+0.0314896*1) : cho mô hình sử dụng kiểu biến time.


 exp(-53.81+0.0314896*1960) : Cho mô hình sử dụng kiểu biến T.

Tuy nhiên kết quả của ước lượng rgdp (và tất cả các kết quả khác) vẫn không đổi. Thực vậy, chúng ta
có thể tính rgdp ước lượng cho cả hai tình huống và thấy chúng chính là một:

exp(predict(ahi, dung))

Nguyễn Chí Dũng http://rpubs.com/chidungkt


229

## 1 2 3 4 5 6 7
## 2716.642 2803.549 2893.236 2985.793 3081.310 3179.883 3281.609

exp(predict(loveyou, dung))

## 1 2 3 4 5 6 7
## 2716.642 2803.549 2893.236 2985.793 3081.310 3179.883 3281.609

Tất nhiên kế quả chẳng có thay đổi nếu chúng ta thay T bằng dãy số từ -1 đến -48. Việc tạo biến thời
gian là tùy ý nhưng chúng ta nên chọn sao cho thuận tiện với các phân tích và diễn giải nếu cần. Chẳng
hạn bài tập 3.9 (chương 2) cuốn giáo trình kinh tế lượng của tác giả Nguyễn Thành Cả và Nguyễn
Thị Ngọc Miên từ UEH có yêu cầu sinh viên đặt biến t bắt đầu từ 0 cho bộ số liệu gdp.xls sẽ gây khó
sinh viên và làm méo mó mô hình vì khi thực hiện mô hình có ln(t) thì giá trị ln0 sẽ không xác định.
Và như vậy khi thực hiện trong Eviews hay Stata thì các phần mềm này mặc định bỏ đi một quan sát.

5.4.3 Mô hình xu hướng tuyến tính


Chúng ta sẽ xét bộ số liệu gdp.xls được miêu tả ở 5.4.2 ở trên. Đây là bộ số liệu về tăng trưởng GDP
theo 52 quý của Việt Nam từ quý 1 năm 2000 đến quý 4 năm 2012:

dung <- read.xls("gdp.xls")


View(dung)

Chúng ta xét mô hình xu hướng tuyến tính sau:

R_GDP = β1 + β2T (10)

Trong đó T là biến biểu diễn quý theo trình tự thời gian. Như đã phân tích ở mục trên, chúng ta không
nên chọn T bắt đầu từ 0 mà nên lấy T từ 1 trở đi (vì sau này còn có mô hình sử dụng biến lnT nữa) và
thực hiện ước lượng (10) trong R:

dung$T = 1:52
summary(lm(R_GDP ~ T, data = dung))

##
## Call:
## lm(formula = R_GDP ~ T, data = dung)
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


230

## Residuals:
## Min 1Q Median 3Q Max
## -36616 -4533 3220 9444 31939
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 57915.5 4496.7 12.88 <2e-16 ***
## T 1888.5 147.7 12.79 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 15980 on 50 degrees of freedom
## Multiple R-squared: 0.7659, Adjusted R-squared: 0.7612
## F-statistic: 163.6 on 1 and 50 DF, p-value: < 2.2e-16

Kết quả này chỉ ra rằng cứ một năm GDP của Việt Nam sẽ tăng một lượng tuyệt đối là 1888.5 (không
rõ đơn vị là gì vì hai tác giả này không nói). Chúng ta cũng có thể đánh giá hình ảnh về tăng trưởng
theo thời gian:

ggplot(dung, aes(T, R_GDP)) + geom_line() + geom_point(col = "red")

Dễ dàng thấy rằng tăng trưởng kinh tế của Việt Nam có tính chu kì. Cụ thể, so với các quý còn lại GDP
là cao nhất trong quý 4 và tuân theo quy luật từ quý 1 đến quý 2 thì tăng, rồi lại giảm, rồi lại tăng.
Kiểm định chính thức cho tính chất chu kì này chúng ta sẽ nghiên cứu ở các chương sau.

Cũng có thể tạo ra các hình ảnh động (interactive graph) như sau:

k <-ggplot(dung, aes(T, R_GDP)) + geom_line() + geom_point(col = "red")


library(plotly)
ggplotly(k)

5.4.4 Mô hình tuyến tính – logarit


Để minh họa cho mô hình này chúng ta xét bộ số liệu có tên TienLuong(Chuong3).xls từ cuốn sách
giáo trình kinh tế lượng của UEH:

dung <- read.xls("TienLuong(Chuong3).xls")


View(dung)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


231

Mô hình tuyến tính – logarit, trong tình huống với bộ số liệu này, là mô hình kiểu như sau:

TienLuong = α + βLKN (11)

Trong đó, biến LNK là logarit cơ số tự nhiên của KinhNghiem. Nhưng, trước khi lấy logarit chúng ta
phải đánh giá khoảng giá trị của KinhNghiem vì rằng phép lấy logarit không tồn tại nếu có giá trị bé
hơn hoặc bằng 0. Sử dụng lệnh range() ta có:

range(dung$KinhNghiem) # Tìm khoảng giá trị của biến KinhNghiem.

## [1] 0 46

Như vậy kinh nghiệm có giá trị từ 0 đến 46. Dưới đây là lệnh chỉ thị cho R: (1) chỉ lấy các quan sát
mà biến KinhNghiem dương, (2) tạo biến mới LKN, và (3) thực hiện hồi quy cho mô hình (11):

dung <- subset(dung, dung$KinhNghiem > 0) # Những quan sát có KinhNghiem > 0.
dung$LKN <- log(dung$KinhNghiem) # Tạo biến LNK = ln(KinhNghiem)
summary(lm(TienLuong ~ LKN, data = dung))

##
## Call:
## lm(formula = TienLuong ~ LKN, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -4.8794 -0.9070 0.2159 0.8715 2.6079
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 7.89542 0.22239 35.503 < 2e-16 ***
## LKN 0.33301 0.08366 3.981 9.15e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.354 on 236 degrees of freedom
## Multiple R-squared: 0.06292, Adjusted R-squared: 0.05895
## F-statistic: 15.85 on 1 and 236 DF, p-value: 9.154e-05

Chúng ta có thể vẽ đường hồi quy cho mô hình với khoảng tin cậy 95% :

ggplot(dung, aes(LKN, TienLuong)) + geom_point() + geom_smooth(method = "lm")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


232

Ý nghĩa của các ước lượng thu được là nếu kinh nghiệm tăng lên 1% thì mức lương sẽ tăng
0.33301/100 = 0.003331 (%). 1% của một năm chừng 3.65 ngày hay xấp xỉ 3 ngày 16 tiếng. Nói cách
khác, kinh nghiệm làm việc tăng 3 ngày 16 tiếng thì mức lương tăng 0.003331 (%). Cho nên, mô hình
này có thể sẽ diễn đạt hơn nếu thay đổi đơn vị của biến kinh nghiêm từ năm sang tuần hoặc ngày.

5.4.5 Mô hình nghịch đảo


Xét bộ số liệu Table2_8.xls chứa các thông tin về tổng chi tiêu (biến expend) và chi chi tiêu cho thực
phẩm và đồ uống không gồm đồ uống có cồn (biến fdho) của 869 hộ gia đình Hoa Kì trong năm 1995:

library(readxl)
dung <- read_excel("Table2_8.xls")

Với bộ số liệu này, mô hình nghịch đảo sẽ có dạng:

fdho = a + b(1/expend) (12)

Ở mô hình này, biến độc lập là nghịch đảo của tổng chi tiêu. Thực hiện ước lượng mô hình này chúng
ta có:

summary(lm(sfdho ~ I(expend^-1), data = dung))

##
## Call:
## lm(formula = sfdho ~ I(expend^-1), data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.2989 -0.0421 -0.0112 0.0323 0.4461
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.07726 0.00401 19.3 <2e-16 ***
## I(expend^-1) 1331.33806 63.95713 20.8 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Nguyễn Chí Dũng http://rpubs.com/chidungkt


233

##
## Residual standard error: 0.0697 on 867 degrees of freedom
## Multiple R-squared: 0.333, Adjusted R-squared: 0.332
## F-statistic: 433 on 1 and 867 DF, p-value: <2e-16

Hệ số của b có ý nghĩa thống kê và dương ngụ ý rằng khi tổng chi tiêu hộ gia đình tăng lên thì mức chi
cho thực phẩm sẽ giảm đi. Chúng ta cũng có thể vẽ đường hồi quy cho mô hình với khoảng tin cậy
95% cho các ước lượng:

theme_set(theme_minimal())
dung %>%
ggplot(aes(x = expend, y = sfdho)) +
geom_point(alpha = 0.3) +
geom_smooth(formular = y ~ 1/x, method = "loess")

5.4.6 Mô hình đa thức


Trở lại với bộ số liệu được sử dụng ở mục 5.4.3. Mô hình đa thức là mô hình có dạng sau:

R_GDP = a + bT + cT2 (13)

Ước lượng mô hình này trong R:

summary(lm(R_GDP ~ T + I(T^2), data = dung))

##
## Call:
## lm(formula = R_GDP ~ T + I(T^2), data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -40137 -5080 1458 8630 26614
##
## Coefficients:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


234

## Estimate Std. Error t value Pr(>|t|)


## (Intercept) 63892.47 6891.26 9.272 2.33e-12 ***
## T 1224.38 599.86 2.041 0.0466 *
## I(T^2) 12.53 10.97 1.142 0.2590
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 15930 on 49 degrees of freedom
## Multiple R-squared: 0.772, Adjusted R-squared: 0.7627
## F-statistic: 82.94 on 2 and 49 DF, p-value: < 2.2e-16

Nếu như mô hình (10) ở mục 5.4.3 nói rằng khi t tăng 1 (quý) thì GDP tăng 1888.5 và con số này là
không đổi bất kể ở quý nào thì kết quả ước lượng ở mô hình (13) có nghĩa hoàn toàn khác. Thực vậy,
lấy đạo hàm hai vế của (13) ta có:

𝑑(𝑅𝐺𝐷𝑃 )
= 𝑏 + 2𝑐𝑇 = 1124.38 + 25.06𝑇
𝑑𝑇
Điều này có nghĩa là mức tăng trưởng theo quý sẽ không phải là một con số không đổi cho tất cả các
quý mà là phụ thuộc vào mốc thời gian được chọn và là một hàm của thời gian T.

Có hai điểm chúng ta cần chú ý đối với mô hình đa thức. Thứ nhất, đây là mô hình tuyến tính tham số
chứ không phải tuyến tính dạng hàm. Thứ hai, sử dụng mô hình đa thức sẽ tồn tại nguy cơ đa cộng
tuyến ở mức cao vì, chẳng hạn, biến T và T2 thường tương quan rất chặt với nhau.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


235

Chương 6: Mô hình hồi quy bội

Mục tiêu của chương này là hướng dẫn các thao tác thực hành trong R cho mô hình hồi quy bội, kiểm
định Wald về sự ràng buộc của các hệ số hồi quy, ước lượng khoảng cho một hệ thức của hệ số hồi quy.

6.1 Thực hiện hồi quy bội trong R và khoảng tin cậy cho các hệ số
Từ mục 6.1 đến 6.3 chúng ta sẽ nghiên cứu bộ số liệu ch2vd5.WF1. Tôi mặc định rằng các bạn đã biết
cách chỉ thị cho R đọc file Eviews này thành một data.frame với tên gọi dung. Giả sử chúng ta đánh
giá tác động của thu nhập (TN) và tài sản (TS) lên chi tiêu (CT) bằng mô hình sau:

CT = β1 + β2TN. + β3TS. + ui (1)

Uớc lượng mô hình này trong R:

setwd("D:/KTLR")
library(hexView)
dung <- readEViews("ch2vd5.WF1", as.data.frame = TRUE)
hoiquyboi <- lm(data = dung, CT ~ TN + TS)
summary(hoiquyboi)

##
## Call:
## lm(formula = CT ~ TN + TS, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -16.026 -10.504 0.373 5.784 32.274
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 18.860180 8.832144 2.135 0.041010 *
## TN 0.791224 0.015991 49.481 < 2e-16 ***
## TS 0.015818 0.003984 3.970 0.000414 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 12.27 on 30 degrees of freedom
## Multiple R-squared: 0.9995, Adjusted R-squared: 0.9995
## F-statistic: 3.296e+04 on 2 and 30 DF, p-value: < 2.2e-16

Khoảng tin cậy của hệ số hồi quy, ví dụ, của 𝛽2 được tính theo công thức:

𝛽̂2 − 𝑡𝛼/2 𝑠𝑒(𝛽̂2 ) ≤ 𝛽2 ≤ 𝛽̂2 + 𝑡𝛼/2 𝑠𝑒(𝛽̂2 )

Nguyễn Chí Dũng http://rpubs.com/chidungkt


236

Tất nhiên chúng ta có thể áp dụng công thức này cho các hệ số beta khác. Với α = 5% chúng ta có thể
tính khoảng tin cậy 95% cho cả ba hệ số hồi quy:

confint(hoiquyboi)

## 2.5 % 97.5 %
## (Intercept) 0.822534473 36.89782483
## TN 0.758567036 0.82388141
## TS 0.007681386 0.02395467

R sẽ mặc định tính khoảng tin cậy 95% như lệnh chúng ta vừa thực hiện. Nếu muốn tìm khoảng tin
cậy 99% cho các hệ số (không hiển thị kết quả):

confint(hoiquyboi, level = 0.99)

6.2 Khoảng tin cậy cho một biểu thức của hệ số hồi quy
Khoảng tin cậy cho, chẳng hạn, biểu thức (aβ2 + bβ3) được tính theo công thức sau:

(𝑎𝛽̂2 + 𝑏𝛽̂3 ) − 𝑡𝛼/2 𝑠𝑒(𝑎𝛽̂2 + 𝑏𝛽̂3 ) ≤ 𝑎𝛽2 + 𝑏𝛽3 ≤ (𝑎𝛽̂2 + 𝑏𝛽̂3 ) + 𝑡𝛼/2 𝑠𝑒(𝑎𝛽̂2 + 𝑏𝛽̂3 )
Trong đó:

se(𝑎𝛽̂2 + 𝑏𝛽̂3 ) = √𝑎2 var(𝛽̂2 ) + 𝑏 2 var(𝛽̂3 ) − 2𝑎𝑏cov(𝛽̂2 , 𝛽̂3 )

Với mô hình OLS thu được, giả sử cần tìm khoảng tin cậy 95% cho (−𝛽̂2 + 10𝛽̂3 ). Trước hết tìm
các giá trị của var(𝛽̂2 ), var(𝛽̂3 ), và cov(𝛽̂2 , 𝛽̂3 ):

vcov(hoiquyboi)

## (Intercept) TN TS
## (Intercept) 78.00677420 7.375351e-02 -2.395591e-02
## TN 0.07375351 2.556997e-04 -6.231694e-05
## TS -0.02395591 -6.231694e-05 1.587315e-05

Sau đó thực hiện một loạt các lệnh:

se<-sqrt(0.00025569967637 + 100*0.00001587315149 + 20*0.00006231694374)


cd<-((-0.79122422 + 10*0.01581803) - abs(qt(0.025, 30))*se)
ct<-((-0.79122422 + 10*0.01581803) + abs(qt(0.025, 30))*se)
cd

## [1] -0.7465574

ct

## [1] -0.5195304

Nguyễn Chí Dũng http://rpubs.com/chidungkt


237

Như vậy khoảng tin cậy 95% cho (−𝛽̂2 + 10𝛽̂3 ) là (-0.746; -0.519).

6.3 Kiểm định Wald về sự ràng buộc của các hệ số hồi quy
Kiểm định Wald về sự ràng buộc của các hệ số hồi quy áp dụng cho cặp giả thuyết H0: mβ2 + nβ3 = p;
H1: mβ2 + nβ3 # p trong đó m, n, và p là các số thực.

Chúng ta có thể kiểm tra giả thuyết rằng β2 =50β3 (tức là m=1, n = -50, p=0) như sau:

library(AER)
linearHypothesis(hoiquyboi, "TN = 50*TS")

## Linear hypothesis test


##
## Hypothesis:
## TN - 50 TS = 0
##
## Model 1: restricted model
## Model 2: CT ~ TN + TS
##
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 31 4520.3
## 2 30 4520.3 1 0.00033997 0 0.9988

Giá trị Pr(>F) = 0.998 > 5% nên chúng ta có bằng chứng thống kê để chấp nhận giả thuyết gốc.

Chúng ta có thể kiểm tra giả thuyết rằng β2 =25β3 +0.4 (tức là m=1, n = -25, p=0.4) như sau:

linearHypothesis(hoiquyboi, "TN = 25*TS + 0.4")

## Linear hypothesis test


##
## Hypothesis:
## TN - 25 TS = 0.4
##
## Model 1: restricted model
## Model 2: CT ~ TN + TS
##
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 31 4520.5
## 2 30 4520.3 1 0.20249 0.0013 0.971

Giá trị Pr(>F) = 0.971 > 5% nên chúng ta có bằng chứng thống kê để chấp nhận giả thuyết gốc.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


238

6.4 Kiểm định F về việc đồng thời bằng không của nhiều hệ số hồi quy
Đây là nhóm các kiểm định cho cặp giả thuyết dạng H0: β2i + β2j = 0; H1: β2i + β2j # 0. Chúng ta sử dụng
kiểm định F cho những tình huống như vậy.

Từ mục 5.4 trở đi chúng ta sẽ sử dụng bộ số liệu ch5bt10.WF1. Chúng ta chỉ thị cho R đọc file dữ liệu
dưới dạng một data.frame với tên dung. Chúng ta xét mô hình sau:

WAGE = β1 + β2EDUC. + β3MEDUC. + β4SSIBS. + ui (2)

Giả sử chúng ta muốn kiểm định cặp giả thuyết H0: β23 + β24 = 0; H1: β23 + β24 # 0. Nếu giả thuyết Ho
đúng thì mô hình (2) trở thành:

WAGE = β1 + β2EDUC. + wi (3)

Lúc này mô hình (2) gọi là mô hình không bị giới hạn (Unrestricted Model) còn mô hình (3) gọi là mô
hình bị giới hạn (Restricted Model). Để thực hiện kiểm định F chúng ta làm theo ba bước sau.

Bước thứ nhất chạy cả hai mô hình (2) và (3) nhằm thu được R2ur và R2r trong đó R2ur và R2r lần lượt
là R2 của mô hình (2) và (3).

Bước thứ hai chúng ta tính thống kê F theo công thức sau:
2
(𝑅𝑢𝑟 − 𝑅𝑟2 )/𝑚
𝐹= 2 )/(𝑛 − 𝑘)
(1 − 𝑅𝑢𝑟
Trong đó m là số biến bị bỏ ở mô hình (3) so với mô hình (2), n là số quan sát, k là số biến số trong
mô hình không bị giới hạn. Trong tình huống của chúng ta thì n = 32, m=2, k = 4, α = 5% (mặc định),
còn Rur và Rr lần lượt là R2 của mô hình không bị và bị giới hạn.

Bước cuối cùng chúng ta so sánh thống kê F tính ở bước thứ hai với Fα(m,n-k). Nếu F > Fα(m,n-k) thì
chúng ta có bằng chứng thống kê bắc bỏ Ho, nếu không chúng ta có bằng chứng thống kê chấp nhận
H1.

Chúng ta tuân theo ba bước này thực hiện kiểm định này trong R như sau (chỉ hiển thị phần kết quả
chứa R2):

dung <- readEViews("D:/KTLR/ch5bt10.WF1 ", as.data.frame = TRUE)


luong <- lm(data = dung, WAGE ~ EDUC + MEDUC + SSIBS)
summary(luong)
## Residual standard error: 361 on 28 degrees of freedom
## Multiple R-squared: 0.1687, Adjusted R-squared: 0.07965
## F-statistic: 1.894 on 3 and 28 DF, p-value: 0.1535

luonggh <- lm(data=dung,WAGE~EDUC)


summary(luonggh)
## Residual standard error: 354.5 on 30 degrees of freedom
## Multiple R-squared: 0.1412, Adjusted R-squared: 0.1126
## F-statistic: 4.933 on 1 and 30 DF, p-value: 0.03405

Nguyễn Chí Dũng http://rpubs.com/chidungkt


239

Ta tính thống kê F:

((0.1687 - 0.1412) / 2) / ((1 - 0.1687) / (32 - 4))

## [1] 0.46313

Kế tiếp tính F0.05(2,28-4) :

qf(0.95, df1 = 2, df2 = 32 - 4)

## [1] 3.340386

Do 0.463 < 3.340 nên chúng ta chưa có bằng chứng thống kê để bắc bỏ H0.

Chúng ta có thể tính kiểm định F cách khác trong R nhanh hơn và chắc chắn không gặp sai sót như
sau:

anova(luonggh, luong)

## Analysis of Variance Table


##
## Model 1: WAGE ~ EDUC
## Model 2: WAGE ~ EDUC + MEDUC + SSIBS
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 30 3770332
## 2 28 3649563 2 120769 0.4633 0.634

Chúng ta vẫn thu được F = 0.463 như ở trên. Và cách này cũng không cần bạn phải tìm F0.05(2,28-4) mà
chỉ cần so sánh Pr(>F) = 0.634 với 5%. Do Pr(>F) = 0.634 > 5% nên chúng ta chưa có bằng chứng
thống kê bắc bỏ Ho.

Chúng ta có thể sử dụng kiểm định Wald trong tình huống này:

linearHypothesis(luong, c("MEDUC = 0", "SSIBS =0"))

## Linear hypothesis test


## Hypothesis:
## MEDUC = 0
## SSIBS = 0
## Model 1: restricted model
## Model 2: WAGE ~ EDUC + MEDUC + SSIBS
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 30 3770332
## 2 28 3649563 2 120769 0.4633 0.634

Chúng ta cũng có thể tính thống kê F thông qua RSS(R) và RSS(U) của mô hình bị giới hạn và không
bị giới hạn theo công đã biết ở mục 5.4.1:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


240

(𝑅𝑆𝑆𝑅 − 𝑅𝑆𝑆𝑈𝑅 )/𝑚


𝐹= ~𝐹𝑚,(𝑛−𝑘)
𝑅𝑆𝑆𝑈𝑅 /(𝑛 − 𝑘)
Trước hết ta cần tính các RSS:

anova(luong)

## Analysis of Variance Table


##
## Response: WAGE
## Df Sum Sq Mean Sq F value Pr(>F)
## EDUC 1 619924 619924 4.7562 0.03775 *
## MEDUC 1 43067 43067 0.3304 0.57000
## SSIBS 1 77702 77702 0.5961 0.44652
## Residuals 28 3649563 130342
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

anova(luonggh)

## Analysis of Variance Table


##
## Response: WAGE
## Df Sum Sq Mean Sq F value Pr(>F)
## EDUC 1 619924 619924 4.9326 0.03405 *
## Residuals 30 3770332 125678
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Thay số RSS(R) = 3770332, RSS(U) = 3649563, k =4, n = 32 ta cũng có F = 0.463.

6.5 Mối liên hệ hình chữ U ngược giữa giáo dục và mức lương
Trong kinh tế học lao động người ta thường quan tâm đến mô hình sau về tác động của giáo dục
(EDUC) lên logarit cơ số tự nhiên của lương (lnWAGE):

lnWAGE = β1 + β2EDUC. + β3EDUC2. + β4MEDUC. + β5SSIBS. + ui (3)

Các lý thuyết của kinh tế học lao động chỉ ra rằng β3 < 0, β2 > 0 đồng thời hai hệ số hồi quy này phải
có ý nghĩa thống kê với ngụ ý về mối quan hệ hình chữ U ngược giữa EDUC và ln(WAGE). Nghĩa là,
ban đầu số năm học tăng dẫn đến mức lương cũng tăng. Nhưng khi năm học đạt một ngưỡng nào đó,
tác động của số năm đi học lên mức lương lại ngược lại. Nói cách khác, vượt qua ngưỡng này thì mức
lương tuân theo quy luật cận biên giảm dần so với số năm đi học.

Trong R chúng ta thực hiện ước lượng cho (3) như sau:

lnluong <- lm(data = dung, log(WAGE) ~ EDUC + I(EDUC^2) + MEDUC + SSIBS)


summary(lnluong)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


241

##
## Call:
## lm(formula = log(WAGE) ~ EDUC + I(EDUC^2) + MEDUC + SSIBS, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.25091 -0.10462 0.05347 0.07849 0.15292
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 8.335686 0.822291 10.137 1.06e-10 ***
## EDUC -0.049861 0.122870 -0.406 0.688
## I(EDUC^2) 0.002788 0.004501 0.620 0.541
## MEDUC -0.004551 0.006258 -0.727 0.473
## SSIBS -0.011027 0.012458 -0.885 0.384
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1147 on 27 degrees of freedom
## Multiple R-squared: 0.1711, Adjusted R-squared: 0.04835
## F-statistic: 1.394 on 4 and 27 DF, p-value: 0.2626

Ở đây các bạn chú ý phải gõ I(EDUC^2) để tạo biến mới EDUC2 trong R. Kết quả cho thấy rằng hệ số
của EDUC2 là dương – ngược lại những phát biểu của kinh tế học lao động. Nguyên nhân có thể là mô
hình còn thiếu một số biến số quan trọng. Chúng ta sẽ nghiên cứu vấn đề này ở các chương sau.

6.6 hồi quy chuẩn hóa và vấn đề so sánh tác động của các biến độc lập
Một câu hỏi đặt ra là, ví dụ với mô hình hồi quy ở mục 6.1, là so sánh mức độ ảnh hưởng (hay tác
động) của các biến độc lập lên biến phụ thuộc. Có thể thấy mức chênh lệch giữa hệ số hồi quy của biến
TN và TS là 50 (0.791224 so với 0.015818) nên thường đưa ra kết luận sai trái rằng tác động của thu
nhập lên biến CT mạnh gấp 50 lần so với tác động của biên TS lên CT. Để so sánh đúng vai trò, mức
độ ảnh hưởng của các biến độc lập lên biến phụ thuộc chúng ta phải sử dụng hồi quy chuẩn hóa
(Gujarati & Porter, 2009). Với tình huống ở mục 6.1, thực hiện hồi quy chuẩn hóa trong R:

summary(lm(scale(CT) ~ scale(TN) + scale(TS), data = dung))

##
## Call:
## lm(formula = scale(CT) ~ scale(TN) + scale(TS), data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.02876 -0.01885 0.00067 0.01038 0.05791
##
## Coefficients:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


242

## Estimate Std. Error t value Pr(>|t|)


## (Intercept) 1.930e-16 3.834e-03 0.00 1.000000
## scale(TN) 9.269e-01 1.873e-02 49.48 < 2e-16 ***
## scale(TS) 7.437e-02 1.873e-02 3.97 0.000414 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.02203 on 30 degrees of freedom
## Multiple R-squared: 0.9995, Adjusted R-squared: 0.9995
## F-statistic: 3.296e+04 on 2 and 30 DF, p-value: < 2.2e-16

0.92690 / 0.07437

## [1] 12.46336

Căn cứ vào hệ số hồi quy chuẩn hóa, có thể thấy tác động của biến TN so với tác động của biến TS lên
CT thực tế là chừng 12.5 lần. Để hiểu rõ hơn kết luận này chúng ta cần đọc được ý nghĩa của hệ số hồi
quy chuẩn hóa. Cụ thể ở đây, ví dụ, căn cứ vào hệ số hồi quy chuẩn hóa của TN có thể nói khi TN tăng
1 sai số chuẩn (a standard deviation increase) thì CT tăng 0.9269.

Nhắc lại rằng trong hồi quy chuẩn hóa, hệ số chặn luôn bằng 0 với Pr(>|t|) luôn bằng 1. Cũng cần chú
ý rằng các tiêu chí đánh giá mô hình như các giá trị Pr(>|t|) (trừ hệ số chặn), R2 hay thống kê F đều
không thay đổi. Vì hồi quy chuẩn hóa thực chất là hồi quy không có hệ số chặn nên có thể thu được
kết quả trên theo một cách khác như sau (không hiển thị kết quả):

summary(lm(scale(CT) ~ 0 + scale(TN) + scale(TS), data = dung))

6.7 Kiểm định LM, LR trong trường hợp kích cỡ mẫu là lớn
Nếu phần dư là phân phối chuẩn thì các thống kê t và F được sử dụng với mọi kích thước mẫu. Tuy
nhiên, nếu phần dư không tuân theo quy luật chuẩn thì thống kê t và F sẽ không tuân theo quy luật
Student, Fisher với kích thước mẫu là bé do vậy sử dụng thống kê t và F có thể không áp dụng được
trong tình huống này. Nhưng nếu kích thước mẫu là lớn thì chúng ta có thể sử dụng thống kê t và F
bất kể phần dư có phân phối chuẩn hay không.

Với kích thước mẫu là lớn, ngoài việc sử dụng thống kê F như đã được trình bày ở các mục trên chúng
ta có thể sử dụng: (1) Wald Test, (2) Likelihood Ratio Test, và (3) Lagrange Multiplier Test. Ba kiểm
định này không những sử dụng được cho các mô hình tuyến tính mà còn được sử dụng cho các mô
hình phi tuyến tính.

Để đảm bảo vấn đề kích cỡ mẫu là lớn, trong mục này chúng ta sử dụng bộ dữ liệu ch4bt8.wf1 với
935 quan sát. Con số này trong các nghiên cứu định lượng thực tế thì vẫn chưa được coi là lớn tuy
nhiên với mục đích minh họa chúng ta tạm sử dụng bộ dữ liệu này. Chúng ta nhập bộ dữ liệu này vào
R như sau:

trang <- readEViews("D:/KTLR/ch4bt8.wf1", as.data.frame = TRUE)


attach(trang)

Chúng ta nghiên cứu hai mô hình sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


243

WAGE = β1 + β2EDUC. + β3EXPER. + β4FEDUC. + β5MEDUC. + β6IQ. + ui (mô hình 1)

WAGE = γ1 + γ2EDUC. + γ3EXPER. . + γ4IQ. + ei (mô hình 2)

Để thực hiện Likelihood Ratio Test (LR Test) trước hết chúng ta cài đặt và sử dụng package có tên
lmtest bằng cách gõ install.packages(“lmtest”) tại cửa sổ lệnh của R. Sau đó chúng ta thực hiện ước
lượng cho hai mô hình trên như sau:

mohinh1 <- lm(data = trang, WAGE ~ EDUC + EXPER + FEDUC + MEDUC + IQ)
mohinh2 <- lm(data = trang, WAGE ~ EDUC + EXPER + IQ)

Thực hiện LR Test trong R:

lrtest(mohinh1, mohinh2)

## Likelihood ratio test


##
## Model 1: WAGE ~ EDUC + EXPER + FEDUC + MEDUC + IQ
## Model 2: WAGE ~ EDUC + EXPER + IQ
## #Df LogLik Df Chisq Pr(>Chisq)
## 1 7 -6849.9
## 2 5 -6855.7 -2 11.697 0.002884 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Chúng ta thấy giá trị của Pr(>Chisq) = 0.00288 < 5% (tương ứng với χ2qs = 11.697) nên chúng ta có
bằng chứng thống kê để bắc bỏ giả thiết rằng hai hệ số của FEDUC và MEDUC đồng thời bằng 0.

Chúng ta có thể tính trực tiếp LR Test bằng cách sử dụng thống kê λ (Gujarati & Porter, 2009) mà
không cần sử dụng package lmtest. Giá trị λ được tính theo công thức sau:

λ= 2(ULLF – RLLF) (4)

Trong đó ULLF và RLLF lần lượt là giá trị Log Likehood của mô hình không giới hạn (mô hình 1) và
mô hình bị giới hạn (mô hình 2). Với n đủ lớn thì thống kê λ tuân theo phân phối χ2 với số bậc tự do
bằng số biến bị loại khỏi mô hình 1. Trong một số phần mềm như Eviews, khi chạy các mô hình hồi
quy thì nó luôn hiển thị ULLF và RLLF. Trong R chúng ta có thể gọi giá trị ULLF như sau:

logLik(mohinh1)

## 'log Lik.' -6849.9 (df=7)

Làm tương tự để tìm RLLF:

logLik(mohinh2)

## 'log Lik.' -6855.749 (df=5)

Thay vào công thức (4) chúng ta tính ngay trong R như sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


244

LRtest <- 2*(-6849.9003 + 6855.7489)


LRtest

## [1] 11.6972

Giá trị 11.6972 này chính là giá trị ở cột Chisq. Bước cuối cùng là chúng ta cần so sánh λ = 11.6972
này với χ20.95 với số bậc tự do trùng với số biến bị loại bỏ ở mô hình 2 (hay df = 2). Chúng ta tính hai
giá trị này trong R:

qchisq(0.95, 2)

## [1] 5.991465

Do giá trị 11.6972 > 5.99 nên λ thuộc miền bắc bỏ. Nghĩa là chúng ta có bằng chứng thống kê để bắc
bỏ giả thiết rằng hai hệ số hồi quy của FEDUC và MEDUC đồng thời bằng 0.

Chú ý rằng các nhà kinh tế lượng – thống kê đã chứng minh rằng (4) có thể viết lại như sau:

-2ln(λ)= n[ln(RRSS) – ln(RLLF)] (5)

Trong đó RRSS và URSS lần lượt là tổng phần dư bình phương của mô hình 2 (mô hình bị giới hạn) và
mô hình 1 (mô hình không bị giới hạn) còn n là số quan sát. Nếu chúng ta sử dụng (5) để tính toán thì
chúng ta cũng rút ra cùng một kết luận mà không cần biết các giá trị Log Likehood của các mô hình.

Người ta cũng chứng minh được hai thống kê Wald (Wald Test) và Lagrange Multiplier (LM Test)
tuân theo phân phối χ2 như sau:

(𝑛 − 𝑘)(RRSS − URSS)
Wald Statistic (W) = ~ χ2𝑟
URSS
(𝑛 − 𝑘 + 𝑟)(RRSS − URSS)
Lagrange Multiplier Statistic (LM) = ~ χ2𝑟
RRSS
Trong đó k là số biến số độc lập trong mô hình không bị giới hạn còn r là số biến số bị loại bỏ từ mô
hình bị giới hạn, n là số quan sát.

Người ta cũng chỉ ra mối liên hệ giữa ba kiểm định (hay ba thống kê) này là:

W ≥ LR ≥ LM (8)
Nghĩa là khi n lớn đến vô cùng thì ba thống kê này hội tụ về cùng một giá trị. Nói cách khác, với n là
bé thì một giả thuyết có thể bị bắc bỏ bởi kiểm định Wald nhưng không bị bắc bỏ bởi kiểm định LM.
Chúng ta có thể tính trực tiếp kiểm định (thống kê) Wald theo như (6) sau:

phandu1 <- residuals(mohinh1)


URSS <- sum(phandu1^2)
phandu2 <- residuals(mohinh2)
RRSS <- sum(phandu2^2)
kiemdinhw <- (930 / URSS)*(RRSS - URSS)
kiemdinhw

Nguyễn Chí Dũng http://rpubs.com/chidungkt


245

## [1] 11.70765

Giá trị của thống kê Wald = 11.7076 cao hơn không đáng kể so với λ = 11.6972 mà chúng ta đã tính ở
trên. Ngoài ra 11.7076 > χ20.95;2 = 5.99 nên chúng ta bắc bỏ giả thuyết rằng hai hệ số của FEDUC và
MEDUC đồng thời bằng 0.

Tương tự chúng ta có thể tính LM Test theo (7) như sau:

LM <- (932 / RRSS)*(RRSS - URSS)


LM

## [1] 11.58696

Tương tự ta cũng thấy 11.587 > χ20.95;2 = 5.99 nên chúng ta bắc bỏ giả thuyết rằng hai hệ số của FEDUC
và MEDUC đồng thời bằng 0.

Một lần nữa chúng ta có thể kiểm tra lại bất đẳng thức (8) về mối liên hệ giữa ba thống kê này với ngụ
ý rằng W là thống kê Wald, LR là thống kê λ, và LM là thống kê Lagrange Multiplier:

W = 11.76 > LR = 11.697 > LM = 11.587

Tất nhiên các bạn hoàn toàn có thể sử dụng kiểm định F như đã trình bày ở mục 5.4 của chương này.

6.8 Gợi ý trả lời một sô bài tập chương 2 thuộc cuốn giáo trình của NEU
Chúng ta sẽ trả lời một số khía cạnh lý thuyết, thực tiễn, cũng như thực hành trong R với các bài tập
từ 2.4 đến 2.6 (trang 120 và 131 sách giáo trình của NEU). Theo quan điểm cá nhân của tôi, nguồn
gốc số liệu đáng tin cũng như giải thích ở mức tối thiểu các biến là cần thiết cho nghiên cứu kinh tế
lượng. Rất tiếc sách của NEU nhiều bộ số liệu thì không có (nhưng sách vẫn nói có) lại còn không có
thông tin về dữ liệu. Vì lý do này, để trả lời cho câu hỏi của các bài tập từ 2.4 đến 2.6 chúng ta nghiên
cứu bộ số liệu hoàn toàn tương tự có tên WAGE1.DTA lấy từ sách của Wooldridge (2013).

Trước hết cần nhắc lại một lý thuyết khá phổ biến về quy luật cận biên giảm dần của số năm đi học
hoặc kinh nghiệm của kinh tế học lao động (Labour Economics). Theo lý thuyết này thì mức lương sẽ
tăng cùng với số năm đi học hoặc kinh nghiệm nhưng sau đó mối quan hệ này đổi chiều nếu số năm
đi học hoặc kinh nghiệm vượt một ngưỡng nào đó. Để kiểm định lý thuyết kinh tế này, chúng ta có
thể xét mô hình sau:

wage = β0 + β1exper + β2exper2 (mô hình 1)

Trong đó wage là mức lương của người lao động, exper là số năm kinh nghiệm. Nếu lý thuyết này là
đúng thì chúng ta kì vọng rằng hệ số hồi quy của exper là dương và hệ số hồi quy của exper2 là âm.
Chúng ta sử dụng bộ dữ liệu WAGE1.DTA để đánh giá mô hình này:

setwd("D:/KTLR")
library(haven)
trang <- read_stata("WAGE1.DTA")
names(trang)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


246

## [1] "wage" "educ" "exper" "tenure" "nonwhite" "female"


## [7] "married" "numdep" "smsa" "northcen" "south" "west"
## [13] "construc" "ndurman" "trcommpu" "trade" "services" "profserv"
## [19] "profocc" "clerocc" "servocc" "lwage" "expersq" "tenursq"

options(scipen = 3)
trang$exper2 <- trang$exper^2 # Tạo ra biến exper2 = exper*exper
qols <- lm(wage ~ exper + exper2, data = trang)
summary(qols)
## Call:
## lm(formula = wage ~ exper + exper2, data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -5.5916 -2.1440 -0.8603 1.1801 17.7649
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.7254058 0.3459392 10.769 < 2e-16 ***
## exper 0.2981001 0.0409655 7.277 1.26e-12 ***
## exper2 -0.0061299 0.0009025 -6.792 3.02e-11 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 3.524 on 523 degrees of freedom
## Multiple R-squared: 0.09277, Adjusted R-squared: 0.0893
## F-statistic: 26.74 on 2 and 523 DF, p-value: 8.774e-12

Căn cứ vào kết quả này chúng ta có thể dấu của các hệ số hồi quy là phù hợp với kì vọng và lại còn có
ý nghĩa thống kê. Chúng ta có thể biểu diễn đường cong hồi quy thu được như sau:

library(ggplot2)
ggplot(trang, aes(x = exper, y = wage)) +geom_point()
+ stat_smooth(method = "lm", formula = y ~ x + I(x^2), size = 1)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


247

Đến đây nhiều bạn có thể tự hài lòng vì những kết quả tốt đẹp này. Nhưng hãy khoan. Câu hỏi đặt ra
ở đây là mô hình thu được ở trên, dù phù hợp với lý thuyết mà kinh tế học lao động đề xuất nhưng
liệu nó có đúng trong thực tế? Thực vậy, nếu theo kêt quả thu được của mô hình thì những mức lương
sẽ tăng cùng với kinh nghiệm nhưng khi số năm kinh nghiệm này đến giới hạn 24.4 (con số này tìm
được bằng cách lấy giá trị tuyệt đối của 2β2/β1 ) thì mức lương của anh ta giảm. Liệu điều này có phù
hợp với thực tế?

Câu trả lời là không. Có thể rằng mức lương giảm cùng với số năm kinh nghiệm nhưng cái ngưỡng đó
phải lớn hơn con số 24.4. Thực vậy, cứ cho rằng bạn học NEU ra trường đúng hạn là 22 tuổi. Tại tuổi
46 (tức sau 24 năm đi làm) chính là phong độ cao nhất trong sự nghiệp kiếm tiền của bạn, chẳng có
lý do gì để tin rằng thu nhập của bạn từ độ tuổi 47 trở đi lại giảm. Một vấn đề nữa là chúng ta cần lưu
ý đến tỉ lệ khá lớn của những người có số năm kinh nghiệm lớn hơn ngưỡng 24.4. Dưới đây là những
câu lệnh tạo ra một biến mới có tên nkn (viết tắt của năm kinh nghiệm) trong đó gán nhãn A cho
những người có số năm kinh nghiệm bé hơn 24.4 và B cho những người còn lại.

# Tạo biến mới nkn và gán A cho nhóm có exper < 24.4 và >= 24.4:
trang <- trang %>% mutate(nkn = case_when(exper < 24.4 ~ "A",
exper >= 24.4 ~ "B"))
# Xem tỉ lệ của mỗi nhóm:
round(prop.table(table(trang$nkn)) * 100, digits = 2)

##
## A B
## 72.05 27.95

Như vậy, có thể thấy nhóm B chiếm tầm 28% - một tỉ lệ lớn. Con số này tương đương với 147 người
có số năm kinh nghiệm lớn hơn 24.4 và mức lương của anh ta đang giảm theo số năm kinh nghiệm.
Rõ ràng, để mô hình của chúng ta phù hợp với thực tế hơn, chúng ta cần điều chỉnh mô hình.

Một cách khác để mổ xẻ những kết quả thu được từ mô hình là xem tương quan giữa mức lương và
năm kinh nghiệm của từng nhóm. Câu lệnh dưới đây tạo ra hai data frame tương ứng với từng nhóm
và tính tương quan giữa hai biến số này:

nhomA <- trang %>% filter(nkn == "A")


cor(nhomA$wage, nhomA$exper)

## [1] 0.3063432

nhomB <- trang %>% filter(nkn != "A")


cor(nhomB$wage, nhomB$exper)

## [1] -0.2640143

Có thể thấy với nhóm A thì tương quan này là dương còn nhóm B thì ngược lại. Kết quả này, cũng như
kết hợp với kết quả hồi quy thu được tạo cơ sở cho chúng ta có thể đề xuất một cách tiếp cận khác để
nghiên cứu quy luật cận biên giảm dần của số năm kinh nghiệm:

wage = β0 + β1exper + β2nkn + β3nkn*exper (mô hình 2)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


248

Trong đó wage là mức lương của người lao động, exper là số năm còn nkn là biến giả. Cách tiếp cận
biến giả này được đề cập chi tiết ở chương 6. Kết quả hồi quy của mô hình này là:

love <- trang %>% lm(wage ~ exper + nkn + exper*nkn, data = .)


love %>% summary()

##
## Call:
## lm(formula = wage ~ exper + nkn + exper * nkn, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -5.5358 -2.0412 -0.9489 1.1095 17.6242
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.23791 0.31787 13.332 < 2e-16 ***
## exper 0.15585 0.02683 5.809 1.09e-08 ***
## nknB 7.75661 1.55560 4.986 8.39e-07 ***
## exper:nknB -0.31581 0.04960 -6.367 4.24e-10 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 3.536 on 522 degrees of freedom
## Multiple R-squared: 0.08846, Adjusted R-squared: 0.08322
## F-statistic: 16.89 on 3 and 522 DF, p-value: 1.758e-10

Kết quả này có nghĩa là với nhóm A thì mối liên hệ giữa năm kinh nghiệm và mức lương là wage =
4.238 +0.156exper còn đối với nhóm B là wage = (4.237 + 7.75)+(0.155 – 0.316)exper = 11.99 –
0.160exper. Chúng ta có thể vẽ đường hồi quy cho cả hai nhóm:

trang %>%
ggplot(aes(exper, wage, colour = nkn)) + geom_point() +
geom_smooth(method = "lm") + theme_minimal() +
theme(legend.position = "top")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


249

Phương trình hồi quy đối với hai nhóm ở trên chúng ta có thể có được bằng một cách khác:

ols1 <- nhomA %>% lm(wage ~ exper, data = .) # Chạy OLS cho nhóm A.
ols2 <- nhomB %>% lm(wage ~ exper, data = .) # Chạy OLS cho nhóm B.
library(stargazer)
stargazer(ols1, ols2,
title = "Mo Hinh Ung Voi Hai Nhom Kinh Nghiem", type = "text")

##
## Mo Hinh Ung Voi Hai Nhom Kinh Nghiem
## ===================================================================
## Dependent variable:
## -----------------------------------------------
## wage
## (1) (2)
## -------------------------------------------------------------------
## exper 0.156*** -0.160***
## (0.025) (0.049)
##
## Constant 4.238*** 11.995***
## (0.296) (1.771)
##
## -------------------------------------------------------------------
## Observations 379 147
## R2 0.094 0.070
## Adjusted R2 0.091 0.063
## Residual Std. Error 3.287 (df = 377) 4.113 (df = 145)
## F Statistic 39.044*** (df = 1; 377) 10.864*** (df = 1; 145)
## ===================================================================
## Note: *p<0.1; **p<0.05; ***p<0.01

Nguyễn Chí Dũng http://rpubs.com/chidungkt


250

Chúng ta thấy rằng, nếu chưa tính đến khía cạnh phù hợp thực tế hay không thì cả hai mô hình đề mô
tả cùng một thứ: khi exper bé hơn 22.4 thì wage tăng cùng exper nhưng vượt qua ngưỡng 22.4 này
thì quan hệ này đảo chiều. Một câu hỏi mới phát sinh là mô hình 1 có R2 = 0.093 cao hơn mô hình 2
có R2 = 0.088 (chừng 5% cao hơn) thì có nghĩa mô hình 1 tốt hơn?

Rõ ràng, để trả lời câu hỏi trên chúng ta so sánh trực tiếp bằng cách sử dụng tiêu chí R2 có thể chưa
phù hợp. Trong tình huống này chúng ta có thể sử dụng tiêu chí MSE để so sánh và đánh giá hai mô
hình. Chú ý rằng MSE được tính theo công thức đã biết sau:
𝑛
1 2
MSE = ∑(𝑌̂𝑖 − 𝑌𝑖 )
𝑛
𝑖=1

Từ công thức này chúng ta thấy một môt hình tốt là một mô hình có MSE thấp hơn so với mô hình
còn lại vì điều này có nghĩa là các giá trị dự báo của mô hình sát với giá trị thực tế hơn.

Dưới đây là các lệnh thực hiện so sánh hai mô hình dựa trên tiêu chí MSE:

library(Metrics) # Giả sử các bạn đã cài đặt gói này.


MSE1 <- mse(trang$wage, predict(qols, trang)) # Tính MSE1 của mô hình 1.
MSE2 <- mse(trang$wage, predict(love, trang))
print(paste(MSE1, MSE2)) # In ra hai giá trị MSE.

## [1] "12.3500900460304 12.4087963001075"

Có thể thấy mô hình 2 có giá trị MSE cao hơn chừng 0.05% - một con số rất bé. Như vậy nếu căn cứ
vào đồng thời cả hai tiêu chí thì mô hình 1 là mô hình tốt hơn với mẫu đã cho. Tuy nhiên cần phải
nhắc lại rằng: kết luận này chỉ đúng với mẫu cụ thể này mà thôi, chưa chắc đúng nếu mẫu là khác.
Ngoài ra bạn cũng cần lưu ý rằng những giá trị MSE, R2 ở cả hai mô hình là tỉ lệ sai sót huấn luyện.

Về vấn đề lựa chọn và cả so sánh các mô hình các bạn nên nhớ câu “all models are wrong, but some
are useful” của George Box (nhà thống kê – kinh tế lượng nổi tiếng người Anh và cũng là người cùng
với Jenkins xây dựng Box-Jenkins Methods cho phân tích chuỗi thời gian). Thực vậy, tất cả các mô
hình đều sai, chỉ có một số (mô hình) là hữu ích. Như trong tình huống của chúng ta mặc dù cả hai mô
hình đều đưa ra bằng chứng thống kê rằng quy luật cận biên giảm dần và do đó ủng hộ những lý
thuyết của kinh tế học lao động nhưng nếu xét trên khía cạnh thực tế thì chúng đều “vô nghĩa” ở một
mức độ nào đó. Thực vậy, khó có thể tin rằng sau gần 25 năm làm việc, mức lương lại giảm dần cùng
với kinh nghiệm có được. Trong thực tế, mức lương của người lao động chỉ có tăng theo thời gian
cùng với kinh nghiệm. Điều này gợi ý rằng nếu các lý thuyết của kinh tế học lao động là đúng thì
ngưỡng mà tại đó mức lương tuân theo quy luật cận biên giảm dần phải lớn hơn con số 24.4 nhiều.

Một vấn đề khác cho việc trả lời câu hỏi trong số các mô hình cạnh tranh nhau, mô hình nào tốt hơn
ngoài căn cứ vào một số tiêu chí thống kê (R2, MSE chẳng hạn) và mức độ phù hợp với thực tiễn thì
cũng còn một tiêu chí quan trọng khác đó là khả năng diễn giải của mô hình. Chẳng hạn, ở mô hình 1
nếu chúng ta cho thêm biến số bình phương của lg(exper) vào thì R2 của mô hình mới chắc chắn cao
hơn (và trong nhiều tình huống, mức tăng của R2 là đáng kể). Tuy nhiên chúng ta có thể thấy rằng

Nguyễn Chí Dũng http://rpubs.com/chidungkt


251

chúng ta rất khó diễn đạt (hay giải thích) cho các kết quả thu được, thậm chí trong nhiều tình huống
là không thể diễn đạt được những kết quả đó. Do vậy, lựa chọn giữa các mô hình cạnh tranh, ngoài rất
nhiều các yếu tố cần nhắc, chúng ta phải lưu ý đến khả năng diễn giải của mô hình. Một mô hình mà
chúng ta có thể diễn giải một cách thuyết phục các kết quả thu được nên được ưu tiên lựa chọn mặc
dù nếu căn cứu vào một số tiêu chí khác, nó có thể thua kém so với các mô hình cạnh tranh.

Như đã nói ở trên, mặc dù với tình huống mẫu là toàn bộ 526 quan sát thì chúng ta chỉ ra rằng, căn cứ
vào các tiêu chí đánh giá sai sót huấn luyện thì mô hình 1 là tốt hơn mô hinh 2. Tuy nhiên, chúng ta
chưa có bằng chứng thống kê cho kết luận này, vì sự khác biệt này chỉ đúng với một mẫu, chưa chắc
đã đúng với mẫu khác.

Để đưa ra bằng chứng thống kê có hay không có sự khác biệt về chất lượng của hai mô hình, dưới đây
là các R code cho đánh giá hai tiêu chí này với mẫu huấn luyện (train) và mẫu kiểm định (test) được
chia theo tỉ lệ 50:50 cho 1000 tình huống khác nhau với vòng lặp 1000 lần. Điểm khác ở đây là không
giống như trên, chúng ta sẽ đánh giá dựa trên sai sót kiểm định với tiêu chí lựa chọn là MSE. Vì rằng
với mục đích dự báo lương (wage) thì sai sót kiểm định sẽ là phù hợp hơn (James et al., 2013). Chúng
ta thực hiện bằng vòng lặp for loop:
MSE1 <- c()
MSE2 <- c()
set.seed(29)
for (i in 1:1000){
train <- trang[sample(526, 0.5*526), ]
test <- trang[-sample(526, 0.5*526), ]
qols <- train %>% lm(wage ~ exper + exper2, data = .)
love <- train %>% lm(wage ~ exper + nkn + exper*nkn, data = .)

# MSE1, R2_MH1 cho mô hình 1:


tinhMSE1 <- mean((test$wage - predict(qols, test))^2)
MSE1 <- c(MSE1, tinhMSE1)

# MSE2, R2_MH2 cho mô hình 2:


tinhMSE2 <- mean((test$wage - predict(love, test))^2)
MSE2 <- c(MSE2, tinhMSE2)
}
trang2611 <- data.frame(MSE1, MSE2)
summary((trang2611))

## MSE1 MSE2
## Min. : 7.542 Min. : 7.62
## 1st Qu.:11.470 1st Qu.:11.59
## Median :12.449 Median :12.56
## Mean :12.411 Mean :12.51
## 3rd Qu.:13.368 3rd Qu.:13.48
## Max. :16.454 Max. :16.34

Chúng ta thấy rằng có sự khác biệt về MSE giữa hai mô hình. Chú ý rằng có tất cả 1000 cặp MSE1 và
MSE2 ứng với hai mô hình với trung bình lần lượt là 12.411 và 12.510. Tuy nhiên để chứng minh rằng
sự khác biệt này có ý nghĩa thống kê hay không, chúng ta phải sử dụng kiểm định t để có kết luận

Nguyễn Chí Dũng http://rpubs.com/chidungkt


252

chính thức. Do p-value = 0.089 > 5% nên chúng ta có thể thấy rằng sự khác biệt về chất lượng dự báo
của hai mô hình là không có ý nghĩa thống kê:
t.test(trang2611$MSE1, trang2611$MSE2)

##
## Welch Two Sample t-test
##
## data: trang2611$MSE1 and trang2611$MSE2
## t = -1.7002, df = 1998, p-value = 0.08924
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -0.2217237 0.0158003
## sample estimates:
## mean of x mean of y
## 12.41148 12.51444

Ví dụ này một lần nữa nhấn mạnh nguyên lý suy nghĩ một cách thống kê trong nghiên cứu: mô hình
1 tốt hơn mô hình 2 chỉ trong 1 tình huống. Để khẳng định có sự khác biệt về chất lượng trong, chẳng
hạn, dự báo của hai mô hình thì bạn phải đưa ra bằng chứng thống kê cho kết luận của mình. Nói cách
khác, bạn phải có bằng chứng rằng sự khác biệt ấy có tính phổ quát, tức đúng cho nhiều trường hợp,
chứ không chỉ mới đúng với một tình huống của mẫu mà thôi.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


253

Chương 7: Các mô hình hồi quy biến giả

Chương này chúng ta sẽ nghiên cứu các mô hình hồi quy mà một số hay tất cả biến giải thích là các biến
định tính (Qualitative Variables). Các mô hình hồi quy như vậy còn được biết đến với cái tên là các mô
hình hồi quy biến giả (Dummy Variable Regression Models). Sự thưc thực thì biến giả có tác động thực
sự đến biến phụ thuộc như chúng ta sẽ thấy. Do vậy, tôi ưa thích hơn sử dụng cụm từ biến định tính thay
vì biến giả. Vì lí do này, hai danh từ trên được sử dụng thay thế cho nhau mà không có sự khác biệt về ý
nghĩa.

7.1 Bản chất của biến giả và các mô hình hồi quy ANOVA
Trong phân tích hồi quy, biến phụ thuộc không chỉ phụ thuộc vào biến giải thích là biến định lượng
mà còn phụ thuộc vào cả các biến định tính (hay còn gọi là biến giả - dummy variables). Chẳng hạn,
mức lương theo giờ Y không chỉ phụ thuộc vào số năm đi học X (biến định lượng) mà còn phụ thuộc
vào cả giới tính (biến định tính). Thậm chí, có những mô hình mà biến giải thích hoàn toàn là các
biến định tính – những mô hình như vậy có tên gọi là các mô hình ANOVA (ANOVA Models) . Chúng
ta nghiên cứu về một số mô hình như vậy ngay sau đây. Chương này chúng ta sẽ sử dụng bộ dữ liệu
ch4bt8.wf1 với 935 quan sát được cung cấp bởi khoa toán NEU và đã được sử dụng ở mục 5.7 ở
chương 5.

7.1.1 mô hình ANOVA với chỉ một biến giải thích là biến giả duy nhất
Chúng ta xét mô hình sau:

WAGE = β1 + β2BLACK + ui (1)

Trước hết chúng ta đọc dữ liệu và thực hiện một số phân tích sơ bộ:

library(hexView)
trang <- readEViews("D:/KTLR/ch4bt8.wf1", as.data.frame = TRUE)
# Đánh giá sơ bộ về từng nhóm chủng tộc:
library(tidyverse)
theme_set(theme_minimal())
trang %>%
group_by(BLACK) %>%
count() %>%
ggplot(aes(BLACK, n)) +
geom_col() +
geom_text(aes(label = n), color = "white", hjust = 1.2) +
coord_flip()

Nguyễn Chí Dũng http://rpubs.com/chidungkt


254

# Tỉ lệ của từng nhóm chủng tộc:


dung <- table(trang$BLACK)
addmargins(prop.table(dung))

## BLACK
## 0 1 Sum
## 0.8716578 0.1283422 1.0000000

Như vậy có 87.16% lao động là người da trắng, 12.83 % là người Mĩ gốc Phi. Những tỉ lệ này có thể
được biểu thị bằng Bar Plot như trên.

Như chúng ta đã biết, mức lương trung bình ở Mĩ có thể khác biệt giữa các nhóm chủng tộc. Chúng ta
có thể đánh giá sơ bộ như sau:

trang %>%
mutate(BLACK = as.factor(BLACK)) %>%
ggplot(aes(BLACK, WAGE)) +
geom_boxplot()

Chúng ta có nhận định trực giác rằng mức lương của người da trắng là cao hơn. Chúng ta thực hiện
phân tích hồi quy cho mô hình (1):

anova1 <- lm(data = trang, WAGE ~ BLACK)


summary(anova1)

##
## Call:
## lm(formula = WAGE ~ BLACK, data = trang)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


255

##
## Residuals:
## Min 1Q Median 3Q Max
## -875.65 -269.15 -52.65 209.35 2087.35
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3490.65 13.85 251.977 < 2e-16 ***
## BLACK -254.81 38.67 -6.589 7.37e-11 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 395.5 on 933 degrees of freedom
## Multiple R-squared: 0.04447, Adjusted R-squared: 0.04345
## F-statistic: 43.42 on 1 and 933 DF, p-value: 7.37e-11

Dựa vào kết quả hồi quy này ta có WAGE = 3490.64785 -254.80619BLACK. Phương trình này có ý
nghĩa như sau:

1. Khi BLACK = 0 (không phải là người Mĩ gốc Phi) thì WAGE = 3490.64785. Đây chính là mức
lương trung bình tháng của nhóm lao động da trắng, người gốc Tây Ban Nha, người gốc Á.
2. Khi BLACK = 1 mức lương trung bình của người Mĩ gốc Phi luôn thấp hơn nhóm còn lại là
254.80619. Không những thế, hệ số hồi quy này còn có ý nghĩa thống kê ở mức cao. Điều này
cũng có nghĩa là chúng ta có bằng chứng thống kê rất mạnh để đưa ra kết luận rằng mức lương
trung bình của người Mĩ gốc Phi thấp hơn đáng kể so với nhóm còn lại.

Chú ý rằng kết luận mà chúng ta vừa có được có thể thu được bằng cách khác với kiểm định t:

t.test(WAGE ~ BLACK)

##
## Welch Two Sample t-test
##
## data: WAGE by BLACK
## t = 8.3373, df = 192.73, p-value = 1.42e-14
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## 194.5269 315.0854
## sample estimates:
## mean in group 0 mean in group 1
## 3490.648 3235.842

Kết quả chỉ ra rằng mức lương của nhóm 0 (da trắng) là 3490.54, của nhóm 1 (da màu) là 3235.84 và
sự khác biệt này có ý nghĩa thống kê do p-value = 1.42⨉10-14 là rất bé.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


256

7.1.2 mô hình ANOVA với hai biến giả trở lên


Chúng ta biết rằng ngoài nhân tố chủng tộc, yếu tố vùng miền cũng có ảnh hưởng đến mức lương tại
Hoa Kì:

WAGE = β1 + β2BLACK + β3SOUTH + ei (2)

Chúng ta đánh giá sơ bộ bằng hình ảnh về mức lương biến đổi ra sao giữa vùng miền và chủng tộc:

trang %>%
mutate(BLACK = as.factor(BLACK), SOUTH = as.factor(SOUTH)) %>%
ggplot(aes(BLACK:SOUTH, WAGE)) +
geom_boxplot()

Hình ảnh này cho thấy, ví dụ, người da trắng và ở khu vực phi miền nam (box plot màu xanh) có mức
lương khác biệt so với người da màu và ở miền nam (box plot màu vàng). Để củng cố nhận định này
cũng như thực hiện các phân tích sâu hơn ta thực hiện hồi quy trong R cho mô hình (2):

anova2 <- lm(data = trang, WAGE ~ BLACK + SOUTH)


summary(anova2)
## Call:
## lm(formula = WAGE ~ BLACK + SOUTH, data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -905.13 -266.13 -58.13 191.87 2156.76
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3520.13 16.09 218.825 < 2e-16 ***
## BLACK -221.66 39.55 -5.604 2.76e-08 ***
## SOUTH -98.89 27.90 -3.544 0.000414 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 393.1 on 932 degrees of freedom
## Multiple R-squared: 0.05718, Adjusted R-squared: 0.05515
## F-statistic: 28.26 on 2 and 932 DF, p-value: 1.216e-12

Nguyễn Chí Dũng http://rpubs.com/chidungkt


257

Dựa vào kết quả hồi quy này ta có WAGE = 3520.13 -221.66BLACK - 98.89SOUTH. Phương trình này
có ý nghĩa như sau:

1. Khi BLACK = 0 và SOUTH = 0 (không phải là người Mĩ gốc Phi và không ở khu vực miền nàm)
thì WAGE = 3520.13. Đây chính là mức lương trung bình tháng của nhóm lao động người phi
da đen và không ở miền nam.
2. Khi BLACK = 1 và SOUTH = 1 mức lương trung bình của người Mĩ gốc Phi lại còn sống ở miền
Nam (tệ phân biệt chủng tộc rất gay gắt ở các ban miền Nam và là một trong những nguyên
nhân của nội chiến Mĩ) luôn thấp hơn (221.66+98.89).
3. Khi BLACK = 1 và SOUTH = 0 mức lương trung bình của người Mĩ gốc Phi không sống ở miền
Nam được cải thiện hơn chút ít khi mức lương của anh ta chỉ thấp hơn nhóm còn lại 221.66.
4. Khi BLACK = 0 và SOUTH = 1 mức lương trung bình của người Mĩ da trắng (và các màu da
khác) thấp hơn 98.89.
5. Tất cả 4 kết luận trên là có ý nghĩa thống kê vì tất cả các hệ số hồi quy đều có ý nghĩa thống kê
ở mức cao.

7.1.3 mô hình ANOVA có sự tương tác của các biến giả


Ngoài nhân tố chủng tộc, yếu tố vùng miền cũng có ảnh hưởng đến mức lương tại Hoa Kì. Tuy nhiên
ở mô hình (2) chúng ta chưa xét đến tương tác giữa hai yếu tố này. Do vậy chúng ta có thể mở rộng
mô hình (2) thành:

WAGE = β1 + β2BLACK + β3SOUTH+ β4SOUTH*BLACK + wi (3)

Thực hiện hồi quy trong R chúng ta có:

anova3 <- lm(data = trang, WAGE ~ BLACK + SOUTH + BLACK*SOUTH)


summary(anova3)
## Call:
## lm(formula = WAGE ~ BLACK + SOUTH + BLACK * SOUTH, data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -900.38 -265.38 -53.38 188.10 2145.58
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3515.38 16.43 214.019 < 2e-16 ***
## BLACK -155.16 61.46 -2.525 0.01175 *
## SOUTH -82.96 30.08 -2.758 0.00593 **
## BLACK:SOUTH -113.44 80.27 -1.413 0.15791
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 392.8 on 931 degrees of freedom
## Multiple R-squared: 0.05919, Adjusted R-squared: 0.05616
## F-statistic: 19.53 on 3 and 931 DF, p-value: 2.783e-12

Nguyễn Chí Dũng http://rpubs.com/chidungkt


258

Diễn giải mô kết quả của mô hình cũng tương tự như trên với chú ý rằng hệ số hồi quy β4 cho
BLACK*SOUTH là -113.44. Điều này có nghĩa là nếu một quan sát mà anh ta vừa là người da màu, vừa
là dân miền nam thì mức lương của anh ta sẽ thấp hơn so với nhóm còn lại là (155 + 83 + 113). Chúng
ta có thể liên hệ tình huống này cho nghiên cứu ở Việt Nam theo kiểu lao động vừa là người dân tộc
thiểu số, lại ở vùng Tây Bắc – địa bàn khó khăn nhất của cả nước.

7.2. Mô hình có chứa cả biến giả lẫn biến định lượng – mô hình ANCOVA
Mô hình ANOVA – mô hình chỉ chứa toàn biến định tính như chúng ta vừa nghiên cứu ở trên thường
rất phổ biến trong các nghành xã hội học, tâm lý học, giáo dục, marketing nhưng lại không quá phổ
biến trong nghiên cứu kinh tế. Trong kinh tế, chúng ta thường gặp hơn những mô hình vừa chứa các
biến định tính, vừa chứa cả các biến định lượng. Những mô hình này có tên là mô hình ANCOVA
(ANCOVA Models).

7.2.1 Mô hình ANCOVA không có sự tương tác giữa các biến


Chúng ta hãy nghiên cứu một ví dụ về mô hình ANCOVA được đề cập ở trang 181 sách giáo trình của
NEU:

WAGE = β1 + β2URBAN + β3EDUC + wi (4)

Thực hiện hồi quy trong R chúng ta có:

ancova1 <- lm(data = trang, WAGE ~ URBAN + EDUC)


summary(ancova1)
## Call:
## lm(formula = WAGE ~ URBAN + EDUC, data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -802.5 -254.6 -20.9 197.0 2102.6
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2565.167 77.715 33.007 < 2e-16 ***
## URBAN 157.763 27.380 5.762 1.13e-08 ***
## EDUC 57.880 5.614 10.310 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 375.9 on 932 degrees of freedom
## Multiple R-squared: 0.1377, Adjusted R-squared: 0.1359
## F-statistic: 74.43 on 2 and 932 DF, p-value: < 2.2e-16

Mô hình này chỉ ra rằng nếu mọi thứ khác là như nhau thì mức lương của người ở khu vực thành thị
sẽ cao hơn so với mức lương của người ở khu vực khác 158 USD và sự khác biệt này có ý nghĩa thống
kê.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


259

7.2.2 Mô hình ANCOVA có sự tương tác giữa các biến


Chúng ta hãy nghiên cứu một ví dụ về mô hình ANCOVA được đề cập ở trang 181 sách giáo trình của
NEU. Đây là mô hình có xuất hiện tương tác giữa biến định lượng và biến định tính:

WAGE = β1 + β2URBAN + β3EDUC + β4EDUC*URBAN + wi (5)

Thực hiện hồi quy trong R chúng ta có:

ancova2 <- lm(data = trang, WAGE ~ URBAN + EDUC + URBAN*EDUC)


summary(ancova2)
## Call:
## lm(formula = WAGE ~ URBAN + EDUC + URBAN * EDUC, data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -816.47 -254.36 -27.24 193.11 2106.70
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2815.83 143.23 19.660 < 2e-16 ***
## URBAN -190.27 169.39 -1.123 0.26161
## EDUC 38.91 10.70 3.638 0.00029 ***
## URBAN:EDUC 26.14 12.56 2.082 0.03762 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 375.2 on 931 degrees of freedom
## Multiple R-squared: 0.1417, Adjusted R-squared: 0.1389
## F-statistic: 51.24 on 3 and 931 DF, p-value: < 2.2e-16

Việc diễn giải các mô hình (4) và (5) các bạn có thể xem ở trang 182, 183 sách giáo trình kinh tế lượng
NEU. Một nhận xét quan trọng ở đây là nếu lao động thuộc khu vực thành thị thì tác động đến việc gia
tăng thêm một năm học đến mức lương là mạnh hơn so với lao động thuộc khu vực khác. Thực vậy,
theo kết quả này thì gia tăng thêm một năm học, nếu là lao động ở thành thị thì mức lương sẽ tăng
(38.91 + 26.14) nhưng nếu là lao động ở khu vực khác thì mức lương chỉ tăng 38.91. Chi tiết hơn về
vấn đề này chúng ta sẽ nghiên cứu ngay sau đây.

7.2.3 Vai trò của biến định tính và kiểm định Chow
Giả sử ngoài trình độ học vấn, chúng ta muốn đánh giá xem yếu tố vùng miền, cụ thể là khu vực thành
thị (URBAN = 1) và khu vực phi thành thị (URBAN = 0) tác động như thế nào đến mức lương và tác
động này có ý nghĩa thống kê hay không chúng ta có thể vận dụng cách tiếp cận dưới đây do Chow
(1960) đề xuất. Trước hết chúng ta tách hai nhóm lao động như sau: giả sử các lao động ở khu vực
phi thành thị được sắp xếp từ 1 đến m còn các lao động thành thị được sắp xếp từ m+1 đến n. Sau đó
chúng ta xét hai mô hình hồi quy sau:

WAGEi = γ1 + γ2EDUCi với i =1,m (6)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


260

WAGEj = λ1 + λ2EDUCj với j = m+1,n (7)

Nếu chúng ta đưa ra bằng chứng thống kê cho thấy γ1 = λ1 và γ2 = λ2 thì chúng ta có thể gộp (6) và (7)
thành một phương trình duy nhất:

WAGEk = α1 + α2EDUCk với k = 1,n (8)

Chúng ta có thể sử dụng kiểm định F theo cách tiếp cận của Chow (công thức 4.3.6 trang 186 sách
giáo trình NEU) để kiểm tra khả năng gộp (6) và (7) thành duy nhất mô hình (8) như sau:

nongthon <- lm(WAGE ~ EDUC, data = trang, subset = (URBAN == 0))


thanhthi <- lm(WAGE ~ EDUC, data = trang, subset = (URBAN == 1))
pooled <- lm(WAGE ~ EDUC, data = trang)
RSS <- sum((residuals(pooled))^2)
RSS1 <- sum((residuals(nongthon))^2)
RSS2 <- sum((residuals(thanhthi))^2)
Fqs <- 931*(RSS - RSS1 - RSS2) / (2*(RSS1 + RSS2))
Fqs

## [1] 18.82677

So sánh Fqs = 18.827 với F0.95(2,931):

qf(0.95, df1 = 2, df2 = 931)

## [1] 3.005393

Do Fqs = 18.827> F0.95(2,931) = 3.000 nên chúng ta bắc bỏ giả thuyết gốc rằng γ1 = λ1 và γ2 = λ2 . Nói
cách khác, tác động của giáo dục lên mức lương là khác biệt giữa hai nhóm lao động nông thôn và
thành thị.

7.2.4 Sử dụng biến định tính thay thế cho kiểm định Chow
Để chỉ ra nhược điểm của kiểm định Chow (hay cách tiếp cận kiểu Chow) chúng ta hãy phân tích mối
liên hệ giữa hai mô hình (6) và (7) căn cứ vào các khả năng có thể xẩy ra giữa các hệ số hồi quy tương
ứng. Giữa hai mô hình này có 4 khả năng sau có thể xẩy ra (hình 1):

1. Cả hệ số chặn lẫn hệ số góc là như nhau. Trường hợp này được gọi là các hồi quy trùng lặp
(coincident regressions). Trong tình huống này thì γ1 = λ1 và γ2 = λ2 và chúng ta chỉ cần sử
dụng duy nhất mô hình (8).
2. Hệ số chặn là khác nhưng hệ số góc như nhau. Trong tình huống này thì γ1 # λ1 và γ2 = λ2 .
Nghĩa là chúng ta có các hồi quy song song (parallel regressions).
3. Hệ số chặn giống nhau nhưng hệ số góc thì khác. Lúc này ta có các hồi quy chung hệ số chặn
(concurrent regressions) với γ1 = λ1 và γ2 # λ2.
4. Cả hệ số chặn lẫn hệ số góc khác nhau. Lúc này ta có các hồi quy khác biệt (dissimilar
regressions) ứng với tình huống γ1 # λ1 và γ2 # λ2.

Quan phân tích ở trên chúng ta thấy rõ ràng hạn chế của kiểm định Chow: sử dụng kiểm định Chow có
thể chỉ ra rằng mô hình (6) và (7) là khác biệt – tức có sự thay đổi về cấu trúc nhưng nó không chỉ ra
sự khác biệt này có nguyên nhân là do sự khác biệt về hệ số chặn, hệ số góc, hay cả hai loại hệ số này.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


261

Chúng ta có thể sử dụng cách tiếp cận biến giả nhằm xử lý hạn chế của kiểm định Chow bằng cách xét
mô hình sau:

WAGE = β1 + β2EDUC + β3URBAN + β4EDUC*URBAN (9)

Thật vậy, với lao động nông thôn:

WAGE = β1 + β2EDUC (10)

Với lao động thành thị:

WAGE = (β1 +β3) +( β2 + β4)EDUC (11)

Sự khác biệt về mức lương giữa hai nhóm, theo Gujarati (1970, 2009) là tồn tại nếu xẩy ra một trong
ba tình huống sau:

1. β3 có ý nghĩa thống kê và β4 không có ý nghĩa thống kê. Trong tình huống này chúng ta parallel
regressions.
2. β3 không có ý nghĩa thống kê và β4 có ý nghĩa thống kê. Trong tình huống này chúng ta có
concurrent regressions.
3. Cả β3 và β4 có ý nghĩa thống kê. Trong tình huống này chúng ta có dissimilar regressions.
Ngược lại, nếu cả ba tình huống trên không thỏa mãn (tức là cả β3 và β4 không có ý nghĩa thống kê)
thì chúng ta có thể lấy (9) làm mô hình mô tả chung cho tác động của học vấn lên mức lương của hai
nhóm lao động mà không tính đến yếu tố vùng miền. Nghĩa là chúng ta có thể bỏ qua nhân tố khu vực
cũng như tương tác giữa nhân tố này với EDUC trong việc đánh giá mức lương. Tất cả điều này được
giải quyết trọn vẹn chỉ bởi chạy duy nhất mô hình (9).

Nguyễn Chí Dũng http://rpubs.com/chidungkt


262

(Hình 1. Các tình huống có thể xẩy ra giữa mô hình 5 và 7)

Thực hiện hồi quy cho mô hình (9) trong R:

love <- lm(data = trang, WAGE ~ EDUC + URBAN + URBAN*EDUC)


summary(love)
## Call:
## lm(formula = WAGE ~ EDUC + URBAN + URBAN * EDUC, data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -816.47 -254.36 -27.24 193.11 2106.70
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2815.83 143.23 19.660 < 2e-16 ***
## EDUC 38.91 10.70 3.638 0.00029 ***
## URBAN -190.27 169.39 -1.123 0.26161
## EDUC:URBAN 26.14 12.56 2.082 0.03762 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 375.2 on 931 degrees of freedom

Nguyễn Chí Dũng http://rpubs.com/chidungkt


263

## Multiple R-squared: 0.1417, Adjusted R-squared: 0.1389


## F-statistic: 51.24 on 3 and 931 DF, p-value: < 2.2e-16

Căn cứ vào kết quả này ta thấy β3 không có ý nghĩa thống kê còn β4 có ý nghĩa thống kê. Nói cách khác
chúng ta có thể thấy đường hồi quy cho nhóm cư dân đô thị là dốc hơn so với đường hồi quy của cư
dân nông thôn (trường hợp 3). Chúng ta có thể minh họa đường hồi quy cho hai nhóm lao động như
sau:

trang %>%
mutate(Region = case_when(URBAN == 1 ~ "Urban",
URBAN != 1 ~ "Country")) %>%
ggplot(aes(EDUC, WAGE, color = Region)) + geom_point() +
geom_smooth(method = "lm", se = FALSE) + theme_minimal() +
labs(x = NULL, y = NULL,
title = "The Relationship between Wage and Education",
caption = "Data Source: GSO")

7.3. Biến định tính có nhiều phạm trù


Trong phần này, do các số liệu được cung cấp bởi khoa toán (đi kèm với cuốn giáo trình) là không rõ
ràng về nguồn gốc cũng như thiếu tính thực tế nên với mục đích minh họa chúng ta sẽ sử dụng bộ số
liệu CPS1988 đi kèm với gói AER. Bộ dữ liệu này là thông tin về mức lương, trình độ học vấn, kinh
nghiệm cũng như một số biến định tính khác đặc trưng cho khía cạnh địa lý và nhân chủng học của
28.155 cá nhân được thu thập bởi bộ thống kê Hoa Kì (US Census Bureau) vào năm 1988 và sau đó
được sử dụng trong một loạt các nghiên cứu khác nhau. Để chỉ định R làm việc với bộ số liệu này
chúng ta làm như sau:

data("CPS1988", package = "AER")

Chúng ta có thể xem các thông tin vắn tắt về bộ dữ liệu này:

summary(CPS1988)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


264

## wage education experience ethnicity


## Min. : 50.05 Min. : 0.00 Min. :-4.0 cauc:25923
## 1st Qu.: 308.64 1st Qu.:12.00 1st Qu.: 8.0 afam: 2232
## Median : 522.32 Median :12.00 Median :16.0
## Mean : 603.73 Mean :13.07 Mean :18.2
## 3rd Qu.: 783.48 3rd Qu.:15.00 3rd Qu.:27.0
## Max. :18777.20 Max. :18.00 Max. :63.0
## smsa region parttime
## no : 7223 northeast:6441 no :25631
## yes:20932 midwest :6863 yes: 2524
## south :8760
## west :6091

Ở đây biến định tính khu vực (region) có bốn cặp phạm trù đại diện cho 4 khu vực địa lý của nước Mĩ.
Giả sử chúng ta xét mô hình ANCOVA đơn giản thường được nghiên cứu bởi kinh tế học lao động như
sau:

ln(wage) = β1 + β2(experience) + β3(experience)2 + β4(region) (12)

Thực hiện ước lượng mô hình này trong R:

npt <- lm(data = CPS1988, log(wage) ~ experience + I(experience^2) + region)


summary(npt)
## Call:
## lm(formula = log(wage) ~ experience + I(experience^2) + region,
## data = CPS1988)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.6441 -0.3761 0.0524 0.4145 4.2395
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 5.565e+00 1.134e-02 490.959 <2e-16 ***
## experience 8.136e-02 9.490e-04 85.733 <2e-16 ***
## I(experience^2) -1.528e-03 2.026e-05 -75.394 <2e-16 ***
## regionmidwest -9.509e-02 1.095e-02 -8.687 <2e-16 ***
## regionsouth -1.948e-01 1.035e-02 -18.816 <2e-16 ***
## regionwest -1.130e-01 1.128e-02 -10.018 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.6307 on 28149 degrees of freedom
## Multiple R-squared: 0.224, Adjusted R-squared: 0.2238
## F-statistic: 1625 on 5 and 28149 DF, p-value: < 2.2e-16

Nguyễn Chí Dũng http://rpubs.com/chidungkt


265

Căn cứ vào kết quả chúng ta thấy rằng nếu các yếu tố khác không đổi, khi kinh nghiệm = 0 thì mức
lương của lao động vùng northeast là 5.56$ một giờ (chính là hệ số chặn Intercept) trong khi mức
lương của người vùng south là thấp nhất và thua kém các lao động vùng northeast (lấy làm chuẩn) là
0.19$. Ngoài ra các hệ số hồi quy thu được cũng có dấu phù hợp với các lý thuyết về kinh tế học lao
động cũng như bối cảnh ở nước Mĩ: mối quan hệ hình chữ U ngược giữa kinh nghiệm và mức lương
cũng như mức lương cao hơn hẳn của vùng đông bắc so với các khu vực khác.

Như đã phân tích về mối quan hệ hình chữ U ngược giữa kinh nghiệm và mức lương chúng ta có thể
minh họa mối quan hệ này bằng hình ảnh trong R như sau:

data("CPS1988", package = "AER")


CPS1988 %>%
ggplot(aes(x = experience, y = log(wage))) +
geom_point(alpha = 0.1) +
stat_smooth(method = "lm",
formula = y ~ x + I(x^2),
size = 1, se = FALSE)

Chú ý dạng đường cong này là chung cho cả 4 nhóm lao động ứng với 4 khu vực địa lý. Nếu lấy
northeast làm chuẩn thì ba đường cong cho ba nhóm lao động còn lại chỉ là phép tịnh tiến xuống dưới
của hình 3 mà thôi.

7.4. Hồi quy riêng lẻ cho từng nhóm


Trong nhiều tình huống chúng ta có thể quan tâm đến mô hình hồi quy cho từng nhóm cụ thể một
cách riêng lẻ. Chẳng hạn, ứng với 4 khu vực địa lý chúng ta có 4 mô hình hồi quy cho 4 nhóm lao động
lần lượt như sau:

ln(wage) = α1 + β2(experience) + α3(experience)2 (13)

ln(wage) = β1 + β2(experience) + β3(experience)2 (14)

ln(wage) = λ1 + λ2(experience) + λ3(experience)2 (15)

ln(wage) = ψ1 + ψ2(experience) + ψ3(experience)2 (16)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


266

Nghĩa là với mô hình (13) chúng ta chỉ chạy mô hình này ứng với các số liệu về wage, experience thu
được từ người lao động ở vùng northeast. Làm tương tự như vậy đối với ba nhóm lao động còn lại.

Để thực hiện hồi quy cho 4 mô hình trên (ứng với 4 nhóm dữ liệu con) chúng ta thực hiện trong R
như sau:

nor <- lm(log(wage) ~ experience + I(experience^2),


data = CPS1988, subset = (region == "northeast"))
mid <- lm(log(wage) ~ experience + I(experience^2),
data = CPS1988, subset = (region == "midwest"))
sou <- lm(log(wage) ~ experience + I(experience^2),
data = CPS1988, subset = (region== "south"))
wes <- lm(log(wage) ~ experience + I(experience^2),
data = CPS1988, subset = (region== "west"))

Thực ra chúng ta đã thực hiện kiểu hồi quy với nhóm dữ liệu con như vậy ở mục 7.2.3. Điểm khác biệt
ở đây là ở mục 7.2.3 thì biến số URBAN = 0 hoặc 1 và cả 0 và 1 đều là biến dạng số học trong khi biến
region nhận giá trị kí tự (character). Vì lý do này chúng ta phải sử dụng dấu “ ” trong câu lệnh.

Các bạn có thể xem kết quả hồi quy cho nhóm lao động đến từ northeast:

summary(nor)
## Call:
## lm(formula = log(wage) ~ experience + I(experience^2), data = CPS1988,
## subset = (region == "northeast"))
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.63780 -0.34942 0.04541 0.39147 2.71906
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 5.606e+00 1.801e-02 311.31 <2e-16 ***
## experience 7.893e-02 1.907e-03 41.40 <2e-16 ***
## I(experience^2) -1.518e-03 4.044e-05 -37.54 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.6047 on 6438 degrees of freedom
## Multiple R-squared: 0.2151, Adjusted R-squared: 0.2148
## F-statistic: 881.9 on 2 and 6438 DF, p-value: < 2.2e-16

Chúng ta cũng thấy rằng số quan sát ở mô hình (13) là 6438+3 = 6441. Đây chính là số lao động từ
vùng northeast được khảo sát. Chúng ta có thể kiểm tra lại:

summary(region)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


267

## northeast midwest south west


## 6441 6863 8760 6091

Tất nhiên chúng ta có thể sử dụng gói stargazer để trình bày hoặc so sánh các ước lượng OLS thu
được cho 4 nhóm.

Liên hệ với tình huống nghiên cứu mà chúng ta đã đề cập ở mục 4.8 có thể thấy số năm kinh nghiệm
mà vượt qua đó mức lương giảm là xấp xỉ 26 (đối với vùng northeast). Làm tương tự với ba vùng còn
lại các bạn có thể thấy điểm turning point này là gần như nhau. Để giải thích kết quả này xem có phù
hợp thực tế hay không cần các bạn cân nhắc nhiều vấn đề cũng như hiểu chi tiết về thị trường lao
động ở Hoa Kì thời điểm năm 1988.

Trong R chúng ta có thể biểu diễn 4 đường cong hồi quy cho 4 mô hình trên:

CPS1988 %>%
ggplot(aes(x = experience, y = log(wage))) +
geom_point(alpha = 0.05) +
stat_smooth(method = "lm",
formula = y ~ x + I(x^2),
size = 1, se = FALSE) +
facet_wrap(~ region)

(Hình 4. Mối liên hệ hình chữ U ngược giữa kinh nghiệm và mức lương ứng với 4 vùng)

Cũng có thể biểu diễn cả 4 đường cong hồi quy này trên cùng một hình (không hiển thị hình):

CPS1988 %>%
ggplot(aes(x = experience, y = log(wage), colour = region)) +
geom_point(alpha = 0.1) +
stat_smooth(method = "lm",
formula = y ~ x + I(x^2),
size = 1, se = FALSE)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


268

Ở mục trên chúng ta đã thực hiện hồi quy một cách lần lượt cho 4 nhóm đến từ bốn vùng khác nhau.
Thực tế, tất cả các câu lệnh dài dòng trên có thể làm nhanh gọn hơn nhiều. Đây là một thế mạnh của
R khi nó có thể thực hiện hồi quy với biến giả nhiều phạm trù:

trang <- lm(log(wage) ~ region*experience + region*I(experience^2),


data = CPS1988)
summary(trang)

##
## Call:
## lm(formula = log(wage) ~ region * experience + region * I(experience^2),
## data = CPS1988)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.6378 -0.3725 0.0509 0.4158 4.1966
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 5.606e+00 1.876e-02 298.814 < 2e-16 ***
## regionmidwest -2.176e-01 2.595e-02 -8.385 < 2e-16 ***
## regionsouth -1.747e-01 2.474e-02 -7.060 1.71e-12 ***
## regionwest -1.875e-01 2.722e-02 -6.888 5.79e-12 ***
## experience 7.893e-02 1.986e-03 39.737 < 2e-16 ***
## I(experience^2) -1.518e-03 4.213e-05 -36.029 < 2e-16 ***
## regionmidwest:experience 9.792e-03 2.772e-03 3.533 0.000412 ***
## regionsouth:experience -3.792e-03 2.593e-03 -1.462 0.143632
## regionwest:experience 5.345e-03 2.881e-03 1.855 0.063606 .
## regionmidwest:I(experience^2) -1.109e-04 5.951e-05 -1.864 0.062367 .
## regionsouth:I(experience^2) 9.547e-05 5.477e-05 1.743 0.081322 .
## regionwest:I(experience^2) -4.714e-05 6.179e-05 -0.763 0.445509
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.63 on 28143 degrees of freedom
## Multiple R-squared: 0.2257, Adjusted R-squared: 0.2254
## F-statistic: 745.9 on 11 and 28143 DF, p-value: < 2.2e-16

Ở đây northeast được lấy làm chuẩn. Với gợi ý này các bạn hãy so sánh những kết quả thu được với,
chẳng hạn, câu lệnh summary(nor) ở trên.

7.5 Vấn đề gán giá trị cho biến giả


Những giá trị của biến giả được gán bất kì giá trị nào bạn cảm thấy thích mà không hề ảnh hưởng gì
đến ý nghĩa của mô hình. Thực vậy, trở lại mô hình ở mục 6.1.1:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


269

WAGE = β1 + β2BLACK + ui (1)

Thay vì gán cho BLACK = 0 với ý nghĩa không phải là người Mĩ gốc Phi và BLACK = 1 là người Mĩ gốc
Phi bạn hoàn toàn có thể gán BLACK = 1 để mô tả không phải người Mĩ gốc Phi và BLACK = -1 là người
Mĩ gốc Phi. Dưới đây là R code thực hiện chạy mô hình (1) với các đổi biến mới:

trang$BLACK[trang$BLACK == 1] <- -1
trang$BLACK[trang$BLACK == 0] <- 1
hehe <- lm(WAGE ~ BLACK, data = trang)
summary(hehe)

##
## Call:
## lm(formula = WAGE ~ BLACK, data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -875.65 -269.15 -52.65 209.35 2087.35
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3363.24 19.33 173.951 < 2e-16 ***
## BLACK 127.40 19.33 6.589 7.37e-11 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 395.5 on 933 degrees of freedom
## Multiple R-squared: 0.04447, Adjusted R-squared: 0.04345
## F-statistic: 43.42 on 1 and 933 DF, p-value: 7.37e-11

Dựa vào kết quả hồi quy này ta có WAGE = 3363.24 +127.40BLACK. Nếu bạn không là người Mĩ gốc
Phi thì lương trung bình là 3363.24 + 127.40 =3490.64. Tính toán tương tự (cũng như so sánh các
tiêu chí khác, từ kiểm định F đến R2) các bạn thấy rằng ý nghĩa của mô hình chẳng có gì thay đổi cả
ngoại trừ một số điểm thuộc hình thức bề ngoài.

Một vấn đề nữa cần lưu ý là bản chất của biến định tính. Không giống như một số phần mềm khác, R
cho phép một biến định tính được gán bằng một trong hai cách: (1) hoặc là gán số cho biến định tính,
hoặc (2) gán kí tự. Để minh họa điều này chúng ta trở lại với bộ số liệu dữ liệu ch4bt8.wf1.

Bộ dữ liệu này có nhiều biến định tính. Chẳng hạn biến BLACK có hai giá trị là số nguyên 0 ứng với
người đa trắng và 1 ứng với người da màu. Mặc dù mang giá trị là số nhưng đây không phải là biến
định lượng. Với biến định lượng, chúng ta thường dùng kí hiệu kí tự để biểu diễn để thể hiện rõ hơn
bản chất của biến. Lệnh dưới đây cho phép chúng ta tạo một một biến mới có tên là chungtoc trong
đó white ứng với người da trắng, black ứng với người da màu. Đương nhiên ý nghĩa của hai biến
BLACK và chung toc là như nhau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


270

trang$chungtoc <- factor(trang$BLACK,


levels = c("0", "1"),
labels = c("white", "black"))
# Có thể thấy hai biến BLACK và chungtoc là như nhau:
head(trang[, c("WAGE","BLACK","chungtoc")])

## WAGE BLACK chungtoc


## 1 3942 0 white
## 2 2700 0 white
## 3 2765 0 white
## 4 2789 0 white
## 5 2825 0 white
## 6 2825 1 black

Tất nhiên, kết quả hồi quy như ở mục 7.1.1 là không có gì thay đổi nếu ta sử dụng biến giả này (không
hiển thị kết quả):

anova1 <- lm(data = trang, WAGE ~ chungtoc)


summary(anova1)

Điều này một lần nữa nhắc nhở các bạn về ý nghĩa thực sự của những biến định tính nằm ẩn sau
những con số. Ví dụ này cũng cho thấy R có thể xử lý linh hoạt biến định tính bất kể chúng được gán
chữ số hay kí tự - một lợi thế mà các phần mềm khác không có.

7.6 Sử dụng biến định tính cho hồi quy từng khúc và phân tích mùa vụ
Phần này chúng ta nghiên cứu việc ứng dụng kĩ thuật biến giả (biến định tính) cho một số phân tích
kinh tế thường thấy.

7.2.1 Hồi quy từng khúc


Việc thay đổi các chính sách kinh tế là có ảnh hưởng đến hành vi, chẳng hạn, tiết kiệm hay tiêu dùng.
Tại Mĩ, từ những năm 1982 trở đi xuất hiện nhiều chính sách kinh tế mới mà người ta tin rằng sẽ có
ảnh hưởng lớn đến hành vi tiết kiệm của hộ gia đình. Bộ dữ liệu table9_2.xls gồm các thông tin về
tiết kiệm (savings) và thu nhập (income) của các hộ gia đình từ năm 1970 đến 1995. Để đánh giá xem
sự xuất hiện của các chính sách này có gây ra những thay đổi về tiết kiệm hay không chúng ta xét mô
hình hồi quy từng khúc (piecewise linear regression) sau:

savings = β1 + β2income + β3giaidoan + ei (17)

Trong đó, savings là tiết kiệm, income là thu nhập còn giaidoan là biến định tính chỉ khoảng thời gian.
Cụ thể, giaidoan = A ứng với khoảng thời gian nghiên cứu từ năm 1981 trở về trước, giaidoan = B ứng
với khoảng thời gian nghiên cứu từ 1982 đến 1995.

Do bộ dữ liệu gốc chưa có biến giả giaidoan nên trước hết, chúng ta tạo biến này với mô tả như trên.
Dưới đây là lệnh đọc dữ liệu và tạo biến:

library(gdata)
dung <- read.xls("table9_2.xls")
head(dung)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


271

## year savings income


## 1 1970 61.0 727.1
## 2 1971 68.6 790.2
## 3 1972 63.6 855.3
## 4 1973 89.6 965.0
## 5 1974 97.6 1054.2
## 6 1975 104.4 1159.2

tail(dung)

## year savings income


## 21 1990 208.7 4166.8
## 22 1991 246.4 4343.7
## 23 1992 272.6 4613.7
## 24 1993 214.4 4790.2
## 25 1994 189.4 5021.7
## 26 1995 249.3 5320.8

dung$giaidoan[dung$year <= 1981] <- "A" # Tạo biến cho giai đoạn trước 1981
dung$giaidoan[dung$year > 1981] <- "B" # Tạo biến cho giai đoạn từ 1982.
head(dung)

## year savings income giaidoan


## 1 1970 61.0 727.1 A
## 2 1971 68.6 790.2 A
## 3 1972 63.6 855.3 A
## 4 1973 89.6 965.0 A
## 5 1974 97.6 1054.2 A
## 6 1975 104.4 1159.2 A

tail(dung)

## year savings income giaidoan


## 21 1990 208.7 4166.8 B
## 22 1991 246.4 4343.7 B
## 23 1992 272.6 4613.7 B
## 24 1993 214.4 4790.2 B
## 25 1994 189.4 5021.7 B
## 26 1995 249.3 5320.8 B

Chúng ta có thể đánh giá sơ bộ bằng hình ảnh về hành vi của tiết kiệm ứng với hai giai đoạn như sau:

library(ggplot2)
ggplot(dung, aes(income, savings, colour = giaidoan)) + geom_point()+
geom_smooth(method = "lm", se = FALSE) + theme_bw()

Nguyễn Chí Dũng http://rpubs.com/chidungkt


272

Có vẻ như những chính sách kinh tế mới này có ảnh hưởng to lớn đến hành vi tiết kiệm. Cụ thể, đường
hồi quy ở giai đoạn B (từ năm 1982 đến 1995) là ít dốc hơn giai đoạn trước. Tuy nhiên đây mới chỉ là
nhận định ban đầu. Để có bằng chứng thống kê chúng ta thực hiện hồi quy cho mô hình (17)

love <- lm(savings ~ giaidoan + income + giaidoan*income, data = dung)


summary(love)

##
## Call:
## lm(formula = savings ~ giaidoan + income + giaidoan * income,
## data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -38.729 -14.777 -1.398 11.689 50.535
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.01612 20.16483 0.050 0.960266
## giaidoanB 152.47855 33.08237 4.609 0.000136 ***
## income 0.08033 0.01450 5.541 1.44e-05 ***
## giaidoanB:income -0.06547 0.01598 -4.096 0.000477 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 23.15 on 22 degrees of freedom
## Multiple R-squared: 0.8819, Adjusted R-squared: 0.8658
## F-statistic: 54.78 on 3 and 22 DF, p-value: 2.268e-10

Chúng ta thấy rằng hệ số hồi quy của giaidoan*income là -0.06547 và có ý nghĩa thống kê ở mức 1%
nên chúng ta có bằng chứng thống kê xác nhận giả thuyết rằng các hộ gia đình từ năm 1982 trở về
sau tiết kiệm ít hơn (hay chi tiêu dùng nhiều hơn) giai đoạn trước.

6.7.1 Tính chất mùa vụ trong phân tích kinh tế sử dụng biến định tính
Nhiều chuỗi dữ liệu kinh tế có tính chất chu kì (seasonal pattern). Chẳng hạn như CPI ở Việt Nam có
xu hướng tăng vào những quý cuối năm. Một ví dụ khác là doanh thu bán của tủ lạnh rõ ràng cũng có
tính chu kì. Chúng ta hãy nghiên cứu doanh thu theo quý của tủ lạnh (biến FRIG) được lưu ở bộ dữ

Nguyễn Chí Dũng http://rpubs.com/chidungkt


273

liệu table9_3.xls trong 8 năm liên tiếp (từ 1978 đến 1985), tức là dữ liệu trải dài trong thời gian 32
quý. Trước hết ta đọc bộ dữ liệu này:

dung <- read.xls("table9_3.xls")

Vì chúng ta nhận định rằng doanh thu của tủ lạnh là khác biệt giữa các quý, trong khi bộ dữ liệu gốc
này chưa có những biến định tính thể hiện doanh thu ứng với các quý nên chúng ta cần tạo ra các biến
giả này trước hết:

dung$quy1 <- rep(c(1, 0, 0, 0), 8) # Tạo biến giả ứng với quý 1.
dung$quy2 <- rep(c(0, 1, 0, 0), 8) # Tạo biến giả ứng với quý 2.
dung$quy3 <- rep(c(0, 0, 1, 0), 8) # Tạo biến giả ứng với quý 3.
dung$quy4 <- rep(c(0, 0, 0, 1), 8) # Tạo biến giả ứng với quý 4.
dung$t <- 1:32 # Tạo biến t ứng với 32 quý.
head(dung) # Xem kết quả của việc tạo biến giả.

## DISH FRIG WASH DUR quy1 quy2 quy3 quy4 t


## 1 841 1317 1271 252.6 1 0 0 0 1
## 2 957 1615 1295 272.4 0 1 0 0 2
## 3 999 1662 1313 270.9 0 0 1 0 3
## 4 960 1295 1150 273.9 0 0 0 1 4
## 5 894 1271 1289 268.9 1 0 0 0 5
## 6 851 1555 1245 262.9 0 1 0 0 6

Chúng ta có thể minh họa doanh thu của tủ lạnh theo thời gian như sau:

ggplot(dung, aes(t,FRIG)) + geom_line() + geom_point(col = "red")

Hình ảnh này cho thấy rằng doanh thu về tủ lạnh cao nhất sẽ là quý 3, thấp nhất là quý 4 và có vẻ như
quy luật này được lặp lại hàng năm.

Để chắc chắn hơn cho nhận định này, chúng ta xét mô hình hồi quy sau:

FRIG = β1 + β2quy1 + β3quy2 + β4quy3 + ei (17)

Chạy mô hình này chúng ta có:

apple <- lm(FRIG ~ quy1 + quy2 + quy3, data = dung)


summary(apple)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


274

##
## Call:
## lm(formula = FRIG ~ quy1 + quy2 + quy3, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -300.75 -130.81 51.88 104.91 231.50
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1160.00 59.99 19.336 < 2e-16 ***
## quy1 62.12 84.84 0.732 0.47009
## quy2 307.50 84.84 3.625 0.00114 **
## quy3 409.75 84.84 4.830 4.42e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 169.7 on 28 degrees of freedom
## Multiple R-squared: 0.5318, Adjusted R-squared: 0.4816
## F-statistic: 10.6 on 3 and 28 DF, p-value: 7.908e-05

Chúng ta thấy rằng nếu lấy quý 4 làm gốc, thì doanh thu trung bình của quý này là 1160 còn doanh
thu trung bình của quý 3 là cao hơn 490.75. Đáng chú ý là hệ số hồi quy của quy3 có ý nghĩa thống kê
nên chúng ta có thể nói kết luận rằng doanh thu trung bình tủ lạnh cao nhất ở quý 3.

Nếu đưa vào biến giả quy4 vào mô hình thì chúng ta sẽ mắc bẫy biến giả (dummy variable trap).

Nguyễn Chí Dũng http://rpubs.com/chidungkt


275

Chương 8: Hiện tượng đa cộng tuyến và cách xử lý đa cộng tuyến

Chương này chúng ta sẽ nghiên cứu về hiện tượng đa cộng tuyến (tiếng Anh là Multicollinearity hoặc
Collonearity) cũng như cách xử lý hiện tượng này bằng một số giải pháp xử lí hiện tượng đa cộng
tuyến.

8.1 Hiện tượng đa cộng tuyến


Hiện tượng đa cộng tuyến xẩy ra khi tồn tại mức độ tương quan cao giữa các biến độc lập trong các
mô hình hồi quy. Xét bộ dữ liệu giả thuyết sau:

X2 X3 X4
10 50 52
15 75 75
18 90 97
24 120 129
30 150 152

Chúng ta có thể nhập bộ dữ liệu này vào R dưới dạng một data.frame với tên gọi ct:

ct <- data.frame(x2 = c(10, 15, 18, 24, 30),


x3 = c(50, 75, 90, 120, 150),
x4 = c(52, 75, 97, 129, 152))
ct

## x2 x3 x4
## 1 10 50 52
## 2 15 75 75
## 3 18 90 97
## 4 24 120 129
## 5 30 150 152

Chúng ta có thể thấy rằng thấy rằng X3=5X2 (cộng tuyến hoàn hảo). Nói theo ngôn ngữ thống kê thì
tương quan giữa X3 và X2 bằng 1 còn tương quan gữa X3 và X4 gần bằng 1 (cộng tuyến phi hoàn hảo)
như chúng ta có thể thấy dưới đây:

cor(ct)

## x2 x3 x4
## x2 1.0000000 1.0000000 0.9958817
## x3 1.0000000 1.0000000 0.9958817
## x4 0.9958817 0.9958817 1.0000000

Nguyễn Chí Dũng http://rpubs.com/chidungkt


276

Ở đây trường hợp của X3 và X2 gọi là cộng tuyến hoàn hảo (Perfect Collinearity) còn tình huống của
X3 và X4 gọi là cộng tuyến không hoàn hảo (Imperfect Collinearity). Theo Gujarati & Porter (2009),
hiện tượng đa cộng tuyến gây ra những hậu quả sau:

1. Các ước lượng OLS vẫn có tính chất BLUE nhưng sai số chuẩn của các ước lượng này rất lớn
dẫn đến ước lượng khoảng tin cậy là không chính xác.
2. Do khoảng tin cậy là rất rộng nên chúng ta có thể thất bại trong việc bắc bỏ giả thuyết rằng
một hệ số hồi quy nào đó là bằng 0.
3. Một hoặc nhiều thống kê t trong mô hình không có ý nghĩa trong khi R2, giá trị thống kê F có
thể rất cao.
4. Các ước lượng OLS và sai số chuẩn của chúng đạc biệt nhạy cảm với một sự thay đổi nhỏ của
số liệu.
5. Thêm một biến số có tương quan cao với một biến bất kì có ở mô hình đã chọn có thể làm thay
đổi rất lớn các giá trị ước lượng của các biến số khác trong mô hình.

Theo Montgomery & Peck(1975), hiện tượng đa cộng tuyến có thể xẩy ra vì những nguyên nhân sau:

1. Phương pháp thu thập dữ liệu. Chẳng hạn như chọn mẫu với một khoảng nhỏ các giá trị cho
biến độc lập.
2. Những hạn chế về mô hình hoặc tổng thể được chọn mẫu. Ví dụ, trong hồi quy tiêu dùng điện
Y với thu nhập hộ gia đình (X2) và diện tích hộ gia đình (X3) thì thường các hộ gia đình có thu
nhập cao diện tích lớn.
3. Định dạng mô hình sai. Chẳng hạn chúng ta cho thêm biến X2 vào mô hình đã có biến độc lập
X. Điều này càng nghiêm trọng khi X nhận giá trị trong một khoảng nhỏ.
4. Số lượng biến độc lập nhiều hơn số quan sát (Overdetermined Model). Điều này thường xẩy
ra trong các nghiên cứu về Y Khoa. Thông thường, mẫu thử nghiệm (bệnh nhân) có số lượng
rất bé trong khi nhà nghiên cứu lại phải thu thập rất nhiều thông tin cho biến độc lập từ họ.
5. Xu hướng chung của các chuỗi thời gian. Nhiều chuỗi thời gian cùng tăng hoặc cùng giảm theo
thời gian (common trend). Do đó nếu thực hiện hồi quy tăng trưởng chi tiêu theo thu nhập và
tài sản thì hai biến độc lập thường là những biến có cùng xu hướng và do vậy có tương quan
cao.

Để thấy rõ các hậu quả trên chúng ta xét mô hình sau:

Y = b1 +b2X2i + b3X3i + ui

Ước lượng bằng phương pháp OLS chỉ ra rằng:


2
(∑ 𝑦𝑖 𝑥2𝑖 )(∑ 𝑥3𝑖 ) − (∑ 𝑦𝑖 𝑥3𝑖 )(∑ 𝑥2𝑖 𝑥3𝑖 )
𝑏2 = 2 )(∑ 2 )
(∑ 𝑥2𝑖 𝑥3𝑖 − (∑ 𝑥2𝑖 𝑥3𝑖 )2
2
(∑ 𝑦𝑖 𝑥3𝑖 )(∑ 𝑥2𝑖 ) − (∑ 𝑦𝑖 𝑥2𝑖 )(∑ 𝑥2𝑖 𝑥3𝑖 )
𝑏3 = 2 )(∑ 2
(∑ 𝑥2𝑖 𝑥3𝑖 ) − (∑ 𝑥2𝑖 𝑥3𝑖 )2

𝑏1 = 𝑌̅ − 𝑏2 𝑋̅2 − 𝑏3 𝑋̅3
Với các phương sai lần lượt là:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


277

𝜎2 𝜎2
var(𝑏2 ) = 2 (1 2 ) = ∑ 2 VIF
∑ 𝑥2𝑖 − 𝑟23 𝑥2𝑖

𝜎2 𝜎2
var(𝑏3 ) = 2 (1 2 ) = ∑ 2 VIF
∑ 𝑥3𝑖 − 𝑟23 𝑥3𝑖
Trong đó:
1
VIF = 2
1 − 𝑟23
Với r223 là bình phương hệ số tương quan giữa biến X3 và X2 , VIF gọi là hệ số phóng đại phương sai
(Variance Inflating Factor). Chúng ta có thể thấy khi r23 càng lớn thì hệ số VIF này càng cao, var(b3)
càng lớn và nếu r23 = 1 (cộng tuyến hoàn hảo) thì var(b3) là vô cùng:

r23 VIF Var(b2)


𝜎2
0.0 1.00 2 = 𝐾
∑ 𝑋2𝑖
0.50 1.33 1.33 x K
0.70 1.96 1.96 x K
0.80 2.78 2.78 x K
0.90 5.26 5.26 x K
0.95 10.26 10.26 x K
0.99 50.25 50.25 x K
0.995 100.00 100 x K
1.00 Không XĐ Không XĐ
(Bảng 1: Hệ số tương quan 23 và VIF)

Chú ý rằng ngoài hệ số VIF như trên người ta còn lấy TOL = 1/VIF (nghịch đảo của VIF) là tiêu chí
nhận định về hiện tượng đa cộng tuyến. Hiện tại, ngưỡng VIF (hay TOL, r23) bằng bao nhiêu để chỉ ra
hiện tượng đa cộng tuyến vẫn là một vấn đề chưa có sự thống nhất giữa các nhà kinh tế lượng. Gujarati
& Porter (2009) chỉ ra một số dấu hiệu của hiện tượng đa cộng tuyến trong mô hình khi: (1) hệ số VIF
≥ 10, hoặc (2) hệ số tương quan r của bất kì cặp biến nào trong mô hình lớn hơn 0.8. Trong khi đó
Allison (1999) đưa ra tiêu chí chặt hơn khi chọn VIF > 2.5 (hay r > 0.775).

8.2 Một ví dụ minh họa hiện tượng đa cộng tuyến


Chúng ta nghiên cứu một ví dụ điển hình về hiện tượng đa cộng tuyến với số liệu ở bảng 2. Giả sử
chúng ta cần đánh giá tác động của thu nhập (X2) và tài sản (X3) lên tiêu dùng Y. Do bộ số liệu này
không lớn nên các bạn tự nhập số liệu này vào R dưới dạng một data.frame với tên gọi là dung như
cách làm ở mục 8.1.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


278

Y, $ X2, $ X3, $
70 80 810
65 100 1009
90 120 1273
95 140 1425
110 160 1633
115 180 1876
120 200 2052
140 220 2201
155 240 2435
150 260 2686
(Bảng 2: Dữ liệu về tiêu dùng, thu nhập, và tài sản)

Thực hiện ước lượng trong R ta có:

Y <- c(70, 65, 90, 95, 110, 115, 120, 140, 155, 150)
X2 <- c(80, 100, 120, 140, 160, 180, 200, 220, 240, 260)
X3 <- c(810, 1009, 1273, 1425, 1633, 1876, 2052, 2201, 2435, 2686)
dung <- data.frame(Y, X2, X3)
attach(dung)
jj <- lm(data = dung, Y ~ X2 + X3)
summary(jj)

##
## Call:
## lm(formula = Y ~ X2 + X3, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -11.1120 -4.4767 0.9206 4.1744 7.5844
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 24.77473 6.75250 3.669 0.00798 **
## X2 0.94154 0.82290 1.144 0.29016
## X3 -0.04243 0.08066 -0.526 0.61509
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 6.808 on 7 degrees of freedom
## Multiple R-squared: 0.9635, Adjusted R-squared: 0.9531
## F-statistic: 92.4 on 2 and 7 DF, p-value: 9.286e-06

Nguyễn Chí Dũng http://rpubs.com/chidungkt


279

Kết quả này chỉ ra rằng mặc dù R2 là rất cao (0.9635) và thống kê F rất lớn (92.4) nhưng không một
hệ số hồi quy nào của X2, X3 có ý nghĩa thống kê. Điều này cho thấy mô hình có dấu hiệu của bệnh đa
cộng tuyến vì rằng thu nhập (X2) và tài sản (X3) là những biến có tương quan dương rất cao. Chúng
ta có thể kiểm tra bảng hệ số tương quan:

cor(dung)

## Y X2 X3
## Y 1.0000000 0.9808474 0.9780997
## X2 0.9808474 1.0000000 0.9989624
## X3 0.9780997 0.9989624 1.0000000

Chúng ta có thể thấy tương qua giữa X2 và X3 là 0.9989 (gần bằng 1).

Khi thực hiện hồi quy cho Y theo X2:

chimse <- lm(data = dung, Y ~ X2)


summary(chimse)

##
## Call:
## lm(formula = Y ~ X2, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -10.364 -4.977 1.409 4.364 8.364
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 24.45455 6.41382 3.813 0.00514 **
## X2 0.50909 0.03574 14.243 5.75e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 6.493 on 8 degrees of freedom
## Multiple R-squared: 0.9621, Adjusted R-squared: 0.9573
## F-statistic: 202.9 on 1 and 8 DF, p-value: 5.753e-07

Và Y theo X3:

dinang <- lm(data = dung, Y ~ X3)


summary(dinang)

##
## Call:
## lm(formula = Y ~ X3, data = dung)
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


280

## Residuals:
## Min 1Q Median 3Q Max
## -9.6227 -5.5867 0.9576 5.0414 9.4142
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 24.411045 6.874097 3.551 0.0075 **
## X3 0.049764 0.003744 13.292 9.8e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 6.938 on 8 degrees of freedom
## Multiple R-squared: 0.9567, Adjusted R-squared: 0.9513
## F-statistic: 176.7 on 1 and 8 DF, p-value: 9.802e-07

Căn cứ vào các kết quả trên chúng ta có thể thấy rằng: mặc dù cả hai hệ số hồi quy của X2 và X3 không
có ý nghĩa thống kê khi chúng cùng xuất hiện trong một mô hình nhưng loại bỏ biến số có tương quan
cao (hoặc là X2, hoặc là X3) với các biến số khác thì việc này làm cho hệ số hồi quy của các biến số
khác có ý nghĩa thống kê ở mức cao.

Chúng ta cũng có thể tính hệ số VIF cho mô hình hồi quy Y = β1+ β2X2+ β3X3 như sau:

1 / (1 - cor(X2, X3)*cor(X2, X3))

## [1] 482.1275

Chúng ta có thể thấy hệ số VIF là rất lớn: 482.13. Trong tình huống mà mô hình hồi quy có nhiều biến
số thì tính hệ số VIF như vậy phải lặp đi lặp lại. Chúng ta có thể tính cách khác với gói car (đã đề cập
trong mục 4.2.1 của chương 4) trong R như sau:

library(car)
vif(jj)

## X2 X3
## 482.1275 482.1275

Do mô hình của chúng ta chỉ có hai biến độc lập nên r23 = r32 do đó VIF ứng với X2 và X3 như nhau và
cùng bằng 482.1275 như chúng ta tính trực tiếp từ công thức như ở trên.

Chúng ta cũng có thể mở rộng công thức tính VIF cho mô hình hồi quy k biến số (mô hình có k-1 biến
độc lập) như sau:

𝜎2 1 𝜎2
var(𝑏𝑘 ) = ( )= VIF
∑ 𝑥𝑘2 1 − 𝑅𝑘2 ∑ 𝑥𝑘2
Trong đó R2k chính là R2 thu được từ hồi quy biến độc lập thứ k với k-2 biến độc lập còn lại – gọi là
các hồi quy phụ (Auxiliary Regression). Như vậy nếu mô hình hồi quy 11 biến số thì chúng ta sẽ có 10

Nguyễn Chí Dũng http://rpubs.com/chidungkt


281

hồi quy phụ ứng với 10 biến độc lập và do vậy chúng ta phải tính 10 hệ số VIF. Chúng ta có thể tính
các hệ số VIF này nhanh chóng với sự trợ giúp của lệnh vif() của gói car được trình bày ở trên.

Chúng ta cũng có thể tìm hiểu mức độ nhạy cảm của các mô hình hồi quy đối với một sự thay đổi nhỏ
của số liệu khi có hiện tượng đa cộng tuyến giữa các biến số. Chúng ta hãy xem xét hai bộ số liệu sau:

Y X2 X3 Y X2 X3
1 2 4 1 2 4
2 0 2 2 0 2
3 4 12 3 4 0
4 6 0 4 6 12
5 8 16 5 8 16

Nhập hai bộ dữ liệu này vào R dưới dạng hai data.frame với tên gọi là dulieu1 và dulieu2 rồi thực hiện
hồi quy cho Y theo X2 và X3:

dulieu1 <- data.frame(y = c(1:5),


x2 = c(2, 0, 4, 6, 8),
x3 = c(4, 2, 12, 0, 16))
dulieu2 <- data.frame(y = c(1:5),
x2 = c(2, 0, 4, 6, 8),
x3 = c(4, 2, 0, 12, 16))
summary(lm(data = dulieu1, y ~ x2 + x3))

##
## Call:
## lm(formula = y ~ x2 + x3, data = dulieu1)
##
## Residuals:
## 1 2 3 4 5
## -1.09878 0.80000 -0.01585 0.12805 0.18659
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.193902 0.773679 1.543 0.263
## x2 0.446341 0.184810 2.415 0.137
## x3 0.003049 0.085066 0.036 0.975
##
## Residual standard error: 0.9744 on 2 degrees of freedom
## Multiple R-squared: 0.8101, Adjusted R-squared: 0.6202
## F-statistic: 4.267 on 2 and 2 DF, p-value: 0.1899

summary(lm(data = dulieu2, y ~ x2 + x3))

Nguyễn Chí Dũng http://rpubs.com/chidungkt


282

##
## Call:
## lm(formula = y ~ x2 + x3, data = dulieu2)
##
## Residuals:
## 1 2 3 4 5
## -1.12162 0.73514 0.18378 0.05676 0.14595
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.21081 0.74802 1.619 0.247
## x2 0.40135 0.27206 1.475 0.278
## x3 0.02703 0.12523 0.216 0.849
##
## Residual standard error: 0.9635 on 2 degrees of freedom
## Multiple R-squared: 0.8143, Adjusted R-squared: 0.6286
## F-statistic: 4.386 on 2 and 2 DF, p-value: 0.1857

Ở bảng số liệu 2 chúng ta chỉ thực hiện thay đổi thứ tự cho một cặp giá trị của X3. Tuy nhiên sự thay
đổi này gây ra những tác động rất mạnh lên độ lệch chuẩn (cả cả giá trị thống kê t) ứng với hệ số của
X2: giá trị thống kê t giảm gần 2 lần. Nguyên nhân là tương quan giữa X2 và X3 tăng từ 0.5523 lên
0.8285 như chúng ta có thể thấy:

cor(dulieu1)

## y x2 x3
## y 1.000000 0.9000000 0.5063160
## x2 0.900000 1.0000000 0.5523448
## x3 0.506316 0.5523448 1.0000000

cor(dulieu2)

## y x2 x3
## y 1.0000000 0.9000000 0.7824884
## x2 0.9000000 1.0000000 0.8285172
## x3 0.7824884 0.8285172 1.0000000

Ví dụ này một lần nữa nhấn mạnh kết luận như các bạn đã biết ở trên: sai số chuẩn, thống kê t, và giá
trị p-value bị ảnh hưởng rất mạnh bởi một sự thay đổi nhỏ của số liệu.

8.3 Xử lý hiện tượng đa cộng tuyến bằng bỏ biến số căn cứ vào tiêu chí Cp của Mallows
Theo Gujarati (2011), Goldberger (1991) thì có ba cách có thể áp dụng để xử lí hiện tượng đa cộng
tuyến: (1) bỏ biến có mức độ tương quan cao với biến số khác, (2) sử dụng phương pháp phân tích
thành phần chính, và (3) không làm gì – Do Nothing. Phương pháp thứ hai đặc biệt hiệu quả khi xử lý
các mô hình có nhiều biến độc lập.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


283

Trong phần này chúng ta sẽ nghiên cứu phương pháp bỏ biến số căn cứ vào tiêu chí Cp của Mallows.

Với mục đích minh họa, trong phần này chúng ta sẽ sử dụng bộ dữ liệu có tên Table4_0.dta từng
được sử dụng bởi Mroz (1987). Đây là bộ dữ liệu về 753 phụ nữ đã kết hôn trong năm 1975. Giả sử
chúng ta nghiên cứu tác động của các biến số như mức thu nhập của gia đình năm 1975 (faminc), mức
lương của chồng (hwage), độ tuổi (age), số năm đi học (educ).. lên số giờ làm việc (hours) của những
phụ nữ này. Tuy nhiên trong số đó có 325 người không làm việc trong năm đó và do vậy biến hours
= 0 cho các quan sát này. Chúng ta sẽ loại bỏ các quan sát này trong mô hình nghiên cứu. Như vậy
mẫu của chúng ta còn lại 428.

Trước hết, tôi giả định rằng các bạn đã thành thạo cách chỉ thị cho R đọc file dữ liệu Excel này dưới
dạng một data.frame có tên dacongtuyen. Sau khi thao tác nhập dữ liệu này, chúng ta bắt đầu thực
hành trong R.

Trước hết chúng ta xem xét mô hình gốc với hours là biến phụ thuộc với 15 biến độc lập còn lại. Trong
tình huống này không cần gõ tên của 15 biến độc lập trên khi thực hiện hồi quy mà chỉ làm như sau
là R tự hiểu rằng hours được hồi quy theo tất cả các biến còn lại:

setwd("D:/KTLR")
library(foreign)
dacongtuyen <- read.dta("Table4_0.dta")
# Loại một số biến không có trong mô hình cho gọn bộ số liệu:
nghiyeu <- dacongtuyen[, -c(1, 2, 3, 4, 5, 6, 7, 14, 24)]
# Chỉ lấy các quan sát mà hours > 0 từ data frame nghiyeu:
yeunghi <- subset(nghiyeu, hours > 0)
haha <- lm(data = yeunghi, hours~.)
summary(haha)

##
## Call:
## lm(formula = hours ~ ., data = yeunghi)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1683.9 -436.8 40.8 384.4 3500.3
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 8.595e+03 1.027e+03 8.368 9.21e-16 ***
## kidsl6 -1.916e+02 8.783e+01 -2.181 0.0297 *
## kids618 -2.451e+01 2.806e+01 -0.873 0.3830
## age -1.431e+01 9.661e+00 -1.481 0.1394
## educ -1.840e+01 1.934e+01 -0.951 0.3421
## wage -4.815e+01 1.041e+01 -4.624 5.04e-06 ***
## hhours -4.735e-01 7.327e-02 -6.463 2.91e-10 ***
## hage -5.586e+00 8.938e+00 -0.625 0.5323
## heduc -6.769e+00 1.399e+01 -0.484 0.6287

Nguyễn Chí Dũng http://rpubs.com/chidungkt


284

## hwage -1.418e+02 1.662e+01 -8.532 2.78e-16 ***


## faminc 1.389e-02 6.042e-03 2.299 0.0220 *
## mtr -6.273e+03 1.085e+03 -5.779 1.49e-08 ***
## mothereduc -1.838e+00 1.190e+01 -0.154 0.8774
## fathereduc -7.471e+00 1.119e+01 -0.668 0.5048
## unemployment -1.612e+01 1.064e+01 -1.515 0.1305
## exper 2.288e+01 4.777e+00 4.789 2.34e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 642.4 on 412 degrees of freedom
## Multiple R-squared: 0.3392, Adjusted R-squared: 0.3151
## F-statistic: 14.1 on 15 and 412 DF, p-value: < 2.2e-16

Trước khi chạy mô hình chúng ta kì vọng rằng số giờ làm việc có mối quan hệ tỉ lệ thuận với số năm
đi học (wage), trình độ giáo dục của bố (fathereduc), trình độ giáo dục của mẹ (mothereduc) và tỉ lệ
nghịch với tuổi (age), tuổi của chồng (hage), số giờ làm việc của chồng (hhours), mức lương của chồng
(hwage), tỉ lệ thuế thu nhập (mtr), số con nhỏ dưới 6 tuổi (kidsl6). Tuy nhiên, một số hệ số hồi quy
có dấu ngược với kì vọng. Ngoài ra, mô hình của chúng ta có tới 8 hệ số hồi quy không có ý nghĩa
thống kê.

Chúng ta có thể tính các 15 hệ số VIF trong R:

library(car)
vif(haha)

## kidsl6 kids618 age educ wage


## 1.225962 1.410795 5.756163 2.021618 1.229041
## hhours hage heduc hwage faminc
## 1.887424 5.224349 1.864803 3.643849 5.144349
## mtr mothereduc fathereduc unemployment exper
## 7.215127 1.603344 1.608908 1.077137 1.532452

Mặc dù các hệ số VIF này chưa phải là lớn lắm nhưng số lượng các biến không có ý nghĩa thống kê là
lớn gợi ý rằng rất có thể tồn tại hiện tượng đa cộng tuyến. Chẳng hạn, rõ ràng trình độ giáo dục của
mẹ (mothereduc) có tương quan cao với trình độ giáo dục của bố (fathereduc) và cũng tương quan
cao với trình độ giáo dục của con (educ). Như chúng ta đã biết, nguyên nhân là do các biến độc lập có
trong mô hình có thể có tương quan cao. Theo Gujarati & Porter (2009) nếu hệ số tương quan của
một cặp biến độc lập bất kì mà cao hơn 0.8 thì mô hình có thể gặp lỗi đa cộng tuyến nghiêm trọng.
Chúng ta có thể tìm hệ số tương quan của các biến độc lập bằng lệnh cor như đã làm ở mục 8.1 và 8.2.
Tuy nhiên, chúng ta có thể sử dụng gói PerformanceAnalytics để tìm hệ số tương quan giữa các biến
số cùng với các thông tin khác như mức ý nghĩa thống kê cùng histogram của các biến. Trước hết
chúng ta cài đặt bằng lệnh install.packages(“PerformanceAnalytics”). Bảng ma trận hệ số tương
quan của các biến độc lập từ kids đến faminc:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


285

library(PerformanceAnalytics)
chart.Correlation(yeunghi[,-c(1, 12:16)], histogram = TRUE, pch = 19)

Kết quả chỉ ra rằng tương quan giữa, chẳng hạn, age và hage là rất cao (0.89) và có ý nghĩa thống kê
ở mức 1% (tương ứng với ba dấu ***).

Chú ý rằng nếu bạn gõ chart.Correlation(yeunghi[,-c(1)], histogram=TRUE, pch=19) thì bạn sẽ


có một cái bảng có mật độ dày đặc nên khó quan sát các giá trị hiển thị. Trừ khi máy tính của bạn có
màn hình lớn.

Từ phân tích trên, chúng ta có thể loại biến số hage ra khỏi mô hình. Lập luận tương tự cho các biến
số khác chúng ta xét mô hình sau:

hours = a1 +a2age + a3educ + a4exper + a5faminc + a6hwage + a7hhours + a8kidsl6 + a9wage +


a10mtr + a11unemployment

Thực hiện trong R:

# Bỏ các biến ở cột 3,8,9,13,và 14:


yamato <- yeunghi[, -c(3, 8, 9, 13, 14)]
# Chạy mô hình 10 biến độc lập:
bb1 <- lm(data = yamato, hours~.)
summary(bb1)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


286

##
## Call:
## lm(formula = hours ~ ., data = yamato)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1660.5 -446.5 15.6 393.8 3495.9
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 8.485e+03 9.876e+02 8.591 < 2e-16 ***
## kidsl6 -1.804e+02 8.637e+01 -2.089 0.037297 *
## age -1.773e+01 4.903e+00 -3.616 0.000336 ***
## educ -2.703e+01 1.579e+01 -1.712 0.087713 .
## wage -4.743e+01 1.031e+01 -4.601 5.59e-06 ***
## hhours -4.865e-01 7.046e-02 -6.904 1.89e-11 ***
## hwage -1.450e+02 1.588e+01 -9.127 < 2e-16 ***
## faminc 1.378e-02 5.866e-03 2.349 0.019279 *
## mtr -6.351e+03 1.030e+03 -6.167 1.64e-09 ***
## unemployment -1.650e+01 1.056e+01 -1.563 0.118826
## exper 2.420e+01 4.653e+00 5.201 3.11e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 640.2 on 417 degrees of freedom
## Multiple R-squared: 0.3358, Adjusted R-squared: 0.3199
## F-statistic: 21.08 on 10 and 417 DF, p-value: < 2.2e-16

Có thể thấy rằng sau khi bỏ các biến số, hầu hết các hệ số hồi quy đều có ý nghĩa thống kê. Cách làm
trên phải qua hai bước: (1) trước tiên là loại các biến từ bộ số liệu, và (2) chạy lại mô hình. Có thể thu
được kết quả hoàn toàn tương tự (không hiển thị kết quả) theo cách thức khác như sau:

bb1 <- lm(data = yeunghi[, -c(3, 8, 9, 13, 14)], hours~.)


summary(bb1)

Hoặc cũng có thể sử dụng hàm update(). Các bạn có thể gõ ?update() trong R để tìm hiểu thêm.

Chúng ta cũng có thể tìm các hệ số VIF cho mô hình mới và có thể thấy rằng tất cả chúng đều khá bé:

vif(bb1)

## kidsl6 age educ wage hhours


## 1.193771 1.493132 1.357462 1.213341 1.757566

Nguyễn Chí Dũng http://rpubs.com/chidungkt


287

## hwage faminc mtr unemployment exper


## 3.352382 4.883432 6.540321 1.068847 1.464052

Một lần nữa chúng ta chú ý rằng hệ số VIF được tính cho biến age chẳng hạn được tính bằng VIF =
1/(1-R2) trong đó R2 chính là hệ số xác định (Multiple R-Squared) thu được khi hồi quy, chẳng hạn,
kidsl6 theo 9 biến số còn lại là age cho đến exper.

Cần nhắc lại rằng chiến lược xử lý bằng cách bỏ biến như vậy là cần phải rất thận trọng (Gujarati,
2011) vì việc bỏ biến có thể còn gây ra những hậu quả nghiêm trọng hơn những hậu quả gây ra bởi
hiện tượng đa cộng tuyến (Nguyễn & Nguyễn, 2012). Một vấn đề nữa là chiến lược bỏ biến mà chúng
ta vừa thực hiện ở trên có vẻ tùy tiện và không tuân theo một quy tắc cụ thể nào ngoài việc căn cứ vào
hiểu biết của chúng ta về mối quan hệ giữa các biến số. Để xử lý vấn đề này, chúng ta có thể căn cứ
vào tiêu chí Cp của Mallows (Mallows’ Cp) để lựa chọn mô hình (Ledolter, 2013). Theo đó, chúng ta
sẽ chọn mô hình bằng căn cứ vào hai tiêu chí sau: (1) R2 hoặc R2 hiệu chỉnh càng cao càng tốt, và (2)
có Cp càng thấp càng tốt.

Để thực hiện việc loại biến nhằm xử lý đa cộng tuyến ở mức cao của mô hình, trước hết chúng ta cần
cài đặt gói leaps bằng lệnh install.packages(“leaps”). Sau khi cài đặt gói này, chúng ta có thể thực
hiện chiến lược bỏ biến cho mô hình một cách khoa học hơn như sau:

X <- yeunghi[, 2:16] # chú ý chữ X in hoa.


y <- yeunghi[, 1]
library(leaps) # Gọi gói leaps.
out <- summary(regsubsets(X, y, nbest = 2, nvmax = ncol(X)))
yeu <- cbind(out$which, out$rsq,out$cp)
yeu # Hiển thị kết quả (chú ý đến R2 cũng như Cp ở hai cột cuối cùng).

## (Intercept) kidsl6 kids618 age educ wage hhours hage heduc hwage faminc
## 1 1 0 0 0 0 0 0 0 0 0 0
## 1 1 0 0 0 0 0 0 0 0 0 0
## 2 1 0 0 0 0 0 0 0 0 1 0
## 2 1 0 0 0 0 0 0 0 0 0 0
## 3 1 0 0 0 0 0 1 0 0 1 0
## 3 1 0 0 0 0 0 0 0 0 1 0

….
## mtr mothereduc fathereduc unemployment exper R2 Cp
## 1 0 0 0 0 1 0.08953864 143.625603
## 1 1 0 0 0 0 0.03293060 178.917792
## 2 1 0 0 0 0 0.13923672 114.641418
## 2 1 0 0 0 1 0.11801302 127.873299
## 3 1 0 0 0 0 0.22821590 61.167499
## 3 1 0 0 0 1 0.19322075 82.985167

Nguyễn Chí Dũng http://rpubs.com/chidungkt


288

Ở đây các bạn có thể thấy hai cột giá trị cuối cùng lần lượt chính là R2 và Cp. Với các biến độc lập, cột
biến số nào mà đánh số 1 thì mô hình có biến ấy, đánh số 0 thì không có biến trong mô hình. Ở đây có
ba mô hình có Cp thấp hơn cả. Ví dụ, có một mô hình có 9 biến độc lập (là các biến độc lập nào các bạn
căn cứ vào cột biến có giá trị 1) với R2 và Cp lần lượt là 0.33189522 và 8.528801. Tuy nhiên, nếu
chúng ta theo đuổi chiến lược chọn mô hình có Cp thấp nhất nhưng lại có R2 lớn nhất có thể thì chúng
ta sẽ chọn mô hình có 10 biến ở dòng trên (chú ý có hai mô hình có 10 biến độc lập) thì chúng ta sẽ
có kết quả như sau:
greek <- yeunghi[, -c(3, 8, 9, 13, 14)] # Bỏ các biến ở cột 3,8,9,13,và 14.
bb2 <- lm(data = greek, hours~.) # Chạy mô hình 10 biến độc lập.
summary(bb2)

##
## Call:
## lm(formula = hours ~ ., data = greek)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1660.5 -446.5 15.6 393.8 3495.9
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 8.485e+03 9.876e+02 8.591 < 2e-16 ***
## kidsl6 -1.804e+02 8.637e+01 -2.089 0.037297 *
## age -1.773e+01 4.903e+00 -3.616 0.000336 ***
## educ -2.703e+01 1.579e+01 -1.712 0.087713 .
## wage -4.743e+01 1.031e+01 -4.601 5.59e-06 ***
## hhours -4.865e-01 7.046e-02 -6.904 1.89e-11 ***
## hwage -1.450e+02 1.588e+01 -9.127 < 2e-16 ***
## faminc 1.378e-02 5.866e-03 2.349 0.019279 *
## mtr -6.351e+03 1.030e+03 -6.167 1.64e-09 ***
## unemployment -1.650e+01 1.056e+01 -1.563 0.118826
## exper 2.420e+01 4.653e+00 5.201 3.11e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 640.2 on 417 degrees of freedom
## Multiple R-squared: 0.3358, Adjusted R-squared: 0.3199
## F-statistic: 21.08 on 10 and 417 DF, p-value: < 2.2e-16

Chú ý rằng giá trị R2 ở mô hình bb2 chỉ có 10 biến độc lập này là 0.3358. Đây chính là giá trị R2 mà
chúng ta đã biết trước vì nó cũng chính là mô hình bb1 (việc trùng lặp giữa hai mô hình bb1 và bb2
chỉ là ngẫu nhiên). Mô hình bb2 so với mô hình 15 biến độc lập ban đầu có R2 thua kém 1% (0.3358
so với 0.3392). Nói cách khác, khi chúng ta loại đi 5 biến số, thì sức mạnh giải thích của mô hình giảm
không đáng kể.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


289

Bạn cũng có thể chọn mô hình chỉ có 9 biến số (nếu ưu tiên Cp thấp nhất) một cách tương tự. Ví dụ
này cũng cho thấy ưu thế của R so với các phần mềm thống kê khác trong việc hỗ trợ chiến lược loại
biến khi xử lý hiện tượng đa cộng tuyến với tiêu chí Cp và R2, đặc biệt là với các mô hình có số lượng
biến độc lập rất lớn.

8.4 Xử lý hiện tượng đa cộng tuyến bằng phân tích thành phần chính PCA
Ngoài cách xử lý bằng cách bỏ biến như trên, Gujarati (2011) còn đề xuất sử dụng phương pháp phân
tích thành phần chính PCA (Principal Component Analysis). Với R chúng ta có thể thực hiện PAC cho
dữ liệu với sự trợ giúp của gói psych và gói factoextra. Trước hết cài đặt gói psych:
install.packages("psych")

Riêng gói factoextra cài đặt có chút phức tạp hơn vì phải cài đặt từ Github:
install.packages("devtools")
library(devtools)
install_github("kassambara/factoextra")

Để minh họa cho PCA chúng ta tiếp tục sử dụng data frame có tên yeunghi ở mục 8.3. Để thực hiện
PCA trước hết chúng ta cần loại biến hours ra khỏi data frame này rồi mới thực hiện PCA:
dung <- yeunghi[, -c(1)]
Kế tiếp chúng ta cần đảm bảo rằng sử dụng PCA là phù hợp bằng kiểm định KMO:
library(psych)
KMO(dung)

## Kaiser-Meyer-Olkin factor adequacy


## Call: KMO(r = dung)
## Overall MSA = 0.68
## MSA for each item =
## kidsl6 kids618 age educ wage
## 0.80 0.68 0.63 0.78 0.78
## hhours hage heduc hwage faminc
## 0.28 0.64 0.77 0.65 0.73
## mtr mothereduc fathereduc unemployment exper
## 0.65 0.72 0.73 0.70 0.73

Để phân tích PCA chúng ta cần giá trị KMO này tối thiểu là 0.5. Với dữ liệu của chúng ta, KMO Test là
0.68 cho thấy sử dụng PCA là phù hợp. Với số liệu đã cho chúng ta thực hiện PCA trong R như sau:
pca <- prcomp(dung, scale = TRUE)
library(factoextra); library(ggplot2); library(factoextra)
get_eig(pca)

## eigenvalue variance.percent cumulative.variance.percent


## Dim.1 3.54481880 23.6321253 23.63213
## Dim.2 2.88141539 19.2094359 42.84156
## Dim.3 1.45982184 9.7321456 52.57371

Nguyễn Chí Dũng http://rpubs.com/chidungkt


290

## Dim.4 1.29650183 8.6433455 61.21705


## Dim.5 1.04000140 6.9333427 68.15040
## Dim.6 0.88426249 5.8950833 74.04548
## Dim.7 0.82592243 5.5061495 79.55163
## Dim.8 0.69843990 4.6562660 84.20789
## Dim.9 0.64950612 4.3300408 88.53793
## Dim.10 0.58739822 3.9159881 92.45392
## Dim.11 0.41507530 2.7671687 95.22109
## Dim.12 0.34694362 2.3129575 97.53405
## Dim.13 0.18225132 1.2150088 98.74906
## Dim.14 0.10463671 0.6975781 99.44664
## Dim.15 0.08300464 0.5533643 100.00000

Số lượng các nhân tố được rút ra căn cứ vào tiêu chuẩn giá trị eigenvalue lớn hơn 1. Từ kết quả phân
tích PCA, chúng ta thấy 15 biến số ban đầu rút lại còn 5 nhân tố chính. Nhân tố thứ nhất (Dim1) giải
thích cho 24% tổng biến thiên (dòng variance.percent) và 5 nhân tố này (từ Dim1 đến Dim5) giải
thích tất cả 74% biến thiên (dòng cumulative.variance.percent). Chúng ta có thể minh họa các nhân
tố được rút ra cùng tỉ lệ phương sai giải thích của chúng:
fviz_screeplot(pca, addlabels = TRUE, n = 15)

Chúng ta cũng có thể minh họa các nhân tố rút ra cùng trị số eigenvalue tương ứng:
# Mặc định độ chính xác 1 chữ số sau dấu phẩy:
fviz_screeplot(pca, n=15, choice = "eigenvalue", addlabels = TRUE)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


291

Thực hiện hồi quy cho hours theo 5 điểm nhân tố được rút ra như sau:
choson <- principal(dung, nfactors = 15, rotate = "none", scores = TRUE)
yeunghi <- cbind(yeunghi, choson$scores)
summary(lm(data = yeunghi, hours ~ PC1 + PC2 + PC3 + PC4 + PC5))

##
## Call:
## lm(formula = hours ~ PC1 + PC2 + PC3 + PC4 + PC5, data = yeunghi)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1568.4 -635.4 68.2 559.7 3682.7
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1302.930 36.619 35.580 < 2e-16 ***
## PC1 -2.812 36.662 -0.077 0.938889
## PC2 142.660 36.662 3.891 0.000116 ***
## PC3 22.496 36.662 0.614 0.539817
## PC4 -120.400 36.662 -3.284 0.001109 **
## PC5 4.884 36.662 0.133 0.894092
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 757.6 on 422 degrees of freedom
## Multiple R-squared: 0.05872, Adjusted R-squared: 0.04757
## F-statistic: 5.265 on 5 and 422 DF, p-value: 0.0001053

Nguyễn Chí Dũng http://rpubs.com/chidungkt


292

Kết quả này chỉ ra rằng có vẻ như hai nhân tố PC2 và PC4 giải thích hành vi của biến hours tốt nhất.
Tuy nhiên, điểm khó ở đây là diễn đạt các kết quả thu được. Thực vậy, một trong những khó khăn đàu
tiên là chúng ta không thể sử dụng cách diễn đạt thường thấy kiểu như “.. khi các biến số khác không
đổi, thì PC2 tăng 1 dẫn đến biến phụ thuộc hours tăng 142.66..”.

Cách diễn giải đó là không chính xác. Thực vậy, PC2 được tạo ra bằng cách “tổ hợp” các biến số khác
và do đó, nó không có đơn vị. Nếu diễn giải như trên thì câu hỏi đầu tiên là: PC2 tăng 1, thế thì 1 ở đây
là 1 m, 1 h, hay 1 năm? Việc sử dụng hồi quy OLS cho các biến thành phần chính PC (và nhân tố chính
sau khi thực hiện EFA – một nội dung được đề cập kĩ ở chương 15) là không có ý nghĩa với mục đích
giải thích vì các biến độc lập là không có đơn vị trong tình huống chúng ta vừa nghiên cứu.

Một vấn đề nữa cần phải lưu ý ở đây là việc loại bỏ các biến tương quan cao một cách thủ công bằng
cách quan sát các cặp biến số có tương quan cao hơn một ngưỡng nào đó (chẳng hạn là 0.8) như trên
là không khuyến khích, đặc biệt là nếu mô hình có hàng trăm biến số. Việc loại bỏ chúng một cách có
hệ thống dựa trên một ngưỡng nào đó được thực hiện một cách nhanh chóng bằng gói caret.

Chúng ta cũng có thể khảo sát chi tiết các thông số về chất lượng của mô hình cũng như việc lựa chọn
biến số cho mô hình theo một cách khác được trình bày ngay sau đây.

8.5 Lựa chọn số lượng biến căn cứ vào các tiêu chuẩn thông tin BIC
Chúng ta biết rằng khi tăng số lượng biến số cho mô hình thì R2 của mô hình tăng. Tuy nhiên nỗ lực
tăng R2 cho mô hình bằng tăng biến số có mặt trong mô hình đối mặt với một số hạn chế sau. Thứ
nhất, gia tăng khả năng chúng ta cho vào một biến có tương quan cao với một hoặc một số biến sẵn
có. Thứ hai, càng nhiều biến số mô hình càng trở nên khó diễn giải. Và cuối cùng, R2 cũng tuân theo
quy luật “lợi ích cận biên giảm dần” – điều mà chúng ta sẽ nghiên cứu ở trong mục này. Hơn nữa ngoài
R2 chúng ta cũng cần căn cứ vào một số tiêu chuẩn khác, chẳng hạn, tiêu chuẩn thông tin BIC/AIC hoặc
hệ số Cp của Mallows để lựa chọn biến số cho mô hình.

Dưới đây chúng ta sẽ khảo sát một số tiêu chí lựa chọn mô hình đã biết để từ đó đưa ra một chiến
lược lựa chọn biến số khoa học hơn. Chúng ta trở lại với bộ số liệu yeunghi đã sử dụng ở các mục
trên với hàm regsubsets() của gói leaps. Hàm này cho biết sự thay đổi của các tiêu chí lưa chọn mô
hình ra sao khi số lượng biến số thay đổi. Từ đó, chúng ta có thể đưa ra chiến lược lựa chọn biến số
phù hợp.
# nvmax = 15 chính là số biến độc lập của mô hình đầy đủ. Nếu không có lựa ch
ọn này, mặc định là 8:
full <- regsubsets(hours~., data = yeunghi, nvmax = 15)
love <- summary(full)
# Hiển thị các tiêu chí sử dụng để đánh giá mô hình:
names(love)

## [1] "which" "rsq" "rss" "adjr2" "cp" "bic" "outmat" "obj"

Ở đây chúng ta thấy có những tiêu chí quên thuộc như R2 (kí hiệu rsq), BIC (ki hiệu bic). Giả sử chúng
ta chọn bốn tiêu chí là R2, BIC, Cp, và RSS:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


293

r2 <- love$rsq
bic <- love$bic
which.min(bic) # Số lượng biến số trong mô hình cho BIC thấp nhất.

## [1] 6

cp <- love$cp
which.min(cp) Số lượng biến số trong mô hình cho Cp thấp nhất.

## [1] 10

rss=love$rss

Chúng ta đánh giá các tiêu chuẩn lựa chọn mô hình thay đổi ra sao với biến số có trong mô hình bằng
hình ảnh sau:
par(mfrow=c(2, 2))
par(bg = "grey90")
plot(r2, xlab = "So luong bien", ylab = "R2", type = "b", pch = 16)
plot(rss, xlab = "So luong bien", ylab = "RSS", type="b", pch = 16)
plot(bic, xlab = "So luong bien", ylab = "BIC", type = "b", pch = 16)
points(which.min(bic), bic[which.min(bic)], col = "red", cex = 2, pch = 20)
plot(cp, xlab = "So luong bien", ylab = "Mallows' Cp", type = "b", pch = 16)
points(which.min(cp), cp[which.min(cp)], col = "red", cex = 2, pch = 20)

Chúng ta thấy rằng với R2 chẳng hạn, khi số lượng biến tăng thì tiêu chí này cũng tăng nhưng với tốc
độ chậm dần. Đến ngưỡng 8 biến số thì gia tăng thêm biến số gần như không dẫn đến tăng tiêu chí
này một cách dáng kể (đồ thị gần như là một đường thẳng). Điều này ngụ ý rằng nếu lấy mục tiêu là
tối đa hóa R2 nhưng lại đảm bảo số lượng biến tối thiểu thì nên chọn mô hình có 8 biến số. Chúng ta
có thể biết mô hình là những biến số nào cùng với hệ số hồi quy của chúng:
coef(full, 8)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


294

## (Intercept) kidsl6 age wage hhours


## 7.788982e+03 -2.102096e+02 -1.781368e+01 -5.164861e+01 -4.824780e-01
## hwage faminc mtr exper
## -1.481521e+02 1.454887e-02 -5.999149e+03 2.403856e+01

Tương tự nếu chúng ta chọn mô hình có BIC thấp nhất thì mô hình ấy sẽ có 6 biến số. Cụ thể các biến
ấy cùng hệ số hồi quy của chúng là:
coef(full, 6)

## (Intercept) age wage hhours hwage


## 9240.9657901 -13.4809911 -51.8696076 -0.4783684 -146.1494179
## mtr exper
## -7969.8887550 22.6693838

Nếu chọn mô hình là tối thiểu hóa Cp thì các bạn gõ lệnh coef(full,10). Kết quả thu được (hệ số hồi
quy) sẽ trùng với kết quả ở mục 8.3.
Nếu chọn tiêu chí BIC, chúng ta có thể phân tích chi tiết hơn như sau:
par(mfrow=c(1, 1))
par(bg = "white") # Trả lại nền trắng.
plot(full, scale = "bic")

Hình ảnh này cho thấy có 5 mô hình khác nhau có BIC là -110. Một mô hình trong số đó gồm các biến
kidsl6, age, wage, hhours, hwage, mtr, faminc, và exper. Riêng mô hình có BIC là -120 thì chỉ có 6 biến
và là những biến nào thì chúng ta đã biết.

Ở đây tôi không trình bày lựa chọn mô hình theo tiêu chí AIC vì lựa chọn tiêu chí theo AIC là khá tương
đồng với lựa chọn mô hình theo tiêu chí BIC.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


295

Nguyễn Chí Dũng http://rpubs.com/chidungkt


296

Chương 9: Phương sai sai số thay đổi trong mô hình hồi quy

Một trong những giả định nền tảng của mô hình hồi quy tuyến tính cổ điển là sai số ngẫu nhiên phải có
phương sai không đổi, đồng nhất (Homoskedasticity). Rõ ràng trong thực tế giả định này là khó tồn
tại. Trong chương này chúng ta sẽ nghiên cứu những nguyên nhân của hiện tượng phương sai sai số
thay đổi (Heteroskedasticity), các kiểm định nhằm chẩn đoán hiện tượng này cũng như một số cách
khác phục đơn giản nhất.

9.1 Phương sai sai số thay đổi và hậu quả


Một trong những giả định của mô hình hồi quy tuyến tính cổ điển CLMR là phương sai của sai số ngẫu
nhiên ứng với các quan sát là không đổi (Homoscedasticity):

𝐸(𝑢𝑖2 ) = 𝜎 2 𝑖 = 1, 2, … , 𝑛
Điều này được minh họa như sau:

Ngược lại, nếu phương sai của sai số ngẫu nhiên ứng với mỗi quan sát là khác nhau thì chúng ta gặp
hiện tượng phương sai sai số thay đổi (Heteroscedasticity). Hình dưới đây minh họa phương sai sai
số ngẫu nhiên tăng dần:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


297

Theo Valavanis (1959), hiện tượng heteroscedasticity có thể xuất hiện bởi các nguyên nhân sau:

1. Nếu chúng ta xét mô hình hồi quy giữa tiết kiệm (savings) với thu nhập (income) thì rõ ràng
các gia đình có thu nhập cao sẽ có nhiều lựa chọn hơn về quyết định tiết kiệm của mình và do
vậy biến động khoản tiết kiệm của họ có thể rất lớn. Tương tự, các công ti có lợi nhuận lớn
thường có chính sách cổ tức biến động hơn các công ti có lợi nhuận bé. Hiện tượng phương
sai sai số ngẫu nhiên thay đổi là một hiện tượng thường gặp trong các nghiên cứu kinh tế sử
dụng dữ liệu chéo.
2. Tuân theo hành vi học – sửa lỗi. Chúng ta hãy xem xét ví dụ về số lỗi đánh máy phụ thuộc như
thế nào vào số giờ thực hành. Rõ ràng, khi số giờ thực hành tăng lên thì số lỗi đánh máy trung
bình và phương sai của chúng giảm dần theo thời gian. Trường hợp này thì phương sai sai số
ngẫu nhiên giảm dần.
3. Phương pháp thu thập dữ liệu ngày càng được cải thiện rất có thể làm cho σ2i ngày càng nhỏ
đi.
4. Do các quan sát bất thường (Outliers – các quan sát rất khác biệt so với nhóm còn lại trong
mẫu). Sự xuất hiện của chúng có thể gây ra thay đổi quan trọng đến kết quả phân tích số liệu,
đặc biệt là với mẫu có kích thước nhỏ.
5. Định dạng mô hình sai. Chẳng hạn như mô hình hồi quy bỏ sót một số biến số quan trọng hay
đổi biến không phù hợp.
6. Do độ méo (Skewness) của một hay nhiều biến độc lập trong mô hình. Trong kinh tế chúng ta
thường biết rằng các biến số như thu nhập, tài sản thường méo về phía dương.

Phương sai sai số thay đổi có thể gây ra các hiện tượng sau:

1. Các ước lượng OLS thu được vẫn là không chệch (Unbiasedness) và là các ước lượng vững
(Consistency).
2. Các ước lượng OLS không còn là các ước lượng có phương sai nhỏ nhất.
3. Kiểm định t và F sẽ bé dẫn đến việc sử dụng các kiểm định liên quan đến hai thống kê này
không còn ý nghĩa.

9.2 Chẩn đoán phương sai sai số thay đổi


Có hai cách thức chẩn đoán hiện tượng phương sai sai số thay đổi và chúng thường được sử dụng kết
hợp với nhau.

9.2.1 Các phương pháp không chính thức


Nhóm phương pháp này thường dựa vào hiểu biết đã có về bản chất các biến số kinh tế hoặc nhận
định trực quan dựa trên phần dư.

9.2.1.1 Căn cứ vào bản chất của các biến số kinh tế


Chẳng hạn khi nghiên cứu tác động của thu nhập lên tiết kiệm thì chúng ta thấy rõ rằng phương sai
sai số ngẫu nhiên sẽ tăng. Vì các gia đình với thu nhập cao có nhiều lựa chọn hơn cho tiết kiệm.

9.2.1.2 Căn cứ vào đồ thị phần dư


Chúng ta có thể căn cứ vào đồ thị của phần dư ước lượng bình phương với giá trị ước lượng hoặc với
một biến số độc lập bất kì nào đó trong mô hình để đưa ra nhận xét về việc có tồn tại hiện tượng
phương sai sai số thay đổi hay không. Chúng ta xét các đồ thị sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


298

Chúng ta thấy ở trường hợp a, phần dư bình phương không có liên hệ gì với giá trị ước lượng và do
vậy có thể không tồn tại hiện tượng phương sai sai số thay đổi. Tuy nhiên, các tình huống còn lại thì
khác. Chẳng hạn tình huống c ngụ ý rằng phần dư có quan hệ tuyến tính với giá trị ước lượng Ŷ . Con
trường hợp d thì mối quan hệ đó là hình chữ u ngược.

9.2.2 Căn cứ vào các bằng chứng thống kê chính thức


Các phương pháp không chính thức chỉ mới đưa ra nhận định và đóng vai trò định hướng. Để chắc
chắn hơn chúng ta phải dùng đến các kiểm định chính thức.

9.2.2.1 Kiểm định Park


Kiểm định Park hiện thực hóa các phân tích hình ảnh về phần dư (Gujarati & Porter, 2009). Ý tưởng
của kiểm định này là σ2i có thể là một hàm số nào đó của biến độc lập Xi và có dạng:
𝛽
𝜎𝑖2 = 𝜎 2 𝑋𝑖 𝑒 𝑣𝑖
Hay:

ln𝜎𝑖2 = ln𝜎 2 + 𝛽ln𝑋𝑖 + 𝑣𝑖


Vì σ2i là không biết nên Park cho rằng có thể dung û 2i làm đại diện và chạy hồi quy sau:

ln𝑢̂𝑖2 = ln𝜎 2 + 𝛽ln𝑋𝑖 + 𝑣𝑖


= 𝛼 + 𝛽ln𝑋𝑖 + 𝑣𝑖
Nếu β có ý nghĩa thống kê thì chúng ta có thể kết luận là tồn tại hiện tượng phương sai sai số thay đổi.

Trong phần này, chúng ta sử dụng bộ dữ liệu có tên Table5_1.dta (file Stata). Giả sử chúng ta muốn
đánh giá tỉ lệ phá thai trên 1000 phụ nữ ở độ tuổi 15 đến 44 (abortion) ở 50 bang của Hoa Kì phụ
thuộc như thế nào vào tỉ lệ dân số theo đạo (religion), giá của mỗi lần phá thai dưới 10 tuần tuổi

Nguyễn Chí Dũng http://rpubs.com/chidungkt


299

(price), luật (laws = 1 nếu bang có luật chặt chẽ về phá thai, = 0 nếu không có), tỉ lệ dân số trên 25 tốt
nghiệp trung học hoặc hơn (educ), quỹ hỗ trợ (funds = 1 nếu bang có hỗ trợ tài chính, = 0 nếu khác),
thu nhập đầu người (income). Hồi quy trong R:

setwd("D:/KTLR")
library(foreign)
homo <- read.dta("Table5_1.dta")
attach(homo)
c8 <- lm(data = homo, abortion ~ religion + price +
laws + funds + educ + income)
summary(c8)

##
## Call:
## lm(formula = abortion ~ religion + price + laws + funds + educ +
## income, data = homo)
##
## Residuals:
## Min 1Q Median 3Q Max
## -12.894 -5.210 -1.515 5.198 20.484
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.1959887 15.0524658 -0.079 0.937
## religion -0.0051889 0.0923269 -0.056 0.955
## price -0.0416943 0.0238850 -1.746 0.088 .
## laws -2.1751208 2.5040006 -0.869 0.390
## funds 3.4174262 2.9828050 1.146 0.258
## educ -0.1340455 0.2060909 -0.650 0.519
## income 0.0023318 0.0004885 4.773 2.12e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 7.591 on 43 degrees of freedom
## Multiple R-squared: 0.5002, Adjusted R-squared: 0.4304
## F-statistic: 7.172 on 6 and 43 DF, p-value: 2.418e-05

Dấu của các hệ số thu được là phù hợp với các kì vọng của chúng ta. Chẳng hạn, trình độ giáo dục càng
cao thì tỉ lệ phá thai càng bé. Người theo tôn giáo thường có xu hướng phá thai thấp hơn.

Kết tiếp, chúng ta lưu bình phương phần dư cũng như các ước lượng về tỉ lệ phá thai và gán nó vào
data.frame có tên homo đã có với các tên biến là phandubp, aborpre:

homo$phandubp <- residuals(c8)*residuals(c8)


homo$aborpre <- predict(c8)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


300

Chúng ta có thể vẽ cả histogram cho phandubp và biểu diễn phandubp trên trục Y, abopre trên trục
X:

attach(homo)
par(mfrow = c(1, 2))
plot(phandubp ~ aborpre)
hist(phandubp, col = "pink", prob = TRUE, main = "")

Căn cứ vào các đồ thị chúng ta có thể nhận định rằng có thể tồn tại hiện tượng phương sai sai số thay
đổi trong mô hình. Để đưa ra bằng chứng thống kê cho nhận định này cần sử dụng một số kiểm định
chính thức được trình bày dưới đây.

Chúng ta sử dụng kiểm định Park cho mô hình. Nếu chúng ta chọn Xi là biến regilion thì:

park1 <- lm(data = homo, log(phandubp) ~ log(religion))


summary(park1)

##
## Call:
## lm(formula = log(phandubp) ~ log(religion), data = homo)
##
## Residuals:
## Min 1Q Median 3Q Max
## -6.0450 -0.9740 0.8252 1.5875 3.4789
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.6620 3.0149 1.546 0.129
## log(religion) -0.6398 0.8773 -0.729 0.469
##
## Residual standard error: 2.355 on 48 degrees of freedom
## Multiple R-squared: 0.01096, Adjusted R-squared: -0.009646
## F-statistic: 0.5319 on 1 and 48 DF, p-value: 0.4694

Do hệ số của log(religion) không có ý nghĩa thống kê nên theo tinh thần của kiểm định Park chúng ta
có thể kết luận không tồn tại hiện tượng phương sai sai số thay đổi ở mô hình.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


301

Tuy nhiên, Goldfeld & Quandt (1972) chỉ ra rằng kiểm định Park có một số nhược điểm. Chẳng hạn
trong tình huống của chúng ta, có 6 biến độc lập nên về lý thuyết phải có 6 kiểm định Park và có thể
chúng lại ra những kết quả khác nhau. Thực vậy, giả sử chúng ta chọn Xi là biến income thì kết quả là:

park2 <- lm(data = homo, log(phandubp) ~ log(income))


summary(park2)

##
## Call:
## lm(formula = log(phandubp) ~ log(income), data = homo)
##
## Residuals:
## Min 1Q Median 3Q Max
## -5.4689 -0.8049 0.6242 1.5258 3.9064
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -71.674 20.746 -3.455 0.001161 **
## log(income) 7.525 2.105 3.575 0.000812 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.105 on 48 degrees of freedom
## Multiple R-squared: 0.2102, Adjusted R-squared: 0.1938
## F-statistic: 12.78 on 1 and 48 DF, p-value: 0.0008119

Lúc này hệ số của log(income) lại có ý nghĩa thống kê nên chúng ta lại ra kết luận ngược lại so với
trước: tồn tại hiện tượng phương sai sai số thay đổi.

9.2.2.2 Kiểm định Glejser


Kiểm định này cũng tương tự như kiểm định Park. Đó là thực hiện hồi quy giá trị tuyệt đối phần dư
û I theo một trong các biến độc lập Xi ở một trong số các dạng sau:

|𝑢̂𝑖 | = 𝛽1 + 𝛽2 𝑋𝑖 + 𝑣𝑖

|𝑢̂𝑖 | = 𝛽1 + 𝛽2 √𝑋𝑖 + 𝑣𝑖
1
|𝑢̂𝑖 | = 𝛽1 + 𝛽2 + 𝑣𝑖
𝑋𝑖
1
|𝑢̂𝑖 | = 𝛽1 + 𝛽2 + 𝑣𝑖
√𝑋𝑖

|𝑢̂𝑖 | = √𝛽1 + 𝛽2 𝑋𝑖 + 𝑣𝑖

|𝑢̂𝑖 | = √𝛽1 + 𝛽2 𝑋𝑖2 + 𝑣𝑖

Nguyễn Chí Dũng http://rpubs.com/chidungkt


302

Chúng ta sử dụng kiểm định Glejser với dạng đầu tiên, biến Xi là income chẳng hạn. Trước hết chúng
ta cần tạo ra biến giá trị tuyệt đối của phần dư có tên gọi tdphandu theo cách thức như đã làm ở phần
trước:

homo$tdphandu <- abs(residuals(c8))

Sau đó thực hiện hồi quy dạng đầu tiên của kiểm định này:

summary(lm(data = homo, tdphandu ~ income))

##
## Call:
## lm(formula = tdphandu ~ income, data = homo)
##
## Residuals:
## Min 1Q Median 3Q Max
## -6.6422 -2.7862 -0.1683 2.2619 12.8091
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -8.5376347 3.9323971 -2.171 0.034899 *
## income 0.0007303 0.0002025 3.606 0.000739 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 3.984 on 48 degrees of freedom
## Multiple R-squared: 0.2131, Adjusted R-squared: 0.1967
## F-statistic: 13 on 1 and 48 DF, p-value: 0.000739

Theo tinh thần của kiểm định Glejser chúng ta thấy rằng hệ số của income có ý nghĩa thống kê do vậy
tồn tại hiện tượng phương sai sai số thay đổi.

Cũng như với kiểm định Park, kiểm định Glejser cũng có các nhược điểm như kiểm định Park. Ngoài
ra, hai dạng cuối cùng của kiểu kiểm định này là phi tuyến tính về tham số nên không thể thực hiện
bằng OLS.

9.2.2.3 Kiểm định Goldfeld - Quandt


Kiểm định Goldfeld – Quandt do Goldfeld & Quandt (1965) đề xuất có thể được sử dụng cho kiểm
định phương sai sai số thay đổi. Trong R chúng ta có thể nhanh chóng thực hiện kiểm định này với sự
trợ giúp của gói AER:

library(AER)
gqtest(c8)

##
## Goldfeld-Quandt test
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


303

## data: c8
## GQ = 2.8015, df1 = 18, df2 = 18, p-value = 0.0174

Giá trị p-value = 0.0174 < 5% nên chúng ta kết luận rằng có hiện tượng phương sai sai số thay đổi.

9.2.2.4 Kiểm định do Breusch – Pagan đề xuất dựa trên kiểm định F
Chúng ta sử dụng bộ số liệu ch4bt8.wf1 với 935 quan sát được cung cấp bởi khoa toán mà chúng ta
đã nghiên cứu ở mục 6.7 thuộc chương 6 (đây cũng chính là bộ số liệu được sử dụng tại trang 222
sách giáo trình minh họa cho kiểm định Breusch – Pagan Test).

Giả sử chúng ta có mô hình:

WAGE = β1 + β2AGE + β3EDUC (mô hình 1)

Để kiểm định mô hình này có phương sai sai số thay đổi hay không, Breusch & Pagan (1979) đề xuất
nghiên cứu mô hình phụ:

phandubp = λ1 + λ2AGE + λ3EDUC

Trong đó phadubp là phần dư bình phương thu được từ mô hình gốc. Nếu một trong hai hệ số λ2, λ3
mà khác không thì chúng ta có thể kết luận tồn tại phương sai sai số thay đổi.

Phân tích trên chỉ ra rằng chúng ta chỉ cần kiểm định cặp giả thuyết sau:

H0: λ22 + λ23 = 0; H1: λ22 + λ23 ≠ 0.

Nếu chúng ta đưa ra bằng chứng thống kê bắc bỏ H0 thì có nghĩa là mô hình của chúng ta có hiện
tượng phương sai sai số thay đổi. Như vậy chúng ta có thể thực hiện kiểm định này bằng cách sử dụng
thống kê F theo các bước dưới đây.

Trước hết chúng ta chạy mô hình gốc trong R:

library(hexView)
trang <- readEViews("ch4bt8.wf1", as.data.frame = TRUE)
attach(trang)
hello <- lm(data = trang, WAGE ~ AGE + EDUC)
summary(hello)

##
## Call:
## lm(formula = WAGE ~ AGE + EDUC, data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -819.95 -249.87 -43.05 202.86 2233.76
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1950.250 152.823 12.762 < 2e-16 ***

Nguyễn Chí Dũng http://rpubs.com/chidungkt


304

## AGE 20.913 3.969 5.269 1.7e-07 ***


## EDUC 60.577 5.615 10.788 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 377 on 932 degrees of freedom
## Multiple R-squared: 0.1328, Adjusted R-squared: 0.131
## F-statistic: 71.38 on 2 and 932 DF, p-value: < 2.2e-16

Sau đó chúng ta tạo biến mới phần dư bình phương với tên gọi phandubp trong R:

trang$phandubp <- residuals(hello)*residuals(hello)

Cuối cùng thực hiện kiểm định Breuch – Pagan Test bằng chạy mô hình hồi quy phụ. Đây chính là cách
thức được trình bày trong sách giáo trình kinh tế lượng của NEU:

bptest <- lm(data=trang, phandubp ~ AGE + EDUC)


summary(bptest)

##
## Call:
## lm(formula = phandubp ~ AGE + EDUC, data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -236399 -117710 -73131 20546 4868407
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -205606 129447 -1.588 0.113
## AGE 2823 3362 0.840 0.401
## EDUC 18849 4756 3.963 7.98e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 319300 on 932 degrees of freedom
## Multiple R-squared: 0.01722, Adjusted R-squared: 0.01511
## F-statistic: 8.164 on 2 and 932 DF, p-value: 0.0003055

Do p-value = 0.0003055 ứng với Fqs = 8.164 nên chúng ta kết luận rằng tồn tại phương sai sai số thay
đổi trong mô hình (bắc bỏ H0). Chúng ta thu được kết luận tương tự khi so sánh Fqs = 8.164 với
F0.95;2,932 =3.0054:

qf(0.95, df1 = 2, df2 = 932)

## [1] 3.005382

Nguyễn Chí Dũng http://rpubs.com/chidungkt


305

Các tiếp cận này thường được gọi là kiểm định Breusch – Pagan (BP Test) cho hiện tượng phương sai
sai số thay đổi. Cách gọi này thường gây ra sự hiểu lầm. Thực vậy, như chúng ta thấy, thực chất cách
tiếp cận mà Breusch và Pagan đề xuất là sử dụng kiểm định F. Cách tiếp cận này phát sinh từ bài báo
có tên “A Simple Test for Heteroskedasticity and Random Coefficient Variation” đăng trên tạp chí
Econometrica năm 1979 của Breusch và Pagan nhưng chính hai tác giả cũng viết rằng cách tiếp cận
này là đơn giản (a simple test) và được xây dựng trên cơ sở của kiểm định Lagrange (nguyên văn là :
A simple test for heteroscedastic disturbances in a linear regression model is developed using the
framework of the Lagrangian multiplier test) chứ chính hai tác giả cũng chưa bao giờ nói cách tiếp cận
do mình đề xuất là kiểm định mang tên mình. Cách tiếp cận của Breusch và Pagan được gọi tên là
kiểm định BP có lẽ là cách gọi của các tác giả sau này để vinh danh đề xuất của hai ông trong việc đưa
ra cách tiếp cận cho kiểm định phương sai sai số thay đổi.

Như đã trình bày ở trên, kiểm định BP được xây dựng trên cơ sở kiểm định Lagrange (chính xác là
Lagrange Multiplier Test). Do vậy, trong trường hợp mà n là lớn, thay vì sử dụng thống kê F chúng ta
có thể sử dụng thống kê Lagrange Multiplier hay thường gọi là kiểm định Lagrange Multiplier (LM
Test). Theo đó, LM Test (hay LMqs) được tính theo công thức : LMqs = R2*n trong đó R2 là của mô
hình hồi quy phụ, n là số quan sát. Kết tiếp, chúng ta so sánh LMqs này với χ20.95;3 (k= 3 chính là số
biến số trong mô hình). Nếu LMqs > χ20.95;3 thì chúng ta bắc bỏ H0, ngược lại chúng ta chấp nhận H0.
Trong tình huống của chúng ta thì χ2 = 7.8:

qchisq(0.95,3)

## [1] 7.814728

Giá trị này rõ ràng bé hơn 0.01722*935 = 16.1007 = LMqs nên ta bắc bỏ H0.

Chúng ta cũng có thể sử dụng kiểm định Wald để kiểm định sự đồng thời bằng không của các hệ số
hồi quy ở mô hình phụ:

linearHypothesis(bptest, c("AGE = 0", "EDUC = 0"))

## Linear hypothesis test


##
## Hypothesis:
## AGE = 0
## EDUC = 0
##
## Model 1: restricted model
## Model 2: phandubp ~ AGE + EDUC
##
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 934 9.6681e+13
## 2 932 9.5017e+13 2 1.6647e+12 8.1643 0.0003055 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Nguyễn Chí Dũng http://rpubs.com/chidungkt


306

Căn cứ kết quả thu được chúng ta cũng có kết luận tương tự: Bắc bỏ H0.

Chúng ta thấy rằng sử dụng kiểm định F (hay LM Test) như trên cần thông qua một bước trung gian
là thực hiện hồi quy phụ. R cho phép chúng ta thực hiện trực tiếp BP Test mà không cần qua bước
trung gian này với lệnh bptest() của gói lmtest. Cặp giả thuyết được kiểm định là:

Ho: phương sai là không đổi; H1: phương sai là thay đổi.

Thực hiện trong R:

library(lmtest)
bptest(hello)

##
## studentized Breusch-Pagan test
##
## data: hello
## BP = 16.099, df = 2, p-value = 0.0003192

Do giá trị p-value = 0.00032 < 5% nên chúng ta có bằng chứng thống kê bắc bỏ Ho. Một cách khác là
so sánh thống kê BP = 16.099 với χ20.05; 2 = 5.99 để rút ra kết luận tương tự.

9.2.2.5 Kiểm định White


Kiểm định White do White (1980) đề xuất cũng là một kiểm định dựa vào phần dư như kiểm định BP
mà chúng ta đã xét ở trên với một số điều chỉnh nhỏ với mô hình hồi quy phụ như sau:

phandubp = ψ1 + ψ2AGE + ψ3EDUC + ψ4AGE2 + ψ5EDUC2 + ψ6AGE*EDUC

Nếu 1 trong các hệ số hồi quy từ ψ2 đến ψ6 mà khác không thì chúng ta có thể kết luận tồn tại phương
sai sai số thay đổi. Nói cách khác, điều này tương đương với việc chúng ta bắc bỏ H0 ở cặp giả thuyết
sau:

H0: ψ22 +..+ ψ26 = 0; H1: ψ22 +..+ ψ26 ≠ 0.

Do phandubp đã được có nên chúng ta thực hiện kiểm định này trong R như sau:

summary(lm(data = trang,
phandubp ~ AGE + EDUC + I(AGE^2) + I(EDUC^2) + (AGE*EDUC)))

##
## Call:
## lm(formula = phandubp ~ AGE + EDUC + I(AGE^2) + I(EDUC^2) + (AGE *
## EDUC), data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -283588 -116050 -75902 17726 4857368
##
## Coefficients:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


307

## Estimate Std. Error t value Pr(>|t|)


## (Intercept) 1307446.6 1625358.6 0.804 0.421
## AGE -67538.8 86937.3 -0.777 0.437
## EDUC -34174.7 80724.7 -0.423 0.672
## I(AGE^2) 604.0 1275.2 0.474 0.636
## I(EDUC^2) -843.8 2261.1 -0.373 0.709
## AGE:EDUC 2287.5 1619.8 1.412 0.158
##
## Residual standard error: 319400 on 929 degrees of freedom
## Multiple R-squared: 0.0197, Adjusted R-squared: 0.01442
## F-statistic: 3.733 on 5 and 929 DF, p-value: 0.002369

Ở đây Fqs = 3.733 (chính là thống kê F) ứng với p-value = 0.002369 <5% nên chúng ta có bằng chứng
thống kê để kết luận tồn tại phương sai sai số thay đổi.

Chú ý: Ta có LMqs = nR2 = 0.0197*935 = 18.42 > χ2 = 7.8 nên chúng ta có kết luận như trên nếu chúng
ta sử dụng LM Test (chú ý rằng các kết quả về Fqs và LMqs trong sách tại trang 225 là sai).

Gói lmtest cũng cho phép chúng ta tính trực tiếp giá trị 18.42 ở trên mà không cần chạy hồi quy phụ:

bptest(hello, ~ I(AGE^2) + I(EDUC^2) + AGE*EDUC, data = trang)

##
## studentized Breusch-Pagan test
##
## data: hello
## BP = 18.418, df = 5, p-value = 0.002466

Do p-value = 0.0025 < 5% nên chúng ta đi đến kết luận là phương sai thay đổi.

9.2.2.6 Kiểm định Koenker - Basett


Khá tương tự về mặt hình thức với kiểm định Park là kiểm định do Koenker & Basett (1982) đề xuất.
Ý tưởng của kiểm định này là hồi quy phần dư bình phương theo các giá trị dự đoan Ŷ 2i :
2
𝑢̂𝑖2 = 𝛼1 + 𝛼2 (𝑌̂𝑖 ) + 𝑣𝑖
Nếu chúng ta có bằng chứng thống kê cho thấy α2 có ý nghĩa thống kê thì chúng ta kết luận rằng có
hiện tượng phương sai sai số thay đối. Để minh họa chúng ta tiếp tục sử dụng lại mô hình ở mục
9.2.2.4 ở trên. Trước hết chúng ta cần tạo ra chuỗi Ŷ 2i với tên y2:

trang$y2 <- predict(hello)*predict(hello)

Sau đó chúng ta thực hiện hồi quy phần dư bình phương theo các giá trị dự đoan Ŷ 2i :

summary(lm(data = trang, phandubp ~ y2))

##
## Call:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


308

## lm(formula = phandubp ~ y2, data = trang)


##
## Residuals:
## Min 1Q Median 3Q Max
## -244821 -119150 -74624 19908 4879771
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -3.361e+05 1.217e+05 -2.761 0.00587 **
## y2 3.988e-02 1.012e-02 3.940 8.77e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 319300 on 933 degrees of freedom
## Multiple R-squared: 0.01636, Adjusted R-squared: 0.01531
## F-statistic: 15.52 on 1 and 933 DF, p-value: 8.772e-05

Kết quả này chỉ ra rằng có hiện tượng phương sai sai số thay đổi do hệ số của y2 có ý nghĩa thống kê
ở mức cao.

9.3 Một số cách khác phục phương sai sai số thay đổi
Phần trên chúng ta đã xem xét một số cách tiếp cận đánh giá hiện tượng phương sai sai số thay đổi.
Phần này chúng ta sẽ nghiên cứu một số cách thức khắc phục hiện tượng này.

9.3.1 Phương pháp bình phương nhỏ nhất có trọng số và đổi biến số
Theo Gujarati & Porter (2009) và Fox(2002), nếu chúng ta biết các phương sai σi thì chúng ta có thể
thu được các ước lượng có tính chất BLUE bằng cách chia các quan sát cho phương sai σi của chúng.
Cách tiếp cận này gọi là phương pháp bình phương nhỏ nhất có trọng số WLS (Weighted Least
Squares). Tuy nhiên trong thực tế chúng ta gần như không thể thực hiện WLS vì rằng những giá trị
phương sai là chúng ta không thể biết. Gujarati (2011) đưa ra cách tiếp cận thay thế cho vấn đề này
là sử dụng phương pháp đổi biến số. Cụ thể:

1. Nếu phương sai sai số ngẫu nhiên là tỉ lệ với bình phương của một biến độc lập nào đó chúng
ta có thể chia cả hai vế của phương trình hồi quy gốc cho biến số đó. Sau đó, chúng ta thực
hiện một trong các kiểm định (như BP Test, White Test) cho mô hình mới này. Nếu kiểm định
chỉ ra không có bằng chứng cho thấy có phương sai sai số thay đổi thì chúng ta có thể nói cách
biến đổi là thích hợp và mô hình mới không còn hiện tượng phương sai sai số thay đổi. Nếu
phương sai sai số ngẫu nhiên là tỉ lệ với một biến độc lập nào đó chúng ta có thể chia cả hai
vế của phương trình hồi quy gốc cho căn bậc hai biến số đó rồi thực hiện các kiểm định thông
thường như ở trên. Tuy nhiên, trong cả hai tình huống chúng ta lại phải đối diện với một câu
hỏi khó: bằng cách nào chúng ta có thể biết phương sai là tỉ lệ với bình phương của một biến
hay tỉ lệ với một biến số nào đó trong số rất nhiều biến độc lập có thể có trong mô hình? Thứ
hai, nếu một số biến độc lập nào đó mà bằng 0 thì rõ ràng phép biến đổi của chúng ta không
thực hiện được vì phép chia vô nghĩa. Trong nhiều tình huống, khó khăn này có thể được giải

Nguyễn Chí Dũng http://rpubs.com/chidungkt


309

quyết bằng cách thay vì chúng ta chia cả hai vế của mô hình gốc cho biến cụ thể nào đó chúng
ta có thể chia cả hai vế cho giá trị Ŷ ước lượng thu được từ mô hình. Mô hình này được gọi là
mô hình biến đổi (Transformed Model).
2. Chúng ta cũng có thể lấy logarit cơ số tự nhiên cho biến phụ thuộc. Chú ý rằng cách thức này
chỉ thực hiện được nếu biến phụ thuộc là không âm. Mô hình này gọi là mô hình loga biến phụ
thuộc (Logarithmic Model).

Để minh họa, mục này chúng ta sử dụng lại bộ số liệu ch4bt8.wf1 ở trên cho mô hình:

WAGE = β1 + β2AGE + β3EDUC (mô hình 1)

Giả sử rằng phương sai là tỉ lệ với EDUC2. Do vậy chúng ta chia cả hai vế của mô hình này cho EDUC
được mô hình mới là:

WAGE/EDUC = β1/EDUC + β2AGE/EDUC + β3 (mô hình 2)

Chạy mô hình này trong R chúng ta có:

trang <- readEViews("ch4bt8.wf1", as.data.frame = TRUE)


hello2 <- lm(data = trang, I(WAGE / EDUC) ~ I(1/EDUC) + I(AGE / EDUC))
summary(hello2)

##
## Call:
## lm(formula = I(WAGE/EDUC) ~ I(1/EDUC) + I(AGE/EDUC), data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -56.650 -18.461 -3.043 15.508 171.162
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 62.347 5.904 10.560 < 2e-16 ***
## I(1/EDUC) 2001.362 150.608 13.289 < 2e-16 ***
## I(AGE/EDUC) 18.656 3.759 4.963 8.27e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 27.74 on 932 degrees of freedom
## Multiple R-squared: 0.5675, Adjusted R-squared: 0.5666
## F-statistic: 611.5 on 2 and 932 DF, p-value: < 2.2e-16

Chúng ta lại sử dụng một trong các kiểm định, chẳng hạn BP Test bằng hồi quy phụ cho mô hình thu
được sau biến đổi:

trang$resids2 <- residuals(hello2)*residuals(hello2)


summary(lm(data = trang, resids2 ~ I(1 / EDUC) + I(AGE / EDUC)))

Nguyễn Chí Dũng http://rpubs.com/chidungkt


310

##
## Call:
## lm(formula = resids2 ~ I(1/EDUC) + I(AGE/EDUC), data = trang)
##
## Residuals:
## Min 1Q Median 3Q Max
## -800.0 -693.6 -463.8 102.4 28551.7
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 742.15 377.77 1.965 0.0498 *
## I(1/EDUC) -2035.19 9637.07 -0.211 0.8328
## I(AGE/EDUC) 71.26 240.55 0.296 0.7671
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1775 on 932 degrees of freedom
## Multiple R-squared: 0.0001022, Adjusted R-squared: -0.002043
## F-statistic: 0.04764 on 2 and 932 DF, p-value: 0.9535

Do Fqs = 0.04764 ứng với p-value = 0.9535 > 5% nên chúng ta kết luận rằng không tồn tại phương
sai sai số thay đổi trong mô hình 2.

Chúng ta cũng không cần phải thực hiện hồi quy phụ mà có thể làm trực tiếp như sau:

bptest(hello2)

##
## studentized Breusch-Pagan test
##
## data: hello2
## BP = 0.095586, df = 2, p-value = 0.9533

Do giá trị p-value = 0.9533 > 5% nên chúng ta có bằng chứng thống kê chấp nhận Ho của cặp giả
thuyết sau:

Ho: phương sai là không đổi; H1: phương sai là thay đổi.

Nghĩa là mô hình 2 có phương sai sai số không đổi.

Như vậy, bằng ít nhất hai cách khác nhau chúng ta có kết luận rằng mô hình 2 có phương sai sai số
không đổi. Đến đây bạn dễ dàng bị lôi cuốn với ý tưởng rằng mô hình 2 là một mô hình tốt để miêu tả
mối liên hệ giữa mức lương và các biến khác. Tuy nhiên như các bạn có thể thấy: rất khó có thể mô tả
mối liên hệ, chẳng hạn, quan hệ giữ giáo dục và mức lương ở mô hình 2. Trong khi mối liên hệ này lại
vô cùng dễ hiểu và dễ diễn đạt ở mô hình 1: cứ tăng 1 năm học thì mức lương tăng β3 đơn vị. Còn mô
hình 2, nếu giáo dục tăng 1 năm thì mức lương biến động ra sao? Điều này một lần nữa nhắc nhở bạn
về sự đánh đổi trong việc xây dựng mô hình kinh tế lượng: bạn có một mô hình mà xử lý đươc vấn đề

Nguyễn Chí Dũng http://rpubs.com/chidungkt


311

phương sai sai số thay đổi nhưng bạn rất khó (và trong nhiều trường hợp là không thể) diễn đạt được
các kết quả của chính mình. Ngoài ra, cách đổi biến số như vậy cũng còn có hạn chế khác. Thực vậy,
chúng ta không thể nào xác định đượng dạng thức của phương sai, chưa kể nếu mô hình có nhiều biến
độc lập thì vấn đề ở đây là, chẳng hạn, chia hai vế của phương trình ban đầu cho biến số nào? Đây
cũng là nhược điểm chung của các phương pháp đổi biến (Transformed Model) khi thực hiện các mô
hình hồi quy.

9.3.2 Sử dụng biến đổi Box – Cox và Yeo-Johnson


Biến đổi Box – Cox (Box – Cox Transformation) được đặt nền móng từ một nghiên cứu có nhiều ảnh
hưởng của Box và Cox (1964). Không giống như cách đổi biến số có phần ngẫu hứng và không tuân
theo bất kì một cơ sở lý thuyết nào như chúng ta vừa thực hiện ở trên, nghiên cứu này của hai ông đã
đặt nền móng lý thuyết cho cách đổi biến mang tên mình. Theo đó, với biến y không âm thì y được
biến đổi thông qua hàm g với tham số λ như sau:

𝑦𝜆 − 1
𝘨𝜆 (𝑦) = { 𝜆 , 𝜆≠0
lo𝗀𝑦, 𝜆=0
Trong đó tham số λ được ước lượng theo phương pháp xác suất hợp lý cực đại (maximum likelihood)
để đạt giá trị lớn nhất cho hàm:
𝑛
𝐿(𝜆) = − lo𝗀(RSS𝜆 /𝑛) + (𝜆 − 1) ∑ lo𝗀𝑦𝑖
2
Trong đó RSSλ là tổng phần dư bình phương với gλ(y) là biến độc lập. Chi tiết của biến đổi Box – Cox
bạn có thể xem thêm ở nhiều tài liệu khác nhau. Ở đây chúng ta chỉ quan tâm đến khía cạnh thực hành
của việc áp dụng phép biến đổi này cho xử lý vấn đề phương sai sai số thay đổi. Theo Sheather (2009)
và Faraway (2015), biến đổi Box – Cox có thể áp dụng cho: (1) biến độc lập, (2) biến phụ thuộc, và (3)
cả biến phụ thuộc lẫn biến độc lập.

Với R chúng ta có thể sử dụng nhiều gói khác nhau để thực hiện biến đổi này. Tuy nhiên trong tài liệu
này chúng ta sẽ sử dụng gói caret (gói này cũng được sử dụng trong nhiều áp dụng ở các chương
sau). Dưới đây chúng ta sẽ sử dụng biến đổi Box – Cox cho bộ dữ liệu ở mục 9.3.1. Biến số bị biến đổi
là WAGE với tên gọi mới là luong:

setwd("D:/KTLR")
library(hexView)
trang <- readEViews("ch4bt8.wf1", as.data.frame = TRUE)
luong <- trang[, 14] # Lấy biến thứ 14 từ trang.
dung <- data.frame(luong) # Tạo một data frame tên dung với chỉ một biến là
luong (thực chất là WAGE)
library(caret)
chuanbi <- preProcess(dung, method = c("BoxCox"))
chuanbi # Xem các thông số của Box - Cox Transformation.

## Created from 935 samples and 1 variables


##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


312

## Pre-processing:
## - Box-Cox transformation (1)
## - ignored (0)
##
## Lambda estimates for Box-Cox transformation:
## -2

Dung <- predict(chuanbi, dung) # Thực hiện Box - Cox Transformation cho data
frame dung. Thực chất là chỉ có một biến WAGE mà thôi.
# Dưới đây là các câu lệnh so sánh Histogram trước và sau đổi biến. Chúng ta
thấy Histogram sau khi biến đổi là đối xứng hơn so với ban đầu.
par(mfrow=c(1, 2))
hist(dung$luong, col = "green", prob = T, main = "Histogram cua luong")
hist(trang$WAGE, col = "green", prob = T, main = "Histogram cua WAGE")

par(mfrow=c(1, 1))
trang$luong <- dung$luong # Ghép luong vào data frame tên trang.
love <- lm(data = trang, luong ~ AGE + EDUC)
library(lmtest)
bptest(love) # Thực hiện kiểm định Breusch-Pagan.

##
## studentized Breusch-Pagan test
##
## data: love
## BP = 5.2506, df = 2, p-value = 0.07242

Do giá trị p-value = 0.07242 > 5% nên chúng ta có bằng chứng thống kê chấp nhận Ho của cặp giả
thuyết sau:

Ho: phương sai là không đổi; H1: phương sai là thay đổi.

Nghĩa là mô hình hồi quy sau khi thực hiện biến đổi Box – Cox cho biến WAGE có phương sai sai số
ngẫu nhiên là không đổi.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


313

Biến đổi Box – Cox chỉ có thể thực hiện nếu biến số bị biến đổi là dương. Trong tình huống biến số bị
biến đổi ngoài giá trị dương còn có giá trị âm hoặc có giá trị 0, theo Weisberg (2001) chúng ta có thể
sử dụng một phiên bản mạnh hơn của biến đổi Box – Cox là biến đổi Jeo – Johnson. Lý thuyết cho biến
đổi này là rất mới –lý thuyết của phương pháp biến đổi này xuất phát từ nghiên cứu có tên “A new
family of power transformations to improve normality or symmetry “ đăng trên tạp chí Biometrika
năm 2001 của Yeo và Johnson – nhưng đã chứng tỏ sức mạnh của nó trong nhiều tình huống. Để thực
hiện biến đổi này, tất cả các câu lệnh ở trên giữ nguyên nhưng method=c("BoxCox") sẽ được thay
bằng method=c("YeoJohnson"). Bằng cách biến đổi này, thực hiện Breusch-Pagan test cho mô hình
hồi quy mới sẽ có p-value = 0.08286 > 5% nên chúng ta có bằng chứng thống kê đủ mạnh chỉ ra rằng
mô hình mới có phương sai sai số không đổi.

Trong các biến đổi Box – Cox và Jeo – Johnson ở trên, chúng ta mới chỉ áp dụng cho biến phụ thuộc.
Trong thực tế, chúng ta có thể áp dụng cho biến độc lập hoặc cả biến phụ thuộc cũng như biến độc lập
trong mô hình. Dưới đây là các lệnh thực hiện trong R với Box – Cox Transformation cho cả biến độc
lập lẫn phụ thuộc cho mô hình gốc:

WAGE = β1 + β2AGE + β3EDUC (mô hình 1)

chuanbi <- preProcess(trang[, c(1, 3, 14)], method = c("BoxCox"))


dung<- predict(chuanbi,trang[, c(1, 3, 14)])
hoiquy <- lm(data = dung, WAGE~.)
summary(hoiquy)

##
## Call:
## lm(formula = WAGE ~ ., data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.579e-08 -5.453e-09 3.079e-10 5.931e-09 2.968e-08
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 5.000e-01 1.866e-08 2.680e+07 < 2e-16 ***
## AGE 1.691e-08 2.949e-09 5.734e+00 1.33e-08 ***
## EDUC 1.482e-07 1.391e-08 1.065e+01 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 8.464e-09 on 932 degrees of freedom
## Multiple R-squared: 0.1323, Adjusted R-squared: 0.1304
## F-statistic: 71.03 on 2 and 932 DF, p-value: < 2.2e-16

library(lmtest)
bptest(hoiquy)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


314

##
## studentized Breusch-Pagan test
##
## data: hoiquy
## BP = 4.4442, df = 2, p-value = 0.1084

Do giá trị p-value = 0.1084 > 5% nên chúng ta có bằng chứng thống kê chấp nhận giả thuyết rằng
phương sai sai số ngẫu nhiên của mô hình sau khi đổi biến là không đổi.

Hai phép biến đổi mà chúng ta sử dụng nhằm xử lý hiện tượng phương sai sai số thay đổi ở trên dù
có nền tảng lý thuyết vững chắc nhưng nó vẫn còn một nhược điểm. Chẳng hạn, với biến đổi Box –
Cox cho biến phụ thuộc WAGE thì λ = -2. Nghĩa là WAGE được biến đổi thành luong = (1 – WAGE-2)/2
và do vậy rất khó diễn giải các kết quả hồi quy thu được ở mô hình mới. Đây là nhược điểm chung của
phương pháp đổi biến. Tuy nhiên, so với các cách thức đổi biến khác thì biến đổi Box – Cox và Yeo –
Johnson thường được sử dụng hơn.

Chú ý rằng các biến đổi Box – Cox và Yeo – Johnson còn được sử dụng nhằm biến đổi một biến có
phân phối không đối xứng thành biến có phân phối đối xứng hơn.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


315

Chương 10: Lỗi định dạng và lựa chọn mô hình

Chương này chúng ta sẽ nghiên cứu các lỗi định dạng mô hình (Model Specification Errors) bao gồm lỗi
dạng hàm sai, thêm biến không cần thiết, bỏ sót biến quan trọng, lỗi đo lường biến số và một số vấn đề
khác mà sách giáo trình không đề cập như sự tồn tại của các quan sát bất thường (Outliers) trong mô
hình. Ngoài ra chương này cũng đề cập đến tiêu chuẩn thông tin Akaike, Schwarz, và Mallows cho việc
lựa chọn mô hình cũng như các kiểm định chẩn đoán lỗi định dạng mô hình.

10.1 Các tiêu chuẩn lựa chọn mô hình


Theo Hendry & Richard (1983), sự lựa chọn mô hình cho phân tích thực chứng (Empirical Analysis)
nên thỏa mãn các tiêu chí sau:

1. Các dự đoán thu được từ mô hình phải là logic và hợp lý (be data admissible).
2. Phải phù hợp với lý thuyết (be consistent with theory). Nghĩa là mô hình phải có ý nghĩa kinh
tế (economic sense). Chẳng hạn, nếu hàm tiêu dùng của Keynes là đúng thì hệ số hồi quy của
thu nhập phải bé hơn 1 và dương.
3. Có các biến độc lập là nội sinh yếu (have weakly exogenous regressors). Nghĩa là biến giải
thích phải không tương quan với sai số ngẫu nhiên. Ngoài ra, trong một số tình huống thì yêu
cầu này còn cao hơn: chúng phải là các biến nội sinh chặt (strictly exogenous) – là các biến số
mà độc lập với sai số ngẫu nhiên hiện tại, quá khứ, và tương lai.
4. Ổn định về tham số (parameter constancy). Nghĩa là các giá trị của tham số nên là ổn định .
Nếu điều này không thoản mãn thì sử dụng mô hình cho dự báo là rất khó khăn.
5. Các sai số ngẫu nhiên thu được từ mô hình phải là ngẫu nhiên thuần túy (purely random) –
hay nhiễu trắng (white noise).
6. Có khả năng giải thích được kết quả của các mô hình cạnh tranh.

10.2 Các loại lỗi mô hình


Giả sử rằng căn cứ vào các tiêu chuẩn lựa chọn mô hình trên chúng ta đưa ra mô hình về mối liên hệ
giữa tổng chi phí Y và sản lượng mà chúng ta đã quen thuộc trong các giáo trình về kinh tế vi mô:

𝑌𝑖 = 𝛽1 + 𝛽2 𝑋𝑖 + 𝛽3 𝑋𝑖2 + 𝛽4 𝑋𝑖3 + 𝑢1𝑖 (1)


Giả sử, vì một lý do nào đó (do chưa học kinh tế vi mô chẳng hạn) một nhà nghiên cứu lại sử dụng mô
hình sau thay vì dùng mô hình (1):

𝑌𝑖 = 𝛼1 + 𝛼2 𝑋𝑖 + 𝛼3 𝑋𝑖2 + 𝑢2𝑖 (2)


Điều này có nghĩa là sai số ngẫu nhiên của mô hình (2) liên hệ với sai số ngẫu nhiên ở mô hình (1)
theo công thức sau:

𝑢2𝑖 = 𝑢1𝑖 + 𝛽4 𝑋𝑖3 (3)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


316

Chúng ta lại giả sử rằng một nhà nghiên cứu khác lại sử dụng mô hình sau:

𝑌𝑖 = 𝜆1 + 𝜆2 𝑋𝑖 + 𝜆3 𝑋𝑖2 + 𝜆4 𝑋𝑖3 + 𝜆5 𝑋𝑖4 + 𝑢3𝑖 (4)


Hay sai số ngẫu nghiên của (4) là :

𝑢3𝑖 = 𝑢1𝑖 − 𝜆5 𝑋𝑖4 (5)


= 𝑢1𝑖 𝑣ì 𝜆5 = 0
Nếu một nhà nghiên cứu nữa lại sử dụng mô hình sau:

ln𝑌𝑖 = 𝛾1 + 𝛾2 𝑋𝑖 + 𝛾3 𝑋𝑖2 + 𝛾4 𝑋𝑖3 + 𝑢4𝑖 (6)


Cuối cùng một nhà nghiên cứu khác lại sử dụng mô hình:

𝑌𝑖∗ = 𝛽1∗ + 𝛽2∗ 𝑋𝑖∗ + 𝛽3∗ 𝑋𝑖∗2 + 𝛽4∗ 𝑋𝑖∗3 + 𝑢𝑖∗ (7)
Trong đó:

Y*i =Yi +εi và X*i =Xi +wi với εi và wi là sai số của phép đo (errors of measurement). Nếu mô hình (1) là
mô hình đúng thì:

 Mô hình (2) gọi là bỏ sót biến quan trọng (omitting a relevant variable).
 Mô hình (4) gọi là thêm biến không cần thiết (including an irrelevant variable).
 Mô hình (6) gọi là dạng hàm sai (wrong functional form).
 Mô hình (7) gọi là lỗi đo lường (errors of measurement bias).

10.3 Bỏ sót biến quan trọng


10.3.1 Các hậu quả của việc bỏ sót biến quan trọng
Theo Gujarati (2011), việc bỏ sót các biến sẽ gây ra các hậu quả sau:

1. Nếu biến bỏ sót là tương quan với một (hay một số) biến độc lập trong mô hình thì các hệ hồi
quy của mô hình sẽ là các ước lượng chệch (Biased). Ngoài ra, tính chất này còn không biến
mất khi kích cỡ mẫu được tăng lên. Nghĩa là các ước lượng còn là không vững (Inconsistent).
2. Nếu các biến bỏ sót là không tương quan với một (hay một số) biến trong mô hình thì hệ số
chặn là ước lượng chệch.
3. Ước lượng cho σ2 là không chính xác.
4. Phương sai ước lượng của các hệ số hồi quy là chệch dẫn đến các sai số chuẩn ước lượng là
chệch dẫn đến các méo mó về khoảng tin cậy và các tham số được ước lượng.
5. Các dự báo về khoảng tin cậy từ mô hình bỏ sót biến là không thực tế.

10.3.2 Kiểm định Wald


Trong phần này chúng ta sử dụng bộ số liệu Table1_1.dta (file Stata). Các biến số của bộ số liệu này
là wage (mức lương theo giờ), female (giới tính, = 1 nếu là nữ và = 0 nếu là nam), nonwhile (chủng
tộc, = 1 nếu là người Mĩ phi da trắng, = 0 nếu khác), union (công đoàn, = 1 nếu lao động thuộc tổ chức
công đoàn, = 0 nếu khác), education (số năm đi học), exper (kinh nghiệm làm việc). Đây là bộ số liệu
CPS (tương tự như VHLSS ở Việt Nam) được thực hiện bởi bộ thống kê Hoa Kì (U.S Census Bureau)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


317

năm 1995 với mẫu là 1289 người. Chúng ta chỉ thị cho R nhập vào bộ dữ liệu này ở dạng data.frame
với tên gọi table1:

setwd("D:/KTLR")
library(foreign)
table1<-read.dta("Table1_1.dta")
attach(table1)

Để minh họa, trước hết chúng ta chạy mô hình có tên mse1 như sau:

mse1 <- lm(data = table1, wage ~ female + nonwhite + union + education+exper)


summary(mse1)

##
## Call:
## lm(formula = wage ~ female + nonwhite + union + education + exper,
## data = table1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -20.781 -3.760 -1.044 2.418 50.414
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -7.18334 1.01579 -7.072 2.51e-12 ***
## female -3.07488 0.36462 -8.433 < 2e-16 ***
## nonwhite -1.56531 0.50919 -3.074 0.00216 **
## union 1.09598 0.50608 2.166 0.03052 *
## education 1.37030 0.06590 20.792 < 2e-16 ***
## exper 0.16661 0.01605 10.382 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 6.508 on 1283 degrees of freedom
## Multiple R-squared: 0.3233, Adjusted R-squared: 0.3207
## F-statistic: 122.6 on 5 and 1283 DF, p-value: < 2.2e-16

Kế tiếp chúng ta chạy mô hình mse2:

mse2<-lm(data=table1, wage ~ female + nonwhite + union + education + exper +


I(exper^2))
summary(mse2)

##
## Call:
## lm(formula = wage ~ female + nonwhite + union + education + exper +

Nguyễn Chí Dũng http://rpubs.com/chidungkt


318

## I(exper^2), data = table1)


##
## Residuals:
## Min 1Q Median 3Q Max
## -19.883 -3.751 -0.855 2.455 50.125
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -8.419035 1.035710 -8.129 1.01e-15 ***
## female -3.009360 0.361432 -8.326 < 2e-16 ***
## nonwhite -1.536077 0.504448 -3.045 0.00237 **
## union 1.026979 0.501521 2.048 0.04079 *
## education 1.323745 0.065937 20.076 < 2e-16 ***
## exper 0.424463 0.053580 7.922 5.03e-15 ***
## I(exper^2) -0.006183 0.001227 -5.039 5.34e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 6.447 on 1282 degrees of freedom
## Multiple R-squared: 0.3365, Adjusted R-squared: 0.3334
## F-statistic: 108.4 on 6 and 1282 DF, p-value: < 2.2e-16

Như chúng ta đã biết theo kinh tế học lao động thì kinh nghiệm và mức lương có mối quan hệ hình
chữ U ngược. Điều này được thể hiện qua hệ số hồi quy của exper và I(exper^2). Như vậy, giả sử rằng
mse2 là mô hình đúng thì mô hình mse1 là mô hình thiếu biến quan trọng là I(exper^2). Nói cách
khác, nếu mse2 là mô hình đúng thì hệ số hồi quy của I(exper^2) khác không (Gujarati, 2011). Như
vậy, chúng ta có thể sử dụng kiểm định Wald. Thực hiện trong R như sau:

library(AER)
linearHypothesis(mse2, "I(exper^2) = 0")

## Linear hypothesis test


##
## Hypothesis:
## I(exper^2) = 0
##
## Model 1: restricted model
## Model 2: wage ~ female + nonwhite + union + education + exper + I(exper^2)
##
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 1283 54343
## 2 1282 53287 1 1055.6 25.396 5.336e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Nguyễn Chí Dũng http://rpubs.com/chidungkt


319

Chúng ta có Pr(>F) = 0 (ứng với F = 25.396) nên chúng ta có bằng chứng thống kê cho thấy mse1 là
mô hình bỏ sót biến I(exper^2).

10.3.3 Kiểm định F


Chúng ta cũng có thể sử dụng cách tiếp cận dùng kiểm định F theo công thức đã biết sau:
2
(𝑅𝑢𝑟 − 𝑅𝑟2 )/𝑚
𝐹= 2 )/(𝑛 − 𝑘)
(1 − 𝑅𝑢𝑟
Cho cặp giả thuyết: H0: β7 = 0; H1: β7 # 0 (β7 là hệ số hồi quy của I(exper^2)).

Nếu sử dụng kiểm định F thì mse1 là mô hình bị giới hạn còn mse2 là mô hình không bị giới hạn. Áp
dụng công thức trên ta có giá trị của thống kê F là:

((0.3365 - 0.3233) / 1) / ((1 - 0.3365) / 1288)

## [1] 25.62411

So sánh giá trị của thống kê F này với F0.05(1,1289-7) :

qf(0.95, df1 = 1, df2 = 1289 - 7)

## [1] 3.848723

Do 25.624 > 3.845 nên chúng ta có bằng chứng thống kê chấp nhận H1. Nghĩa là mô hình mse1 là mô
hình thiếu biến.

Tất nhiên, chúng ta có thể sử dụng một số câu lệnh khác để ra kết quả này (xem lại mục 6.4). Chẳng
hạn:

anova(mse2, mse1)

## Analysis of Variance Table


##
## Model 1: wage ~ female + nonwhite + union + education + exper + I(exper^2)
## Model 2: wage ~ female + nonwhite + union + education + exper
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 1282 53287
## 2 1283 54343 -1 -1055.6 25.396 5.336e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

10.3.4 Kiểm định Ramsey RESET


Để xác định mô hình có thiếu biến quan trọng chúng ta cũng có thể sử dụng kiểm định Ramsey RESET
(gọi tắt là Ramsey Test). Các bước thực hiện kiểm định này như sau:

1. Chạy mô hình thiếu biến mse1 để thu được các ước lượng của wage với tên biến là fit.
2. Chạy một hồi quy phụ (chúng ta gọi là ramsey) với các biến như ở mô hình mse1 nhưng có
thêm fit2, fit3. Nếu cần, có thể thêm cả các lũy thừa cao hơn nữa của fit.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


320

3. Tính thống kê F với mse1 là mô hình giới hạn, ramsey là mô hình không bị giới hạn. Nếu thống
kê F này lớn hơn Fα(m,n-k) thì chúng ta bắc bỏ giả thuyết rằng mse1 là mô hình đúng (không
thiếu biến) và chấp nhận giả thuyết rằng mô hình ramsey là mô hình đúng.

Ý tưởng của kiểm định này là đơn giản và rõ ràng. Nếu mô hình mse1 là mô hình đúng thì các hệ số
hồi quy của các biến thêm vào fit2, fit3 (hay các lũy thừa cao hơn của fit) tất cả chúng phải bằng 0
(không có ý nghĩa thống kê) . Nếu một trong số chúng khác không (có ý nghĩa thống kê) thì mse1 là
mô hình thiếu biến.

Chúng ta thực hiện kiểm định này trong R như sau:

table1$fit <- predict(mse1)


ramsey <- lm(data = table1, wage ~ female + nonwhite + union + education +
exper + I(fit^2) + I(fit^3))
summary(ramsey)

##
## Call:
## lm(formula = wage ~ female + nonwhite + union + education + exper +
## I(fit^2) + I(fit^3), data = table1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -25.769 -3.483 -0.997 2.324 50.870
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.4129809 2.4536171 1.799 0.0723 .
## female -0.0590166 0.7975349 -0.074 0.9410
## nonwhite -0.1954657 0.6316463 -0.309 0.7570
## union 0.1241080 0.5641605 0.220 0.8259
## education 0.0801244 0.3023952 0.265 0.7911
## exper 0.0009687 0.0424703 0.023 0.9818
## I(fit^2) 0.0447380 0.0207669 2.154 0.0314 *
## I(fit^3) -0.0003106 0.0006007 -0.517 0.6052
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 6.413 on 1281 degrees of freedom
## Multiple R-squared: 0.344, Adjusted R-squared: 0.3404
## F-statistic: 95.94 on 7 and 1281 DF, p-value: < 2.2e-16

anova(ramsey, mse1)

## Analysis of Variance Table


##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


321

## Model 1: wage ~ female + nonwhite + union + education + exper + I(fit^2) +


## I(fit^3)
## Model 2: wage ~ female + nonwhite + union + education + exper
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 1281 52687
## 2 1283 54343 -2 -1655.4 20.124 2.483e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Chúng ta có Pr(>F) = 2.483*10-9 (ứng với thống kê F = 20.124) là rất bé nên chúng ta chấp nhận giả
thuyết rằng mse1 là mô hình thiếu biến.

Cách tiếp cận dùng thống kê F như trên cần thực hiện hồi quy phụ với lắm thủ tục lằng nhằng. Chúng
ta có thể tính trực tiếp thống kê F này cũng như p-value tương ứng của nó bằng lệnh resettest() của
gói lmtest:

library(lmtest)
resettest(mse1)

##
## RESET test
##
## data: mse1
## RESET = 20.124, df1 = 2, df2 = 1281, p-value = 2.483e-09

Tuy dễ thực hiện nhưng kiểm định này có hai nhược điểm. Thứ nhất, nếu kiểm định chỉ ra rằng mô
hình là thiếu biến thì nó không chỉ ra mô hình thay thế. Thứ hai, kiểm định này không đưa ra bất kì
chỉ dẫn nào cho việc thêm số biến là dừng ở lũy thừa bao nhiêu của fit mặc dù trong thực tế chúng ta
có thể thực hiện bằng quá trình thử - làm lại dựa trên các tiêu chuẩn thông tin như Akaike, Schwarz.

10.3.5 Kiểm định Lagrange Multiplier


Kiểm định Lagrange Multiplier (gọi tắt là LM Test) cho mô hình thiếu biến dựa trên ý tưởng sau.

1. Chúng ta chạy mô hình mse1 nhằm thu được phần dư với tên gọi resids.
2. Nếu mse1 là mô hình đúng thì phần dư này sẽ không liên quan gì đến bất kì biến số bị bỏ sót
nào, chẳng hạn, là biến I(exper^2).
3. Chúng ta chạy một hồi quy phụ với tên gọi lmt với biến phụ thuộc là resids theo các biến độc
lập xuất hiện ở mse1 cộng với biến bỏ sót I(exper^2).
4. Nếu kích cỡ mẫu là lớn thì nR2 (với R2 thu được từ hồi quy phụ) sẽ tuân theo phân phối χ2(m)
với m bậc tự do (m là số biến bỏ sót). Nếu nR2 lớn hơn χ2(m) với mức ý nghĩa α chọn trước
chẳng hạn, thì chúng ta kết luận mse1 là mô hình bị thiếu biến I(exper^2). Ngược lại thì mse1
là mô hình không thiếu biến.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


322

Chúng ta thực hiện LM Test trong R như sau:

table1$resids <- residuals(mse1)


lmt <- lm(data = table1, resids ~ female + nonwhite + union + education +
exper + I(exper^2))
summary(lmt)

##
## Call:
## lm(formula = resids ~ female + nonwhite + union + education +
## exper + I(exper^2), data = table1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -19.883 -3.751 -0.855 2.455 50.125
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.235697 1.035710 -1.193 0.233
## female 0.065516 0.361432 0.181 0.856
## nonwhite 0.029237 0.504448 0.058 0.954
## union -0.068997 0.501521 -0.138 0.891
## education -0.046556 0.065937 -0.706 0.480
## exper 0.257856 0.053580 4.813 1.67e-06 ***
## I(exper^2) -0.006183 0.001227 -5.039 5.34e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 6.447 on 1282 degrees of freedom
## Multiple R-squared: 0.01943, Adjusted R-squared: 0.01484
## F-statistic: 4.233 on 6 and 1282 DF, p-value: 0.0003152

Kết tiếp chúng ta: (1) tính nR2 , và (2) χ2(m) với m = 1 (số biến thiếu) ứng với α = 5%:

0.01943*1289

## [1] 25.04527

qchisq(0.95, 1)

## [1] 3.841459

Chúng ta có thể thấy rằng 25.045 > 3.841 nên chúng ta bắc bỏ giả thuyết rằng mse1 là mô hình đúng
và kết luận rằng mse1 là mô hình thiếu biến exper2.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


323

10.4 Thêm biến không cần thiết


10.4.1 Các hậu quả của thêm biến không cần thiết
Chúng ta thường có xu hướng cho thêm biến số vào mô hình với niềm tin sai trái rằng một giá trị R2
cao hơn do thêm biến số là một mô hình tốt hơn. Nếu biến số được thêm vào là không có ý nghĩa kinh
tế và không thích hợp thì một chiến lược như vậy là không được khuyến khích. Mặc dù các ước lượng
OLS thu được từ mô hình được thêm biến vẫn thỏa mãn: (1) là các ước lượng không chệch (Unbiased)
và hiệu quả (Consistent), (2) phương sai σ2 vẫn được ước lượng chính xác, và (3) ước lượng khoảng
tin cậy và kiểm định giả thuyết vẫn còn là phù hợp tuy nhiên so với mô hình đúng thì các ước lượng
OLS có phương sai thường lớn hơn và do vậy các suy luận thống kê (Probability Inferences) về các
tham số là kém chính xác hơn.

10.4.2 Các kiểm định


Chúng ta hoàn toàn có thể áp dụng một số ý tưởng cho kiểm định mô hình thiếu biến cho mô hình
thừa biến số như đã trình bày ở các mục trước.

10.5 Dạng hàm sai


Trong nghiên cứu kinh tế, thường chúng ta gặp những mô hình cạnh tranh giải thích cho cùng một
hiện tượng kinh tế. Ví dụ, hành vi người tiêu dùng có thể được giải thích bằng hai lý thuyết là mô hình
khuynh hướng tiêu dùng cận biên MPC (Marginal Propensity to Consume) của Keynes và giả thuyết
tiêu thu nhập thường trực PIH (Permanent Income Hypothesis) của Friedman. Câu hỏi của chúng ta
ở đây là mô hình nào phù hợp hơn trong việc giải thích hành vi của người tiêu dùng?

10.5.1 Kiểm định Koop


Để minh họa, chúng ta xét hai mô hình sau:

wagei = β1+ β2femalei + β3nonwhitei + β4unioni + β5educationi + β6experi (mse1)

ln(wagei) = β1+ β2femalei + β3nonwhitei + β4unioni + β5educationi + β6experi (mse3)

Khi chúng ta ước lượng hai mô hình này trong R chúng ta thấy mse1 có R2 là 0.323 còn mse3 có R2 là
0.346. Mặc dù sức mạnh giải thích của mse3 lớn hơn mse1 nhưng chúng ta nếu chỉ dựa vào so sánh
hai R2 để đi đến kết luận mse3 là mô hình tốt hơn thì chưa đủ vì các biến phụ thuộc ở hai mô hình là
khác nhau. Để đưa ra quyết định lựa chọn mô hình đúng (thực chất là dạng hàm đúng), Koop (2008)
đề xuất kiểm định như sau:

1. Tính toán trung bình trung bình hình học GM (Geometric Mean) của wage theo công thức GM
= (wage1⨉wage2⨉… wagen)1/n . Trong tình huống của chúng ta, trung bình hình học của lương
là 10.406.
2. Chúng ta tính các biến số mới wage*i = wagei/10.406. Nghĩa là lấy các wagei chia cho trung
bình hình học của nó.
3. Ở các mô hình mse1 và mse3, thay wage bằng wage* chúng ta lần lượt thu được RSS1 và RSS2.
4. Kế tiếp chúng ta tính:
𝑛 𝑅𝑆𝑆1
𝜆= 𝑙𝑛 ( ) ~ χ12
2 𝑅𝑆𝑆2

Nguyễn Chí Dũng http://rpubs.com/chidungkt


324

Nếu λ (tuân theo phân phối χ2 với 1 bậc tự do) có ý nghĩa thống kê thì chúng ta kết luận mse1 là mô
hình phù hợp hơn. Ngược lại, mse3 là mô hình phù hợp hơn.

Để thực hiện kiểm định này theo cách tiếp cận của Koop, chúng ta làm như sau trong R. Trước hết
chúng ta tìm trung bình hình học của wage với sự trợ giúp của gói psych:

library(psych)
geometric.mean(table1)

## obs wage female nonwhite union education


## 475.854882 10.406343 0.000000 0.000000 0.000000 0.000000
## exper age wind femalenonw lnwage fit
## 0.000000 36.154604 0.000000 0.000000 2.263445 11.716291
## resids
## 2.824233

Kế tiếp chúng ta tính các wage*i và gán cho chúng tên biến là gmw:

attach(table1)
table1$gmw <- wage / 10.406343

Để tính các giá trị RSS:

anova(lm(data = table1, gmw ~ female + nonwhite + union + education + exper))

## Analysis of Variance Table


##
## Response: gmw
## Df Sum Sq Mean Sq F value Pr(>F)
## female 1 36.98 36.979 94.545 < 2.2e-16 ***
## nonwhite 1 10.38 10.376 26.527 3.005e-07 ***
## union 1 6.43 6.428 16.436 5.336e-05 ***
## education 1 143.85 143.848 367.779 < 2.2e-16 ***
## exper 1 42.16 42.158 107.787 < 2.2e-16 ***
## Residuals 1283 501.82 0.391
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

anova(lm(data = table1, log(gmw) ~ female + nonwhite + union + education +


exper))

## Analysis of Variance Table


##
## Response: log(gmw)
## Df Sum Sq Mean Sq F value Pr(>F)
## female 1 26.994 26.994 119.520 < 2.2e-16 ***
## nonwhite 1 6.722 6.722 29.761 5.858e-08 ***

Nguyễn Chí Dũng http://rpubs.com/chidungkt


325

## union 1 10.698 10.698 47.369 9.175e-12 ***


## education 1 81.872 81.872 362.504 < 2.2e-16 ***
## exper 1 26.780 26.780 118.572 < 2.2e-16 ***
## Residuals 1283 289.766 0.226
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Ta thu được RSS1 = 501.820 , RSS2 = 289.766 . Kế tiếp ta tính thống kê λ và so sánh nó với χ2(0.05,
df=1):

(1289 / 2)*log(501.82 / 289.766)

## [1] 353.9386

qchisq(0.95, 1)

## [1] 3.841459

Do 353.938 > 3.841 nên chúng ta có thể kết luận mse3 là mô hình phù hợp.

Ngoài cách tiếp cận theo kiểu Koop như trên, theo Nguyễn & Nguyễn (2012) thì chúng ta còn có thể
sử dụng cách tiếp cận do Ramsey (1969) và Davidson & MacKinnon (1981) đề xuất dưới đây.

10.5.2 Ramsey Test


Để minh họa chúng ta sử dụng bộ số liệu ch2vd5.WF1 cung cấp bởi khoa toán của NEU. Chúng ta xét
mô hình xu hướng tiêu dùng cận biên MPC (Keynes, 1936) dạng dưới đây:

CT = β1+ β2TN+ β3TS (Mô hình 1)

Để trả lời câu hỏi dạng hàm ở mô hình là đúng hay không ta xét mô hình sau:

CT = γ1+ γ2TN+ γ3TS+ γ4TN2+ γ5TS2+ γ6TN3+ γ7TN3+ γ8TN*TS (Mô hình 2)

Cách tiếp cận này giống như đã được trình bày ở mục 10.3.4. Theo đó nếu mô hình 1 là đúng thì tương
đương với việc chúng ta đưa ra bằng chứng thống kê chấp nhận giả thiết gốc ở cặp giả thuyết sau:

H0: γ24 + ..+ γ28 = 0; H1: γ24 + ..+ γ28 > 0

Như vậy, chúng ta có thể sử dụng kiểm định F để thực hiện việc bắc bỏ (hay chấp nhận) Ho. Chúng ta
chỉ thị cho R đọc bộ số liệu này dưới dạng một data.frame có tên gọi là dung. Trong R chúng ta thực
hiện kiểm định này nhanh chóng như sau:

library(hexView)
dung <- readEViews("ch2vd5.WF1", as.data.frame = TRUE)
attach(dung)
mohinh1 <- lm(data = dung, CT ~ TN + TS)
mohinh2 <- lm(data = dung, CT ~ TN + TS + I(TN^2) + I(TS^2) + I(TN^3) +
I(TS^3) + I(TN*TS))
anova(mohinh1, mohinh2)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


326

## Analysis of Variance Table


##
## Model 1: CT ~ TN + TS
## Model 2: CT ~ TN + TS + I(TN^2) + I(TS^2) + I(TN^3) + I(TS^3) + I(TN *
## TS)
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 30 4520.3
## 2 25 3574.7 5 945.52 1.3225 0.2868

Thống kê F = 1.322 ứn với Pr(>F) = 0.2868 >5% nên chúng ta có bằng chứng thống kê đủ mạnh để
chấp nhận Ho. Nghĩa là dạng hàm ở mô hình 1 là đúng.

Tuy nhiên, cũng theo Nguyễn & Nguyễn (2012) thì việc thêm nhiều lũy thừa bậc cao sẽ tiêu tốn nhiều
bậc tự do, nhất là với các mô hình có nhiều biến độc lập. Một giải pháp đưa ra là chúng ta có thể sử
dụng lũy thừa bậc hai và ba ước lượng chi tiê u CT̂ (kì kiệu là CTpre trong R) từ mô hình 1 cho mô hình
dưới đây:

CT = ψ1+ ψ2TN+ ψ3TS+ ψ4CTpre2+ ψ5Ctpre3 (Mô hình 3)

Lúc này, nếu mô hình 1 là mô hình đúng thì tương đương với việc chúng ta đưa ra bằng chứng thống
kê chấp nhận giả thiết gốc ở cặp giả thuyết sau:

H0: ψ24 + ..+ ψ25 = 0; H1: ψ24 + ..+ ψ25 > 0

Chúng ta thực hiện một loạt lệnh sau trong R để thực hiện kiểm định F:

dung$CTpre <- predict(mohinh1)


mohinh3 <- lm(data = dung, CT ~ TN + TS + I(CTpre^3) + I(CTpre^3))
anova(mohinh1, mohinh3)

## Analysis of Variance Table


##
## Model 1: CT ~ TN + TS
## Model 2: CT ~ TN + TS + I(CTpre^3) + I(CTpre^3)
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 30 4520.3
## 2 29 4442.0 1 78.294 0.5112 0.4804

Thống kê F = 0.511 ứn với Pr(>F) = 0.480 >5% nên chúng ta có bằng chứng thống kê đủ mạnh để chấp
nhận Ho. Nghĩa là dạng hàm ở mô hình 1 là đúng.

Ngoài cách sử dụng thống kê F như trên, chúng ta cũng có thể sử dụng lệnh resettest() như đã trình
bày ở mục trên:

resettest(mohinh1)

##
## RESET test

Nguyễn Chí Dũng http://rpubs.com/chidungkt


327

##
## data: mohinh1
## RESET = 2.3879, df1 = 2, df2 = 28, p-value = 0.1103

Ở đây p-value = 0.1103 > 5% nên chúng ta có bằng chứng thống kê đủ mạnh để chấp nhận Ho.

10.5.3 Davidson – MacKinnon Test


Chúng ta vẫn sử dụng lại bộ số liệu ch2vd5.WF1 ở trên. Để minh họa chúng ta xét hai mô hình sau:

CT = β1+ β2TN+ β3TS (Mô hình 1)

CT = ψ1+ ψ2TN2+ γ3TS2 (Mô hình 4)

Ý tưởng của cách kiểm định này như sau: nếu dạng hàm ở mô hình 1 là đúng thì khi đưa thêm biến
ước lượng của CT từ mô hình 2 (kí hiệu trong R là CTpre4) vào mô hình 1 thì hệ số ước lượng của
CTpre4 sẽ không có ý nghĩa thống kê (và ngược lại). Do vậy, việc xác định mô hình nào trong hai mô
hình (hay cả hai mô hình) quy về việc kiểm định hai cặp giả thuyết sau:

Cặp giả thuyết thứ nhất: H0: λ =0; H1: λ # 0.

Cặp giả thuyết thứ hai: J0: γ =0; J1: γ # 0.

Trong đó λ và γ là các hệ số hồi quy thu được từ 2 mô hình:

CT = β1+ β2TN+ β3TS+λCTpre4 (Mô hình 5)

CT = ψ1+ ψ2TN2+ γ3TS2 +γCTpre (Mô hình 6)

Căn cứ vào các bằng chứng thống kê thu được chúng ta có 4 tình huống sau:

1. Không bắc bỏ cả Ho lẫn Jo: cả hai mô hình ( hay 2 dạng hàm) đều chấp nhận được.
2. Không bắc bỏ Ho và bắc bỏ Jo: chỉ có dạng hàm ở mô hình 4 là dạng hàm đúng.
3. Bắc bỏ Ho và không bắc bỏ Jo: chỉ có dạng hàm ở mô hình 1 là dạng hàm đúng.
4. Bắc bỏ cả Ho lẫn Jo: Không dạng hàm nào là dạng hàm đúng.

Chúng ta thực hiện ý tưởng kiểm định dạng hàm này như sau trong R:

mohinh4 <- lm(data = dung, CT ~ I(TN^2) + I(TS^2))


dung$CTpre4 <- predict(mohinh4)
summary(lm(data = dung, CT ~ TN + TS + CTpre4))

##
## Call:
## lm(formula = CT ~ TN + TS + CTpre4, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -17.156 -9.970 0.236 5.247 32.893
##
## Coefficients:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


328

## Estimate Std. Error t value Pr(>|t|)


## (Intercept) 16.980024 8.984888 1.890 0.068813 .
## TN 0.750888 0.040959 18.333 < 2e-16 ***
## TS 0.015309 0.004003 3.824 0.000643 ***
## CTpre4 0.049937 0.046704 1.069 0.293790
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 12.25 on 29 degrees of freedom
## Multiple R-squared: 0.9996, Adjusted R-squared: 0.9995
## F-statistic: 2.208e+04 on 3 and 29 DF, p-value: < 2.2e-16

summary(lm(data = dung, CT ~ I(TN^2) + I(TS^2) + CTpre))

##
## Call:
## lm(formula = CT ~ I(TN^2) + I(TS^2) + CTpre, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -17.100 -9.988 0.338 5.140 32.788
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.637e+01 3.517e+01 1.034 0.310
## I(TN^2) 5.519e-06 6.344e-06 0.870 0.391
## I(TS^2) 2.684e-07 2.857e-07 0.939 0.355
## CTpre 9.506e-01 4.645e-02 20.466 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 12.24 on 29 degrees of freedom
## Multiple R-squared: 0.9996, Adjusted R-squared: 0.9995
## F-statistic: 2.209e+04 on 3 and 29 DF, p-value: < 2.2e-16

Căn cứ vào các kết quả thu được kết luận của chúng ta ở đây là: dạng hàm ở mô hình 1 là dạng hàm
đúng (Ho bị bắc bỏ và không bắc bỏ Jo).

Thay vì thực hiện dài dòng như trên chúng ta có thể sử dụng lệnh jtest của gói lmtest:

jtest(mohinh1, mohinh4)

## J test
##
## Model 1: CT ~ TN + TS
## Model 2: CT ~ I(TN^2) + I(TS^2)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


329

## Estimate Std. Error t value Pr(>|t|)


## M1 + fitted(M2) 0.04994 0.046704 1.0692 0.2938
## M2 + fitted(M1) 0.95064 0.046450 20.4659 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Chúng ta thấy rằng hệ số hồi quy của CTpre4 và CTpre có Pr(>|t|) lần lượt là 2.934 và 0 nên chúng ta
vẫn có kết luận tương tự như trên.

Có cùng ý tưởng như cách tiếp cận của Davidson & Mac Kinnon là cách tiếp cận do Mizon & Richard
(1986) đề xuất. Bạn đọc quan tâm đến cách tiếp cận này có thể xem tại trang 214 sách giáo trình kinh
tế lượng của NEU.

10.6 Lỗi đo lường


Như chúng ta đã biết, một trong những giả định của mô hình hồi quy tuyến tính cổ điển CLRM là đạng
hàm được xác định chính xác. Điều này cũng mặc định rằng giá trị các biến phụ thuộc và biến độc lập
là được đo lường chính xác. Tuy nhiên, trong thực tế, giả định rằng giá trị các biến được đo lường
chính xác thường không đúng trong thực tế vì nhiều lý do như có những quan sát chúng ta không thu
được thông tin (Missing Data) hay đơn giản hơn là chúng ta ..vào sai dữ liệu quan sát. Những điều này
có thể gây ra các hậu quả nghiêm trọng, đặc biệt là nếu lỗi đo lường (Errors of Mesuarement) lại xẩy
ra với biến độc lập. Cụ thể là:

Nếu lỗi đo lường xẩy ra với các biến phụ thuộc. Khi đó, mặc dù các ước lượng OLS cũng như phương
sai của các ước lượng thu được vẫn có tính chất không chệch (Unbiased) nhưng các phương sai ước
lượng thu được là lớn hơn so với các phương sai thu được nếu không tồn tại lỗi này (Ipso Factor
Variances).

Nếu lỗi đo lường xẩy ra với các biến độc lập. Lúc này các ước lượng OLS thu được sẽ là các ước lượng
chệnh và không hiệu quả. Nó nghiêm trọng đến mức, mặc dù lỗi đo lường có thể xẩy ra ở một biến số
nhưng nó có thể làm cho các ước lượng thu được ứng với các biến số khác là chệch và không hiệu quả
(Gujarati, 2011). Để xử lý vấn đề này, chúng ta có thể sử dụng phương pháp biến công cụ
(Instrumental Variables) cho những biến số mà chúng ta nghi ngờ là có lỗi đo lường – một vấn đề mà
chúng ta sẽ nghiên cứu kĩ trong các chương sau.

10.7 Lỗi do các quan sát bất thường, đòn bẩy cao, quan sát gây ảnh hưởng
Ngoài các lỗi trên, sự méo mó của mô hình thu được so với mô hình thực tế (Ipso Factor Model) còn
đến từ một trong ba hoặc một sự kết hợp nào đó trong số các nguyên nhân sau:

1. Các quan sát bất thường (Outliers). Đó là những quan sát mà phần dư ứng với chúng quá lớn
về giá trị tuyệt đối so với phần dư của các quan sát còn lại. Nếu bạn nào từng đọc cuốn sách
có tên “Những Kẻ Xuất Chúng” – cuốn sách về những người phi thường (nhưng trong số họ
nhiều người không thành công về mặt tài chính) của Malcolm Gladwell thì chắc chắn nhớ cái
tên này: Outliers.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


330

2. Một quan sát được gọi là có đòn bẩy cao (High Leverage) nếu điểm dữ liệu này quá “khác biệt”
theo một thước đo thống kê nào đó so với dữ liệu còn lại. Một trong các tiêu chí (thước đo)
đánh giá là khoảng cách Cook (Cook’s Distance) mà chúng ta sẽ nghiên cứu ngay sau đây.
Các quan sát có đòn bẩy cao có thể gây ra méo mó đối với các hệ số hồi quy.
3. Quan sát ảnh hưởng (Influence Point). Nếu quan sát có đòn bẩy cao thực tế kéo đường hồi
quy về phía mình thì chúng lúc này có tên gọi mới: điểm dữ liệu ảnh hưởng hay quan sát ảnh
hưởng.

Trên đây chúng ta đã xét đến các quan sát bất thường, quan sát có đòn bẩy cao, quan sát gây ảnh
hưởng. Ước lượng vững (Robust Regression) là một cách tiếp cận thay thế cho ước lượng OLS khi dữ
liệu được phân tích có chứa các quan sát bất thường (Outliers) hoặc các quan sát gây ảnh hưởng
(influential observations) và cũng có thể được sử dụng cho mục đích điều tra các quan sát gây ảnh
hưởng cũng như bất thường.

Để sử dụng ước lượng vững trong R, cần sử dụng đến hai gói là foreign và MASS. Nếu chưa cài đặt hai
gói này trước đó trên máy tính của bạn, cần cài đặt hai gói bằng cách gõ lần lượt hai câu lệnh
install.packages(“foreign”) và install.packages(“MASS”). Kế tiếp, để sử dụng cho phân tích gõ liên
tiếp hai câu lệnh library(foreign), library(MASS). Gói đầu tiên sử dụng để đọc file dữ liệu Stata vào R.
Gói thứ hai gồm các lệnh cho phép chúng ta thực hiện ước lượng vững.

Chúng ta sẽ sử dụng lại bộ số liệu ch2_health.wf1 đã được sử dụng trong chương 4 với kết quả hồi
quy là:

dung <- readEViews("ch2_health.wf1", as.data.frame = TRUE)


hoiquy <- lm(data = dung, HEALTH ~ INCOME)
summary(hoiquy)

##
## Call:
## lm(formula = HEALTH ~ INCOME, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -10396.3 -1272.7 -361.3 1088.0 9019.5
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.264e+03 5.554e+02 2.275 0.0273 *
## INCOME 1.295e-01 2.514e-03 51.514 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 3006 on 49 degrees of freedom
## Multiple R-squared: 0.9819, Adjusted R-squared: 0.9815
## F-statistic: 2654 on 1 and 49 DF, p-value: < 2.2e-16

Nguyễn Chí Dũng http://rpubs.com/chidungkt


331

Trong R, chúng ta có thể tìm ra các quan sát bất thường chỉ bằng một vài dòng lệnh đơn giản:

library("ggfortify")
autoplot(hoiquy, which = 1:4, ncol = 2, label.size = 3)

Những quan sát bất thường sẽ được đánh số. Trong tình huống của chúng ta, 4 Graphs chỉ ra rằng các
quan sát, ví dụ, thứ 33, 39, 10 và 5 là các quán sát bất thường căn cứ vào một tiêu chuẩn thống kê
được gọi là khoảng cách Cook (Cook’s Distance). Nghĩa là sự xuất hiện của chúng trong mô hình hồi
quy sẽ có tác động rất mạnh lên các kết quả thu được. Chúng ta có thể xem lại những quan sát này:

par(mfrow = c(1, 1))


dung[c(5, 10, 33, 39), 1:3]

## HEALTH INCOME POP


## 5 110057 920500 32683
## 10 59724 400200 14908
## 33 85785 583100 18159
## 39 51322 329700 12002

Về mặt kĩ thuận, khoảng cách Cook (thường kí hiệu là D) ứng với quan sát thứ i được tính toán bằng
cách loại bỏ quan sát đó ra khỏi mẫu ban đầu, chạy mô hình hồi quy khi không có quan sát đó và tính
toán biểu thức sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


332

Trong đó Di là khoảng cách Cook ứng với quan sát thứ i, ŷ j là giá trị dự báo của quan sát thứ j khi mô
hình hồi quy có đầy đủ cac quan sat, con ŷ j(i) là giá trị dự báo của quan sát thứ j khi mô hình hồi quy
được bỏ đi quan sát thứ i, p là số hệ số hồi quy có trong mô hình còn MSE là sai số trung bình bình
phương mà chúng ta đã biết.

R cho phép chúng ta tính toán các Di này bằng hàm cooks.distance() một cách nhanh chóng. Căn
cứ vào khoảng cách Cook thì bất kì quan sát nào có khoảng cách Cook lớn hơn 4/n (với n là số quan
sát trong mẫu ban đầu) thì nó sẽ là một quan sát bất thường. Chúng ta có thể hiểu rõ hơn kết quả vừa
thu được ở trên bằng cách gõ 3 lệnh sau trong R:

khoangcachcooks <- cooks.distance(hoiquy)


dung1 <- cbind(dung, khoangcachcooks)
dung1[khoangcachcooks > 4 / 51, ]

## HEALTH INCOME POP khoangcachcooks


## 5 110057 920500 32683 8.4373592
## 10 59724 400200 14908 0.1828241
## 33 85785 583100 18159 0.9710668
## 39 51322 329700 12002 0.1434226

Lệnh đầu tiên tạo ra các khoảng cách Cook cho 51 quan sát. Lệnh thứ hai hợp nhất các khoảng cách
này vào data.frame sẵn có dung nhằm tạo ra data.frame mới có tên dung1. Lệnh cuối cùng liệt kê bất
cứ quan sát nào có khoảng cách Cook lớn hơn 4/51.

Khi thực hiện hồi quy OLS thông thường , chúng ta có thể thấy một số quan sát bất thường (hoặc có
đòn bẩy cao). Nếu chúng ta quyết định rằng các bất thường này không phải đến từ nguyên nhân lỗi
vào dữ liệu và do vậy chúng ta không có lý do thuyết phục nào để loại bỏ chúng khỏi mô hình nghiên
cứu. Trong bối cảnh đó, chúng ta có thể sử dụng ước lượng vững cho phân tích. Ý tưởng của phương
pháp này là gán cho các quan sát những trọng số khác nhau dựa trên mức độ ảnh hưởng của chúng.
Lệnh rlm() của gói MASS có thể thực hiện kiểu ước lượng này bằng phương pháp M (M-Estimation)
với trọng số Huber trong tình huống mẫu có những quan sát bất thường hoặc gây ảnh hưởng.

Cách tiếp cận này thuộc về một nhóm được gọi là ước lượng vững (Robust Regression).

Để sử dụng ước lượng vững trong R, cần sử dụng đến gói MASS. Nếu chưa cài đặt gói này trước đó
trên máy tính của bạn, cần cài đặt MASS bằng cách gõ câu lệnh install.packages(“MASS”). Chúng ta
thực hiện hồi quy vững với trọng số Huber như sau trong R:

library(MASS)
robustHuber <- rlm(data = dung, HEALTH ~ INCOME)
summary(robustHuber)

##
## Call: rlm(formula = HEALTH ~ INCOME, data = dung)
## Residuals:
## Min 1Q Median 3Q Max
## -14469.4 -910.9 -181.7 1008.7 6647.3

Nguyễn Chí Dũng http://rpubs.com/chidungkt


333

##
## Coefficients:
## Value Std. Error t value
## (Intercept) 696.3860 350.9770 1.9841
## INCOME 0.1345 0.0016 84.6946
##
## Residual standard error: 1491 on 49 degrees of freedom

Với phương pháp ước lượng này, hệ số hồi quy của INCOME tăng, thống kê t tăng, phương sai ước
lượng của hồi quy giảm từ 3006 xuống còn 1491.

Trên đây tôi đã giới thiệu lệnh rlm với trọng số Huber nhằm xử lý tình huống khi dữ liệu của chúng
ta có các qua sát bất thường. Tuy nhiên, nếu các quan sát này có nguyên nhân là lỗi vào số liệu (Data
Entry Error) thì cách xử lý là .. loại chúng ta khỏi mẫu và chạy OLS bình thường. Trong R chúng ta
thực hiện một loạt lệnh sau:

olsloaibien <- lm(data = dung[-c(5, 10, 33, 39), ], HEALTH ~ INCOME])


summary(olsloaibien)

##
## Call:
## lm(formula = HEALTH ~ INCOME, data = dung, subset = (ID != 5 &
## 10 & 33 & 39))
##
## Residuals:
## Min 1Q Median 3Q Max
## -6322.6 -703.9 98.6 1097.0 5130.2
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.734e+02 4.576e+02 0.379 0.706
## INCOME 1.396e-01 2.524e-03 55.292 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2280 on 48 degrees of freedom
## Multiple R-squared: 0.9845, Adjusted R-squared: 0.9842
## F-statistic: 3057 on 1 and 48 DF, p-value: < 2.2e-16

Chúng ta thấy rằng việc loại các quan sát này ra khỏi mẫu nghiên cứu làm thay đổi đáng kể, ví dụ hệ
số hồi quy và thống kê t của INCOME. Ngoài ra phương sai của hồi quy giảm mạnh từ 3006 xuống chỉ
còn 2280.

R có nhiều gói có thể thực hiện nhiều phương pháp ước lượng vững khác nhau nhưng trong tài liệu
này chúng ta chỉ xét một phương pháp là ước lượng vững với trọng số Huber mà thôi.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


334

Nguyễn Chí Dũng http://rpubs.com/chidungkt


335

Chương 11: Hồi quy với biến công cụ và hồi quy hai giai đoạn 2SLS

Chương này chúng ta sẽ nghiên cứu việc sử dụng các biến công cụ (Instrumental Variables) cũng như
hồi quy hai giai đoạn 2SLS (tên đầy đủ là Two Stage Least Squares – ước lượng bình phương nhỏ nhất
hai giai đoạn) nhằm xử lý hiện tượng biến nội sinh vốn rất phổ biến trong các mô hình kinh tế lượng.

11.1 Nguyên nhân của việc sử dụng biến công cụ cho mô hình hồi quy
Chúng ta xét mô hình đơn giản sau:

lwage = β0 + β1educ + β2abil + e (1)

Trong đó wage là mức lương, educ là số năm đi học và abil là biến đại diện cho tiềm năng trí tuệ của
người lao động. Chúng ta biết rằng dưới một số giả định của mô hình hồi quy tuyến tính cổ điển thì
chúng ta có thể chọn chỉ số thông minh IQ là một đại diện (proxy) cho tiềm năng trí tuệ của người lao
động và do vậy mô hình trên trở thành:

lwage = β0 + β1educ + β2IQ + e (2)

Lúc đó ước lượng thu được của β1 từ (2) là ước lượng vững (consistent).

Tuy nhiên, vì một lý do nào đó chúng ta không thể tìm được bất kì một biến số nào đại diện cho abil
thì lúc đó ta buộc phải “nhóm” abil vào e và do vậy (1) trở thành:

lwage = β0 + β1educ + u (3)

Trong tình huống này, ước lượng của β1 thu được từ (3) sẽ là ước lượng chệch (biased) và không
vững nếu như biến educ và abil (hay educ và u) là tương quan với nhau. Lúc này chúng ta có thể nói
educ là biến nội sinh (endogenous) với ý nghĩa rằng biến này có tương quan với sai số ngẫu nhiên u.
Chúng ta vẫn có thể sử dụng mô hình (3) nhằm tìm ước lượng cho β1 miễn là chúng ta tìm được một
biến đại diện (proxy) cho educ. Tổng quát hơn chúng ta xét mô hình:

y = β0 + β1x + u (4)

Nếu chúng ta tin rằng x và u là tương quan, tức là Cov(x,u) ≠ 0 thì để có được các ước lượng vững cho
các hệ số hồi quy chúng ta tìm một đại diện z của biến x sao cho hai điều kiện sau thỏa mãn:

Cov(z,u) = 0 (5)

Cov(z,x) ≠ 0 (6)

Biến z thỏa mãn hai điều kiện này thì z được gọi là biến công cụ (Intrumental Variable, viết tắt là IV)
của x. Trong nhiều tình huống có thể gọi tắt là công cụ của x.

Theo Wooldridge (2013), điều kiện (5) liên quan đến việc đánh giá tương quan giữa z và sai số ngẫu
nhiên không thể quan sát được u nên chúng ta gần như không thể nào kiểm tra được điều kiện này.
Thay vào đó, trong hầu hết các trường hợp chúng ta phải chấp nhận điều kiện (5) là thỏa mãn. Riêng

Nguyễn Chí Dũng http://rpubs.com/chidungkt


336

điều kiện (6) thì chúng ta có thể dễ dàng kiểm tra bằng nhiều cách, chẳng hạn, thực hiện hồi OLS giữa
hai biến số này.

Trong tình huống chúng ta tìm được biến công cụ (là z) cho x thì ước lượng OLS và ước lượng thu
được từ việc thay x bằng biến công cụ z của nó được tính như sau:

β̂ 1OLS = Cov(x,y)/Var(x) (7)

β̂ 1IV = Cov(z,y)/Cov(z,x) (8)

Để thực hiện hồi quy với biến công cụ chúng ta sử dụng lệnh ivreg của gói AER (Kleiber & Zeileis,
2008) theo cú pháp sau:

ivreg(y~x|z)

Để minh họa cho hồi quy biến công cụ, chúng ta sử dụng bộ số liệu MROZ.DTA. Ở đây chúng ta đánh
giá tác động của giáo dục (biến educ) lên mức lương (biến lwage) của phụ nữ trong đó biến fatheduc
(số năm đi học của cha) được chọn là IV cho biến educ. Dưới đây là các dòng lệnh tính trực tiếp ước
lượng cho hệ số hồi quy theo công thức (7) và (8) đồng thời so sánh kết quả thu được từ OLS và IV:

setwd("D:/KTLR")
library(foreign)
trang <- read.dta("MROZ.DTA")
trang <- na.omit(trang) # Xử lý dữ liệu thiếu cho data frame tên trang.
attach(trang)
cov(educ, lwage) / var(educ) # Tính trực tiếp ước lượng OLS theo (7).

## [1] 0.1086487

cov(fatheduc, lwage) / cov(fatheduc, educ) # TÍnh ước lượng IV theo (8).

## [1] 0.05917348

library(AER); library(stargazer)
OLS <- lm(data = trang, lwage ~ educ)
IV <- ivreg(data = trang, lwage ~ educ|fatheduc)
stargazer(OLS, IV, type = "text") # So sánh ước lượng OLS và IV.

##
## ===================================================================
## Dependent variable:
## ------------------------------------
## lwage
## OLS instrumental
## variable
## (1) (2)
## -------------------------------------------------------------------
## educ 0.109*** 0.059*

Nguyễn Chí Dũng http://rpubs.com/chidungkt


337

## (0.014) (0.035)
##
## Constant -0.185 0.441
## (0.185) (0.446)
##
## -------------------------------------------------------------------
## Observations 428 428
## R2 0.118 0.093
## Adjusted R2 0.116 0.091
## Residual Std. Error (df = 426) 0.680 0.689
## F Statistic 56.929*** (df = 1; 426)
## ===================================================================
## Note: *p<0.1; **p<0.05; ***p<0.01

So sánh các kết quả chúng ta thấy trước hết các ước lương thu được từ sử dụng trực tiếp công thức
(7) và (8) là trùng với các kết quả thu được từ ước lượng OLS và IV. Ngoài ra so sánh các ước lượng
thu được từ OLS và IV chúng ta thấy khoảng tin cậy 95% thu được từ IV là chứa khoảng tin cậy 95%
thu được từ OLS. Nói cách khác khoảng tin cậy 95% từ OLS là hẹp hơn. Mặc dù sự khác biệt từ hai
ước lượng này là đủ lớn nhưng chúng ta chưa thể nói khác biệt này có ý nghĩa thống kê hay không.
Chúng ta sẽ nghiên cứu vấn đề này ở các mục sau.

Khi sử dụng biến công cụ cho các phân tích chúng ta có thể thấy rằng, chẳng hạn, có thể có nhiều lựa
chọn biến công cụ làm cho educ. Một ứng cử viên khác có thể lựa chọn làm biến công cụ cho educ là
số năm đi học của người mẹ (motheduc). Điều này ngụ ý một vấn đề sâu xa hơn của việc lựa chọn biến
công cụ: một biến công cụ tốt thì được đặc trưng, hay được mô tả, bởi những tiêu chí nào? Theo
Wooldridge (2013) và Greene (2008), biến công cụ cho educ được lựa chọn phải thỏa mãn: (1) không
tương quan với biến abil (khả năng) hay bất cứ nhân tố không quan sát nào được “nhóm” và sai số
ngẫu nhiên u, và (2) tương quan cao nhất có thể được với educ. Nếu chúng ta chọn số chứng minh
nhân dân làm biến công cụ cho educ thì rõ ràng điều kiện thứ nhất được thỏa mãn vì số chứng minh
được lựa chọn ngẫu nhiên và không tương quan gì đến abil tuy nhiên nó cũng không tương quan gì
với educ. Do vậy, chọn số chứng minh làm biến công cụ cho educ thì đây là một biến công cụ yếu
(weak instrumental variable). Chúng ta sẽ nghiên cứu chi tiết việc đánh giá chất lượng của một biến
công cụ được sử dụng bởi các kiểm định chính thức ở các mục sau.

Đối với điều kiện biến được chọn làm biến công cụ phải tương quan với educ (điều kiện 2), ngoài việc
chú ý đến ý nghĩa thống kê chúng ta còn phải chú ý đến dấu, thậm chí là độ lớn của hệ số hồi quy.
Chẳng hạn, ở ví dụ trên chúng ta chọn fatheduc làm biến công cụ cho educ. Rõ ràng trình độ giáo dục
của người cha chắc chắn có ảnh hưởng tích cực lên trình độ giáo dục của con, nghĩa là hệ số hồi quy
của fatheduc phải dương. Để minh họa chúng ta trở lại với việc lựa chọn fatheduc làm biến công cụ
cho educ:

summary(lm(educ ~ fatheduc, data = trang))

##
## Call:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


338

## lm(formula = educ ~ fatheduc, data = trang)


##
## Residuals:
## Min 1Q Median 3Q Max
## -8.4704 -1.1231 -0.1231 0.9546 5.9546
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 10.23705 0.27594 37.099 <2e-16 ***
## fatheduc 0.26944 0.02859 9.426 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.081 on 426 degrees of freedom
## Multiple R-squared: 0.1726, Adjusted R-squared: 0.1706
## F-statistic: 88.84 on 1 and 426 DF, p-value: < 2.2e-16

Kết quả này cho thấy rằng fatheduc có tác động dương (hệ số hồi quy là 0.27), và có ý nghĩa thống kê,
đến educ. Nghĩa là căn cứ vào điều kiện 2, thì việc lựa chọn fatheduc làm biến đại diện cho educ có
thể là hợp lý. Nếu hệ số này mà là âm thì rõ ràng điều này là phi thực tế và do vậy, fatheduc là một lựa
chọn không phù hợp để làm biến công cụ cho educ và chúng ta cần tìm kiếm biến công cụ khác cho
educ.

11.2 Sử dụng đồng thời nhiều biến công cụ cho một biến số
Chúng ta mở rộng mô hình (3) bằng cách đưa vào biến exper:

lwage = β0 + β1educ + β2exper + w (9)

Ở đây chúng ta giả thiết rằng không giống như educ, biến exper là không tương quan với sai số ngẫu
nhiên w. Bên cạnh đó, ngoài chọn fatheduc, chúng ta còn chọn biến motheduc – giáo dục của người
mẹ làm biến đại diện cho educ. Nghĩa là biến educ được đại diện bởi đồng thời cả hai biến công cụ là
fatheduc và motheduc. Dưới đây là các câu lệnh thực hiện trong R với chú ý rằng biến ngoại sinh xuất
hiện ở cả hai vế của dấu gạch thẳng đứng:

trangyeu <- ivreg(lwage ~ educ + exper | exper + fatheduc + motheduc)


summary(trangyeu)

##
## Call:
## ivreg(formula = lwage ~ educ + exper | exper + fatheduc + motheduc)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.03043 -0.32963 0.03599 0.39554 2.24339
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


339

## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.147841 0.402215 0.368 0.713378
## educ 0.066389 0.031252 2.124 0.034219 *
## exper 0.015488 0.004064 3.811 0.000159 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.6762 on 425 degrees of freedom
## Multiple R-Squared: 0.1298, Adjusted R-squared: 0.1257
## Wald test: 9.258 on 2 and 425 DF, p-value: 0.0001159

Tất nhiên chúng ta có thể chọn nhiều hơn hai biến công cụ cho một biến nội sinh.

11.3 Kiểm định biến công cụ yếu, kiểm định Wu-Hausman và Sargan
Như đã trình bày ở phần trước, chúng ta có thể sử dụng một số kiểm định chính thức nhằm đánh giá
sự hợp lý của việc sử dụng biến công cụ. Chúng ta có thể thực hiện đồng thời cả ba kiểm định như sau
(dạng rút gọn):

summary(trangyeu, vcov = sandwich, diagnostics = TRUE)

##
## Diagnostic tests:
## df1 df2 statistic p-value
## Weak instruments 2 424 50.810 <2e-16 ***
## Wu-Hausman 1 424 2.234 0.136
## Sargan 1 NA 0.384 0.536
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Thứ nhất là kiểm định biến công cụ yếu (Test for Weak Instruments) với cặp giả thuyết:

H0: Biến công cụ sử dụng là yếu (không hợp lý)

H1: Biến công cụ sử dụng là mạnh.

Nếu chúng ta có bằng chứng thống kê bắc bỏ H0 thì việc sử dụng biến công cụ cho mô hình là hợp lý.
Trong tình huống của chúng ta thì p-value là bằng 0 nên chúng ta có thể kết luận rằng việc sử dụng
biến công cụ là phù hợp.

Thứ hai là kiểm định Wu – Hausman. Cặp giả thuyết của kiểm định này có thể được phát biểu ở nhiều
dạng thức khác nhau nhưng trong tình huống của chúng ta sẽ là thuận lợi hơn khi phát biểu cặp giả
thuyết của kiểm định này như sau:

H0: Các ước lượng thu được từ OLS và IV là vững

Nguyễn Chí Dũng http://rpubs.com/chidungkt


340

H1: Chỉ có ước lượng thu được từ IV là vững

Nghĩa là, nếu chúng ta có bằng chứng chấp nhận giả thuyết gốc thì vấn đề nội sinh không phải là
nghiêm trọng và chúng ta không cần thiết phải sử dụng ước lượng biến công cụ. Ngược lại, nếu chúng
ta bắc bỏ giả thuyết gốc thì có nghĩa là việc sử dụng biến công cụ là cần thiết. Trong tình huống của
chúng ta thì p-value là 0.136 > 5% nên chúng ta có bằng chứng thống kê chấp nhận giả thuyết gốc.

Chú ý rằng trong một số tài liệu (như sách của NEU) cũng như nghiên cứu, kiểm định Wu – Hausman
còn được sử dụng cho kiểm tra tính nội sinh cho một biến số.

Thứ ba là kiểm định Sargan được sử dụng cho cặp giả thuyết thuyết sau:

H0: Tất cả biến công cụ được sử dụng là phù hợp

H1: Có ít nhất một biến công cụ là không phù hợp

Kiểm định này được sử dụng cho trường hợp chúng ta sử dụng từ hai biến công cụ trở lên đại diện
cho chỉ một biến nội sinh như trường hợp của chúng ta ở trên. Do p-value = 0.536 > 5% nên có thể
nói fatheduc và motheduc là những biến công cụ phù hợp cho educ.

Thực hiện ước lượng biến công cụ cũng như các phân tích và kiểm định liên quan ngoài sử dụng gói
AER chúng ta còn có thể sử dụng các gói sem (Fox et al., 2014) hoặc lfe (Gaure, 2013). Gần đây nhất
vào tháng 5 năm 2016 xuất hiện gói ivmodel (Jiang et al., 2016) cho thực hiện ước lượng biến công
cụ với nỗ lực tính đến những phát triển mới nhất về lý thuyết liên quan đến ước lượng biến công cụ.
Bạn đọc nào quan tâm có thể tìm hiểu việc sử dụng những gói này cho những phân tích chuyên sâu
nâng cao liên quan đến biến công cụ.

11.4 Hậu quả của việc sử dụng biến công cụ yếu


Mục trên chúng ta đã nghiên cứu sử dụng một số kiểm định nhằm đánh giá sự phù hợp của việc sử
dụng biến công cụ. Một trong những kiểm định đó là nhằm đánh giá tồn tại hay không biến công cụ
mà chúng ta sử dụng là yếu. Một biến công cụ được gọi là yếu nếu như nó tương quan yếu hoặc cực
đoan nhất là không hề tương quan gì với biến số được công cụ (intrusmented variables). Hậu quả của
việc sử dụng biến công cụ yếu trong nhiều tính huống là nghiêm trọng hơn cả việc sử dụng OLS thuần
túy. Với mục đích minh họa chúng ta xét tác động của việc hút thuốc lên cân nặng của trẻ sơ sinh qua
mô hình sau:

lbwght = β0 + β1packs + u (10)

Trong đó lbwght là logarit cơ số tự nhiên trọng lượng (tính theo gam) của trẻ sơ sinh, packs là số gói
thuốc tiêu thụ bởi người mẹ mỗi ngày. Số liệu được sử dụng là BWGHT.DTA. Nếu chúng ta tin rằng
tồn tại hiện tượng nội sinh ở mô hình này, nghĩa là biến packs có tương quan với u và do vậy chúng
ta chọn, chẳng hạn, biến cigprice (giá của một bao thuốc) làm biến công cụ đại diện cho biến packs.
Chúng ta đánh giá lượng biến công cụ cho lựa chọn biến công cụ này:

dung <- read.dta("BWGHT.DTA")


love <- ivreg(lbwght ~ packs | cigprice, data = dung)
summary(love)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


341

##
## Call:
## ivreg(formula = lbwght ~ packs | cigprice, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -7.4200 0.1368 0.3055 0.4194 1.1540
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.4481 0.9082 4.898 1.08e-06 ***
## packs 2.9887 8.6989 0.344 0.731
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.9389 on 1386 degrees of freedom
## Multiple R-Squared: -23.23, Adjusted R-squared: -23.25
## Wald test: 0.118 on 1 and 1386 DF, p-value: 0.7312

Như chúng ta có thể thấy hệ số R2 là âm. Nguyên nhân chính là vì chúng ta sử dụng biến cigprice làm
IV cho biến packs là không hợp lý. Nói chính xác hơn cigprice là một biến công cụ yếu như chúng ta
có thể thấy:

summary(lm(packs ~ cigprice, data = dung))

##
## Call:
## lm(formula = packs ~ cigprice, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.1106 -0.1061 -0.1032 -0.1015 2.4016
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.0674257 0.1025384 0.658 0.511
## cigprice 0.0002829 0.0007830 0.361 0.718
##
## Residual standard error: 0.2987 on 1386 degrees of freedom
## Multiple R-squared: 9.417e-05, Adjusted R-squared: -0.0006273
## F-statistic: 0.1305 on 1 and 1386 DF, p-value: 0.7179

Kết quả này chỉ ra rằng cigprice và packs có tương quan rất thấp. Nói chính xác hơn chúng ta có thể
kết luận giữa hai biến này không có tương quan.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


342

Tất nhiên chúng ta cũng có thể sử dụng kiểm định biến công cụ yếu để đưa kết luận chính thức:

summary(love, vcov = sandwich, diagnostics = TRUE)

##
## Diagnostic tests:
## df1 df2 statistic p-value
## Weak instruments 1 1386 0.121 0.728
## Wu-Hausman 1 1385 3.489 0.062 .
## Sargan 0 NA NA NA
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Giá trị p-value = 0.728 > 5% nên chúng ta có thể kết luận rằng cigprice là biến công cụ yếu. Chú ý rằng
trong trường hợp này kiểm định Sargan không tồn tại nên có kí hiệu là NA.

11.5 Ước lượng bình phương nhỏ nhất hai giai đoạn 2SLS
Ước lượng bình phương nhỏ nhất 2SLS (còn gọi là hồi quy hai giai đoạn 2SLS) là một cách tiếp cận
tổng quát hơn cho hai tình huống sau.

Tình huống thứ nhất là mô hình của chúng ta có một biến nội sinh nhưng chúng ta sử dụng từ hai biến
công cụ trở lên làm đại diện cho nó. Tình huống này chúng ta đã xét ở mục 11.2 trước.

Tình huống thứ hai là mô hình của chúng ta có từ hai biến nội sinh trở lên. Để minh họa chúng ta xét
mô hình sau:

y1 = β0 + β1y2 + β2y3 + β3z1 + β4z2 + β5z3 + u (11)

Trong đó y2 và y3 là các biến nội sinh (tức là có tương quan với u) và các biến z1, z2, và z3 không tương
quan với u (ngoại sinh). Vì chúng ta có hai biến nội sinh nên chúng ta cần ít nhất hai biến công cụ đại
diện cho y2 và y3. Giả sử hai biến công cụ ấy là z4 và z5. Tên gọi hồi quy hai giai đoạn 2SLS bắt nguồn
từ thực tế sau khi thực hiện hồi quy cho mô hình trên.

Giai đoạn 1 (Stage1) chúng ta lần lượt thực hiện hai hồi quy OLS cho y2 và y3 đối với các biến từ z1
đến z5 nhằm thu được các giá trị ước lượng ŷ 2 va ŷ 3.

Giai đoạn 2 (Stage2) chúng ta thực hiện hồi quy OLS cho y1 đối với các biến ŷ 2 , ŷ 3 và các biến từ z1
đến z3.

Để thực hiện hồi quy hai giai đoạn 2SLS chúng ta sử dụng lệnh ivreg như đã từng làm ở mục 11.2.
Tuy nhiên, để làm sáng tỏ hơn bản chất của hồi quy hai giai đoạn chúng ta trở lại với ví dụ ở mục 11.2
theo hai cách làm khác nhau: sử dụng lệnh lm và lệnh ivreg. Chú ý rằng ở đây chúng ta chỉ có một biến
nội sinh là educ và hai biến công cụ là fatheduc và motheduc:

trangyeu <- ivreg(lwage ~ educ + exper | exper + fatheduc + motheduc) # Chạy


2SLS trực tiếp bằng lệnh ivreg.
stage1 <- lm(educ ~ fatheduc + motheduc + exper, data = trang) # Chạy OLS
giai đoạn 1.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


343

stage2 <- lm(lwage ~ fitted(stage1) + exper)


stargazer(trangyeu, tage2, type = "text") # So sánh cách làm trực tiếp bằng
lệnh ivreg và gián tiếp qua hai lệnh lm.
## ==================================================================
## Dependent variable:
## -----------------------------------
## lwage
## instrumental OLS
## variable
## (1) (2)
## ------------------------------------------------------------------
## educ 0.066**
## (0.031)
##
## fitted(stage1) 0.066**
## (0.033)
##
## exper 0.015*** 0.015***
## (0.004) (0.004)
##
## Constant 0.148 0.148
## (0.402) (0.423)
##
## ------------------------------------------------------------------
## Observations 428 428
## R2 0.130 0.038
## Adjusted R2 0.126 0.033
## Residual Std. Error (df = 425) 0.676 0.711
## F Statistic 8.374*** (df = 2; 425)
## ==================================================================
## Note: *p<0.1; **p<0.05; ***p<0.01

So sánh chúng ta có thể thấy các giá trị ước lượng cho các hệ số là không khác biệt (có một số kết quả,
chẳng hạn sai số chuẩn của hệ số tự do là có khác biệt chừng 5% nhưng đây chỉ là kết quả của việc
làm tròn số trong tính toán của R). Ở đây các bạn cũng cần chú ý rằng chúng ta không thể so sánh R2
từ lệnh lm và ivreg. Nguyên nhân là đối với ước lượng IV, công thức R2 =1 - SSR/SST có thể tạo ra kết
quả âm vì có thể xẩy ra tình huống SSR lớn hơn SST như chúng ta có thể thấy ở mục 11.4. Điều này
cũng có nghĩa là khi thực hiện các nghiên cứu sử dụng ước lượng IV, báo cáo R2 là không có ý nghĩa.
Bạn đọc quan tâm có thể đọc tại trang 523 cuốn Introductory Econometrics: A Modern Approach
ấn bản lần thứ 5 của Wooldridge. Một số nghiên cứu ở Việt Nam mà tôi có dịp đọc, nhiều tác giả không
chú ý đến chi tiết này nên vẫn trình bày tiêu chí R2 cho các mô hình của mình.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


344

Nguyễn Chí Dũng http://rpubs.com/chidungkt


345

Chương 12: Phân tích dữ liệu bảng (Panel Data)

Chương này chúng ta sẽ nghiên cứu một số mô hình cơ bản với dữ liệu bảng (Panel Data) – là một
nhóm dữ liệu được sử dụng nhiều trong nghiên cứu kinh tế - tài chính cũng như một số lĩnh vực khác.
Dữ liệu mảng còn được gọi với các tên gọi khác như dữ liệu mảng, dữ liệu tổng hợp. Các mô hình được
nghiên cứu trong chương này là Pooled OLS, FEM, REM, LSDV cùng một số kiểm định lựa chọn và chẩn
đoán lỗi của mô hình. Các mô hình nâng cao là ước lượng GMM, Hausman – Taylor, biến công cụ IV và
FGLS.

12.1 Giới thiệu về dữ liệu bảng


Panel Data là bộ dữ liệu bao gồm cả hai chiều không gian và thời gian. Chẳng hạn, chúng ta xét nghiên
cứu có tên “Tác động của cấu trúc sở hữu tới kết quả hoạt động của các công ti xây dựng niêm yết trên
sàn HOSE trong gian đoạn 2007 – 2013”, số tháng 3 năm 2014, tạp chí Kinh Tế và Phát Triển. Trong
nghiên cứu này, các tác giả thu thập số liệu của 80 công ti xây dựng niêm yết trên sàn HOSE (chiều
không gian) trong khoảng thời gian từ 2007 đến 2013 (chiều thời gian). Như vậy, tổng số quan sát là
80⨉7 = 560. Tình huống cụ thể này, chúng ta có Panel Data kích cỡ 80⨉7. Trong tình huống tổng quát,
các Panel Data thường đi kèm kí hiệu (N,T) với ngụ ý rằng đây là dữ liệu cho N cá thể (hãng, quốc gia)
trong T năm.

Dữ liệu mảng và phân tích dữ liệu mảng ra đời từ khá sớm và bắt đầu xuất hiện tầm khoảng hơn 50
năm trước của Kuh (1959) về đầu tư, của Mundlak (1961) và Hoch (1962) về hàm sản xuất. Một trong
những bộ dữ liệu mảng nối tiếng (và cũng là nguồn số liệu cho rất nhiều nghiên cứu khác nhau) là bộ
dữ liệu PSID được thu thập và phân tích bởi Đại Học Michigan từ năm 1968
(http://psidonline.isr.umich.edu ) với hơn 4800 hộ gia đình. Tới năm 2003, bộ dữ liệu này đã thu
thập rất nhiều các thông tin về thu nhập, trình độ học vấn, các thông tin về nhân chủng học.. của 7000
hộ gia đình với hơn 65.000 cá nhân (Baltagi, 2005). Tương tự như bộ số liệu PSID của Hoa Kì là bộ dữ
liệu UKHLS của Viện Nghiên Cứu kinh Tế và Xã Hội thuộc Đại Học Essex ở Anh Quốc với thông tin về
40.000 hộ gia đình và xấp xỉ 100.000 các nhân. Vai trò của hai bộ dữ liệu PSID và UKHLS trong việc
nghiên cứu các xu hướng kinh tế, xã hội ở Mĩ và Anh là rất quan trọng và tương đương với bộ dữ liệu
VHLSS được thu thập và tính toán bởi Tổng Cục Thống Kê ở Việt Nam.

Có nhiều cách phân loại Panel Data tùy theo mức độ đầy đủ của bảng dữ liệu và kích thước của bảng
dữ liệu cũng như kích thước giữa tương đối giữa N và T. Việc phân loại này là cần thiết và quan trọng
cho việc lựa chọn mô hình cũng như phương pháp phân tích dữ liệu (Cameron & Trivedi ; Baltagi,
2005) vì chúng có các đặc điểm thống kê khác nhau.

Nếu căn cứ vào mức độ đầy đủ của dữ liệu (Gujarati & Porter, 2009; Cameron & Trivedi, 2009) chúng
ta có dữ liệu bảng cân bằng (Balanced Panel) và dữ liệu bảng không cân bằng (Unbalanced Panel).
Chẳng hạn, nếu như bộ số liệu ở trên, vì một lí do nào đó một trong số 80 công ti ở trên chúng ta không
thể thu được dữ liệu của nó ở năm 2012 thì trong tình huống này chúng ta có dữ liệu bảng không cân
bằng.

Nếu căn cứ vào kích thước tương đối giữa N và T. Nếu T là rất lớn so với N chúng ta có chúng ta có
dữ liệu mảng loại dài (Long Panel Data). Ngược lại, nếu T là rất bé so với N thì chúng ta có dữ liệu

Nguyễn Chí Dũng http://rpubs.com/chidungkt


346

mảng loại ngắn (Short Panel Data). Một điển hình về sử dụng dữ liệu mảng loại ngắn là nghiên cứu
về cấu trúc vốn có tên “Testing trade-off and pecking order theories financing SMEs” của López-
Gracia và Sogorb-Mira (2007). Trong nghiên cứu này, hai tác giả sử dụng các thông tin tài chính của
N= 3,569 doanh nghiệp vừa và nhỏ trong khoảng thời gian nghiên cứu T = 10 năm. Như vậy tỉ số giữa
N và T là 357 lần.

Bằng việc kết hợp cả các đặc điểm của dữ liệu chéo (Cross Sections) và dữ liệu chuỗi thời gian (Time
Series), Baltagi (2005) nêu ra một số lợi thế dưới đây của việc sử dụng Panel Data trong các nghiên
cứu:

1. Vì Panel Data chứa các cá thể khác nhau nên các phân tích có tính đến sự khác biệt đặc trưng
(heterogeneity) cho các cá thể ấy. Nghiên cứu nếu chỉ sử dụng thuần túy dữ liệu chéo hoặc dữ
liệu chuỗi thời gian không kiểm soát khác biệt đặc trưng này vào các mô hình nghiên cứu. Ví
dụ, trong nghiên cứu của Baltagi và Levin (1992) về cầu đối với thuốc lá ở 46 bang của Mĩ
trong giai đoạn 1963 – 1988, cầu được mô hình hóa như là một hàm biến trễ của tiêu dùng,
giá của thuốc, và thu nhập. Những biến số này thay đổi theo từng bang (chiều không gian) và
cả theo thời gian (chiều thời gian). Tuy vậy. có thể có nhiều biến khác là không thay đổi theo
các bang (gọi là individual-invariant) cũng như không thay đổi theo thời gian (time-invariant)
nhưng có ảnh hưởng đến tiêu dùng. Ví dụ, trình độ giáo dục hay tôn giáo. Bỏ qua các biến số
này có thể dẫn đến các ước lượng chệch. Dữ liệu mảng có khả năng kiểm soát các biến số
không đổi theo chiều không gian và thời gian này vào mô hình – điều mà sử dụng dữ liệu chéo
hay dữ liệu thời gian không làm được.
2. Bằng việc kết hợp cả chiều không gian và thời gian lại với nhau, panel data cung cấp “nhiều
thông tin hơn, nhiều bậc tự do hơn, hiệu quả hơn, nhưng ít đa cộng tuyến hơn giữa các biến số”.
3. Sử dụng Panel Data là phù hợp hơn cho các nghiên cứu những động lực (hay nhân tố) của
thay đổi (dynamics of change). Chẳng hạn các nghiên cứu thu nhập, sự di chuyển của lao động
sẽ là tốt hơn nếu sử dụng dữ liệu mảng.
4. Sử dụng Panel Data có thể đánh giá tốt hơn những tác động mà không thể quan sát thấy nếu
sử dữ liệu chéo hay dữ liệu thời gian thuần túy. Chẳng hạn, tác động của mức lương tối thiểu
lên công ăn việc làm và thu nhập có thể được nghiên cứu chính xác hơn khi chúng ta tính đến
sự gia tăng mức lương tối thiểu một cách liên tiếp
5. Panel Data cho phép chúng ta nghiên cứu các mô hình có hành vi phức tạp. Chẳng hạn trong
nghiên cứu kinh tế, các hiện tượng như hiệu quả theo qui mô (economies of scale) hay các
thay đổi về mặt công nghệ có thể được đánh giá tốt hơn nếu sử dụng dữ liệu mảng so với sử
dụng thuần túy dữ liệu chéo hay dữ liệu thời gian (Cornwell, Schmidt & Sickles, 1990;
Kumbhakar & Lovell, 2000; Koop & Steel, 2001).

12.2 Giới thiệu bộ số liệu sử dụng và package cần thiết cho phân tích
Phần này chúng ta sẽ nghiên cứu bộ dữ liệu có tên panel1.dta – ban đầu được thu thập bởi giáo sư
Moshe Kim và được sử dụng lại bởi Greene (2008). Dữ liệu này bao gồm các thông tin về 6 hãng hàng
không (N=6) trong khoảng thời gian 15 năm từ 1970 đến 1984 (T = 15). Như vậy dữ liệu của chúng
ta thuộc loại Long Panel Data. Chúng ta nghiên cứu tổng chi phí C có mối liên hệ như thế nào so với
doanh thu Q, giá nhiên liệu PF, và số chỗ ngồi bình quân của mỗi một chuyến bay LF qua mô hình sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


347

Cit. = βit + β1itQit. + β2itPFit. + β3itLFit + uit (1)

Trong đó i chạy từ 1 đến 6, t chạy từ 1 đến 15. Như vậy tổng cộng chúng ta có 6⨉15 = 90 quan sát.
Chúng ta cần sử dụng gói plm cho các phân tích dữ liệu mảng. Trong R chúng ta cài đặt gói này bằng
lệnh install.packages(“plm”).

Chúng ta nhập dữ liệu từ file panel1.dta (Stata file) vào R và gán cho nó tên file mới là dung như sau:

setwd("D:/KTLR")
library(foreign)
library(car)
dung <- read.dta("Panel1.dta")
head(dung) # Xem 6 quan sát đầu tiên.

## i t C Q PF LF
## 1 1 1 1140640 0.952757 106650 0.534487
## 2 1 2 1215690 0.986757 110307 0.532328
## 3 1 3 1309570 1.091980 110574 0.547736
## 4 1 4 1511530 1.175780 121974 0.540846
## 5 1 5 1676730 1.160170 196606 0.591167
## 6 1 6 1823740 1.173760 265609 0.575417

tail(dung) # Xem 6 quan sát cuối cùng.

## i t C Q PF LF
## 85 6 10 276797 0.092749 564867 0.554276
## 86 6 11 381478 0.112640 874818 0.517766
## 87 6 12 506969 0.154154 1013170 0.580049
## 88 6 13 633388 0.186461 930477 0.556024
## 89 6 14 804388 0.246847 851676 0.537791
## 90 6 15 1009500 0.304013 819476 0.525775

Các bạn có thể đánh giá xu hướng của chi phí C cho cả 6 hãng theo thời gian:

scatterplot(C ~ t|i, reg.line=FALSE, data = dung)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


348

Từ hình 1 các bạn có thể thấy chi phí C nhìn chung là tăng nhưng hãng 1 và 2 là tăng mạnh hơn cả
(căn cứ vào độ dốc của các đường).

Chúng có thể tìm bảng hệ số tương quan cho các biến số:

cor(dung)

## i t C Q PF LF
## i 1.00000000 0.0000000 -0.7086242 -0.8679359 0.01329393 -0.3399570
## t 0.00000000 1.0000000 0.5000271 0.2711141 0.93118760 0.6001491
## C -0.70862418 0.5000271 1.0000000 0.9263269 0.47904374 0.4143377
## Q -0.86793588 0.2711141 0.9263269 1.0000000 0.22761248 0.4248100
## PF 0.01329393 0.9311876 0.4790437 0.2276125 1.00000000 0.4867001
## LF -0.33995702 0.6001491 0.4143377 0.4248100 0.48670008 1.0000000

Bảng này cho thấy chi phí C có quan hệ cùng chiều với t (hệ số tương quan là +0.5) với ngụ ý rằng chi
phí C tăng theo thời gian. Tương tự, chi phí C là tương quan mạnh nhất với Q, tương quan yếu nhất
với LF. Ngoài ra các hệ số tương quan giữa các biến độc lập với nhau (Q, PF, và LF) là bé hơn 0.8 nên
khó có thể xẩy ra hiện tượng đa cộng tuyến trong mô hình 1.

12.3 Phân tích dữ liệu mảng cho mô hình nghiên cứu


Việc ước lượng phương trình (1), theo Gujarati & Porter (2009) và Hsiao (2014) phụ thuộc vào những
giả định của chúng ta về: (1) các hệ số chặn, (2) các hệ số góc, và (3) sai số ngẫu nhiên uit . Các giả định
được sắp xếp theo mức độ phức tạp tăng dần là:

 Các hệ số chặn cũng như hệ số góc là không đổi theo chiều không gian (giữa các hãng) và thời
gian và sai số ngẫu nhiên bao gồm các khác biệt giữa các hãng cũng như theo thời gian.
 Hệ số góc là không đổi nhưng hệ số chặn thì thay đổi giữa các hãng (hay hệ số chặn thay đổi
theo chiều không gian) nhưng không đổi theo thời gian.
 Hệ số góc là không đổi nhưng hệ số chặn thì thay đổi theo thời gian nhưng không đổi giữa các
hãng.
 Hệ số góc là không đổi nhưng hệ số chặn thì thay đổi theo cả chiều không gian lẫn thời gian.
 Cả hệ số chặn lẫn hệ số góc thay đổi theo chiều không gian (giữa các hãng) nhưng không thay
đổi theo thời gian.
 Cả hệ số chặn lẫn hệ số góc thay đổi theo chiều không gian và thời gian.

Phần dưới đây chúng ta sẽ nghiên cứu một số mô hình đơn giản dựa trên các giả định này.

12.3.1 Hồi quy gộp (Pooled OLS)


Cách tiếp cận đơn giản nhất, và cũng có lẽ là thô sơ nhất, là chúng ta giả định rằng các hệ số hồi quy
(hệ số chặn và hệ số góc) là không thay đổi giữa các hãng cũng như không thay đổi theo thời gian. Một
giả định quan trọng nữa, theo Gujarati & Porter (2009) là các biến độc lập phải là các biến ngoại sinh
chặt (strictly exogenous). Một biến gọi là ngoại sinh chặt nếu nó không phụ thuộc vào các giá trị quá
khứ, hiện tại, và thương lai của sai số ngẫu nhiên. Kết quả trong R:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


349

ols <- lm(data = dung, C ~ Q + PF + LF)


summary(ols)

##
## Call:
## lm(formula = C ~ Q + PF + LF, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -520654 -250270 37333 208690 849700
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.159e+06 3.606e+05 3.213 0.00185 **
## Q 2.026e+06 6.181e+04 32.781 < 2e-16 ***
## PF 1.225e+00 1.037e-01 11.814 < 2e-16 ***
## LF -3.066e+06 6.963e+05 -4.403 3.06e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 281600 on 86 degrees of freedom
## Multiple R-squared: 0.9461, Adjusted R-squared: 0.9442
## F-statistic: 503.1 on 3 and 86 DF, p-value: < 2.2e-16

Nếu căn cứ theo các tiêu chuẩn quy ước thì mô hình thu được có kết quả rất đẹp. Thể hiện ở R2 là cao,
các hệ số hồi quy có dấu phù hợp với kì vọng và có ý nghĩa thống kê ở mức cao. Dựa vào kết quả phân
tích này chúng ta có:

C = 1159000 + 2026000Q + 1225000PF -3066000LF

Mặc dù vậy, giả thiết rằng cả 6 hãng có cùng hệ số chặn và hệ số góc không đổi theo thời gian có thể
rất phi thực tế. Chẳng hạn, chúng ta có lí do để tin rằng mỗi một hãng có chi phí ban đầu (initial cost)
là khác nhau, nghĩa là chúng có hệ số chặn khác nhau. Ngoài ra, rất có thể sai số ngẫu nhiên là thay
đổi giữa các hãng hoặc thay đổi theo thời gian. Hoặc vừa thay đổi theo các hãng cũng như theo thời
gian. Chúng ta sẽ nghiên cứu vấn đề này ở các chương sau.

Như đã đề cập ở trên, điểm yếu nhất của Pooled OLS là mô hình này không nói cho chúng ta biết phản
ứng (hay hành vi) của chi phí C có thay đổi giữa các hãng và thay đổi theo thời gian hay không. Nguyên
nhân là bằng cách nhóm tất cả cá quan sát lại bất kể sự khác biệt giữa các hãng và sự thay đổi về hành
vi của chi phí C chúng ta đã bỏ qua sự khác biệt đặc trưng (uniqueness) của các hãng. Nếu chúng ta
xử lý vấn đề này bằng cách “gộp” các đặc trưng cá nhân này vào sai số ngẫu nhiên thì lại dẫn đến tình
huống khó xử khác: sai số ngẫu nhiên có thể tương quan (correlated) ở một mức độ nào đó với biến
độc lập và do vậy là vi phạm các giả định về mô hình hồi quy tuyến tính cổ điển. Điều này có thể làm
cho các ước lượng thu được là chệch (biased) và không vững (inconsistent).

Chú ý rằng kết quả ở trên là tương đương với sử dụng câu lệnh sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


350

ols <- plm(data = dung, C ~ Q + PF + LF, model = "pooling")


summary(ols)

12.3.2 Mô hình tác động cố định biến giả SLDV và kiểm định gộp
Như đã phân tích ở trên, chúng ta có thể giả định rằng mỗi hãng hàng không có chi phí ban đầu của
riêng nó và không thay đổi theo thời gian. Nghĩa là chúng ta cần ước lượng mô hình sau:

Cit. = βi + β1itQit. + β2itPFit. + β3itLFit + uit (2)

Trong đó, i chạy từ 1 đến 6, t chạy từ 1 đến 15. Theo mô hình này chúng ta có thể thấy dù mỗi một
hãng hàng không có hệ số chặn của riêng mình (đặc trưng cho chi phí ban đầu khác nhau giữa các
hãng) nhưng các hệ số chặn này cố định theo thời gian (time-invariant). Trong tình huống này, hệ số
chặn của mỗi một hãng là không đổi theo thời gian (time invariant). Chú ý rằng, nếu chúng ta kí hiệu
βit thì điều này có nghĩa là các hệ số chặn là thay đổi theo thời gian (time variant).

Để ước lượng mô hình trong đó chúng ta muốn đưa vào các hệ số chặn khác nhau cho mỗi hãng, chúng
ta sử dụng hồi quy với biến giả và (2) được viết thành:

Cit. = β1 + β2D2 + β3D3 + β4D4 + β5D5 + β6D6 + b1itQit. + b2itPFit. + b3itLFit + uit (3)

Trong đó các D2 đến D6 là các biến giả đặc trưng cho hãng cụ thể. Ví dụ, D2 = 1 nếu là hãng thứ 2, bằng
0 nếu không phải. Ước lượng mô hình (3) trong R:

lsdv <-lm(C ~ Q + PF + LF + factor(i), data = dung)


summary(lsdv)

##
## Call:
## lm(formula = C ~ Q + PF + LF + factor(i), data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -551783 -159259 1796 137226 499296
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.312e+05 3.508e+05 -0.374 0.709
## Q 3.319e+06 1.714e+05 19.369 < 2e-16 ***
## PF 7.731e-01 9.732e-02 7.944 9.70e-12 ***
## LF -3.797e+06 6.138e+05 -6.187 2.37e-08 ***
## factor(i)2 6.017e+05 1.009e+05 5.964 6.17e-08 ***
## factor(i)3 1.337e+06 1.862e+05 7.183 2.99e-10 ***
## factor(i)4 1.778e+06 2.132e+05 8.339 1.61e-12 ***
## factor(i)5 1.828e+06 2.312e+05 7.907 1.15e-11 ***
## factor(i)6 1.706e+06 2.283e+05 7.475 8.07e-11 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Nguyễn Chí Dũng http://rpubs.com/chidungkt


351

##
## Residual standard error: 210400 on 81 degrees of freedom
## Multiple R-squared: 0.9716, Adjusted R-squared: 0.9688
## F-statistic: 346.9 on 8 and 81 DF, p-value: < 2.2e-16

Căn cứ vào kết quả này chúng ta có thể đưa ra phương trình hồi quy cho hãng thứ nhất và hãng thứ
hai lần lượt là:

C = -131200 + 3319000Q + 0.7731PF -3797000LF

C = (-131200+601700) + 3319000Q + 0.7731PF -3797000LF

Các bạn chú ý rằng hệ số hồi quy của D2 là 601700, hệ số hồi quy của D6 là 1706000. Qua đây chúng
ta cũng có thể thấy R thực hiện LSDV nhanh hơn so với Eviews hay Stata do chúng ta không cần thực
hiện thao tác tạo biến giả do R tự động thực hiện thao tác này khi chạy.

Kết quả này cũng cho thấy: (1) ngoại từ hệ số chặn của hãng thứ nhất thì tất cả các hệ số chặn của 5
hãng còn lại đều có ý nghĩa thống kê, (2) các tiêu chí đánh giá độ phù hợp của mô hình tốt hơn thể
hiện ở tổng bình phương phần dư SSE giảm từ 6.82⨉1012 xuống 3.59⨉1012 và R2 tăng. Mô hình có
biến giả như vậy có thể được gọi bằng một cái tên khác là mô hình tác động cố định bình phương
nhỏ nhất với biến giả (Fixed Effect Least-Squares Dummy Variable (LSDV) Model) hay nói gọn là mô
hình LSDV. Chú ý rằng kết quả ở trên có thể thu đượng bằng cách gõ:

trang <-lm(C ~ Q + PF + LF + factor(i) - 1, data = dung)


summary(trang)

##
## Call:
## lm(formula = C ~ Q + PF + LF + factor(i) - 1, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -551783 -159259 1796 137226 499296
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## Q 3.319e+06 1.714e+05 19.369 < 2e-16 ***
## PF 7.731e-01 9.732e-02 7.944 9.70e-12 ***
## LF -3.797e+06 6.138e+05 -6.187 2.37e-08 ***
## factor(i)1 -1.312e+05 3.508e+05 -0.374 0.709286
## factor(i)2 4.705e+05 3.091e+05 1.522 0.131839
## factor(i)3 1.206e+06 3.324e+05 3.628 0.000497 ***
## factor(i)4 1.646e+06 3.183e+05 5.172 1.64e-06 ***
## factor(i)5 1.697e+06 3.348e+05 5.069 2.48e-06 ***
## factor(i)6 1.575e+06 3.073e+05 5.126 1.98e-06 ***
## ---

Nguyễn Chí Dũng http://rpubs.com/chidungkt


352

## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 210400 on 81 degrees of freedom
## Multiple R-squared: 0.985, Adjusted R-squared: 0.9834
## F-statistic: 593 on 9 and 81 DF, p-value: < 2.2e-16

Chúng ta có thể đưa ra kiểm định chính thức nhằm xác định xem có thể “gộp” các hệ số chặn đặc trưng
cho từng hãng ở mô hình LSDV bằng kiểm định F mà trong nhiều tài liệu còn gọi là kiểm định tính
gộp - Poolability Test cho mô hình LSDV với cặp giả thuyết sau:

H0: Tất cả các hệ số từ β2 đến β6 bằng không

H1: Có ít nhất một hệ số từ β2 đến β6 khác không.

Nếu chúng ta đưa ra bằng chứng thống kê bắc bỏ H0 thì có nghĩa mô hình LSDV là mô hình phù hợp.
Ngược lại thì Pooled OLS là mô hình phù hợp hơn. Trong tình huống của chúng ta thì mô hình có kết
quả ở mục 12.3.1 gọi là mô hình giới hạn (restricted model) vì nó áp đặt một hệ số chặn chung duy
nhất cho cả 6 hãng còn mô hình có kết quả ở mục 11.3.2 là mô hình không giới hạn (unrestricted
model). Áp dụng kiểm định F giới hạn (restricted F test ) chúng ta có:

(0.971642 − 0.946093)/5
𝐹= ≈ 14.59
(1 − 0.971642)/81
So sánh giá trị tới hạn của F0.95,5/81 = 2.373 chúng ta đi đến kết luận là bắc bỏ giả thuyết H0. Kết luận
của chúng ta là tồn tại sự khác biệt về hệ số chặn giữa các hãng hàng không. Trong tình huống ngược
lại – nghĩa là chúng ta có bằng chứng thống kê đủ mạnh để chấp nhận H0 thì chúng ta có thể sử dụng
Pooled OLS để thực hiện phân tích số liệu.

Chúng ta cũng có thể sử dụng kiểm định Wald để kiểm định tính gộp của cho mô hình LSDV (Hill et
al., 2008) trong R:

library(AER)
linearHypothesis(lsdv, c("factor(i)2 = 0", "factor(i)3 = 0", "factor(i)4 = 0"
, "factor(i)5 = 0", "factor(i)6 = 0" ))

## Linear hypothesis test


##
## Hypothesis:
## factor(i)2 = 0
## factor(i)3 = 0
## factor(i)4 = 0
## factor(i)5 = 0
## factor(i)6 = 0
##
## Model 1: restricted model
## Model 2: C ~ Q + PF + LF + factor(i)
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


353

## Res.Df RSS Df Sum of Sq F Pr(>F)


## 1 86 6.8177e+12
## 2 81 3.5865e+12 5 3.2312e+12 14.595 3.467e-10 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Chúng ta có thể tìm lại kiểm định F = 14.595 như ở trên ứng với Pr(>F) = 0 nên chúng ta có thể bắc
bỏ giả thuyết gốc.

Những mô hình được mô tả ở (2 hoặc viết cụ thể hơn ở dạng 3) còn được gọi là mô hình tác động cố
định một chiều (one-way fixed effects) và được hiểu theo nghĩa là mặc dù mỗi hãng có một hệ số chặn
của riêng nó nhưng hệ số chặn này không đổi theo thời gian. Nói cách khác, chúng ta đã tính đến tác
động cá thể (The Individual Effect) đặc trưng cho từng hãng khi nghiên cứu hành vi của chi phí C.
Tương tự như vậy, chúng ta có thể tính đến tác động thời gian (The Time Effect) khi nghiên cứu với
giả định rằng hệ số góc của các hãng là không đổi theo thời gian nhưng hệ số chặn lại biến đổi theo thời
gian bằng cách đưa vào biến giả thời gian như sau:

Cit. = γ1 + λ2T2 +…+ λ15T15 + β1itQit. + β2itPFit. + β3itLFit + uit (4)

Trong đó T2 = 1 ứng với năm nghiên cứu thứ 2, bằng 0 nếu khác. Chú ý rằng khoảng thời gian nghiên
cứu của chúng ta là 15 năm và do vậy chúng ta đưa vào 14 biến giả thời gian.

Lập luận như trên, chúng ta có thể nghiên cứu hành vi của chi phí C với giả định rằng hệ số góc của
các hãng là không đổi nhưng hệ số chặn thay đổi theo từng hãng và theo thời gian. Lúc này mô hình
của chúng ta có tất cả 5 + 14 = 19 biến giả như sau:

Cit. = a1 + (λ2T2 +…+ λ15T15) +( β2D2 +…+ β6D6) + b1itQit. + b2itPFit. + b3itLFit + uit (5)

Chúng ta cũng có thể nghiên cứu mô hình với giả định rằng tất cả các hệ số hồi quy (hệ số chặn lẫn hệ
số góc) là khác nhau giữa các hãng nhưng không thay đổi theo thời gian:

Cit. = a1 + (β2D2 +…+ β6D6) + b1itQit. + b2itPFit. + b3itLFit + (D2b1itQit. + D2b2itPFit. + D2b3itLFit) +…+(
D6b1itQit. + D6b2itPFit. + D6b3itLFit)+ uit (6)

Mô hình (6) sẽ bao gồm 5+3+3*5 = 23 biến số và con số sẽ tăng nhanh chóng nếu số lượng các biến
độc lập trong mô hình là nhiều và số cá thể nghiên cứu lên đến hàng trăm. Chẳng hạn, nếu nghiên cứu
vẫn lấy thời gian nghiên cứu là 15 năm nhưng có 10 biến số độc lập với 100 cá thể (một con số còn
quá khiêm tốn trong các nghiên cứu định lượng thực tế) thì các biến số ở vế phải của phương trình
(5) lên đến 99+10+10*99 = 1109 biến số. Qua đây bạn cũng có thể hình dung ra hạn chế rõ ràng của
phương pháp LSDV. Ngoài ra, theo Gujarati & Porter (2009), việc đưa quá nhiều biến giả vào mô hình
cũng gây ra một số vấn đề sau.

Thứ nhất, mỗi khi chúng ta đưa thêm biến giả vào mô hình, thì chúng ta lại phải hi sinh bặc tự do dẫn
đến khả năng chúng ta không có đủ các quan sát để thực hiện các phân tích thống kê có ý nghĩa.

Thứ hai, nguy cơ xẩy ra hậu quả nghiêm trọng do đa cộng tuyến.

Thứ ba và cũng là nhược điểm cốt lõi của các mô hình LSDV là trong một số tình huống nó không thể
xác định tác động của các biến số không đổi theo thời gian (time-invariant variables). Ví dụ, nếu chúng

Nguyễn Chí Dũng http://rpubs.com/chidungkt


354

ta muốn nghiên cứu hàm lương của một mẫu nghiên cứu sử dụng dữ liệu mảng theo kinh nghiệm. Rõ
ràng, ngoài kinh nghiệm thì chúng ta cũng có thể thấy các nhân tố như giới tính, chủng tộc cũng có
ảnh hưởng đến lương nhưng rõ ràng các nhân tố này là không thay đổi theo thời gian. Do vậy, các mô
hình LSDV không có thể không tính đến được tác động của những biến số không đổi theo thời gian
này lên mức lương.

Thứ tư, giả định về sai số ngẫu nhiên có phân phối chuẩn với trung bình bằng 0, độc lập, và phương
sai không đổi là một giả định khó có thể đáp ứng trong thực tế. Ví dụ, tại một thời điểm nào đó, sai số
ngẫu nhiên ứng với hãng thứ nhất có thể tương quan với sai số ngẫu nhiên của hãng thứ hai.

12.3.3 Mô hình tác động cố định không có biến giả


Như đã phân tích ở trên, việc đưa vào biến giả vào vào các mô hình phân tích là có nhiều hạn chế. Do
vậy, trong nhiều tình huống chúng ta cần chạy mô hình tác động cố định FEM không có biến giả. Trong
R chúng ta thực hiện FEM như sau:

library(plm)

FEM <- plm(C ~ Q + PF + LF, data = dung, index = c("i", "t"), model = "within
")
summary(FEM)

## Oneway (individual) effect Within Model


##
## Call:
## plm(formula = C ~ Q + PF + LF, data = dung, model = "within",
## index = c("i", "t"))
##
## Balanced Panel: n=6, T=15, N=90
##
## Residuals :
## Min. 1st Qu. Median 3rd Qu. Max.
## -552000 -159000 1800 137000 499000
##
## Coefficients :
## Estimate Std. Error t-value Pr(>|t|)
## Q 3.3190e+06 1.7135e+05 19.3694 < 2.2e-16 ***
## PF 7.7307e-01 9.7319e-02 7.9437 9.698e-12 ***
## LF -3.7974e+06 6.1377e+05 -6.1869 2.375e-08 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Total Sum of Squares: 5.0776e+13
## Residual Sum of Squares: 3.5865e+12
## R-Squared: 0.92937

Nguyễn Chí Dũng http://rpubs.com/chidungkt


355

## Adj. R-Squared: 0.83643


## F-statistic: 355.254 on 3 and 81 DF, p-value: < 2.22e-16

Cũng như Stata, trước khi phân tích thì R cần nhận diện dữ liệu mà nó đang xử lý là dữ liệu mảng.
Trong câu lệnh trên chúng ta đã “gộp” định dạng dữ liệu mảng bằng lựa chọn. Tương tự lệnh xtset của
Stata, chúng ta có thể bỏ lựa chọn này với điều kiện là trước khi phân tích chúng ta chỉ định dữ liệu
được phân tích là dữ liệu mảng. Điều này được trình bày chi tiết ở mục 12.6 của chương này.
Chú ý rằng không như các phần mềm khác (Eviews, Stata), R không đưa ra hệ số chặn chung cho mô
hình (2) vì mô hình FEM bản thân nó đã ngụ ý rằng mỗi một hãng có một hệ số chặn riêng đặc trưng
(như ta đã thấy trong mô hình LSDV). Tuy nhiên nếu muốn chúng ta cũng có thể chỉ ra hệ số chặn
(hay tác động cố định) ứng với mỗi hãng:

fixef(FEM)

## 1 2 3 4 5 6
## -131236.0 470497.3 1205944.6 1646356.2 1697016.5 1575238.4

Đây chính là kết quả mà chúng ta đã thu được ở mô hình LSDV. Chú ý rằng mô hình LSDV ở mục
12.3.2, để tiện so sánh với kết quả vừa thu được chúng ta có thể gõ như sau trong R:

lsdv <-lm(C ~ Q + PF + LF + factor(i) - 1, data = dung)


summary(lsdv)

##
## Call:
## lm(formula = C ~ Q + PF + LF + factor(i) - 1, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -551783 -159259 1796 137226 499296
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## Q 3.319e+06 1.714e+05 19.369 < 2e-16 ***
## PF 7.731e-01 9.732e-02 7.944 9.70e-12 ***
## LF -3.797e+06 6.138e+05 -6.187 2.37e-08 ***
## factor(i)1 -1.312e+05 3.508e+05 -0.374 0.709286
## factor(i)2 4.705e+05 3.091e+05 1.522 0.131839
## factor(i)3 1.206e+06 3.324e+05 3.628 0.000497 ***
## factor(i)4 1.646e+06 3.183e+05 5.172 1.64e-06 ***
## factor(i)5 1.697e+06 3.348e+05 5.069 2.48e-06 ***
## factor(i)6 1.575e+06 3.073e+05 5.126 1.98e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 210400 on 81 degrees of freedom

Nguyễn Chí Dũng http://rpubs.com/chidungkt


356

## Multiple R-squared: 0.985, Adjusted R-squared: 0.9834


## F-statistic: 593 on 9 and 81 DF, p-value: < 2.2e-16

Sử dụng câu lệnh như vậy cho phép chúng ta có thể thấy trực tiếp hệ số chặn của các hãng mà không
cần thực hiện các phép tính trung gian cộng hoặc trừ thường gây nhầm lẫn với những con số dài dòng.
Chú ý rằng hệ số chặn Intercept ở 8.3.2 chính là factor(i)1 ở câu lệnh này và đây cũng là hệ số chặn
của hãng thứ nhất. Còn hãng thứ hai hệ số chặn tương ứng là factor(i)2 = 470500.

Chúng ta cũng có thể thực hiện kiểm định tính gộp của mô hình FEM theo một cách khác:

pFtest(FEM, ols)

##
## F test for individual effects
##
## data: C ~ Q + PF + LF
## F = 14.595, df1 = 5, df2 = 81, p-value = 3.467e-10
## alternative hypothesis: significant effects

Ở đây giá trị của kiểm định F = 14.595 (đã thấy ở các kiểm định mà chúng ta đã thực hiện ở trước đó)
ứng với P-value = 0 nên mô hình FEM là mô hình phù hợp so với Pooled OLS. Các giá trị kiểm định
thu được cũng như kết luận là không có gì thay đổi so với các kết luận ở mục 12.3.2.

12.3.4 Mô hình tác động ngẫu nhiên một chiều


Mặc dù dễ hiểu và áp dụng, cách tiếp cận cố định FEM cho phân tích dữ liệu mảng cũng có một số hạn
chế. Chẳng hạn, cái giá mà chúng ta phải trả cho việc sử dụng mô hình LSDV là chúng ta buộc phải hi
sinh bậc tự do nếu như mẫu nghiên cứu của chúng ta chỉ có một vài cá thể (Kmenta, 1986). Chúng ta
sẽ nghiên cứu một cách tiếp cận khác cho phân tích dữ liệu mảng bằng mô hình tác động ngẫu nhiên
REM (Random Effects Model). Trong một số tài liệu thì mô hình này còn được gọi là mô hình sai số
bộ phận ECM (Error Components Model). Chúng ta xét mô hình sau:

Cit. = βi + β1itQit. + β2itPFit. + β3itLFit + uit (7)

Ý tưởng của cách tiếp cận này như sau. Nếu các biến giả trong thực tế là đại diện cho những hiểu biết
chưa đầy đủ của chúng ta về mô hình thật thế thì tại sao chúng ta lại không biểu diễn các hệ số chặn
βi thành hai bộ phận như sau:

βi =γ1 + εi (8) với i chạy từ 1 đến 6.

Nghĩa là, thay vì coi hệ số chặn βi của các hãng là cố định thì chúng ta coi hệ số chặn này là một biến
ngẫu nhiên gồm hai bộ phận với trung bình β1 (không có kí hiệu i ở đây) và sai số ngẫu nghiên εi với
phương sai không đổi σ2ε . Như vậy phương trình (6) trở thành:

Cit. = γ1 + β1itQit. + β2itPFit. + β3itLFit + εi + uit

= γ1 + β1itQit. + β2itPFit. + β3itLFit + wit (9)

Trong đó wit = εi + uit . Nghĩa là chúng ta tách sai số ngẫu nhiên wit thành hai bộ phận: đại diện cho
bộ phận sai số ngẫu nhiên đặc trưng cho từng hãng riêng biệt và uit đại diện cho bộ phận sai số ngẫu

Nguyễn Chí Dũng http://rpubs.com/chidungkt


357

nhiên kết hợp theo cả chiều không gian và thời gian. Chính vì thế cách tiếp cận này còn được gọi là
mô hình sai số bộ phận ECM (Gujarati & Porter, 2009) với các giả định sau:

𝜀𝑖 ~𝑁(0, 𝜎𝜀2 )
𝑢𝑖𝑡 ~𝑁(0, 𝜎𝑢2 )

𝐸(𝜀𝑖 𝑢𝑖𝑡 ) = 0 𝐸(𝜀𝑖 𝜀𝑗 ) = 0 (𝑖 ≠ 𝑗)

𝐸(𝑢𝑖𝑡 𝑢𝑖𝑠 ) = 𝐸(𝑢𝑖𝑡 𝑢𝑗𝑡 ) = 𝐸(𝑢𝑖𝑡 𝑢𝑗𝑠 ) = 0 (𝑖 ≠ 𝑗; 𝑡 ≠ 𝑠)


Các giả thuyết trên có thể được viết ngắn gọn thành:

𝐸(𝑤𝑖𝑡 ) = 0
var(𝑤𝑖𝑡 ) = 𝜎𝜀2 + 𝜎𝑢2
Nếu σ2ε = 0 thì có nghĩa là chúng ta có thể hiện hồi quy gộp cho (8). Ngoài ra chúng ta có thể thấy rằng
wit và wis là tương quan với nhau với t ≠ s. Nghĩa là sai số ngẫu nhiên của một cá thể bất kì là tương
quan với nhau tại hai thời điểm khác nhau theo chiều thời gian. Lúc này, tương quan giữa wit và wis
được tính theo công thức sau:

𝜎𝜀2
corr(𝑤𝑖𝑡 , 𝑤𝑖𝑠 ) = 2 (10)
𝜎𝜀 + 𝜎𝑢2
Gujarati & Porter (2009), Baltagi (2005) đưa ra các kết luận sau về tương quan giữa wit và wis . Thứ
nhất, đối với một cá thể nhất định (trong tình huống của chúng ta là hãng) thì tương quan này không
đổi bất kể khoảng cách giữa hai quãng thời gian là bao nhiêu. Thứ hai, tương quan này là như nhau
cho mọi cá thể. Nếu chúng ta bỏ qua tương quan này trong phân tích thì chúng ta áp dụng OLS và các
ước lượng thu được là không hiệu quả (inefficient). Để giải quyết vấn đề này chúng ta sử dụng mô
hình tác động ngẫu nhiên REM (Random Effect Model). Trong R chúng ta thực hiện như sau:

REM <- plm(C ~ Q + PF + LF, data = dung, index = c("i", "t"), model="random")
summary(REM)

## Oneway (individual) effect Random Effect Model


## (Swamy-Arora's transformation)
##
## Call:
## plm(formula = C ~ Q + PF + LF, data = dung, model = "random",
## index = c("i", "t"))
##
## Balanced Panel: n=6, T=15, N=90
##
## Effects:
## var std.dev share
## idiosyncratic 4.428e+10 2.104e+05 0.906
## individual 4.615e+09 6.793e+04 0.094

Nguyễn Chí Dũng http://rpubs.com/chidungkt


358

## theta: 0.3754
##
## Residuals :
## Min. 1st Qu. Median 3rd Qu. Max.
## -531000 -242000 50200 204000 783000
##
## Coefficients :
## Estimate Std. Error t-value Pr(>|t|)
## (Intercept) 1.0952e+06 3.7697e+05 2.9052 0.004665 **
## Q 2.1446e+06 8.8171e+04 24.3228 < 2.2e-16 ***
## PF 1.1757e+00 1.0356e-01 11.3531 < 2.2e-16 ***
## LF -3.0261e+06 7.2713e+05 -4.1616 7.466e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Total Sum of Squares: 8.0306e+13
## Residual Sum of Squares: 6.2698e+12
## R-Squared: 0.92193
## Adj. R-Squared: 0.88095
## F-statistic: 338.508 on 3 and 86 DF, p-value: < 2.22e-16

Ngoài sử dụng REM, theo Greene (2012), Maddala & Lahiri (2006), Davidson & MacKinnon (1993),
và Judge et al. (1985), chúng ta có thể áp dụng áp dụng phương pháp bình phương tổng quát nhỏ
nhất GLS (Generalized Least Squares). Chúng ta sẽ nghiên cứu ước lượng GLS cho dữ liệu mảng ở
phần sau.

Tương tự như sử dụng gói outreg2 của Stata cho so sánh kết quả của những mô hình khác nhau chúng
ta cũng có thể sử dụng gói cho so sánh, chẳng hạn, các ước lượng thu được từ FEM và REM như sau:

library(stargazer)
stargazer(FEM, REM, title = "So sánh FEM và REM", type = "text")

##
## So sánh FEM và REM
## ============================================================
## Dependent variable:
## -----------------------------------------------
## C
## (1) (2)
## ------------------------------------------------------------
## Q 3,319,023.000*** 2,144,561.000***
## (171,354.100) (88,170.630)
##
## PF 0.773*** 1.176***
## (0.097) (0.104)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


359

##
## LF -3,797,368.000*** -3,026,060.000***
## (613,773.100) (727,130.000)
##
## Constant 1,095,172.000***
## (376,967.000)
##
## ------------------------------------------------------------
## Observations 90 90
## R2 0.929 0.922
## Adjusted R2 0.836 0.881
## F Statistic 355.254*** (df = 3; 81) 338.508*** (df = 3; 86)
## ============================================================
## Note: *p<0.1; **p<0.05; ***p<0.01

Ước lượng mô hình tác động ngẫu nhiên mà chúng ta vừa thực hiện ở trên là sử dụng cách tiếp cận
của Swamy & Arora (1972) và nếu không tuyên bố rõ thì R sẽ mặc định thực hiện ước lượng này.
Ngoài cách tiếp cận này còn có ba cách tiếp cận khác để thực phân tích tác động ngẫu nghiên với lựa
chọn random.method khi thực hiện lệnh plm() là:

 random.method ="walhus”: theo các tiếp cận của Wallace & Hussain (1969)
 random.method = "amemiya”: theo cách tiếp cận của Amemiya (1971)
 random.method = "nerlove”: theo cách tiếp cận của Nerlove (1971).

Chẳng hạn chúng ta thực hiện ước lượng theo cách tiếp cận của Wallace và Hussain đồng thời so sánh
kết quả thu được với cách tiếp cận của Swamy và Arora:

REM <-plm(C ~ Q + PF + LF, data = dung, index=c("i", "t"), model = "random")


REM1 <-plm(C ~ Q + PF + LF, data = dung, index=c("i", "t"), model = "random",
random.method = "walhus")
library(stargazer)
stargazer(REM, REM1, title = "So sánh ket qua uoc luong tu hai phuong phap",
type = "text")

##
## So sánh ket qua uoc luong tu hai phuong phap
## ============================================================
## Dependent variable:
## -----------------------------------
## C
## (1) (2)
## ------------------------------------------------------------
## Q 2,144,561.000*** 2,064,662.000***
## (88,170.630) (71,926.720)
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


360

## PF 1.176*** 1.208***
## (0.104) (0.104)
##
## LF -3,026,060.000*** -3,031,366.000***
## (727,130.000) (714,311.000)
##
## Constant 1,095,172.000*** 1,126,674.000***
## (376,967.000) (369,943.300)
##
## ------------------------------------------------------------
## Observations 90 90
## R2 0.922 0.935
## Adjusted R2 0.881 0.894
## F Statistic (df = 3; 86) 338.508*** 415.028***
## ============================================================
## Note: *p<0.1; **p<0.05; ***p<0.01

Chúng ta có thể thấy rằng hai cách tiếp cận tạo ra những ước lượng không khác biệt đáng kể với bộ
dữ liệu được phân tích.

10.3.5 Mô hình tác động ngẫu nhiên hai chiều


Mặc định R sẽ thực hiện ước lượng tác động ngẫu nhiêu theo chiều cá thể (hay chiều không gian) như
chúng ta vừa thực hiện ở mục 12.3.4. Trong nhiều trường hợp chúng ta có thể cần thực hiện ước
lượng mô hình REM theo: (1) chiều thời gian, hoặc (2) cả chiều thời gian lẫn không gian với các lựa
chọn effect như sau:

 effect = “time” : Thực hiện ước lượng tác động ngẫu nhiên theo chiều thời gian.
 effect = “twoways” : Thực hiện ước lượng tác động ngẫu nhiên theo cả hai chiều.

Dưới đây là ước lượng mô hình tác động ngẫu nhiên hai chiều theo cách tiếp cận của Amemiya:

REMhaichieu <- plm(C ~ Q + PF + LF, data = dung, index = c("i", "t"),


model = "random",
random.method = "amemiya", effect = "twoways")
stargazer(REM1, REMhaichieu,
title = "So sánh ket qua uoc luong tu hai phuong phap",
type = "text")

##
## So sánh ket qua uoc luong tu hai phuong phap
## ============================================================
## Dependent variable:
## -----------------------------------
## C
## (1) (2)
## ------------------------------------------------------------
## Q 2,064,662.000*** 3,278,658.000***

Nguyễn Chí Dũng http://rpubs.com/chidungkt


361

## (71,926.720) (175,834.900)
##
## PF 1.208*** 0.754***
## (0.104) (0.237)
##
## LF -3,031,366.000*** -3,245,771.000***
## (714,311.000) (899,997.100)
##
## Constant 1,126,674.000*** 799,095.900
## (369,943.300) (579,471.800)
##
## ------------------------------------------------------------
## Observations 90 90
## R2 0.935 0.831
## Adjusted R2 0.894 0.794
## F Statistic (df = 3; 86) 415.028*** 141.216***
## ============================================================
## Note: *p<0.1; **p<0.05; ***p<0.01

Có thế thấy rằng hệ số ướng lượng của PF thu được từ hai mô hình có sự khác biệt rất lớn trong khi
hệ số của LF thì không thay đổi nhiều.

12.4 Một số kiểm định lựa chọn và chẩn đoán lỗi của mô hình
Phần này các bạn sẽ thực hành với một số kiểm định nhằm lựa chọn và chấn đoán lỗi mô hình khi
phân tích dữ liệu mảng.

12.4.1 Kiểm định lựa chọn giữa FEM , Pooled OLS và REM
Theo Gujarati & Porter (2009), Baltagi (2005) và Greene (2013), chúng ta có thể thực hiện một số
kiểm định lựa chọn cách tiếp cận phù hợp cho phân tích dữ liệu mảng theo sơ đồ sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


362

(Hình 2: Các kiểm định lựa chọn mô hình cho phân tích dữ liệu mảng)

Có thể tìm trên Internet một số nghiên cứu sử dụng khung phân tích này. Các nghiên cứu mà chúng
ta có thể tìm thấy ở Việt Nam là:

 Luận văn thạc sĩ 2013 của tác giả Nguyễn Thị Ngọc Quỳnh bảo vệ tại Vietnam National
University – Ho Chi Minh City (đại học quốc gia Thành Phố Hồ Chí Minh) có tên “Impact of
Capital Structure on Firm Performance: A Case Study of Listed Manufacturing Companies
on Ho Chi Minh Stock (HOSR) Exchange”. Nghiên cứu này sử dụng các thông tin tài chính của
62 doanh nghiệp thuộc lĩnh vực sản xuất trong giai đoạn 2007 – 2011.
 Nghiên cứu trình bày cho World Business and Social Science Research Conference tháng 10
năm 2013 của hai tác giả Phùng Đức Nam và Hoàng Thị Phương Thảo (công tác tại đại học
kinh tế thành phố Hồ Chí Minh – UEH) có tên “Corporate Ownership and Firm Performance
i n Emerging Market: A Study of Vietnamese Listed Firms” với dữ liệu tài chính của các
công ti niêm yết trên sàn HOSE và HNX từ 2007 đến 2012.

Trong số các kiểm định này thì kiểm định F và Wald đã được trình bày ở các mục trên. Trong phần
này chúng sẽ nghiên cứu kiểm định Hausman nhằm lựa chọn giữa REM và FEM.

Rõ ràng, một trong những thách thức của chúng ta khi phân tích dữ liệu mảng là lựa chọn REM hay
FEM khi phân tích? Về vấn đề này, Judge et al. (2007) chỉ ra một số dấu hiệu như cho việc lựa chọn
mô hình như sau:

1. Nếu T là lớn và N là nhỏ thì rất có thể không tồn tại khác biệt lớn giữa các ước lượng thu được
từ REM và FEM. Sự lựa chọn mô hình lúc này chỉ đơn thuần là căn cứ vào sự thuận tiện khi
tính toán. Theo tiêu chí này thì FEM thường được ưu tiêu hơn.
2. Khi T là nhỏ và N là lớn thì các ước lượng thu được từ hai phương pháp có thể khác biệt đáng
kể. Nhắc lại rằng trong mô hình REM, βi =γ1 + εi với đại diện cho bộ phận sai số ngẫu nhiên
ứng với cá thể thứ i trong mẫu nghiên cứu. Trong khi đó, ở mô hình FEM thì ta coi βi là bộ
phận cố định chứ không phải là biến ngẫu nhiên. Cách tiếp cận FEM là phù hợp nếu chúng ta

Nguyễn Chí Dũng http://rpubs.com/chidungkt


363

tin tưởng mạnh mẽ rằng các cá thể trong mẫu nghiên cứu không được lựa chọn ngẫu nhiên
từ một tổng thể lớn hơn. Ngược lại, nếu các cá thể trong mẫu được lựa chọn ngẫu nhiên thì
REM là phù hợp hơn. Vì trong tình huống này các thống kê suy luận là không có điều kiện
(unconditional).
3. Nếu bộ phận sai số ngẫu nhiên εi và một hay một số biến độc lập là tương quan thì các ước
lượng thu được từ FEM là các ước lượng chệch (biased) trong khi đó các ước lượng thu được
từ FEM là các ước lượng không chệch (unbiased).
4. Nếu T nhỏ và N là lớn và các giả định nền tảng cho REM là đúng thì các ước lượng thu được
từ REM là hiệu quả hơn so với các ước lượng thu được từ FEM (Taylor, 1980).

Tuy nhiên, trong các nghiên cứu, thay vì dựa vào các dấu hiệu ở trên chúng ta nên dựa vào các kiểm
định chính thức để lựa chọn mô hình. Một trong những kiểm định đó là Hausman Test (1978) với cặp
giả thuyết được kiểm định như sau:

H0: Các ước lượng thu được từ hai phương pháp không khác biệt.

H1: Các ước lượng thu được từ hai phương pháp là khác biệt.

Kiểm định được xây dựng bởi Hausman có phân phối χ2 . Nếu giả thuyết H0 bị bắc bỏ thì chúng ta đi
đến kết luận FEM là mô hình phù hợp hơn. Trong R chúng ta thực hiện kiểm định Hausman như sau:

phtest(FEM, REM)

##
## Hausman Test
##
## data: C ~ Q + PF + LF
## chisq = 63.785, df = 3, p-value = 9.126e-14
## alternative hypothesis: one model is inconsistent

Do p-value = 0.0000 < 5% (ứng với χ2 = 63.785) nên chúng ta đi đến kết luận mô hình FEM là mô
hình phù hợp hơn cho phân tích dữ liệu.

12.4.2 Kiểm định Breusch-Pagan cho lựa chọn giữa REM và Pooled OLS
Ngoài kiểm định Hausman, chúng ta có thể thực hiện kiểm định Breusch-Pagan Lagrange Multiplier
(thường gọi tắt là Breusch-Pagan LM Test) cho việc lựa chọn giữa REM và Pooled OLS bằng cách gõ
các lệnh sau trong R:

ols <- plm(data = dung, C ~ Q + PF + LF, model = "pooling")


plmtest(ols, type = c("bp"))

##
## Lagrange Multiplier Test - (Breusch-Pagan)
##
## data: C ~ Q + PF + LF
## chisq = 0.61309, df = 1, p-value = 0.4336
## alternative hypothesis: significant effects

Nguyễn Chí Dũng http://rpubs.com/chidungkt


364

Kiểm định này có p-value = 0.4336 > 5% do đó chúng ta có thể chạy Pooled OLS cho dữ liệu. Trong
tình huống ngược lại, nếu p-value mà nhỏ hơn 5% thì mô hình REM là phù hợp hơn cho phân tích dữ
liệu.

12.4.3 Một số kiểm định khác chẩn đoán lỗi mô hình sử dụng dữ liệu mảng
Ngoài các kiểm định lựa chọn mô hình ở trên chúng ta có thể thực hiện một số kiểm định nhằm chẩn
đoán các lỗi (Diagnotic Tests) có thể có của mô hình. Các kiểm định này được thực hiện sau khi chúng
ta đã lựa chọn một mô hình cụ thể nhất định cho phân tích dữ liệu.

12.4.3.1 Kiểm định tương quan phần dư giữa các cá thể


Các dữ liệu mảng mà có khoảng thời gian nghiên cứu dài thì khả năng rất cao là phần dư tương ứng
của các cá thể là tương quan (Baltagi, 2005). Với mô hình FEM, chúng ta có thể sử dụng kiểm định
Breusch - Pagan LM (Breusch-Pagan LM Test of Independence) cho các phần dư:

pcdtest(FEM, test = c("lm"))

##
## Breusch-Pagan LM test for cross-sectional dependence in panels
##
## data: formula
## chisq = 70.675, df = 15, p-value = 3.386e-09
## alternative hypothesis: cross-sectional dependence

Cặp giả thuyết được kiểm định là:

H0: Phần dư giữa các hãng là không tương quan.

H1. Phần dư giữa các hãng có tương quan.

Căn cứ vào kết quả kiểm định chúng ta thấy p-value = 0.0000 < 5% (với χ2 = 70.67) nên chúng ta
bắc bỏ H0. Kết luận của chúng ta ở đây là phần dư giữa các hãng có tương quan.

12.4.3.2 Kiểm định tương quan chuỗi cho FEM, REM


Mô hình của chúng ta rất có thể có hiện tượng tương quan chuỗi (Serial Correlation hay
Autocorrelation) cho cả REM và FEM, đặc biệt là với các dữ liệu mảng có T lớn và N bé. Chúng ta có
thể thực hiện Breusch-Godfrey Test (2003) nhằm kiểm định tương quan chuỗi cho cặp giả thuyết sau:

H0: Không có tương quan chuỗi trong mô hình

H1. Có tương quan chuỗi trong mô hình

Chúng ta thực hiện như sau trong R để thực hiện kiểm định này cho mô hình FEM:

pbgtest(FEM)

##
## Breusch-Godfrey/Wooldridge test for serial correlation in panel
## models
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


365

## data: C ~ Q + PF + LF
## chisq = 52.863, df = 15, p-value = 4.064e-06
## alternative hypothesis: serial correlation in idiosyncratic errors

Do p-value = 0 <5% nên chúng ta kết luận có bằng chứng thống kê chỉ ra rằng tồn tạo hiện tượng
tương quan chuỗi trong mô hình FEM.

Kiểm định tương quan chuỗi cho mô hình FEM:

pbgtest(REM)

##
## Breusch-Godfrey/Wooldridge test for serial correlation in panel
## models
##
## data: C ~ Q + PF + LF
## chisq = 61.756, df = 15, p-value = 1.256e-07
## alternative hypothesis: serial correlation in idiosyncratic errors

Do p-value = 0 <5% nên chúng ta kết luận có bằng chứng thống kê chỉ ra rằng tồn tại hiện tượng
tương quan chuỗi trong mô hình REM.

12.4.3.3 Kiểm định phương sai sai số thay đổi cho FEM
Chúng ta có thể sử dụng Studentized Breusch-Pagan Test nhằm kiểm tra hiện tượng phương sai sai
số thay đổi ở mô hình FEM với cặp giả thuyết sau:

H0: Phương sai sai số ngẫu nhiên là không đổi (homoskedasticity)

H1. Phương sai sai số ngẫu nhiên là thay đổi (heteroskedasticity).

Thực hiện trong R:

bptest(C ~ Q + PF + LF + factor(i), data = dung, studentize = F)

##
## Breusch-Pagan test
##
## data: C ~ Q + PF + LF + factor(i)
## BP = 37.83, df = 8, p-value = 8.092e-06

Kết quả kiểm định cho ta p-value = 0 < 5% nên chúng ta đi đến kết luận là phương sai sai số ngẫu
nhiên thay đổi (bắc bỏ H0).

Chú ý rằng trong Stata thực hiện kiểm định này bằng Modified Wald Test với câu lệnh xttest3.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


366

12.5 Một số phân tích hình ảnh – đồ thị cho dữ liệu bảng
Để đơn giản hóa việc minh họa các câu lệnh trong R, phần này chúng ta chỉ nghiên cứu hành vi của
chi phí C với một biến độc lập là doanh thu Q mà thôi. Chúng ta xét mô hình LSDV:

Cit. = β1 + β2D2 + β3D3 + β4D4 + β5D5 + β6D6 + β7itQit. + uit (11)

Thực hiện LSDV trong R:

trangtrang <- lm(C ~ Q + factor(i), data = dung)


summary(trangtrang)

##
## Call:
## lm(formula = C ~ Q + factor(i), data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -937342 -72283 2219 77797 790626
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -2611747 244754 -10.671 < 2e-16 ***
## Q 3723326 165063 22.557 < 2e-16 ***
## factor(i)2 954145 125136 7.625 3.62e-11 ***
## factor(i)3 1799520 196388 9.163 3.08e-14 ***
## factor(i)4 2458376 224768 10.937 < 2e-16 ***
## factor(i)5 2481172 239227 10.372 < 2e-16 ***
## factor(i)6 2537253 240642 10.544 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 292900 on 83 degrees of freedom
## Multiple R-squared: 0.9437, Adjusted R-squared: 0.9396
## F-statistic: 231.9 on 6 and 83 DF, p-value: < 2.2e-16

Chúng ta có thể thấy ngay là các hệ số hồi quy của D4, D5, và D6 khá sát nhau. Điều này gợi ý cho chúng
ta rằng nếu chúng ta biểu diễn 6 đường hồi quy ứng với 6 hãng trên cùng một đồ thị thì các đường
hồi quy của hãng 4, 5, và 6 là sát nhau. Chúng ta có thể sử dụng đồ thị để kiểm tra nhận định này:

Chat <-trangtrang$fitted
library(car)
scatterplot(Chat ~ dung$Q|dung$i, xlab = "Q", ylab = "Chat")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


367

Quan phân tích đồ thị chúng ta có thể thấy rằng rất có thể mô hình Pooled OLS có thể phù hợp hơn so
với LSDV. Chúng ta xét mô hình Pooled OLS:

Cit. = ψ1 + ψ2itQit. + uit (11)

Thực hiện LSDV trong R:

pooled <- lm(C ~ Q, data = dung)


summary(pooled)

##
## Call:
## lm(formula = C ~ Q, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -944933 -265773 9185 180057 1338676
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -5336 68243 -0.078 0.938
## Q 2069488 89717 23.067 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 451600 on 88 degrees of freedom
## Multiple R-squared: 0.8581, Adjusted R-squared: 0.8565
## F-statistic: 532.1 on 1 and 88 DF, p-value: < 2.2e-16

Nguyễn Chí Dũng http://rpubs.com/chidungkt


368

Chúng ta có thể vẽ đường hồi quy cho mô hình Pooled OLS (màu vàng) cùng với 6 đường hồi quy ứng
với 6 hãng trên cùng một đồ thị:

abline(pooled, lwd = 3, col = "yellow")

Tất nhiên nhận định rằng Pooled OLS có thể phù hợp hơn so với LSDV chỉ dựa trên trực quan của
chúng ta khi phân tích 6 đường hồi quy cho 6 hãng trên. Để đưa ra quyết định chính thức về việc lựa
chọn LSDV hay Pooled OLS chúng ta phải sử dụng các kiểm định đã trình bày ở các mục trên.

12.6 Một số lưu ý về định dạng dữ liệu và công thức cho mô hình
Cũng như khi sử dụng Stata cho dữ liệu mảng, việc đầu tiên cần làm là chỉ thị cho R hiểu rằng “bạn
đang xử lý dữ liệu mảng”. Với Stata bạn sử dụng lệnh xtset. Tuy nhiên, có vẻ như tất cả những ví dụ ở
trên, chúng ta đã bỏ qua thao tác định dạng dữ liệu mảng cho R.

Sự thực không phải vậy, là vì chúng ta đã “ẩn” thao tác định dạng dữ liệu mảng trong các câu lệnh.
Trở lại với các dòng lệnh ở mục 12.3.3, chúng ta có thể làm cách khác như sau:

dung <- plm.data(dung, index = c("i", "t")) # Định dạng data frame dung là dữ
liệu mảng.
FEM <- plm(C ~ Q + PF + LF, data = dung, model = "within") # Chạy mô hình.
summary(FEM)

Kết quả thu được là không có gì thay đổi. Ở đây câu lệnh đầu tiên chúng ta sử dụng để định dạng dung
là một dữ liệu mảng để R thực hiện phân tích.

Ngoài cách thức trình bày dữ liệu như ở dung, còn có những cách thức trình bày dữ liệu kiểu khác.
Chúng ta xét bộ dữ liệu không cân bằng (unbalanced panel data) có tên Wages về 595 cá thể xuất
hiện trong nghiên cứu của Cornwell & Rupert (1988). Có nhiều cách để có bộ dữ liệu này. Một trong

Nguyễn Chí Dũng http://rpubs.com/chidungkt


369

những cách nhanh nhất là các bạn cài đặt gói Ecdat bằng lệnh install.packages(“Ecdat”). Chúng ta
thấy cách trình bày của bộ dữ liệu này như sau:

data("Wages", package = "Ecdat")


attach(Wages)
head(Wages)

## exp wks bluecol ind south smsa married sex union ed black lwage
## 1 3 32 no 0 yes no yes male no 9 no 5.56068
## 2 4 43 no 0 yes no yes male no 9 no 5.72031
## 3 5 40 no 0 yes no yes male no 9 no 5.99645
## 4 6 39 no 0 yes no yes male no 9 no 5.99645
## 5 7 42 no 1 yes no yes male no 9 no 6.06146
## 6 8 35 no 1 yes no yes male no 9 no 6.17379

Các bạn nên tự so sánh với data frame dung để tìm ra sự khác biệt về cách trình bày của bộ dữ liệu
này. Chúng ta sử dụng câu lệnh sau để thiết lập bộ dữ liệu này là dữ liệu mảng trước khi thực hiện bất
kì phân tích nào với tên gọi là nghiyeu:

nghiyeu <- plm.data(Wages, index = 595)


head(nghiyeu)

## id time exp wks bluecol ind south smsa married sex union ed black
## 1 1 1 3 32 no 0 yes no yes male no 9 no
## 2 1 2 4 43 no 0 yes no yes male no 9 no
## 3 1 3 5 40 no 0 yes no yes male no 9 no
## 4 1 4 6 39 no 0 yes no yes male no 9 no
## 5 1 5 7 42 no 1 yes no yes male no 9 no
## 6 1 6 8 35 no 1 yes no yes male no 9 no
## lwage
## 1 5.56068
## 2 5.72031
## 3 5.99645
## 4 5.99645
## 5 6.06146
## 6 6.17379

Lúc này bạn có thể thấy xuất hiện hai cột “biến” mới là id và time. Bộ số liệu này sẽ được sử dụng
trong mục 12.7.

Một vấn đề khác là biểu diễn các mô hình định lượng sử dụng dữ liệu mảng. Với các mô hình động
(Dynamic Model) thường có cả biến trễ và sai phân các bậc trong mô hình. Với bộ số liệu EmplUK ,
xét mô hình động sau đây:

ln(empi,t) = ln(empi,t-1) + ln(empi,t-2) + ln(wagei,t-2) + ln(wagei,t-3) + diff(capitali,t-2) +


diff(capitali,t-3) + uit

Nguyễn Chí Dũng http://rpubs.com/chidungkt


370

Nghĩa là chúng ta đang nghiên cứu sự phụ thuộc của biến emp theo: (1) biến trễ bậc 1 và 2 của
ln(emp), (2) biến trễ bậc 2 và 3 của ln(wage), và (3) sai phân bậc 2 và 3 của capital. Trong R chúng ta
có thể biểu diễn công thức mô hình này như sau:

mohinhc1 <-log(emp) ~ lag(log(emp), 1) + lag(log(emp), 2) + lag(log(wage), 2)


+ lag(log(wage), 3) + diff(capital, 2) + diff(capital, 3)

Mô hình này có thể được diễn đạt theo một cách khác bằng sử dụng hàm dynformula():

mohinhc2 <-dynformula(emp ~ wage + capital, log = list(capital = FALSE, TRUE)


, lag = list(emp = 2, c(2, 3)), diff = list(FALSE, capital = TRUE))

Chúng ta có thể thấy hai cách diễn đạt mô hình này cùng mô tả một mô hình mà thôi:

mohinhc1

## log(emp) ~ lag(log(emp), 1) + lag(log(emp), 2) + lag(log(wage),


## 2) + lag(log(wage), 3) + diff(capital, 2) + diff(capital,
## 3)

mohinhc2

## log(emp) ~ lag(log(emp), 1) + lag(log(emp), 2) + lag(log(wage),


## 2) + lag(log(wage), 3) + diff(capital, 2) + diff(capital,
## 3)

Cách thức diễn đạt mô hình bằng sử dụng hàm dynformula() là rất thuận tiện (bằng cách tiết kiệm
thời gian đánh máy) cho những trường hợp mô hình nghiên cứu của chúng ta có nhiều biến trễ và sai
phân.

12.7 Một số mô hình nâng cao cho phân tích dữ liệu mảng
Trong mục này chúng ta sẽ thực hiện một số ước lượng nâng cao khi phân tích dữ liệu mảng là ước
lượng biến công cụ IV, ước lượng Hausman – Taylor, moment tổng quá GMM và FGLS. Lý thuyết
những cách tiếp cận này cho phân tích dữ liệu mảng các bạn có thể tìm thấy ở nhiều giáo trình kinh
tế lượng.

12.7.1 Sử dụng biến công cụ


Chúng ta sử dụng bộ số liệu có tên EmplUK được tích hợp cùng gói plm. Đây là bộ dữ liệu bảng không
cân bằng (Unbalanced Panel Data) trong nghiên cứu có tên Some Tests of Specication for Panel
Data: Monte Carlo Evidence and an Application to Employment Equations của Arellano và Bond
(1991) nhằm đánh giá tác động của mức lương (wage) và vốn đầu tư (capital) lên việc làm (emp) của
140 hãng trong khoảng thời gian từ 1976 đến 1984. Nghiên cứu này có thể lấy miễn phí từ Internet.
Trước hết chúng ta đánh giá sơ bộ về bộ dữ liệu này.

data(EmplUK)
head(EmplUK)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


371

## firm year sector emp wage capital output


## 1 1 1977 7 5.041 13.1516 0.5894 95.7072
## 2 1 1978 7 5.600 12.3018 0.6318 97.3569
## 3 1 1979 7 5.015 12.8395 0.6771 99.6083
help("EmplUK") # Xem chi tiết hơn về dữ liệu.
love <- table(EmplUK$firm)
barplot(love, ylim = c(0, 10)) # Xem khoảng thời gian được nghiên cứu cho các
hãng

Từ hình ảnh trên chúng ta thấy rằng đa phần các hãng có khoảng thời gian nghiên cứu là 7 năm. Một
số hãng có thời gian nghiên cứu là 8 hoặc 9 năm. Rõ ràng đây là một bảng dữ liệu không cân bằng. Cụ
thể:

you <- data.frame(love)


table(you$Freq)

##
## 7 8 9
## 103 23 14

Như vậy có 103 công ti với thời gian nghiên cứu là 7 năm, 23 công ti có thời gian nghiên cứu là 8 năm
và 14 công ti có thời gian nghiên cứu là 9 năm. Ngoài ra chúng ta còn có thể thấy khoảng thời gian từ
1978 đến 1982 xuất hiện với tần suất như nhau và nhiều nhất, năm 1984 số quan sát là ít nhất:

iu <- table(EmplUK$year)
library(fBasics)
mausac <- qualiPalette(12, "Set3")
barplot(iu, col = mausac)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


372

Chúng ta có thể có thông tin chi tiết hơn về số quan sát xuất hiện tương ứng với các năm:

iu

##
## 1976 1977 1978 1979 1980 1981 1982 1983 1984
## 80 138 140 140 140 140 140 78 35

Giả sử chúng ta sử dụng trễ bậc 1 của wage làm biến công cụ cho wage. Việc thực hiện ước lượng biến
công cụ có thể được thực hiện theo hai cách tiếp cận với lựa chọn inst.method như sau:

 inst.method = “bvk” : theo cách tiếp cận của Balestra và Varadharajan-Krishnakumar


(1987). R sẽ mặc định sử dụng cách tiếp cận này.
 inst.method = “baltagi” : theo cách tiếp cận của Baltagi (1981).

Thực hiện ước lượng biến công cụ với cách tiếp cận của của Balestra và Varadharajan-Krishnakumar
sẽ được thực hiện theo cú pháp sau (xem lại chương 9 nếu cần):

# Ước lượng biến công cụ:


ivPanel <- plm(emp ~ wage + capital | lag(wage, 1) + capital,
data = EmplUK, model = "random",
inst.method = "bvk")
summary(ivPanel)

## Oneway (individual) effect Random Effect Model


## (Swamy-Arora's transformation)
## Instrumental variable estimation
## (Balestra-Varadharajan-Krishnakumar's transformation)
##
## Call:
## plm(formula = emp ~ wage + capital | lag(wage, 1) + capital,
## data = EmplUK, model = "random", inst.method = "bvk")
##
## Unbalanced Panel: n=140, T=6-8, N=891
##
## Effects:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


373

## var std.dev share


## idiosyncratic 3.644 1.909 0.045
## individual 76.663 8.756 0.955
## theta :
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.9113 0.9113 0.9113 0.9140 0.9179 0.9231
##
## Residuals :
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -12.1000 -0.5640 -0.2740 -0.0121 0.1560 20.9000
##
## Coefficients :
## Estimate Std. Error t-value Pr(>|t|)
## (Intercept) 9.927065 1.936903 5.1252 3.648e-07 ***
## wage -0.216500 0.074108 -2.9214 0.003573 **
## capital 1.298342 0.059661 21.7620 < 2.2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Total Sum of Squares: 5547.8
## Residual Sum of Squares: 3453.3
## R-Squared: 0.37776
## Adj. R-Squared: 0.37649
## F-statistic: 269.3 on 2 and 888 DF, p-value: < 2.22e-16

Chú ý rằng, kết quả sẽ không có gì thay đổi nếu chúng ta không gõ inst.method="bvk" vì R sẽ mặc
định cách tiếp cận này. Chú ý rằng biến số độc lập nào xuất hiện ở cả hai vế của dấu | thì được hiểu là
chúng “triệt tiêu” nhau và biến số còn lại ở vế phải của dấu | sẽ là biến công cụ cho biến còn lại ở vế
trái. Câu lệnh này tương đương với sử dụng lệnh xtivreg của Stata.

Vừa rồi chúng ta thực hiện biến công cụ cho bộ dữ liệu bảng không cân bằng. Dưới đây chúng ta sẽ
thực hiện ước lượng biến công cụ cho bộ dữ liệu bảng cân bằng có tên psi.dta lấy từ nghiên cứu của
Baltagi & Khanti-Akom (1990) xuất hiện trong nhiều giáo trình khác nhau về dữ liệu mảng. Đây là dữ
liệu được sử dụng để đánh giá vài trò của các biến định lượng (như kinh nghiệm exp) cũng như định
tính (như giới tính fem) lên logarit cơ số tự nhiên (lwage). Số liệu được thu nhập từ 595 lao động
trong giai đoạn 1976 – 1982:

setwd("D:/KTLR")
library(foreign)
trang <- read.dta("psi.dta")
dim(trang)

## [1] 4165 22

head(trang)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


374

## exp wks occ ind south smsa ms fem union ed blk lwage id t tdum1 tdum2
## 1 3 32 0 0 1 0 1 0 0 9 0 5.56068 1 1 1 0
## 2 4 43 0 0 1 0 1 0 0 9 0 5.72031 1 2 0 1
## 3 5 40 0 0 1 0 1 0 0 9 0 5.99645 1 3 0 0
## 4 6 39 0 0 1 0 1 0 0 9 0 5.99645 1 4 0 0
## 5 7 42 0 1 1 0 1 0 0 9 0 6.06146 1 5 0 0
## 6 8 35 0 1 1 0 1 0 0 9 0 6.17379 1 6 0 0
## tdum3 tdum4 tdum5 tdum6 tdum7 exp2
## 1 0 0 0 0 0 9
## 2 0 0 0 0 0 16
## 3 1 0 0 0 0 25
## 4 0 1 0 0 0 36
## 5 0 0 1 0 0 49
## 6 0 0 0 1 0 64

table(trang$t)

##
## 1 2 3 4 5 6 7
## 595 595 595 595 595 595 595

Dưới đây chúng ta thực hiện ước lượng biến công cụ cho lwage theo exp và exp2 (bình phương của
exp) và wks trong đó chúng ta chọn ms (trạng thái hôn nhân) là biến công cụ cho wks:

# Thiết lập dữ liệu mảng:


trang <- plm.data(trang, index = c("id", "t"))
ivPanel <- plm(lwage ~ exp + exp2 + wks | exp + exp2 + ms,
data = trang,
model = "within",
inst.method = "bvk")
summary(ivPanel)

## Oneway (individual) effect Within Model


## Instrumental variable estimation
## (Balestra-Varadharajan-Krishnakumar's transformation)
##
## Call:
## plm(formula = lwage ~ exp + exp2 + wks | exp + exp2 + ms, data = trang,
## model = "within", inst.method = "bvk")
##
## Balanced Panel: n=595, T=7, N=4165
##
## Residuals :
## Min. 1st Qu. Median 3rd Qu. Max.
## -4.1100 -0.1190 0.0392 0.1990 2.1600
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


375

## Coefficients :
## Estimate Std. Error t-value Pr(>|t|)
## exp 0.1408101 0.0547014 2.5742 0.01009 *
## exp2 -0.0011207 0.0014052 -0.7975 0.42520
## wks -0.1149742 0.2316926 -0.4962 0.61976
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Total Sum of Squares: 240.65
## Residual Sum of Squares: 946.63
## R-Squared: 0.094827
## Adj. R-Squared: 0.081212
## F-statistic: -886.733 on 3 and 3567 DF, p-value: 1

So với thực hiện trong Stata thì điểm khác biệt là R không báo cáo hệ số chặn của mô hình.

12.7.2 Ước lượng Hausman – Taylor


Để minh họa cho thực hiện ước lượng Hausman – Taylor chúng ta sử dụng lại bộ dữ liệu psi.dta được
sử dụng ở mục 12.7.1. Rõ ràng biến giáo dục (ed) là biến nội sinh (endogenous). Chúng ta xét mô hình
mà trong đó các biến exp, exp2, wks, ms và union là những biến nội sinh và thay đổi theo thời gian
(time-varying) còn các biến occ, south, smsa, và ind là các biến ngoại sinh không thay đổi theo chiều
thời gian. Dưới đây là ước lượng Hausman – Taylor trong R. Do công thức mô tả mô hình rất dài lên
chúng ta làm thành hai bước như sau:

congthuc <- lwage ~ occ + south + smsa + ind + exp + I(exp^2) + wks + ms + un
ion + fem + blk + ed | exp + I(exp^2) + wks + ms + union + ed

hausmantaylor <- plm(congthuc, data = trang, model = "ht") # Tương đương với
câu lệnh xthtaylor
summary(hausmantaylor)

## Oneway (individual) effect Hausman-Taylor Model


## Call:
## pht(formula = congthuc, data = trang)
##
## T.V. exo : exp, I(exp^2), wks, ms, union
## T.V. endo : occ, south, smsa, ind
## T.I. exo : ed
## T.I. endo : fem, blk
##
## Balanced Panel: n=595, T=7, N=4165
##
## Effects:
## var std.dev share
## idiosyncratic 0.02304 0.15180 0

Nguyễn Chí Dũng http://rpubs.com/chidungkt


376

## individual 58.38642 7.64110 1


## theta: 0.9925
##
## Residuals :
## Min. 1st Qu. Median 3rd Qu. Max.
## -1.83000 -0.06430 -0.00215 0.06690 1.94000
##
## Coefficients :
## Estimate Std. Error t-value Pr(>|t|)
## (Intercept) 8.0007e+00 3.4251e+00 2.3359 0.01950 *
## occ -2.1452e-02 1.3643e-02 -1.5724 0.11587
## south -2.1349e-03 3.3949e-02 -0.0629 0.94986
## smsa -4.2543e-02 1.9230e-02 -2.2123 0.02694 *
## ind 1.9173e-02 1.5289e-02 1.2541 0.20982
## exp 1.1315e-01 2.4454e-03 46.2703 < 2.2e-16 ***
## I(exp^2) -4.1901e-04 5.4028e-05 -7.7553 8.812e-15 ***
## wks 8.3480e-04 5.9354e-04 1.4065 0.15958
## ms -2.9846e-02 1.8790e-02 -1.5884 0.11219
## union 3.3223e-02 1.4769e-02 2.2495 0.02448 *
## fem 6.7401e+00 4.2331e+00 1.5922 0.11133
## blk -2.7984e+01 1.6539e+01 -1.6920 0.09064 .
## ed -1.6246e-01 2.1432e-01 -0.7580 0.44843
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Total Sum of Squares: 886.9
## Residual Sum of Squares: 93.974
## F-statistic: 2919.47 on 12 and 4152 DF, p-value: < 2.22e-16

R chỉ ra danh sách các biến nội sinh ở dòng T.V. exo : exp, I(exp^2), wks, ms, union và
hệ số hồi quy ước lượng của những biến số này được chú ý phân tích hơn. Từ kết quả của mô hình có
thể thấy kinh nghiệm và mức lương tuân theo quy luật cận biên giảm dần. Kết quả của ước lượng này
tương đương với sử dụng lệnh xthtaylor của Stata.

Chú ý nếu chúng ta không tạo ra đối tượng congthuc thì chúng ta phải gõ câu lệnh kiểu như sau:

hausmantaylor <- plm(lwage ~ occ + south + smsa + ind + exp + I(exp^2) + wks
+ ms + union + fem + blk + ed | exp + I(exp^2) + wks + ms + union + ed, data
= trang, model = "ht")

Tất nhiên kết quả vẫn không có gì thay đổi. Việc mô tả trước mô hình như chúng ta vừa thấy là cách
thức thường được sử dụng khi mô hình của chúng ta buộc phải mô tả bằng một dãy dài các kí tự.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


377

12.7.3 Phương pháp moment tổng quát GMM


Phương pháp moment tổng quát GMM (viết tắt của Generalized Method of Moments) còn gọi là ước
lượng Arelano – Bond (tương đương câu lệnh xtabond khi sử dụng Stata). Chúng ta sẽ sử dụng lại bộ
số liệu EmplUK. Giả sử chúng ta cần thực hiện ước lượng GMM cho biến logarit tự nhiên của emp (kí
hiệu log(emp)) theo: (1) biến trễ bậc 1 và 2 của log(emp), (2) biến trễ bậc 0 và 1 của log(wage), (3)
biến trễ bậc 0 của log(capital), và (4) biến trễ bậc 0 và 1 của log(output). Đây là mô hình xuất hiện
trong nghiên cứu có tên Some Tests of Specification for Panel Data: Monte Carlo Evidence and an
Application to Employment Equations (chúng ta có thể lấy miễn phí nghiên cứu này trên Internet)
của Arellano & Bond (1991). Dưới đây chúng ta sẽ lặp lại một số kết quả được trình bày trong nghiên
cứu này (cột b của bảng 4) trong R:

gmmPanelc1 <- pgmm(log(emp) ~ lag(log(emp), 1:2) + lag(log(wage), 0:1)


+ log(capital) + lag(log(output), 0:1) | lag(log(emp), 2:99),
data = EmplUK, effect = "twoways", model = "twosteps")
summary(gmmPanelc1)

## Twoways effects Two steps model


##
## Call:
## pgmm(formula = log(emp) ~ lag(log(emp), 1:2) + lag(log(wage),
## 0:1) + log(capital) + lag(log(output), 0:1) | lag(log(emp),
## 2:99), data = EmplUK, effect = "twoways", model = "twosteps")
##
## Unbalanced Panel: n=140, T=7-9, N=1031
##
## Number of Observations Used: 611
##
## Residuals
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -0.6191000 -0.0255700 0.0000000 -0.0001339 0.0332000 0.6410000
##
## Coefficients
## Estimate Std. Error z-value Pr(>|z|)
## lag(log(emp), 1:2)1 0.474151 0.185398 2.5575 0.0105437 *
## lag(log(emp), 1:2)2 -0.052967 0.051749 -1.0235 0.3060506
## lag(log(wage), 0:1)0 -0.513205 0.145565 -3.5256 0.0004225 ***
## lag(log(wage), 0:1)1 0.224640 0.141950 1.5825 0.1135279
## log(capital) 0.292723 0.062627 4.6741 2.953e-06 ***
## lag(log(output), 0:1)0 0.609775 0.156263 3.9022 9.530e-05 ***
## lag(log(output), 0:1)1 -0.446373 0.217302 -2.0542 0.0399605 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Sargan Test: chisq(25) = 30.11247 (p.value=0.22011)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


378

## Autocorrelation test (1): normal = -1.53845 (p.value=0.12394)


## Autocorrelation test (2): normal = -0.2796829 (p.value=0.77972)
## Wald test for coefficients: chisq(7) = 142.0353 (p.value=< 2.22e-16)
## Wald test for time dummies: chisq(6) = 16.97046 (p.value=0.0093924)

Lý thuyết của của phương pháp ước lượng này cũng như diễn giải các kết quả các bạn có thể xem một
cách chi tiết từ nghiên cứu trên.

12.7.4 Ước lượng FGLS


Trong R chúng ta thực hiện ước lượng FGLS bằng lệnh pggls(). Sử dụng bộ dữ liệu EmplUK chúng ta
thực hiện ước lượng này theo cách tiếp cận của Wooldridge (2002):

loveyou <- pggls(log(emp) ~ log(wage) + log(capital),


data = EmplUK, model = "pooling")
summary(loveyou)
## Call:
## pggls(formula = log(emp) ~ log(wage) + log(capital), data = EmplUK,
## model = "pooling")
##
## Unbalanced Panel: n=140, T=7-9, N=1031
##
## Residuals
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -1.80700 -0.36550 0.06181 0.03230 0.44280 1.58700
##
## Coefficients
## Estimate Std. Error z-value Pr(>|z|)
## (Intercept) 2.023480 0.158468 12.7690 < 2.2e-16 ***
## log(wage) -0.232329 0.048001 -4.8401 1.298e-06 ***
## log(capital) 0.610484 0.017434 35.0174 < 2.2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Total Sum of Squares: 1853.6
## Residual Sum of Squares: 402.55
## Multiple R-squared: 0.78283

Chúng ta cũng có thể đánh giá tác động cố định bằng lệnh sau:

loveyou <- pggls(log(emp) ~ log(wage) + log(capital),


data = EmplUK,
model = "within")

Nhìn chung kết quả thu được từ ước lượng FGLS không khác biệt nhiều so với sử dụng hàm plm().

Nguyễn Chí Dũng http://rpubs.com/chidungkt


379

12.8 Vài kết luận cuối cùng về phân tích dữ liệu mảng

Trong chương này chúng ta đã khái quát và xem xét một số mô hình cơ bản cho dữ liệu mảng.

Các chủ đề khác chưa được đề cập cho dữ liệu mảng là:

1. Các mô hình nhiều phương trình (Simultaneous Equation Models) với dữ liệu mảng.

2. Biến định tính và dữ liệu mảng.

Các chủ đề này và một số khía cạnh khác về phân tích dữ liệu mảng khó có thể trình bày chỉ trong
một chương được vì theo truyền thống, phân tích dữ liệu mảng thường được tách hẳn ra thành một
nhánh của kinh tế lượng. Bạn đọc quan tâm có thể tìm hiểu sâu hơn ở những giáo trình chuyên về
dữ liệu mảng. Một số cuốn hay và chi tiết là sách của Baltagi, Greene, và Wooldridge.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


380

Chương 13: Các mô hình với biến phụ thuộc là rời rạc

Các chương trước chúng ta nghiên cứu các mô hình mà ở đó biến phụ thuộc là các biến liên tục. Tuy
nhiên trong nhiều tình huống trong thực tế, biến phụ thuộc có thể là biến rời rạc, biến phân hạng, hoặc
biến định tính. Những mô hình hồi quy áp dụng cho tình huống này thuộc về một lớp gọi là các mô hình
hồi quy với biến phản ứng là định tính (Qualitative Response Regression Models). Chương này chúng
ta chỉ xét tình huống đơn giản nhất của lớp mô hình này với biến phụ thuộc chỉ nhận hai giá trị 0 hoặc
1 (còn gọi là biến nhị phân binary variable) và biến phụ thuộc nhận nhiều hơn hai giá trị 0 và 1. Trước
hết, chúng ta sẽ nghiên cứu tại sao ước lượng OLS (hay mô hình xác suất tuyến tính LPM) là không phù
hợp cho các tình huống như vậy. Kế tiếp, chúng ta sẽ nghiên cứu và thực hành các mô hình Logistic,
Logistic đa cấp độ và Probit và mô hình cây phân loại.

13.1 Mô hình xác suất tuyến tính LPM


Chúng ta xét bộ dữ liệu lưu ở Table8_1.dta về 1196 nam giới với các biến số sau: smoker = 1 nếu anh
ta là người hút thuốc và bằng 0 nếu không hút thuốc, educ là số năm đi học, age là tuổi, income là thu
nhập, pcigs79 là giá của một bao thuốc lá ở thời điểm năm 1979. Chúng ta nghiên cứu hành vi hút
thuốc (smoker) liên hệ như thế nào với các biến số khác bằng ước lượng OLS sau:

smoker = β1 + β2age. + β3educ. + β4income + β5pcigs + uit (1)

Mô hình này còn có tên gọi khác là mô hình xác suất tuyến tính LPM (Linear Probability Model) vì
rằng kì vọng của biến phụ thuộc (trạng thái hút thuốc) có thể được hiểu như xác suất có điều kiện
xuất hiện sự kiện hút thuốc. Ước lượng OLS thu được là:

setwd("D:/KTLR")
library(foreign)
dung <- read.dta("Table8_1.dta")
lmp <- lm(smoker ~ age + educ + income + pcigs79, data = dung)
summary(lmp)

##
## Call:
## lm(formula = smoker ~ age + educ + income + pcigs79, data = dung)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.6417 -0.3880 -0.2782 0.5563 0.8405
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.123e+00 1.884e-01 5.963 3.27e-09 ***
## age -4.726e-03 8.290e-04 -5.701 1.50e-08 ***
## educ -2.061e-02 4.616e-03 -4.465 8.76e-06 ***
## income 1.026e-06 1.632e-06 0.629 0.5298

Nguyễn Chí Dũng http://rpubs.com/chidungkt


381

## pcigs79 -5.132e-03 2.852e-03 -1.799 0.0723 .


## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.477 on 1191 degrees of freedom
## Multiple R-squared: 0.03877, Adjusted R-squared: 0.03554
## F-statistic: 12.01 on 4 and 1191 DF, p-value: 1.431e-09

Mô hình này chỉ ra rằng tuổi tác, giáo dục, và giá của thuốc lá quan hệ ngược chiều với biến phụ thuộc.
Đây là một kết quả không có gì bất ngờ. Chúng ta diễn giải các kết quả thu được như sau: nếu các biến
khác không đổi, xác suất quan sát thấy hành vi hút thuốc là giảm 0.005 khi tuổi tăng lên 1 (có lẽ bởi
vì các ảnh hưởng tiêu cực của hút thuốc đối với sức khỏe). Giá trị R2 = 0.038 có vẻ là thấp nhưng chúng
ta cần chú ý rằng kết quả này không có ý nghĩa quá quan trọng vì biến phụ thuộc chỉ nhận một trong
hai giá trị 0 hoặc 1.

Tuy nhiên, mô hình LMP trên có một số nhược điểm đáng chú ý. Thứ nhất, LPM cho rằng xác xuất
quan sát thấy hành vi hút thuốc là quan hệ tuyến tính với các biến giải thích bất kể quy mô về giá trị
của các biến số này. Thứ hai, xác suất của một sự kiện phải nằm giữa 0 và 1 nhưng LPM không đảm
bảo rằng các giá trị xác suất ước lượng sẽ nằm trong khoảng này. Thứ ba, giả định về sai số ngẫu nhiên
tuân theo phân phối chuẩn có thể không còn đúng nữa khi biến phụ thuộc chỉ nhận một trong hai giá
trị 0 và 1. Thứ tư, phương sai của sai số ngẫu nhiên là thay đổi, làm cho các kiểm định truyền thống
là không đáng tin.
Vì những lí do trên, các mô hình Probit và Logistic thường được sử dụng cho các tình huống mà biến
phụ thuộc là các biến nhị phân.

13.2 Mô hình Logistic và một số tiêu chí đánh giá


Mục này chúng ta nghiên cứu một trong những mô hình phân loại thường được sử dụng nhiều trong
nghiên cứu là mô hình Logistic (một số tài liệu gọi là mô hình Logit) cũng như một số tiêu chí đánh
giá chất lượng của mô hình.
13.2.1 Mô hình Logistic
Mô hình này phát biểu rằng xác suất p quan sát thấy hành vi hút thuốc liên hệ với các biến độc lập
khác trong mô hình như sau:
exp(𝛼 + 𝛽1 𝑥1 + 𝛽2 𝑥2 + ⋯ + 𝛽𝑘 𝑥𝑘 )
𝑝 = 𝑓(𝛼 + 𝛽1 𝑥1 + 𝛽2 𝑥2 + ⋯ + 𝛽𝑘 𝑥𝑘 ) = (2)
1 + exp(𝛼 + 𝛽1 𝑥1 + 𝛽2 𝑥2 + ⋯ + 𝛽𝑘 𝑥𝑘 )
Trong đó x1 = age, x2 = educ…, xk = pcigs79. Mặc khác, bằng đại số phổ thông chúng ta cũng chứng
minh được rằng:
𝑝
𝑙𝑜𝘨 = 𝛼 + 𝛽1 𝑥1 + 𝛽2 𝑥2 + ⋯ + 𝛽𝑘 𝑥𝑘
1−𝑝
Ở đây, tỉ sổ p/(1-p) được gọi là khả năng thành công (odds of success) và hàm log[p/(1-p)] gọi là hàm
logit của p và đương nhiên nó là một hàm liên tục và chúng ta có thể thấy đây là một hàm có dạng
cong chữ S với các đặc điểm sau:
1. Vì p có giá trị từ 0 đến 1 nên hàm logit có giá trị từ - ∞ đến + ∞.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


382

2. Mặc dù log[p/(1-p)] là tuyến tính với các biến giả thích nhưng các xác suất thì không như vậy.
Điều này ngược lại với mô hình LPM.
3. Nếu log[p/(1-p)] là dương thì khi giá trị của biến giải thích tăng dẫn đến khả năng quan sát
thấy hành vi hút thuốc tăng (và ngược lại).
4. Nếu chúng ta thu được các ước lượng cho các α và β thì chúng ta có thể ước lượng xác suất p̂
cho bất kì quan sát nào theo công thức 2.

Việc ước lượng các hệ số của mô hình Logit được thực hiện bằng phương pháp ước lượng hợp lí cực
đại (maximum likelihood). Với R chúng ta có thể thực hiện ước lượng này lệnh glm (viết tắt của
generalized linear models – các mô hình tuyến tính tổng quát):
logit <- glm(smoker ~ age + educ + income + pcigs79,
family = binomial, data = dung)
summary(logit)

##
## Call:
## glm(formula = smoker ~ age + educ + income + pcigs79, family = binomial,
## data = dung)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.4608 -0.9829 -0.8055 1.2769 1.8384
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 2.745e+00 8.292e-01 3.311 0.000931 ***
## age -2.085e-02 3.739e-03 -5.577 2.44e-08 ***
## educ -9.097e-02 2.067e-02 -4.402 1.07e-05 ***
## income 4.720e-06 7.170e-06 0.658 0.510356
## pcigs79 -2.232e-02 1.247e-02 -1.789 0.073538 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 1588.9 on 1195 degrees of freedom
## Residual deviance: 1541.7 on 1191 degrees of freedom
## AIC: 1551.7
##
## Number of Fisher Scoring iterations: 4

Chúng ta diễn giải các kết quả thu được như sau. Ví dụ, hệ số của age = -2.085⨉10-2 có nghĩa là khi
giáo dục tăng 1 (năm) thì xác suất quan sát thấy hành vi hút thuốc của người này giảm xuống 100[1-
exp(-2.085⨉10-2] = 100(1 – 0.979) = 2.06%:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


383

100*(1 - exp(logit$coef[2]))

## age
## 2.063728

Các diễn giải về các hệ số như trên là một cách thức phổ biến. Tuy nhiên, có một cách thức khác diễn
giải các hệ số của mô hình Logistic là diễn giải theo tỉ số khả năng (Nguyễn, 2015) hoặc theo cách gọi
của giáo trình NEU là tỉ số OR (odd ratio). Chúng ta có thể tính các hệ số OR của mô hình như sau:

exp(logit$coefficients) # Tính các hệ số OR

## (Intercept) age educ income pcigs79


## 15.5658975 0.9793627 0.9130426 1.0000047 0.9779284

Nghĩa là, chẳng hạn, khi tuổi tăng một đơn vị thì khả năng người này thuộc nhóm hút thuốc tăng
0.9793627 lần. Nói cách khác, là giảm 2.06% như chúng ta đã tính toán ở trên.

Chúng ta có thể ước lượng xác xuất quan sát thấy người thứ hai trong mẫu nghiên cứu là thuộc nhóm
hút thuốc là bao nhiêu:

1 / (1 + exp(-logit$coef[1] - logit$coef[2]*28 - logit$coef[3]*15


-logit$coef[4]*12500 - logit$coef[5]*60.6))

## (Intercept)
## 0.3782652

Giá trị xác suất ước lượng này là 0.3782. Thực tế thì quan sát thứ 2 này là người hút thuốc. Nên chúng
ta có thể nói mô hình phân loại (hay ước lượng) sai cho quan sát thứ hai này. Trong diễn giải các kết
quả của mô hình logistic (hay bất kì mô hình phân loại nào) nếu một người là hút thuốc và giá trị xác
suất ước lượng ứng với người này mà lớn hơn 0.5 thì ta nói mô hình dự báo đúng và gán cho nó giá
trị 1 và ngược lại (Gujarati, 2011). Trong tình huống của chúng ta mô hình ước lượng xác suất hút
thuốc ứng với quan sát thứ hai là 0.3782 trong khi thực tế anh ta hút thuốc do đó đây là một ước
lượng sai và do vậy được gán giá trị 0.

Sai khác giữa giá trị p thực tế và ước lượng p̂ gọi là deviance – một tiêu chí tương tự như phần dư
(residuals). Sai khác này càng bé càng tốt. Tương tự như tiêu chí R2 đối với ước lượng OLS, với mô
hình Logit chúng ta có chỉ tiêu R2 của MacFadden (MacFadden’s R2) để đo lường mức độ phù hợp của
mô hình với gói pscl (cài đặt gói này bằng lệnh install.packages(“pscl”)). Trong R chúng ta có thể
tìm MacFadden’s R2 với sự trợ giúp của gói pscl như sau:

library(pscl)
pR2(logit)

## llh llhNull G2 McFadden r2ML


## -770.84085505 -794.47478071 47.26785131 0.02974786 0.03875082
## r2CU
## 0.05271218

Nguyễn Chí Dũng http://rpubs.com/chidungkt


384

Giá trị này là 2.97% và chính là được tính theo công thức sau:

𝑙𝑓𝐿
𝑝𝑠𝑒𝑢𝑑𝑜 − 𝑅 2 = 1 −
𝑙𝑓𝐿0
Trong đó lfL = -770.841 và lfL0 = -794.474 (lần lượt ở cột llh và llhNull). Tương tự như kiểm định F
chúng ta có thể sử dụng thống kê tỉ số xác suất LR (likehood ratio statistic) theo công thức sau:

𝜆 = 2(𝑙𝑓𝐿 − 𝑙𝑓𝐿0 )
Để kiểm định cặp giả thuyết:

H0: Tất cả các hệ số hồi quy của biến độc lập bằng không

H0: Có ít nhất một hệ số hồi quy của biến độc lập khác không.

Thống kê này tuân theo phân phối χ2 với (k-1) bậc tự do (cũng chính là số biến độc lập trong mô
hình). Giá trị của thống kê λ = 47.268 là rất lớn nên chúng ta bắc bỏ giá thuyết H0.

Với mô hình logistic, chỉ tiêu R2 của MacFadden mà chúng ta đề cập là rất khó sử dụng để diễn giải
sức mạnh giải thích của mô hình logistic nói riêng và các mô hình phân loại nói chung. Chúng ta sử
dụng một cách tiếp cận khác cho vấn đề này như sau: lấy số lượng các quan sát mà mô hình dự báo
đúng – tức là các quan sát được gán giá trị 1 chia cho tất cẩ các quan sát trong mô hình (Gujarati,
2011) . Nếu tỉ số này bằng 1 thì ta nói mô hình dự báo đúng 100% (rất hiếm khi xẩy ra). Trong thực
tế, tỉ số này sẽ là một con số nằm giữ 0 và 1. Tất nhiên một mô hình tốt thì tỉ số này càng gần 1 càng
tốt. Những câu lệnh dưới đây cho phép chúng ta tính tỉ số này.

Dưới đây là R code tính toán mức độ chính xác trong phân loại:

contrasts(dung$smoker) # Lệnh này chỉ ra rằng nếu quan sát mà là Nonsmoker


nhưng phân loại thành Smoker thì gán cho giá trị 0 và ngược lại.

## Smoker
## Nonsmoker 0
## Smoker 1

glm.probs <- predict(logit, type = "response") # Xác suất dự báo cho tất cả
các quan sát.
glm.probs[1:10] # Xem XS dự báo cho 10 quan sát đầu bao gồm cả giá trị 0.3782
mà ta đã tính.

## 1 2 3 4 5 6 7
## 0.4757920 0.3782652 0.2983162 0.4857104 0.4324134 0.3122390 0.3171300
## 8 9 10
## 0.4361007 0.4237071 0.4737278

Nguyễn Chí Dũng http://rpubs.com/chidungkt


385

glm.pred <- rep("Nonsmoker", 1196)


glm.pred[glm.probs >.5] = "Smoker"
table(glm.pred, dung$smoker)

##
## glm.pred Nonsmoker Smoker
## Nonsmoker 669 394
## Smoker 72 61

mean(glm.pred == dung$smoker)

## [1] 0.6103679

669 / (669 + 394)

## [1] 0.6293509

61 / (72 + 61)

## [1] 0.4586466

(669 + 61) / 1196

## [1] 0.6103679

Kết quả chỉ ra rằng có tất cả (669 + 394) quan sát là không hút thuốc và mô hình xác định đúng 669
quan sát đạt tỉ lệ chính xác 62.93%. Có (72+61) quan sát hút thuốc nhưng mô hình chỉ xác định đúng
72 người hút thuốc và do vậy đạt mức chính xác 45.86%. Tỉ lệ dự báo chính xác của mô hình chính là
bằng (669+61)/1196 = 61.03%. Chú ý rằng (1 - 61.03%) = 38.97% được gọi là tỉ lệ sai sót huấn luyện
– một khái niệm mà chúng ta đã biết ở chương 4. Để biết tỉ lệ 61.3% đã đủ để kết luận mô hình logistic
là đáng tin cậy không trước hết ta tính tỉ lệ những nhóm khác nhau thuộc biến phụ thuộc:

round(prop.table(table(dung$smoker)) * 100, digits = 2)

##
## 0 1
## 61.96 38.04

Có thể thấy nhóm chiếm ưu thế là không hút thuốc với 61.96%. Một trong những tiêu chuẩn để đánh
giá mô hình logistic nói riêng và các mô hình phân loại nói chung là mức độ chính xác trong dự báo
của mô hình tối thiểu phải lớn hơn lớp có tỉ lệ cao nhất ở biến phụ thuộc. Vì chẳng cần xây dựng
mô hình nào chúng ta cũng có thể đoán ngẫu nhiên với mức độ chính xác là 61.96% - con số này chính
bằng tỉ trọng của nhóm chiếm ưu thế (nhóm không hút thuốc).

Để thuận tiện cho các phân tích, chúng ta nên đổi lại cách biểu thị cho biến định tính smoker. Cụ thể,
gán Nonsmoker cho người không hút thuốc (ứng với smoker = 0) và Smoker cho người hút thuốc
(ứng với smoker =1) rồi thực hiện lại mô hình logistic với hàm glm() như đã làm ở trên:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


386

# Chuyển biến smoker ở dạng số sang dạng factor với 0 ứng với
# không hút thuốc (Nonsmoker) và ngược lại:

library(tidyverse)

dung$smoker <- recode_factor(dung$smoker,


"0" = "Nonsmoker",
"1" = "smoker")
# Chạy lại mô hình:
logitdoibien <- glm(smoker ~ age + educ + income + pcigs79,
family = binomial, data = dung)

Tất nhiên chúng ta có thể thấy kiểu gán giá trị này cho biến định tính không làm thay đổi kết quả của
mô hình (không hiển thị kết quả):

summary(logitdoibien)

Ngoài sử dụng hàm glm() như vừa làm chúng ta cũng nên sử dụng hàm train() của gói caret để thực
hiện hồi quy logistic vì những thuận tiện của gói này (không hiển thị kết quả):

library(caret)
# Thực hiện logistic bằng gói caret:
logitdungTrain <- train(smoker ~ age + educ + income + pcigs79,
data = dung, method = "glm", family = "binomial")
summary(logitdungTrain)

Sử dụng gói caret chúng ta có thể nhanh chóng có được các thông tin về khả năng dự báo của mô hình
bằng hàm confusionMatrix():

pred <- predict(logitdungTrain, newdata = dung)


confusionMatrix(data = pred, dung$smoker)

## Confusion Matrix and Statistics


##
## Reference
## Prediction Nonsmoker Smoker
## Nonsmoker 669 394
## Smoker 72 61
##
## Accuracy : 0.6104
## 95% CI : (0.5821, 0.6381)
## No Information Rate : 0.6196
## P-Value [Acc > NIR] : 0.7537
##
## Kappa : 0.0427
## Mcnemar's Test P-Value : <2e-16
##
## Sensitivity : 0.9028
## Specificity : 0.1341
## Pos Pred Value : 0.6294
## Neg Pred Value : 0.4586

Nguyễn Chí Dũng http://rpubs.com/chidungkt


387

## Prevalence : 0.6196
## Detection Rate : 0.5594
## Detection Prevalence : 0.8888
## Balanced Accuracy : 0.5184
##
## 'Positive' Class : Nonsmoker

Bảng kết quả này được gọi là ma trận nhầm lẫn (confusion matrix) và sẽ được giải thích rõ hơn ở
các phần sau. Có thể thấy mức độ chính xác trong phân loại là 61.04%. Kết quả này là trùng với các
tính toán thủ công khi dùng hàm glm().

Tỉ lệ sai sót huấn luyện ở trên càng bé càng tốt tuy nhiên nó chưa phản ánh đúng sức mạnh giải thích
của mô hình vì chúng ta xây dựng mô hình dựa trên toàn bộ các quan sát và sau đó chúng ta sử dụng
lại toàn bộ các quan sát này để thẩm định (testing) mô hình. Để có bức tranh chính xác hơn về sức
mạnh giải thích của mô hình chúng ta phân chia toàn bộ dữ liệu thành hai phần. Phần thứ nhất là dữ
liệu huấn luyện (training data). Phần thứ hai là dữ liệu kiểm định (testing data). Chúng ta sử dụng dữ
liệu huấn luyện để xây dựng mô hình và sử dụng dữ liệu kiểm định để đánh giá mức độ chính xác
trong dự báo của mô mình (James et al., 2013).

Các câu lệnh dưới đây chúng ta lấy 1000 quan sát đầu làm dữ liệu huấn luyện và 192 quan sát còn lại
làm dữ liệu kiểm định để đánh giá sức mạnh giải thích của mô hình logistic với sự trợ giúp của gói
caret. Tỉ lệ dữ liệu kiểm định và huấn luyện thể hiện ở lựa chọn p=1000/1196:

dung <- dung[, c(1:4, 6)] # Chỉ lấy các biến sử dụng cho phân tích.
set.seed(123) # Dùng lệnh này để tái lập kết quả.
Train <- createDataPartition(dung$smoker, p = 1000 / 1196, list = FALSE)
training <- dung[ Train, ]
testing <- dung[ -Train, ]
# Chạy mô hình Logistic với dữ liệu huấn luyện bằng lệnh train():
mod_fit <- train(smoker ~., data = training,
method = "glm", family = "binomial")

summary(mod_fit)
## Call:
## NULL
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.5129 -0.9819 -0.8040 1.2749 1.8671
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 3.300e+00 9.122e-01 3.618 0.000297 ***
## educ -1.052e-01 2.275e-02 -4.621 3.82e-06 ***
## age -1.814e-02 4.081e-03 -4.446 8.76e-06 ***
## income 6.776e-06 7.931e-06 0.854 0.392917
## pcigs79 -3.110e-02 1.377e-02 -2.259 0.023895 *

Nguyễn Chí Dũng http://rpubs.com/chidungkt


388

## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 1330.1 on 1000 degrees of freedom
## Residual deviance: 1289.6 on 996 degrees of freedom
## AIC: 1299.6
##
## Number of Fisher Scoring iterations: 4

Chúng ta có thể đánh giá sức mạnh phân loại của mô hình trên dữ liệu kiểm định (không hiện kết
quả):

pred <- predict(mod_fit, newdata = testing)


confusionMatrix(data = pred, testing$smoker)

Chúng ta thấy rằng mức độ dự báo chính xác toàn cục bây giờ là 60% = (107+10)/196 – thấp hơn một
chút so với kết quả trước đó là 61.03% nhưng nó phản ánh chính hơn xác sức mạnh giải thích (hay
dự báo) của mô hình. Ở đây ta cũng tính được tỉ lệ sai sót kiểm định (training error rate) là 1 – 60% =
40%.

Chúng ta cũng có thể tính tỉ lệ sai sót huấn luyện với mẫu huấn luyện 1000 quan sát. Đương nhiên
con số này không trùng với kết quả 38.97% vì lúc này chúng ta chỉ sử dụng 1000 chứ không phải toàn
bộ các quan sát. Trong R chúng ta thực hiện như sau (không hiển thị kết quả):

pred <- predict(mod_fit, newdata = training)


confusionMatrix(data = pred, training$smoker)

Kết quả này chỉ ra rằng tỉ lệ sai sót huấn luyện là 1 - 0.6104 = 38.96%. Con số này thấp hơn một chút
so với việc sử dụng toàn bộ dữ liệu.

Khi nói đến tỉ lệ sai sót huấn luyện và tỉ lệ sai sót kiểm định, ở chương 4 chúng đã biết đến hiện tượng
gọi là quá khớp (overfiting). Theo James et al. (2013), đây là hiện tượng xẩy ra khi mô hình của chúng
ta rất phù hợp với dữ liệu huấn luyện (tức tỉ lệ sai sót huấn luyện rất thấp) nhưng lại không phù hợp
với dữ liệu kiểm định (tức tỉ lệ sai sót kiểm định là cao). Thông thường chúng ta kì vọng rằng nếu tồn
tại một mô hình mà tỉ lệ sai sót huấn luyện rất thấp thì cũng sẽ dẫn đến tỉ lệ sai sót kiểm định cũng
thấp. Thật đáng tiếc là không có gì đảm bảo cho sự tương quan này cả và gần như không có quy tắc
vàng hay chỉ dẫn cụ thể nào cho ta tìm được một mô hình tối ưu cho tất cả các tình huống.

Gói caret còn cung cấp cho ta một số hàm có thể chỉ ra những manh mối để cải thiện khả năng dự báo
của mô hình bằng lệnh varImp(). Lệnh này cho biết tầm quan trọng của các biến số đối với mô hình
mà chúng ta xây dựng:

varImp(mod_fit)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


389

## glm variable importance


##
## Overall
## educ 100.00
## age 95.34
## pcigs79 37.29
## income 0.00

Chúng ta cũng có thể hình ảnh hóa tầm quan trọng của các biến số này:

plot(varImp(mod_fit))

Như đã nói, lệnh varImp()cho biết mức độ quan trọng và vai trò của các biến độc lập đối với khả năng
phân loại của mô hình. Chúng ta thử lại xem mô hình với hai chỉ biến age và educ thì sức mạnh giải
thích của mô hình thay đổi ra sao (không hiển thị kêt quả):

haibien <- train(smoker ~ age + educ, data = training,


method = "glm", family = "binomial")
pred <- predict(haibien, newdata = testing)
confusionMatrix(data = pred, testing$smoker)

Việc loại bỏ các biến không quan trọng ở mô hình Logistic có thể làm tăng mức độ chính xác của mô
hình dự báo như chúng ta có thể thấy: từ 60% lên 62.56%.

Chúng ta cũng có thể đánh giá tỉ lệ sai sót huấn luyện cho mô hình mới (không hiện kết quả):

pred <- predict(haibien, newdata = training)


confusionMatrix(data = pred, training$smoker)

Chúng ta có thể thấy rằng tỉ lệ sai sót huấn luyện tăng lên một chút so với mô hình có 4 biến ban đầu.
Tình huống này một lần nữa nhắc nhở bạn về vấn đề overfiting: mô hình sau có tỉ lệ sai sót huấn luyện
tăng nhưng tỉ lệ sai sót kiểm định lại giảm. Nghĩa là mức độ dự báo (hút thuốc hay không hút thuốc)
có tính chính xác tăng lên. Thực tế, nếu công việc của chúng ta là tập trung vào dự báo một quan sát
cụ thể có hút thuốc hay không thì chúng ta nên ưu tiên mô hình mà tối thiểu hóa tỉ lệ sai sót kiểm
định.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


390

Một vấn đề khác là việc lựa chọn dữ liệu huấn luyện có ảnh hưởng đến mức độ chính xác trong dự
báo. Câu hỏi là cần lấy tỉ lệ nào cho dữ liệu huấn luyện? Nếu dữ liệu là lớn thì tỉ lệ phân chia là 50/50.
Nếu dữ liệu là bé thì tỉ lệ này là 80/20 hoặc 70/30. Tất nhiên còn nhiều chi tiết tinh tế của việc chọn
tỉ lệ nhưng vấn đề này vượt quá khuôn khổ của tài liệu này. Bạn đọc có thể tìm hiểu thêm trong tài
liệu về gói caret và đặc biệt là cuốn Applied Predictive Modeling của Max Kuhn.

Ở trên chúng ta đã thấy rằng mô hình chỉ có hai biến là age và educ tạo cho tỉ lệ chính xác trong dự
báo cao hơn so với sử dụng toàn bộ bốn biến số age, educ, income và pcigs79. Vậy phải chăng với mục
đích dự báo chúng ta nên sử dụng mô hình hai biến số là age và educ hay một sự kết hợp nào đó từ 4
biến số age, educ, income và pcigs79 ?.

Để trả lời câu hỏi này, chúng ta cần trả lời câu hỏi sau: phải chăng tỉ lệ chính xác cao hơn ở trên mang
tính phổ quát chứ không phải chỉ là một trường hợp ngẫu nhiên?. Để giải thích rõ hơn điều này chúng
ta hãy xem xét một ví dụ mang tính giả thuyết dưới đây.

Tại Hà Nội có hai trường kinh tế lớn là NEU và Đại Học Ngoại Thương (FTU). Là một trường được
tách ra từ NEU nhưng giới sinh viên truyền tai nhau rằng sinh viên FTU ra trường làm việc sẽ được
ưu ái hơn và lương cao hơn. Để kiểm tra nhận định này, một nghiên cứu chọn 10 sinh viên mỗi trường
và tính mức lương trung bình của họ. Dưới đây là hai mẫu khảo sát của 10 sinh viên đến từ hai trường
cùng trung bình mức lương của hai nhóm:

ftu <- c(1, 1, 1, 1, 1, 1, 1, 1, 1, 91)


neu <- c(4, 5, 4, 6, 4, 4, 5, 6, 5, 6)
mean(ftu); mean(neu)

## [1] 10

## [1] 4.9

Như vậy mức lương trung bình dựa trên mẫu khảo sát của 10 sinh viên NEU chỉ là 4.9 – con số chưa
bằng một nửa so với sinh viên đến từ FTU. Phải chăng nhận định rằng tốt nghiệp FTU thì sẽ có mức
lương trung bình cao hơn? Câu tra lời, theo quan điểm thống kê, là ngược lại. Thực vậy, sử dụng kiểm
định t để đánh giá khác biệt trung bình ta có:

t.test(ftu, neu)
## Welch Two Sample t-test
##
## data: ftu and neu
## t = 0.5664, df = 9.017, p-value = 0.5849
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -15.26318 25.46318
## sample estimates:
## mean of x mean of y
## 10.0 4.9

Vì p-value = 0.5849 > 5% nên chúng ta có thể thấy rằng sự chênh lệnh về mức lương trung bình trên
là không có ý nghĩa thống kê. Giải thích như thế này là dễ hiểu hơn: nếu chọn từng cặp 1 – 1 sinh viên
đến từ hai trường thì chúng ta sẽ có 9 tình huống mức lương của của sinh viên NEU cao hơn sinh viên

Nguyễn Chí Dũng http://rpubs.com/chidungkt


391

FTU so với 1 tình huống mức lương của sinh viên FTU cao hơn sinh viên NEU. Nguyên nhân là mức
lương trùng bình 10 triệu được quyết định bởi một quan sát rất bất thường có giá trị 91 trong khi 9
sinh viên FTU khac có mức lương chỉ 1 triệu mà thôi.Ví dụ trực quan này một lần nữa nhắc nhở các
bạn về suy nghĩ thống kê (statistical thinking).

Trở lại với câu hỏi ban đầu của chúng ta. Mức dự báo của mô hình có 2 biến số cao hơn mô hình 4
biến số như chúng ta vừa thấy ở trên chỉ là một tình huống cá biệt. Chúng ta cần đánh giá xem liệu
điều này có mang tính phổ quát hay không. Dưới đây là R code để đánh giá có có hay không tồn tại
tính chất phổ quát này. Trước hết ta chạy hai mô hình:

ctrl <- trainControl(method = "repeatedcv", number = 10, repeats = 10,


classProbs = TRUE, summaryFunction = defaultSummary)
set.seed(123)
# Mô hình chỉ 2 biến:
logit2bien <- train(smoker ~ educ + age, data = dung,
method = "glm", family = "binomial", trControl = ctrl)
# Mô hình cả 4 biến:
logit4bien <- train(smoker ~., data = dung,
method = "glm", family = "binomial", trControl = ctrl)

Ở đây chúng ta chạy cả hai mô hình với 1196 các quan sát đồng thời sử dụng kiểm tra chéo 10 lớp
(number=10), lặp lại 10 lần (repeats=10) với lựa chọn method="repeatedcv". Lựa chọn
classProbs=TRUE áp dụng cho mô hình phân loại và lựa chọn summaryFunction=defaultSummary để
chỉ thị R tính toán chỉ 2 thông tin về phầm chất của mô hình là Accuracy và Kappa. Với những lựa
chọn này chúng ta biết rằng sẽ có tất cả 100 bộ dữ liệu kiểm định, 100 bộ dữ liệu huấn luyện, 100
mô hình con cho mỗi mô hình 2 và 4 biến và chúng sẽ được sử dụng để chạy và đánh giá hai mô
hình.

Kế tiếp ta lấy ra các data frame gồm các thông tin về phẩm chất của mô hình (bao gồm Accuracy và
trị số Kappa). Tuy nhiên ở đây chúng ta chỉ quan tâm đến mức độ chính xác toàn cục Accuracy mà
thôi:

a <- logit2bien$resample # Lấy các thông tin về Accuracy của mô hình 2 biến.
a <- a[, -3]
a$Mohinh="Logit2"
b <- logit4bien$resample
b <- b[, -3]
b$Mohinh <- "Logit4"
resamplemod <- rbind(a, b) # Hợp nhất hai data frame a và b.

Trước khi đi vào các phân tích sâu hơn chúng ta thực hiện một số phân tích hình ảnh:

library(ggplot2); library(ggthemes); library(gridExtra)


h1 <- ggplot(resamplemod) +
geom_boxplot(aes(x = Mohinh, y = Accuracy, fill = Mohinh))+
coord_flip() + geom_hline(yintercept = 0.6196, color = "blue") +
theme_wsj()
h2 <- ggplot(resamplemod, aes(Accuracy, fill=Mohinh)) +

Nguyễn Chí Dũng http://rpubs.com/chidungkt


392

geom_density(alpha = 0.3) + theme_wsj() + facet_wrap(~Mohinh)


grid.arrange(h1, h2, ncol = 2, nrow = 1)

Từ phân tích hình ảnh này chúng ta có hai nhận định sau:

 Khả năng phân loại của cả hai mô hình đều kém. Thể hiện ở không một mô hình nào có mức
độ chính xác lớn hơn 61.96% (đường thẳng đứng màu xanh).
 Mức độ chính xác cao hơn của mô hình 2 biến số so với mô hình 4 biến số chỉ là một tình
huống cá biệt và do vậy không có tính phổ quát thể hiện ở boxplot màu xanh (ứng với mô hình
4 biến) có Q2 lệnh về phía phải hơn so với boxplot màu hồng (ứng với mô hình 2 biến).

Để chắc chắc chắn hơn cho những nhận định trên chúng ta sử dụng kiểm định t để đánh giá sự khác
biệt về Accuracy (mức độ chính xác) của hai mô hình:

t.test(resamplemod$Accuracy ~ resamplemod$Mohinh)

##
## Welch Two Sample t-test
##
## data: resamplemod$Accuracy by resamplemod$Mohinh
## t = -1.35, df = 196.53, p-value = 0.1786
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -0.013396089 0.002508585
## sample estimates:
## mean in group Logit2 mean in group Logit4
## 0.5984358 0.6038795

Vì p-value = 0.1786 > 5% nên chúng ta thấy rằng không có bằng chứng thống kê cho thấy không có
sự khác biệt về mức độ chính xác trong phân loại của hai mô hình. Chú ý rằng mức độ chính xác trung
bình 59.84% ứng với mô hình 2 biến và 60.39% của mô hình 4 biến là được tính toán trên 100 trường
hợp khác nhau vì chúng ta thực hiện kiểm định chéo 10 lớp và thực hiện lại 10 lần. Những giá trị trung
bình này có thể tính theo một cách khác:

summary(a)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


393

## Accuracy Kappa Mohinh


## Min. :0.5417 Min. :-0.121075 Length:100
## 1st Qu.:0.5825 1st Qu.:-0.033333 Class :character
## Median :0.5934 Median : 0.009656 Mode :character
## Mean :0.5984 Mean : 0.008165
## 3rd Qu.:0.6167 3rd Qu.: 0.044121
## Max. :0.6555 Max. : 0.136788

summary(b)

## Accuracy Kappa Mohinh


## Min. :0.5167 Min. :-0.10526 Length:100
## 1st Qu.:0.5882 1st Qu.:-0.00973 Class :character
## Median :0.6042 Median : 0.02550 Mode :character
## Mean :0.6039 Mean : 0.02884
## 3rd Qu.:0.6226 3rd Qu.: 0.07753
## Max. :0.6667 Max. : 0.20319

Cũng có thể thực hiện kiểm định t xem có sự khác biệt về tiêu chí Kappa giữa hai mô hình không theo
cách hoàn toàn tương tự.

Chúng ta cũng có thể sử dụng hiệu chỉnh Bonferroni (Bonferroni correction) một thủ tục thống kê
tương tự kiểm định t của gói caret để đánh đưa ra bằng chứng thống kê cho sự khác biệt về mức độ
chính xác của hai mô hình.

13.2.2 Một số tiêu chí đánh giá chất lượng của mô hình Logistic
13.2.2.1 Kiểm định Hosmer-Lemeshow
Kiểm định này còn có tên gọi là kiểm định sự phù hợp của mô hình (Goodness of fit test) và được diễn
giải rất trừu tượng tại trang 410 sách giáo trình của NEU. Kiểm định này có thể được diễn giải đơn
giản hơn như sau. Nó kiểm định có hay không các xác suất dự báo cho các quan sát (hút thuốc hay
không hút thuốc) là tương tự với các quan sát trong thực tế. Nếu kiểm định này có giá trị p-value bé
hơn, chẳng hạn, 5% thì mô hình của chúng ta có mức độ dự báo kém. Cặp giả thuyết của kiểm định
này là:

H0: Các xác suất dự báo là tương tự với các quan sát trong thực.

H1: Các xác suất dự báo là khác với các quan sát trong thực.

Chúng ta sử dụng gói Mkmisc để thực hiện kiểm định này như sau:

library(MKmisc)
HLgof.test(fit = fitted(logit), obs = dung$smoker) # Thực hiện kiểm định
Hosmer-Lemeshow về độ phù hợp của mô hình.

## $C
##
## Hosmer-Lemeshow C statistic
##
## data: fitted(logit) and dung$smoker

Nguyễn Chí Dũng http://rpubs.com/chidungkt


394

## X-squared = 16.302, df = 8, p-value = 0.03825


##
##
## $H
##
## Hosmer-Lemeshow H statistic
##
## data: fitted(logit) and dung$smoker
## X-squared = 15.642, df = 8, p-value = 0.04781

Giá trị p-value thu được là bé hơn 5% nên chúng ta có bằng chứng thống kê bắc bỏ H0. Nói cách khác
mô hình là không phù hợp. Đáng chú ý là với mô hình Logistic nói riêng và các mô hình phân loại khác,
kiểm định này ít được sử dụng vì nhiều lý do. Thay vào đó, với các mô hình phân loại, bao gồm mô
hình Logistic người ta hay sử dụng các tiêu chí được trình bày dưới đây.

13.2.2.2 Các tiêu chí khác đo lường khả năng phân loại của mô hình
Các tiêu chí đo lường khả năng phân loại (hay dự báo của mô hình), ngoài Accuracy mà chúng ta đã
tìm hiểu sơ bộ ở mục trên, thì còn có các tiêu chí khác là Sensitivity, Specificity, Pos Pred Value, Neg
Pred Value, AUC, và hệ số Gini. Các tiêu chí này không chỉ được sử dụng để đánh giá mô hình Logistic
nói riêng mà còn được sử dụng để đánh giá các mô hình phân loại nói chung.

Để diễn giải chi tiết hơn ý nghĩa của các tiêu chí này chúng ta trở lại với mô hình mod_fit ở mục 13.2.1
với một số thay đổi nhỏ sau: chúng ta dựng mô hình với toàn bộ dữ liệu. Mọi diễn giải sẽ không có gì
thay đổi nếu bạn áp dụng cho dữ liệu kiểm định hoặc dữ liệu huấn luyện:

mod_fit <- train(smoker~., data = dung, method = "glm", family = "binomial")


pred <- predict(mod_fit, newdata = dung)
confusionMatrix(data = pred, dung$smoker)

## Confusion Matrix and Statistics


##
## Reference
## Prediction Nonsmoker Smoker
## Nonsmoker 663 382
## Smoker 78 73
##
## Accuracy : 0.6154
## 95% CI : (0.5871, 0.6431)
## No Information Rate : 0.6196
## P-Value [Acc > NIR] : 0.6292
##
## Kappa : 0.0633
## Mcnemar's Test P-Value : <2e-16
##
## Sensitivity : 0.8947

Nguyễn Chí Dũng http://rpubs.com/chidungkt


395

## Specificity : 0.1604
## Pos Pred Value : 0.6344
## Neg Pred Value : 0.4834
## Prevalence : 0.6196
## Detection Rate : 0.5543
## Detection Prevalence : 0.8737
## Balanced Accuracy : 0.5276
##
## 'Positive' Class : Nonsmoker

Ý nghĩa của một số tiêu chí chính thu được từ ma trận nhầm lẫn này là:

 Mô hình xác định đúng 663 người không hút thuốc và xếp nhầm 382 người không hút thuốc
thành hút thuốc, nghĩa là mức độ chính xác bằng 63.44%. Con số này có thể tìm thấy ở dòng
Pos Pred Value.

 Mô hình xác định đúng 73 người hút thuốc và xếp nhầm 78 người hút thuốc thành không hút
thuốc, nghĩa là mức độ chính xác bằng 48.34%. Con số này có thể tìm thấy ở dòng Neg Pred
Value.

 Mô hình phân loại đúng tất cả (663 + 73) trong tổng số (663 + 73 + 382 + 78) quan sát, đạt
mức độ chính xác toàn cục là 61.65 %. Con số này có thể tìm thấy ở dòng Accuracy.

 Tỉ số giữa những người không hút thuốc mà mô hình xác định đúng chia cho số người không
hút thuốc thực tế trong mẫu là 663 / (663 +78) = 89.47%. Có thể nói mô hình xác định đúng
tới gần 90% người không hút thuốc – một con số ấn tượng. Giá trị này có thể tìm ở dòng
Sensitivity (còn gọi là độ nhạy).

 Tỉ số giữa những người hút thuốc mà mô hình xác định đúng chia cho tổng số người hút thuốc
thực tế trong mẫu là 73 / (73+ 382) = 16.04%. Có thể nói mô hình tuy dự báo rất tốt người
không hút thuốc nhưng lại dự báo rất tồi người hút thuốc. Con số này có thể tìm thấy ở dòng
Specificity (còn gọi là độ đặc hiệu). Chúng ta có thể tính toán lại trực tiếp như sau:

table(dung$smoker)

##
## Nonsmoker Smoker
## 741 455

663 / (663 + 78) # Tính Sensitivity

## [1] 0.8947368

73 / (382 + 73) # Tính Specificity

## [1] 0.1604396

Nguyễn Chí Dũng http://rpubs.com/chidungkt


396

Ngoài các tiêu chí mà chúng ta có thể thấy trực tiếp từ ma trận nhầm lẫn khi sử dụng gói caret, chúng
ta còn sử dụng hai tiêu chí khác là AUC và hệ số Gini. Để hiểu ý nghĩa của hai đại lượng này trước hết
chúng ta cần hiểu về đường ROC (viết tắt của Receiver Operating Characteristics):

Ở đây các bạn chú ý hai điều: (1) trục hoành của đường là (1 – Specificcity) còn trục tung là Sensitivity
và chỉ nằm trong khoảng từ 0 đến 1. Một mô hình có khả năng phân loại tốt là mô hình mà có đường
ROC này càng lồi về phía trên. Chú ý rằng phần diện tích của hình nằm phía dưới đường ROC nằm từ
0 đến 1 và được gọi là AUC – viết tắt của Area Under the Curve. Căn cứ vào AUC, một mô hình phân
loại sẽ được đánh giá như sau:

AUC Đánh giá mô hình


0.9 - 1.0 Rất tốt
0.8 - 0.9 Tốt
0.7 - 0.8 Chấp nhận được
0.7 - 0.6 Kém
Dưới 0.6 Không sử dụng được

Còn hệ số Gini, vốn ít sử dụng hơn, là một đại lượng phái sinh của AUC và được tính bằng:

Gini = 2AUC -1

Để tính toán hai hệ số này chúng ta phải sử dụng gói pROC.

library(pROC)
pred1 <- predict(mod_fit, newdata = dung, type = "prob")
trangyeu <- roc(dung$smoker, pred1$Smoker)
trangyeu$auc # Tính AUC

## Area under the curve: 0.6366

Do AUC là 0.637 nên mô hình của chúng ta được xếp là phân loại kém. Chúng ta cũng có thể vẽ đường
ROC cũng như biểu diễn phần diện tích này:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


397

# ROC thô không làm trơn:


plot(trangyeu, print.thres = "best", col = "red", print.au = TRUE,
auc.polygon = TRUE, auc.polygon.col = "greenyellow", identity = F)

## Call:
## roc.default(response = dung$smoker, predictor = pred1$Smoker)
##
## Data: pred1$Smoker in 741 controls (dung$smoker Nonsmoker) < 455 cases (du
ng$smoker Smoker).
## Area under the curve: 0.6366

Chúng ta cũng có thể “làm trơn” đường ROC đồng thời tính xấp xỉ AUC ứng với đường làm trơn này.
Chú ý rằng AUC thực (không làm tròn) vẫn là 0.637 chứ không phải 0.631 như hình hiển thị:

# ROC được làm trơn:


plot(smooth(trangyeu), print.thres = "best", col = "red", print.auc = TRUE,
auc.polygon = TRUE, auc.polygon.col = "greenyellow", identity = F)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


398

## Call:
## smooth.roc(roc = trangyeu)
##
## Data: pred1$Smoker in 741 controls (dung$smoker Nonsmoker) < 455 cases (du
ng$smoker Smoker).
## Smoothing: binormal
## Area under the curve: 0.6315

Chúng ta cũng có thể tính hệ số Gini:

2*(trangyeu$auc) - 1

## [1] 0.2732363

Tiêu chí AUC (đánh giá mức độ lồi về phía trên của đường ROC) cũng là một tiêu chuẩn thường sử
dụng khi so sánh các mô hình phân loại với nhau.

13.3 Mô hình Logistic đa cấp độ


Với các trường hợp mà biến phụ thuộc là biến nhị phân (chỉ nhận một trong hai giá trị 0 hoặc 1, hoặc
một trong hai phản hồi là no và yes) thì chúng ta sẽ sử dụng mô hình logistic nhị phân như vừa trình
bày ở trên. Trong tình huống mà biến phụ thuộc có nhiều cấp độ chúng ta sẽ sử dụng hồi quy Logistic
đa cấp độ (Multinomial Logistic Regression).

Chúng ta xét ví dụ sau đây. Sau khi tốt nghiệp phổ thông học sinh Mĩ có ba lựa chọn để học tiếp. Một
là và các trường danh giá như Harvard (gọi là academic), hai là và các trường nghề (vocation) và cuối
cùng là trường đại cương (general). Chúng ta sẽ nghiên cứu xem ảnh hưởng của điểm viết (write) và
tầng lớp xã hội (ses) ảnh hưởng như thế nào đến việc chọn trường (prog) của học sinh. Chúng ta sử
dụng bộ dữ liệu có tên nghiyeu.dta gồm 200 quan sát để phân tích. Đây là bộ dữ liệu được lấy từ
chương 3 cuốn Applied Logistic Regression của Hosmer và Lemeshow. Trước hết chúng ta cần cài đặt
gói nnet. Sau khi cài đặt chúng ta có thể thực hiện các phân tích cần thiết.
library(foreign); library(tidyverse); library(nnet)
dung <- read.dta("nghiyeu.dta")

Chúng ta có thể xem xu hướng chọn trường theo tầng lớp xã của họ:
table(dung$ses, dung$prog)

##
## general academic vocation
## low 16 19 12
## middle 20 44 31
## high 9 42 7

Chúng ta có thể tính điểm write trung bình cũng như độ lệch chuẩn của thí sinh ứng với từng nhóm
trường mà họ thi vào:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


399

dung %>% group_by(prog) %>%


summarise_each(funs(mean, sd), write)

## # A tibble: 3 x 3
## prog write_mean write_sd
## <fctr> <dbl> <dbl>
## 1 general 51.33333 9.397775
## 2 academic 56.25714 7.943343
## 3 vocation 46.76000 9.318754

Đúng như kì vọng các thí sinh thi vào trường academic sẽ có điểm trung bình cho write cao và độ lệch
chuẩn bé. Các bạn có thể thấy điều này qua điểm thi vào bác sĩ đa khoa của Y Hà Nội và Y Thái Bình.
Dưới đây là câu lệnh thực hiện hồi quy Logistic đa cấp độ trong R. Mấu chốt của là chúng ta chọn một
trường làm mốc so sánh. Ở đây là chọn nhóm trường academic. Về nguyên tắc các bạn có thể chọn
bất kì nhóm trường nào làm chuẩn so sánh.
dung$nhom1 <- relevel(dung$prog, ref = "academic")
mohinh <- multinom(nhom1 ~ ses + write, data = dung) # Chạy Multinomial
Logistic Regression.

## # weights: 15 (8 variable)
## initial value 219.722458
## iter 10 value 179.982880
## final value 179.981726
## converged

summary(mohinh)

## Call:
## multinom(formula = nhom1 ~ ses + write, data = dung)
##
## Coefficients:
## (Intercept) sesmiddle seshigh write
## general 2.852198 -0.5332810 -1.1628226 -0.0579287
## vocation 5.218260 0.2913859 -0.9826649 -0.1136037
##
## Std. Errors:
## (Intercept) sesmiddle seshigh write
## general 1.166441 0.4437323 0.5142196 0.02141097
## vocation 1.163552 0.4763739 0.5955665 0.02221996
##
## Residual Deviance: 359.9635
## AIC: 375.9635

Chúng ta diễn giải một số kết quả thu được của mô hình như sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


400

 Khi write tăng lên 1 điểm thì khả năng học khối trường general (tính bằng log odds) giảm
0.058 với chuẩn so sánh là trường khối academic.
 Khi write tăng lên 1 điểm thì khả năng học khối trường vocation (tính bằng log odds) giảm
0.1136 với chuẩn so sánh là trường khối academic.
 Nếu thí sinh thuộc tâng lớp thượng lưu (seshigh) thì thì khả năng học khối trường general
(tính bằng log odds) giảm 1.163 với chuẩn so sánh là trường khối academic.

Chúng ta cũng có thể tính các giá trị p-value cho các hệ số:
z <- summary(mohinh)$coefficients / summary(mohinh)$standard.errors
pvalue <- (1 - pnorm(abs(z), 0, 1))*2
pvalue

## (Intercept) sesmiddle seshigh write


## general 0.0144766100 0.2294379 0.02373856 6.818902e-03
## vocation 0.0000072993 0.5407530 0.09894976 3.176045e-07

Tỉ số giữa xác suất chọn một khối trường cụ thể so với xác suất lựa chọn trường khối academic (chúng
ta chọn khối trường này làm chuẩn) được gọi là rủi ro tương đối (relative risk). Chúng ta tính rủi ro
tương đối này:
exp(coef(mohinh))

## (Intercept) sesmiddle seshigh write


## general 17.32582 0.5866769 0.3126026 0.9437172
## vocation 184.61262 1.3382809 0.3743123 0.8926116

Chúng ta cũng có thể tính xác suất ước lượng của việc học khối trường nào cho 6 quan sát cuối:
xs <- fitted(mohinh)
tail(xs)

## academic general vocation


## 195 0.8370332 0.1178875 0.04507931
## 196 0.8559136 0.1073591 0.03672735
## 197 0.6864017 0.1814304 0.13216795
## 198 0.7508140 0.1574097 0.09177625
## 199 0.7200349 0.1694997 0.11046543
## 200 0.6685375 0.1872473 0.14421521

Điều này nghĩa là xác suất ước lượng cho việc học trường khối academic đối với quan sát thứ 195 là
bằng 0.837.
Chúng ta cũng có thể tính các xác suất ước lượng trung bình (averaged predicted probabilities) của
việc học khối trường nào tương ứng với ba tầng lớp xã hội tương ứng với các giá trị khác nhau của
biến liên tục write:
ses <- rep(c("low", "middle", "high"), each = 41)
write <- rep(c(30:70), 3)
dulieumoi <- data.frame(ses, write)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


401

pp.write <- cbind(dulieumoi, predict(mohinh, newdata = dulieumoi,


type = "probs", se = TRUE))
by(pp.write[, 3:5], pp.write$ses, colMeans)

## pp.write$ses: high
## academic general vocation
## 0.6164315 0.1808037 0.2027648
## --------------------------------------------------------
## pp.write$ses: low
## academic general vocation
## 0.3972977 0.3278174 0.2748849
## --------------------------------------------------------
## pp.write$ses: middle
## academic general vocation
## 0.4256198 0.2010864 0.3732938

Ngoài cách tính xác suất trung bình ước lượng ứng với ba tầng lớp xã hội như trên chúng ta cũng có
thể sử dụng công cụ hình ảnh:
lpp <- melt(pp.write, id.vars = c("ses", "write"), value.name = "Prob")
ggplot(lpp, aes(x = write, y = Prob, colour = ses)) + geom_line() +
facet_grid(variable ~ ., scales = "free")

Chúng ta có thể thấy rằng với nhóm high (màu đỏ) khi điểm write càng tăng thì khả năng học trường
khối acadamic cũng tăng theo và có mức xác suất cao nhất so với hai nhóm còn lại. Tuy nhiên tình

Nguyễn Chí Dũng http://rpubs.com/chidungkt


402

hình hoàn toàn đảo ngược nếu chúng ta xét khả năng học nhóm trường general và vocational. Đây là
một kết luận dễ đoán trước không những ở bối cảnh nước Mỹ mà cả ở Việt Nam.
Mô hình Logistic đa cấp độ như vừa trình bày ở trên trong thực tế ít được sử dụng hơn so với một số
mô hình khác. Một trong những nhược điểm của nó là việc diễn giải các kết quả thường phức tạp và
khó khăn. Một trong những tiếp cận thay thế và dễ hiểu hơn cho mô hình Logistic đa cấp độ là mô
hình cây phân loại được trình bày ở mục 13.8.

13.4 Mô hình Probit


Với các trường hợp mà biến phụ thuộc là biến nhị phân (chỉ nhận một trong hai giá trị 0 hoặc 1) chúng
ta cũng có thể sử dụng mô hình Probit thay vì sử dụng Logistic. Chúng ta trở sẽ sử dụng bộ số liệu
probit.dta để nghiên cứu mức độ được nhận vào học một trường đại học (admit = 1 nếu được nhận,
admit = 0 nếu khác) phụ thuộc như thế nào vào điểm GRE (biến gre), điểm GPA (biến gpa), và xếp
hạng của trường (biến rank có giá trị từ 1 đến 4 tương ứng với 4 nhóm trường). Trong R chúng ta có
thể chạy mô hình Probit với sự hỗ trợ của gói aod để thực hiện một số kiểm định liên quan như sau:
library(foreign); library(aod)
prob <- read.dta("probit.dta") %>% select(1:4)
str(prob)

## 'data.frame': 400 obs. of 4 variables:


## $ admit: int 0 1 1 1 0 1 1 0 1 0 ...
## $ gre : int 380 660 800 640 520 760 560 400 540 700 ...
## $ gpa : num 3.61 3.67 4 3.19 2.93 3 2.98 3.08 3.39 3.92 ...
## $ rank : int 3 3 1 4 4 2 1 2 3 2 ...

# Dể thuậ tiện nên dán lại nhãn cho nhóm trường,


# được nhập học ở dạng factor:
prob$rank <- recode_factor(prob$rank,
"1" = "top1",
"2" = "top2",
"3" = "top3",
"4" = "top4")

prob$admit <- recode_factor(prob$admit,


"0" = "Nonadmit",
"1" = "Admit")
# Xem qua bộ số liệu:
table(prob$admit)

##
## Nonadmit Admit
## 273 127

table(prob$rank, prob$admit)

##
## Nonadmit Admit
## top1 28 33
## top2 97 54

Nguyễn Chí Dũng http://rpubs.com/chidungkt


403

## top3 93 28
## top4 55 12

# Có thể tính một số thống kê theo từng nhóm:


prob %>%
group_by(rank) %>%
summarise_each(funs(M = mean, SD = sd), gre)

## # A tibble: 4 × 3
## rank M SD
## <fctr> <dbl> <dbl>
## 1 top1 611.8033 120.2429
## 2 top2 596.0265 107.0083
## 3 top3 574.8760 121.1481
## 4 top4 570.1493 116.2220

prob %>%
group_by(admit) %>%
summarise_each(funs(M = mean, SD = sd), gre)

## # A tibble: 2 × 3
## admit M SD
## <fctr> <dbl> <dbl>
## 1 Nonadmit 573.1868 115.8302
## 2 Admit 618.8976 108.8849

# Có vẻ tỉ lệ nhập học giảm theo hạng của trường:


with(prob, table(rank, admit))

## admit
## rank Nonadmit Admit
## top1 28 33
## top2 97 54
## top3 93 28
## top4 55 12

Ở trên là các câu lệnh phân tích sơ bộ số liệu. Sau khi phân tích sơ bộ chúng ta có thể chạy mô hình
Probit với lệnh glm tương tự như chạy mô hình Logit:
probit <- glm(admit ~ gre + gpa + rank,
family = binomial(link = "probit"), data = prob)
summary(probit)

##
## Call:
## glm(formula = admit ~ gre + gpa + rank, family = binomial(link = "probit")
,
## data = dung)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max

Nguyễn Chí Dũng http://rpubs.com/chidungkt


404

## -1.6163 -0.8710 -0.6389 1.1560 2.1035


##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.386836 0.673946 -3.542 0.000398 ***
## gre 0.001376 0.000650 2.116 0.034329 *
## gpa 0.477730 0.197197 2.423 0.015410 *
## ranktop2 -0.415399 0.194977 -2.131 0.033130 *
## ranktop3 -0.812138 0.208358 -3.898 9.71e-05 ***
## ranktop4 -0.935899 0.245272 -3.816 0.000136 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 499.98 on 399 degrees of freedom
## Residual deviance: 458.41 on 394 degrees of freedom
## AIC: 470.41
##
## Number of Fisher Scoring iterations: 4

Diễn đạt ý nghĩa của mô hình Probit là tương tự như đối với mô hình Logit. Cụ thể, nếu điểm GRE tăng
1 đơn vị thì xác suất được nhận học (tính theo Z-score) tăng 0.1376%. Riêng đối với các biến số cho
hạng của trường được diễn đạt hơi khác: xác suất nhận học vào trường nhóm 2 sẽ giảm 41.54% so
với trường nhóm 1 (là nhóm trường làm gốc so sánh).

Chúng ta có thể đánh giá tác động tổng thể thứ hạng của trường (overall effect of rank) có ảnh hưởng
hay không đến xác suất được nhận học bằng lệnh wald.test của gói oad. Chú ý rằng thứ tự hạng của
trường (hay thứ tự hệ số ứng với hạng của trường là từ 4 đến 6):
wald.test(b = coef(probit), Sigma = vcov(probit), Terms = 4:6)

## Wald test:
## Chi-squared test:
## X2 = 21.4, df = 3, P(> X2) = 8.9e-05

Giá trị của thống kê khi bình phương là 21.4 tương ứng với p-value rất bé nên chúng ta có kết luận
rằng tác động tổng thể về thứ hạng của trường lên khả năng được nhận học là tồn tại và có ý nghĩa
thống kê.

Tương tự chúng ta cũng có thể kiểm định xem liệu, chẳng hạn, trường thứ hạng 2 có tác động khác
biệt so với trường thứ hạng 3 lên xác suất được nhận học hay không:
kiemdinh <- cbind(0, 0, 0, 0, 1, -1)
wald.test(b = coef(probit), Sigma = vcov(probit), L = kiemdinh)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


405

## Wald test:
## Chi-squared test:
## X2 = 0.31, df = 1, P(> X2) = 0.58

Do giá trị p-value = 0.58 > 5% nên chúng ta có thể đưa ra bằng chứng rằng tác động thứ hạng của hai
nhóm trường này là khác biệt và có ý nghĩa thống kê.

Chúng ta cũng có thể sử dụng phân tích hình ảnh để đánh giá vai trò, chẳng hạn như điểm GRE đối với
khả năng nhận học khi các biến số khác cố định. Các câu lệnh dưới đây vẽ đồ thị biểu diễn mức xác
suất (tính theo điểm Z-score) theo biến gre ứng với 4 mức điểm GPA là 2.5, 3, 3.5, và 4 ứng với 4 nhóm
trường:
gre <- rep(seq(from = 200, to = 800, length.out = 100), 16)
gpa <- rep(c(2.5, 3, 3.5, 4), each = 400)
rank <- rep(c("top1", "top2", "top3", "top4"), each = 100)
dulieumoi <- data.frame(gre, gpa, rank)
str(dulieumoi)

## 'data.frame': 1600 obs. of 3 variables:


## $ gre : num 200 206 212 218 224 ...
## $ gpa : num 2.5 2.5 2.5 2.5 2.5 2.5 2.5 2.5 2.5 2.5 ...
## $ rank: Factor w/ 4 levels "top1","top2",..: 1 1 1 1 1 1 1 1 1 1 ...

dulieumoi[, c("XS", "se")] <- predict(probit,dulieumoi,


type = "response", se.fit = TRUE)[-3]
ggplot(dulieumoi, aes(gre, XS, colour = rank)) +
geom_line() + facet_wrap(~ gpa)

13.5 So sánh Probit và Logistic theo tiêu chí AUC


Thông thường các ước lượng thu được từ hai mô hình Probit và Logit là tương tự nhau. Điểm khác
biệt là xác suất có điều kiện của các pi khi tiến đến 0 hoặc 1 ở mô hình Logit sẽ có tốc độ chậm hơn so
với các xác suất tương ứng ở mô hình Probit. Trong thực tế nghiên cứu, thường thì không có lí do gì

Nguyễn Chí Dũng http://rpubs.com/chidungkt


406

đặc biệt để ưu tiêu lựa chọn mô hình này so với mô hình kia. Tuy nhiên các nhà nghiên cứu thường
chọn mô hình Logit do nó có lợi thế đơn giản về mặt toán học và diễn đạt các kết quả thuận tiện hơn
(Gujarati, 2011) cho các nghiên cứu mô tả, diễn giải. Để tìm hiểu kĩ hơn về mặt lý thuyết của các mô
hình Logistic, Probit cũng như các mô hình tương tự có thể đọc cuốn Giáo Trình Kinh Tế Lượng NEU
hoặc một số sách về kinh tế lượng khác.

Một trong những tiêu chí hay sử dụng khi đánh giá, so sánh các mô hình phân loại khác nhau là AUC
hay phần diện tích nằm dưới đường cong ROC (viết tắt của receiver operating characteristic). Chúng
ta trở lại với bộ số liệu ở mục 13.2 và so sánh hai mô hình phân loại là Logistic và Probit căn cứ vào
tiêu chí này. Để thuận lợi chúng ta sẽ sử dụng gói caret. Khác biệt ở đây là chúng ta sẽ sử dụng toàn
bộ các quan sát để đánh giá theo cách tiếp cận 10-folds cross-validation và lặp lại 10 lần. Như thế có
nghĩa là chúng ta sử dụng 9/10 toàn bộ quan sát để dựng mô hình, sử dụng 1/10 quan sát để đánh
giá mô hình. Do vòng này lặp lại 10 lần nên thực tế chúng ta có 100 mô hình “con” ứng với 100 bộ dữ
liệu huấn luyện và kiểm định. Các kết quả có được từ 100 mô hình này sẽ được sử dụng để đánh giá
hiệu quả phân loại của mô hình Logistic và Probit. Tiêu chí đánh giá và so sánh ở đây là AUC/ROC và
được thể hiện bằng lựa chọn metric = "ROC":
set.seed(2611)
ctrl <- trainControl(method = "repeatedcv", number = 10, repeats = 10,
classProbs = TRUE, summaryFunction = twoClassSummary)
# Chạy mô hình Logistic:
logistic <- train(smoker~., data = dung, method = "glm", family = "binomial",
trControl = ctrl, metric = "ROC")
# Chạy mô hình Probit:
probit <- train(smoker~., data = dung, method = "glm", family = "binomial"(li
nk = "probit"),
trControl = ctrl, metric="ROC")

Kế tiết chúng ta tạo trích ra một data frame tên là love chứa các thông tin về chất lượng của hai mô
hình. Chú ý rằng với lựa chọn thì data frame này ngoài ROC còn chứa các thông tin khác là Sens (viết
tắt của Sensitivity) và Spec (viết tắt của Specitivity):
m <- logistic$resample # Lấy các thông tin về Accuracy của mô hình 2 biến.
m$Mohinh <- "LOGISTIC"
n <- probit$resample
n$Mohinh <- "PROBIT"
love <- rbind(m, n) # Hợp nhất hai data frame a và b.

Thực hiện phân tích hình ảnh cho ROC:


h1 <- ggplot(love) + geom_boxplot(aes(x = Mohinh, y = ROC, fill = Mohinh)) +
coord_flip() + theme_wsj()
h2 <- ggplot(love, aes(ROC, fill = Mohinh)) + geom_density(alpha = 0.3) +
theme_wsj() + facet_wrap(~Mohinh)
grid.arrange(h1, h2, ncol = 2, nrow = 1)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


407

Có thể thấy sự khác biệt về ROC là không đáng kể. Chúng ta sử dụng kiểm định t để đánh giá sự khác
biệt này:
t.test(love$ROC~love$Mohinh)

##
## Welch Two Sample t-test
##
## data: love$ROC by love$Mohinh
## t = -0.042881, df = 194.24, p-value = 0.9658
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -0.01463692 0.01401398
## sample estimates:
## mean in group LOGISTIC mean in group PROBIT
## 0.6115125 0.6118240

Kết quả kiểm định t có p-value = 0.9658 là rất lớn nên chúng ta thấy rằng sự khác biệt về chất lượng
phân loại khi căn cứ vào ROC là không có ý nghĩa thống kê.

Tương tự, nếu muốn đánh giá các tiêu chí Sensitivity và Specitivity (hoặc bất cứ tiêu chí nào khác)
chúng ta cũng thực hiện hoàn toàn tương tự như trên.

13.6 Một vài nhận xét về chương 10 sách giáo trình


Cuốn giáo trình 2012 của NEU còn có thiếu sót trong việc cung cấp số liệu cũng như nguồn gốc số liệu.
Về mô hình xác suất tuyến tính LPM, Logit (còn gọi là Logistic), Probit trong sách tại trang 415 (và
một số ví dụ khác của chương này) có đề cập đến bộ số liệu mroz.wf1 thế nhưng bộ data của giáo
trình này không có file nào có tên như vậy. Chưa kể, các biến số, miêu tả các biến số là không đúng.
Người viết tài liệu này đã mất nhiều công sức để tìm kiếm bộ dữ liệu này và kết luận cuối cùng như
sau:
1. Bộ dữ liệu này được sử dụng trong sách của Wooldridge (2008) và Wooldridge (2013) với
tên MROZ.DTA cho cả hai lần ấn bản thứ 4 và 5 của cuốn Introductory Econometrics.
2. Bộ dữ liệu này còn được sử dụng bởi Gujarati (2011) với tên gọi khác là Table4_0.dta ở cuốn
Econometrics by Examples mà các bạn đã gặp ở mục 8.3 của chương 8.
Để minh hoạ cho thực hành trong chương này, tôi quyết định sử dụng bộ dữ liệu MROZ.DTA (dù rằng
MROZ.DTA và Table4_0.dta chính là một). Lý do là tôi muốn lặp lại các kết quả mà Wooldridge đã

Nguyễn Chí Dũng http://rpubs.com/chidungkt


408

trình bày tại trang 594 trong cuốn sách Introductory Econometrics ấn bản lần thứ 5. Chúng ta sử
dụng bộ dữ liệu này để đánh giá (dự báo) tình trạng tham gia lực lượng lao động của nữ giới (biến
inlf) phụ thuộc như thế nào vào trình độ giáo dục (biến educ), tuổi (biến age), kinh nghiệm (exper),
bình phương của kinh nghiệm (exper2), có con nhỏ hơn 6 tuổi (kidslt6), có con từ trên 6 đến 18 tuổi
(kidsge6), và thu nhập của chồng (nwifeinc). Ở đây biến phụ thuộc là inlf = 1 nếu tham gia lực lượng
lao động, = 0 nếu khác.

Dưới đây là các câu lệnh chạy cả ba mô hình LPM, Logit, và Probit cũng như so sánh chúng:
setwd("D:/KTLR")
library(foreign)
trang <- read.dta("MROZ.DTA")
str(trang) # Xem qua bộ dữ liệu.

## 'data.frame': 753 obs. of 22 variables:


## $ inlf : int 1 1 1 1 1 1 1 1 1 1 ...
## $ hours : int 1610 1656 1980 456 1568 2032 1440 1020 1458 1600 ...
## $ kidslt6 : int 1 0 1 0 1 0 0 0 0 0 ...
## $ kidsge6 : int 0 2 3 3 2 0 2 0 2 2 ...
## $ age : int 32 30 35 34 31 54 37 54 48 39 ...
## $ educ : int 12 12 12 12 14 12 16 12 12 12 ...

table(trang$inlf) # Xem có bao nhiêu người tham gia lực lượng lao động.

##
## 0 1
## 325 428

trang <- trang[, c(1, 20, 6, 19, 5, 3, 4)] # Chỉ lấy các biến cần thiết.
trang$exper2 <- (trang$exper)^2 # Tạo biến mới age2 bằng bình phương của age.
lpm <- lm(inlf ~., data = trang) # Chạy LPM.
trang$inlf <- factor(trang$inlf, levels = c("0", "1"),
labels = c("Une", "Emp"))
logit <- glm(inlf ~., family = binomial, data = trang)
probit <- glm(inlf ~., family = binomial(link="probit"), data = trang)
library(stargazer)
stargazer(lpm, logit, probit, title = "So sánh ba mô hình", type = "text")

## So sanh ba mô hình
## ===============================================================
## Dependent variable:
## -------------------------------------------
## inlf
## OLS logistic probit
## (1) (2) (3)
## ---------------------------------------------------------------
## nwifeinc -0.003** -0.021** -0.012**

Nguyễn Chí Dũng http://rpubs.com/chidungkt


409

## (0.001) (0.008) (0.005)


##
## educ 0.038*** 0.221*** 0.131***
## (0.007) (0.043) (0.025)
##
## exper 0.039*** 0.206*** 0.123***
## (0.006) (0.032) (0.019)
##
## age -0.016*** -0.088*** -0.053***
## (0.002) (0.015) (0.008)
##
## kidslt6 -0.262*** -1.443*** -0.868***
## (0.034) (0.204) (0.118)
##
## kidsge6 0.013 0.060 0.036
## (0.013) (0.075) (0.044)
##
## exper2 -0.001*** -0.003*** -0.002***
## (0.0002) (0.001) (0.001)
##
## Constant 0.586*** 0.425 0.270
## (0.154) (0.860) (0.508)
##
## ---------------------------------------------------------------
## Observations 753 753 753
## R2 0.264
## Adjusted R2 0.257
## Log Likelihood -401.765 -401.302
## Akaike Inf. Crit. 819.530 818.604
## Residual Std. Error 0.427 (df = 745)
## F Statistic 38.218*** (df = 7; 745)
## ===============================================================
## Note: *p<0.1; **p<0.05; ***p<0.01

Các bạn có thể đối chiếu với kết quả này với kết quả được Wooldridge trình bày tại trang 594 trong
cuốn sách Introductory Econometrics ấn bản lần thứ 5. Để khai thác thêm thông tin nhằm so sánh
các mô hình, chẳng hạn, giữa Probit là Logit căn cứ vào mức độ chính xác trong việc phân loại các bạn
có thể tạo ra ma trận nhầm lẫn (Confusion Matrix) như ở mục 13.2 của chương này.

13.7 Ứng dụng trong nghiên cứu của mô hình Logit và Probit và một số mô hình phân loại khác
cho xếp hạng tín dụng
Việc tái tạo (replicate) hay chí ít là mô phỏng các nghiên cứu của các tác giả đi trước là một việc cần
thiết. Tại chương 10, trang 440 sách giáo trình của NEU có đề cập đến một nghiên cứu của tác giả
Phan Lê Hà về xếp hạng tín dụng cho khách với mô hình Logit và Probit có tên “Assesing The

Nguyễn Chí Dũng http://rpubs.com/chidungkt


410

Effectiveness of Consumer Credit Scoring: The Case of a Leading Vietnam Commercial Bank” với
bộ số liệu mà giáo trình có đề cập là LEHA.wf1. Tuy nhiên, bộ số liệu thực hành đi kèm cuốn giáo trình
này không tồn tại bộ dữ liệu như miêu tả ở trên.

Để thay thế, tôi sử dụng bộ dữ liệu ở một nghiên cứu tương tự có tên “The comparisons of data
mining techniques for the predictive accuracy of probability of default of credit card clients” của
Yeh & Lien (2009). Nghiên cứu này có ở cơ sở dữ liệu của Sciencedirect:

http://www.sciencedirect.com/science/article/pii/S0957417407006719

Bộ dữ liệu của nghiên cứu này được lưu trữ ở cơ sở dữ liệu của University of California, Irvine. Bộ dữ
liệu này gồm các thông tin về hồ sơ tín dụng của 30000 khách hàng. Biến phụ thuộc ở đây là Y (với Y
= 1 nghĩa là khách hàng mất khả năng thanh toán, bằng 0 nếu khác). Các biến độc lập (cả định tính lẫn
định lượng từ X1 đến X23) với số lượng là 23. Các bạn có thể xem miêu tả chi tiết và download bộ dữ
liệu này tại:

https://archive.ics.uci.edu/ml/datasets/default+of+credit+card+clients

Tuy nhiên, để thuận lợi cho các bạn, tôi đã download bộ data này và gửi cùng bộ data của tài liệu này
với tên gọi credit.csv.

Chúng ta sẽ sử dụng bộ dữ liệu này để mô phỏng nghiên cứu của tác giả Phan Le Hà. Tuy nhiên, các
nghiên cứu thường thấy (bao gồm cả nghiên cứu này) khi sử dụng các mô hình phân loại (như Logit,
Probit) chưa đề cập đến hai khía cạnh sau.

Một là, chưa chỉ rõ tỉ lệ, hay mức độ chính xác của mô hình phân loại. Chẳng hạn, mức độ chính xác
phân loại đối với nhóm hồ sơ xấu là bao nhiêu ?.

Hai là, sử dụng chính tỉ lệ sai sót huấn luyện (hoặc một số tiêu chí khác như R2 của MacFadden) làm
tiêu chuẩn đánh giá mức độ chính xác của mô hình phân loại là một cách tiếp cận chưa chính xác vì
hai lý do dưới đây.

Thứ nhất, về khía cạnh lý thuyết, tỉ lệ sai sót huấn luyện thường có xu hướng bé hơn tỉ lệ sai sót kiểm
định và do đó với mục đích dự báo, sử dụng tỉ lệ sai sót huấn luyện làm tiêu chí đánh giá sức mạnh
phân loại của mô hình là chưa phù hợp (James et al., 2014; Kuhn, 2013).

Thứ hai, về khía cạnh thực tế, các ngân hàng ngoài quan tâm đến tỉ lệ chính xác trong phân loại và dự
báo hồ sơ xấu còn quan tâm đến hậu quả kinh tế (lãi hay lỗ) nếu sử dụng mô hình phân loại. Thực
vậy, một mô hình có tỉ lệ phân loại chính xác toàn cục cao chưa hẳn đã là mô hình tối ưu đối với
ngân hàng. Chúng ta sẽ nghiên cứu vấn đề này chi tiết trong mục này.

Trước hết, chúng ta mô phỏng nghiên cứu của tác giả Phan Lê Hà với bộ dữ liệu của Yeh & Lien (2009)
bằng mô hình Logit và Probit. Tuy nghiên cứu gốc của Yeh & Lien sử dụng toàn bộ 23 biến nhưng với
mục đính minh họa chúng ta chỉ sử dụng 8 biến độc lập là X1,X6, X18, X19, X20, X21, X22, và X23.
Ngoài ra, kích thước cho bộ dữ liệu kiểm định cũng như huấn luyện chỉ là 1000. Việc cắt giảm số biến
số, kích thước dữ liệu chỉ đơn thuần là lý do kĩ thuật: máy tính cần quá nhiều thời gian để thực hiện
một số mô hình phân loại. Nếu máy tính của bạn đủ mạnh và bạn đủ thời gian tôi khuyến khích các

Nguyễn Chí Dũng http://rpubs.com/chidungkt


411

bạn sử dụng cả 23 biến số như nghiên cứu gốc. Dưới đây là Rcode cho mô hình Probit và Logit cũng
như đánh giá mô hình:

setwd("E:/KTLR")
dung <- read.csv("credit.csv")
library(tidyverse)
# Dán lại nhãn cho biến mục tiêu được phân loại:
dung$Y <- recode_factor(dung$Y,
"1" = "Default",
"0" = "NonDefault")
head(dung, 2)

## id X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17


## 1 1 20000 2 2 1 24 2 2 -1 -1 -2 -2 3913 3102 689 0 0 0
## 2 2 120000 2 2 2 26 -1 2 0 0 0 2 2682 1725 2682 3272 3455 3261
## X18 X19 X20 X21 X22 X23 Y
## 1 0 689 0 0 0 0 Default
## 2 0 1000 1000 1000 0 2000 Default

# Loại biến id (thứ tự) và giữ lại 8 biến độc lập và Y:


dung <- dung %>% select(X1, X6, X18:X23, -id, Y)
# Xem qua dữ liệu:
dim(dung)

## [1] 30000 9

head(dung, 2)

## X1 X6 X18 X19 X20 X21 X22 X23 Y


## 1 20000 2 0 689 0 0 0 0 Default
## 2 120000 -1 0 1000 1000 1000 0 2000 Default

# Chỉ lấy 2000 quan sát bất kì trong bộ số liệu đầu:


set.seed(1709)
dung <- dung %>% sample_n(2000)

# Chia bộ dữ liệu thành hai phần bằng nhau (1000 cho mỗi phần):
library(caret)
set.seed(123)
indxTrain <- createDataPartition(y = dung$Y, p = 1 / 2, list = FALSE)
training <- dung[indxTrain, ]
testing <- dung[-indxTrain, ]
# Thiêt lập các lựa chọn thực hiện Cross-Validation:
set.seed(234)
ctrl <- trainControl(method = "repeatedcv",
number = 10,
repeats = 10,
classProbs = TRUE,
summaryFunction = multiClassSummary)
# Mô hình Logistic:
logistic <- train(Y ~.,

Nguyễn Chí Dũng http://rpubs.com/chidungkt


412

data = training,
method = "glm",
family = "binomial",
trControl = ctrl)
# Các tiêu chí đánh giá mô hình Logistic:
pred <- predict(logistic, newdata = testing)
confusionMatrix(data = pred, testing$Y)

## Confusion Matrix and Statistics


##
## Reference
## Prediction Default NonDefault
## Default 66 36
## NonDefault 184 714
##
## Accuracy : 0.78
## 95% CI : (0.753, 0.8053)
## No Information Rate : 0.75
## P-Value [Acc > NIR] : 0.0147
##
## Kappa : 0.2691
## Mcnemar's Test P-Value : <2e-16
##
## Sensitivity : 0.2640
## Specificity : 0.9520
## Pos Pred Value : 0.6471
## Neg Pred Value : 0.7951
## Prevalence : 0.2500
## Detection Rate : 0.0660
## Detection Prevalence : 0.1020
## Balanced Accuracy : 0.6080
##
## 'Positive' Class : Default
##

# Mô hình Probit:
probit <- train(Y ~.,
data = training,
method = "glm",
family = "binomial"(link = "probit"),
trControl = ctrl)

# Các tiêu chí đánh giá mô hình Probit:


pred <- predict(probit, newdata = testing)
confusionMatrix(data = pred, testing$Y)

## Confusion Matrix and Statistics


##
## Reference
## Prediction Default NonDefault

Nguyễn Chí Dũng http://rpubs.com/chidungkt


413

## Default 52 32
## NonDefault 198 718
##
## Accuracy : 0.77
## 95% CI : (0.7426, 0.7958)
## No Information Rate : 0.75
## P-Value [Acc > NIR] : 0.07626
##
## Kappa : 0.2123
## Mcnemar's Test P-Value : < 2e-16
##
## Sensitivity : 0.2080
## Specificity : 0.9573
## Pos Pred Value : 0.6190
## Neg Pred Value : 0.7838
## Prevalence : 0.2500
## Detection Rate : 0.0520
## Detection Prevalence : 0.0840
## Balanced Accuracy : 0.5827
##
## 'Positive' Class : Default
##

Chúng ta đọc kết quả phân tích như sau. Chẳng hạn với mô hình phân loại Probit, mô hình phân loại
đúng 52 hồ sơ xấu trong tổng số 52 + 32 = 84 hồ sơ xấu và do vậy mức độ chính xác trong phân loại
hồ sơ xấu chỉ là 52 / 84 = 61.9 % (giá trị Pos Pred Value). Tương tự mức độ chính xác trong phân loại
hồ sơ tốt của mô hình này là 78.38 % (giá trị Neg Pred Value). Tỉ lệ chính xác toàn cục (Accuracy) cho
phân loại là (52 + 718) / 1000 = 77%.

Nếu căn cứ vào tỉ lệ dự báo toàn cục thì mô hình phân loại Logit tốt hơn (78% so với 77%). Phải chăng
bạn sẽ kiến nghị ngân hàng sử dụng mô hình Logit cho phân loại thay vì Logit?. Câu trả lời là chưa hẳn
như vậy. Trong tình huống của chúng ta, là ngược lại. Thực vậy, nếu chúng ta giả thiết rằng cứ một hồ
sơ xấu mà ta phân loại thành hô sơ tốt, thì cho vay 1$ ngân hàng sẽ mất trắng 1$. Còn hồ sơ tốt mà
phân loại đúng là hồ sơ tốt thì cho vay 1$ ngân hàng chỉ thu về lãi là 0.1 $ (với giả thiết lãi 10 % và
ngân hàng không gánh chi phí nào khác). Chúng ta giả thiết rằng mỗi một hồ sơ được duyệt vay thi sẽ
được vay 1$. Nếu thế, chúng ta có thể tóm tắt kết quả như sau:

Phương Pháp Logit Probit


Xếp nhầm hồ sơ xấu 36 32
Xếp đúng hồ sơ tốt 714 718
Accuracy 78 % 77 %
Tổn Thất - 36 - 32
Lãi 71.4 71.8
Lãi ròng 35.4 39.8

Kết quả này chỉ ra rằng nếu sử dụng mô hình phân loại Probit – một mô hình phân loại kém chính xác
hơn mô hình Logit thì ngân hàng sẽ có nhiều lợi ích kinh tế hơn. Điều này xác nhận một lần nữa rằng:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


414

tiêu chí lựa chọn mô hình phân loại trong thực tế của ngân hàng chưa hẳn đã là căn cứ vào mô
hình phân loại chính xác nhất. Vì lãi ròng của ngân hàng nếu chấp nhận mô hình Probit là 39.8 $ lớn
hơn 35.4 $ so với lựa chọn mô hình Logit.

Nguyên nhân là cái giá phải trả khi xếp nhầm hồ sơ xấu thành hồ sơ tốt là cao hơn rất nhiều lần so
với xếp nhầm hồ sơ tốt. Nên một mô hình mặc dù có mức độ chính xác khi phân loại nói chung cao
hơn lại có thể chưa phải là mô hình mang lại lợi nhuận tối ưu vì có thể đó là mô hình mà xếp nhầm
hồ sơ xấu thành hồ sơ tốt với tỉ lệ cao hơn.

Tuy nhiên cần phải lưu lý rằng, mức lợi nhuận cao hơn khi sử dụng mô hình Probit cho phần loại mà
chúng ta thấy ở đây liệu có tính phổ quát hay không vẫn là một câu hỏi. Vì chúng ta mới chỉ đánh giá
hai mô hình chỉ với một mẫu được chọn mà thôi (là testing data). Nghĩa là, với bộ số liệu mới, không
có gì chắc chắn rằng sử dụng Probit sẽ mang lại nhiều lợi nhuận hơn cho ngân hàng. Chúng ta sẽ
nghiên cứu cách tiếp cận theo ngôn ngữ của khoa học thống kê nhằm đưa ra câu trả lời cho câu hỏi
trên ở mục 13.8.2 . Điểm khác biệt ở đây là thay vì so sánh Logistic với Probit, chúng ta so sánh Logistic
với một mô hình có tên cây phân loại. Việc áp dụng trở lại cho so sánh Logistic với Probit là hoàn toàn
tương tự.

Có thể đánh giá các thước đo đánh giá phẩm chất của hai mô hình Logit và Probit qua phân tích
hình ảnh. Những thông tin về các thước đo đánh giá phẩm chất của hai mô hình này thu được từ 100
mẫu con do chúng ta đã thực hiện 10-fold cross-validation và lặp lại quá trình này 10 lần:

# Lưu lại các tiêu chí đánh giá phẩm chất của 2 mô hình:
r1 <- logistic$resample
r2 <- probit$resample
# Các tiêu chí đánh giá hai mô hình và xem qua:
total <- rbind(r1, r2) %>%
mutate(Model = c(rep("Logistic", 100), rep("Probit", 100)))
head(total[, 1:6])

## logLoss AUC Accuracy Kappa F1 Sensitivity


## 1 2.824719 0.6645333 0.78 0.2280702 0.3125000 0.20
## 2 2.549266 0.5717333 0.75 0.1071429 0.1935484 0.12
## 3 2.616163 0.6266667 0.76 0.2131148 0.3333333 0.24
## 4 2.487841 0.7386667 0.83 0.4137931 0.4848485 0.32
## 5 2.559137 0.5648000 0.77 0.2068966 0.3030303 0.20
## 6 2.650957 0.6336000 0.74 0.1475410 0.2777778 0.20

# Loại cột biến Resample và chuyển về long form:


r1 <- r1 %>%
select(-Resample) %>%
gather(Indicator, Value)

# Vẽ Density cho các tiêu chí đánh giá


# phẩm chất của mô hình Logistic:
r1 %>%
ggplot(aes(Value)) +
geom_density(alpha = 0.3,
show.legend = FALSE,

Nguyễn Chí Dũng http://rpubs.com/chidungkt


415

color = "blue", fill = "blue") +


facet_wrap(~ Indicator, scales = "free") +
theme_bw() +
labs(x = NULL,
y = NULL)

# Vẽ Density cho các tiêu chí đánh giá


# phẩm chất của mô hình Probit (không hiển thị hình ảnh):
r2 %>%
select(-Resample) %>%
gather(Indicator, Value) %>%
ggplot(aes(Value)) +
geom_density(alpha = 0.3,
show.legend = FALSE,
color = "blue", fill = "blue") +
facet_wrap(~ Indicator, scales = "free") +
theme_bw() +
labs(x = NULL,
y = NULL)

# Về Box Plot cho cả 11 tiêu chí đánh giá


# Logistic (làm tương tự cho Probit):
r1 %>%
ggplot(aes(0, Value)) +
geom_boxplot(outlier.colour = "red",
color = "blue",
fill = "blue",
alpha = 0.3) +
facet_wrap(~ Indicator,
scales = "free",
ncol = 6, nrow = 2) +

Nguyễn Chí Dũng http://rpubs.com/chidungkt


416

theme_bw() +
theme(axis.title.x=element_blank(),
axis.text.x=element_blank(),
axis.ticks.x=element_blank())

Có thể đánh gía hình ảnh về Accuracy cho hai mô hình dựa trên 100 mẫu con đồng thời sử dụng kiểm
định t để đưa ra bằng chứng thống kê:

# Đánh giá Accuracy:


total %>% ggplot(aes(Accuracy, fill = Model, colour = Model)) +
geom_density(alpha = 0.3) +
theme_bw()

Căn cứ vào hình ảnh này có thể thấy mức độ chính xác toàn cục của Logistic có thể là cao hơn. Để đưa
ra bằng chứng thống kê cho nhận định trên có thể sử dụng kiểm định t:

t.test(total$Accuracy ~ total$Model)

##
## Welch Two Sample t-test
##
## data: total$Accuracy by total$Model
## t = 4.0803, df = 197.77, p-value = 6.522e-05

Nguyễn Chí Dũng http://rpubs.com/chidungkt


417

## alternative hypothesis: true difference in means is not equal to 0


## 95 percent confidence interval:
## 0.006665305 0.019134695
## sample estimates:
## mean in group Logistic mean in group Probit
## 0.7768 0.7639

Kết quả chỉ ra rằng sự khác biệt về mức độ chính xác khi phân loại của hai mô hình là có ý nghĩa
thống kê.

13.8 Lựa chọn mô hình phù hợp cho bài toán phân loại – xếp hạng hồ sơ tín dụng
Dựa trên những phân tích ở mục 13.7 chúng ta rút ra một số kết luận dưới đây:

 Để tối đa hóa lợi nhuận, hay chí ít là mang lại lợi ích kinh tế tốt nhất có thể (cho ngân hàng)
thì mô hình có mức độ phân loại chính xác toàn cục cao nhất chưa chắc đã là mô hình được
lựa chọn.

 Việc so sánh phẩm chất của mô hình dựa trên một tiêu chí được lựa chọn (ví dụ như lợi nhuận,
mức độ chính xác chung) không thể dựa vào CHỈ MỘT mẫu.

Để có cách tiếp cận hơn trong việc lựa chọn mô hình phân loại chúng ta viết một hàm thực hiện việc
đánh giá phẩm chất của hai mô hình Logit và Probit dựa trên thử nghiệm (hay chạy) với, ví dụ, 100
mẫu khác nhau rồi ghi lại các tiêu chí đánh giá phẩm chất của hai mô hình này. Mẫu này phải là
những quan sát không thuộc dữ liệu huấn luyện (training) để tránh overfitting - tức là hiện tượng mà
mô hình thì rất khớp với dữ liệu đã có nhưng lại dự báo (khớp) rất tồi với dữ liệu mới. Các quy ước ở
đây là:

1. GG nghĩa là hồ sơ là tốt được phân loại đúng là tốt (Good - Good).

2. GB là hồ sơ là tốt nhưng xác phân loại sai thành xấu (Good - Bad).

3. Tự suy ra cho các kí hiệu khác.

# Viết hàm:
my_validation <- function(mohinh, ti_le, solanlap, dulieu, ...) {
luu_kq <- data.frame()
for (i in 1:solanlap) {
set.seed(i)
id <- createDataPartition(y = dulieu$Y, p = ti_le, list = FALSE)
test <- dulieu[id, ]
pred <- predict(mohinh, newdata = test)
u <- confusionMatrix(pred, test$Y, positive = "Default")
k <- as.vector(u$table)
luu_kq <- rbind(luu_kq, k)
tenmoi <- c("BB", "GB", "BG", "GG")
names(luu_kq) <- tenmoi
}
return(luu_kq)
}

Nguyễn Chí Dũng http://rpubs.com/chidungkt


418

Sử dụng hàm vừa viết trong đó chạy 100 lần với 50% bộ dữ liệu testing. Chú ý rằng số cách lấy ra
50% mẫu từ testing là tổ hợp 150 của 300 (một con số rất lớn):

# Khả năng phân loại các nhóm hồ sơ của Logistic:


df1 <- my_validation(logistic, 0.5, 100, testing)
# Khả năng phân loại các nhóm hồ sơ của Probit:
df2 <- my_validation(probit, 0.5, 100, testing)
# Hợp nhất df1 và df2 đồng thời tạo cột biến mới:
df1 <- df1 %>% mutate(Model = "Logistic")
df2 <- df2 %>% mutate(Model = "Probit")
all_df <- bind_rows(df1, df2)
# Tính lợi nhuận tương ứng và tỉ lệ chính xác Accuracy:
all_df <- all_df %>% mutate(Profit = 0.1*GG - BG,
Accuracy = (GG + BB) / (GG + BB + GB + BG))

# Tinh toán Profit và Accuracy trung bình


# (cùng các thống kê khác) ứng với 100 mẫu con này:

all_df %>%
group_by(Model) %>%
summarise_each(funs(mean, min, max, sd), Profit)

## # A tibble: 2 x 5
## Model Profit_mean Profit_min Profit_max Profit_sd
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Logistic 18.569 11.1 25.4 3.310336
## 2 Probit 20.747 13.3 26.5 3.106769

all_df %>%
group_by(Model) %>%
summarise_each(funs(mean, min, max, sd), Accuracy)

## # A tibble: 2 x 5
## Model Accuracy_mean Accuracy_min Accuracy_max Accuracy_sd
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Logistic 0.78144 0.762 0.804 0.009398388
## 2 Probit 0.77122 0.748 0.792 0.009073861

Kết quả trên chỉ ra rằng: khi chạy thử nghiệm trên 100 mẫu con lấy ra từ dữ liệu kiểm định (testing)
thì Accuracy của Logistic cao hơn nhưng mô hình mang lại nhiều lợi nhuận hơn cho ngân hàng chính
là Probit – một mô hình có mức độ chính xác toàn cục trong phân loại thấp hơn.

Chúng ta có thể thực hiện các phân tích hình ảnh minh họa cho kết quả thu được ở trên:

# Thực hiện phân tích hình ảnh cho Profit với box plot:
all_df %>% ggplot(aes(Model, Profit, fill = Model, color = Model)) +
geom_boxplot(alpha = 0.4, show.legend = FALSE) + theme_bw()

Nguyễn Chí Dũng http://rpubs.com/chidungkt


419

# Thực hiện phân tích hình ảnh cho Accuracy với box plot (không hiển thị):
all_df %>% ggplot(aes(Model, Accuracy, fill = Model, color = Model)) +
geom_boxplot(alpha = 0.4, show.legend = FALSE) + theme_bw()

13.9 Mô hình cây phân loại và so sánh với mô hình Logistic


13.9.1 Giới thiệu về mô hình cây phân loại
Như chúng ta có thể thấy ở mục 13.3, mô hình Logistic đa cấp độ có thể áp dụng cho tình huống biến
được phân loại có nhiều hơn 2 nhãn khác nhau. Tuy vậy, việc diễn giải các kết quả thu được là khá
phức tạp và rắc rối. Mục này chúng ta sẽ nghiên cứu một mô hình thay thế cho Logistic đa cấp độ và
so sánh chất lượng của nó với mô hình Logistic truyền thống là mô hình cây phân loại (Classification
Tree) theo cách tiếp cận của Breiman et al., (1984). Đây là một phương pháp phân loại có tuổi đời trẻ
so với các mô hình phân loại khác. Là một phương pháp phân loai mạnh có cơ sở lý thuyết hoàn thiện,
trước đây việc áp dụng mô hình cây là hạn chế do khối lượng tính toán lớn. Tuy nhiên, ở hiện tại, sức
mạnh tính toán của máy tính đã được cải thiện rất nhiều so với khoảng 30 năm trước đây nên việc sử
dụng mô hình này cho giải quyết các vấn đề thực tế đang trở nên ngày càng phổ biến. Nhiều phần
mềm, như SPSS có tích hợp tính năng phân tích mô hình cây. Tuy nhiên, sức mạnh phân tích của SPSS
cho mô hình cây là rất hạn chế.

Để minh họa về mô hình này, chúng ta xét bộ số liệu có tên iris của Fisher (1936). Đây là bộ số liệu
gồm 150 quan sát về 3 loài hoa diên vĩ (setosa, versicolor, virginica - biến định tính Species) với số
lượng như nhau. Mục tiêu của chúng ta là tìm cách phân loại ba giống hoa diên vĩ này căn cứu vào các
thông tin như chiều dài cuống hoa, chiều rộng cuống hoa… Đây là bộ dữ liệu nổi tiếng và xuất hiện
nhiều trong các sách về thống kê, Machine Learning cũng như các sách về Statistical Learning và Data
Mining. Bộ dữ liệu này luôn tồn tại khi cài đặt R:
data("iris")
dim(iris)

## [1] 150 5

str(iris)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


420

## 'data.frame': 150 obs. of 5 variables:


## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1
1 1 1 1 ...

Trước hết chúng ta sẽ sử dụng gói rpart để thực hiện mô hình cây cho phân loại kết hợp với hàm
train() của gói caret:
set.seed(2611)
indxTrain <- createDataPartition(y = iris$Species, p = 8 / 10, list = FALSE)
training <- iris[indxTrain, ]
testing <- iris[-indxTrain, ]
library(rpart)
trang <- rpart(Species ~., data = training, method = "class") # Chạy mô hình
cây bằng gói rpart.
trang # Để xem kết quả của mô hình.

## n= 120
##
## node), split, n, loss, yval, (yprob)
## * denotes terminal node
##
## 1) root 120 80 setosa (0.33333333 0.33333333 0.33333333)
## 2) Petal.Length< 2.45 40 0 setosa (1.00000000 0.00000000 0.00000000) *
## 3) Petal.Length>=2.45 80 40 versicolor (0.00000000 0.50000000 0.50000000
)
## 6) Petal.Width< 1.75 43 4 versicolor (0.00000000 0.90697674 0.0930232
6) *
## 7) Petal.Width>=1.75 37 1 virginica (0.00000000 0.02702703 0.97297297
) *

Kết quả thu được từ mô hình trình bày theo cách này là khó đọc. Chúng ta làm cho việc này sáng tỏ
hơn một cách hình ảnh với sự hỗ trợ của gói rpart.plot:

library(rpart.plot)
rpart.plot(trang, legend.x = 0.7)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


421

Ý nghĩa của sơ đồ này như sau. Nếu chiều dài cuống hoa mà bé hơn 2.4 thì đó là loài sesota. Các con
số 1.00 0.00 0.00 ở ô màu đỏ ngụ ý rằng loài này được phân loại chính xác 100%, sai số là 0%, và
chiếm 33% toàn bộ mẫu huấn luyện. Nếu chiều dài cuốn hoa lớn hơn hoặc bằng 2.4 thì “tạm” xếp
chúng thành loài versicolor. Với nhóm được xếp tạm này, lại căn cứ vào chiều rộng cuống hoa. Cụ thể:
nếu bé hơn 1.8 thì chúng thuộc versicolor và được xếp loại chính xác đến 91% và do vậy tỉ lệ phân
loại sai là 9%. Còn nếu lớn hơn hoặc bằng 1.8 thì chúng thuộc loại virginica và được xếp loại chính
xác đến 97% ứng với tỉ lệ sai sót 3%. Sơ đồ trên cũng có thể được vẽ bằng một kiểu khác nhưng ý
nghĩa vẫn không đổi:
library(rattle)
fancyRpartPlot(trang) # Cách vẽ thứ khác với sự trợ giúp của gói rattle.

Chú ý rằng các tỉ lệ chính xác – sai sót mà chúng ta vừa thấy là cho bộ dữ liệu huấn luyện. Cái chúng
ta quan tâm là mức độ chính xác của mô hình phân loại này cho bộ dữ liệu kiểm định:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


422

pred1 <- predict(trang, training, type = "class")


confusionMatrix(pred1, training$Species) # Tính sai sót huấn luyện

## Confusion Matrix and Statistics


##
## Reference
## Prediction setosa versicolor virginica
## setosa 40 0 0
## versicolor 0 39 4
## virginica 0 1 36
##
## Overall Statistics
##
## Accuracy : 0.9583
## 95% CI : (0.9054, 0.9863)
## No Information Rate : 0.3333
## P-Value [Acc > NIR] : < 2.2e-16
##
## Kappa : 0.9375
## Mcnemar's Test P-Value : NA
##
## Statistics by Class:
##
## Class: setosa Class: versicolor Class: virginica
## Sensitivity 1.0000 0.9750 0.9000
## Specificity 1.0000 0.9500 0.9875
## Pos Pred Value 1.0000 0.9070 0.9730
## Neg Pred Value 1.0000 0.9870 0.9518
## Prevalence 0.3333 0.3333 0.3333
## Detection Rate 0.3333 0.3250 0.3000
## Detection Prevalence 0.3333 0.3583 0.3083
## Balanced Accuracy 1.0000 0.9625 0.9438

13.9.2 So sánh mô hình cây phân loại và Logistic dựa trên hậu quả kinh tế của việc sử dụng

Chúng ta sẽ nghiên cứu khả năng áp dụng của mô hình này trong thực tế với bộ số liệu có tên
GermanCredit. được tích hợp cùng gói caret. Đây là bộ số liệu về 1000 đơn xin vay tín dụng của một
ngân hàng Đức và được sử dụng ở nhiều nghiên cứu về các mô hình phân loại, xếp hạng tín dụng.
Thông tin đầu vào để lấy căn cứ phân loại là 61 biến số khác nhau, bao gồm cả định tính lẫn định
lượng. Các hồ sơ sẽ được xếp loại Good hoặc Bad (biến Class). Với mục đích minh họa, chúng ta sẽ chỉ
sử dụng các biến độc lập có vị trí ở cột thứ 1,2,5, và 9. Biến ở vị trí thứ 10 là Class. Tất nhiên các bạn
có thể sử dụng toàn bộ các biến số để xay dựng mô hình nhưng việc này sẽ đòi hỏi máy tính nhiều
thời gian để chạy:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


423

data("GermanCredit")
trang <- GermanCredit[, c(1, 2, 5, 9, 10)]
str(trang)

## 'data.frame': 1000 obs. of 5 variables:


## $ Duration : int 6 48 12 42 24 36 24 36 12 30 ...
## $ Amount : int 1169 5951 2096 7882 4870 9055 2835 6948 3059 5234 .
## $ Age : int 67 22 49 45 53 35 53 35 61 28 ...
## $ ForeignWorker: num 1 1 1 1 1 1 1 1 1 1 ...
## $ Class : Factor w/ 2 levels "Bad","Good": 2 1 2 2 1 2 2 2 2 1 ...

Để so sánh khả năng dự báo của mô hình cây là logistic cũng như một số tiêu chí khác, trước hết chúng
ta đánh giá sơ bộ cho hai mô hình này cho một tình huống cụ thể. Dưới đây chúng ta chia bộ số liệu
thành hai phần. Dữ liệu huấn luyện và dữ liệu kiểm định được lấy theo tỉ lệ 70/30:

indxTrain <- createDataPartition(y = trang$Class, p = 0.7, list = FALSE)


training <- trang[indxTrain, ]
testing <- trang[-indxTrain, ]
credit <- rpart(Class ~., data = training, method = "class")
fancyRpartPlot(credit)

pred <- predict(credit, testing, type = "class")


confusionMatrix(pred, testing$Class)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


424

## Confusion Matrix and Statistics


##
## Reference
## Prediction Bad Good
## Bad 16 21
## Good 74 189
##
## Accuracy : 0.6833
## 95% CI : (0.6274, 0.7356)
## No Information Rate : 0.7
## P-Value [Acc > NIR] : 0.7572
##
## Kappa : 0.0935
## Mcnemar's Test P-Value : 9.55e-08
##
## Sensitivity : 0.17778
## Specificity : 0.90000
## Pos Pred Value : 0.43243
## Neg Pred Value : 0.71863
## Prevalence : 0.30000
## Detection Rate : 0.05333
## Detection Prevalence : 0.12333
## Balanced Accuracy : 0.53889
##
## 'Positive' Class : Bad
##

mod_fit <- train(Class ~., data = training,


method = "glm",
family = "binomial")
pred <- predict(mod_fit, newdata=testing)
confusionMatrix(data = pred, testing$Class)

## Confusion Matrix and Statistics


##
## Reference
## Prediction Bad Good
## Bad 8 9
## Good 82 201
##
## Accuracy : 0.6967
## 95% CI : (0.6412, 0.7482)
## No Information Rate : 0.7
## P-Value [Acc > NIR] : 0.5781
##

Nguyễn Chí Dũng http://rpubs.com/chidungkt


425

## Kappa : 0.0599
## Mcnemar's Test P-Value : 4.432e-14
##
## Sensitivity : 0.08889
## Specificity : 0.95714
## Pos Pred Value : 0.47059
## Neg Pred Value : 0.71025
## Prevalence : 0.30000
## Detection Rate : 0.02667
## Detection Prevalence : 0.05667
## Balanced Accuracy : 0.52302
##
## 'Positive' Class : Bad
##

So sánh sơ bộ chúng ta có thể thấy mô hình Logistic có vẻ chiếm ưu thế về mức độ chính xác. Mặt
khác, chúng ta hãy xem hiệu quả về mặt kinh tế nếu ngân hàng sử dụng những mô hình xếp hạng tín
dụng này. Với giả thiết là lãi 10%, lợi nhuận của ngân hàng sẽ là -11.55 và -2.1. Nghĩa là Logistic chiếm
ưu thế hơn khi căn cứ cả hai khía cạnh là chính xác trong phân loại và tiêu chí lợi nhuận.

Câu hỏi còn lại là: phải chăng kết luận trên có tính phổ quát và ngân hàng nên sử dụng Logistic?.

Để đảm bảo rằng ưu thế này của mô hình Logistic không phải là một trường hợp cá biệt của mẫu kiểm
định, dưới đây là một vòng lặp chạy 100 lần cả hai mô hình này với dữ liệu kiểm định và huấn luyện
được chia theo tỉ lệ 70:30. Cũng như mục 13.8, các tiêu chí đánh giá mô hình được lựa chọn là:
Accuraccy, số lượng hồ sơ xấu xếp nhầm thành tốt (kí hiệu BG) và số lượng hồ sơ tốt xếp chính xác
thành tốt (kí hiệu là GG) và đương nhiên là lợi nhuận của ngân hàng khi sử dụng các mô hình phân
loại tín dụng khác nhau. Như vậy cứ mỗi một mô hình chúng ta có 100 giá trị cho cả bốn tiêu chí này
và sẽ được đánh giá bằng kiểm định t về sự khác biệt về giá trị trung bình giữa chúng.

Dưới đây là R code để thực hiện đánh giá chất lượng của hai mô hình. Chắc chắn nó là một thử thách
với trí não của bạn, nhất là với những ai chưa bao giờ lập trình (viết code, programming). Nhưng tôi
tin bạn đủ kiên trì và cố gắng để hiểu chúng. Chú ý rằng có thể mất rất nhiều thời gian để chạy chương
trình dưới đây:

total1 <- data.frame()


total2 <- data.frame()
ctrl <- trainControl(method = "repeatedcv", number = 5, repeats = 5,
classProbs = TRUE, summaryFunction = defaultSummary)
n <- 100 # Thiết lập vòng lặp
for (i in 1:n){
set.seed(i)
indxTrain <- createDataPartition(y = trang$Class, p = 7 / 10, list = FALSE)
training <- trang[indxTrain, ]
testing <- trang[-indxTrain, ]
# Chạy logistic
logistic <- train(Class ~., data = training, method = "glm",

Nguyễn Chí Dũng http://rpubs.com/chidungkt


426

family = "binomial", trControl = ctrl)


pred <- predict(logistic, newdata = testing)
log <- confusionMatrix(data = pred, testing$Class)
# Tạo ma trận các thông tin về phẩm chất mô hình Logistic:
love <- log$overall
you <- log$byClass
love <- data.frame(love)
you <- data.frame(you)
love <- as.data.frame(t(love))
you <- as.data.frame(t(you))
# Tạo các thông tin về BG và GG từ Logistic:
dung <- log$table
dungmt <- as.data.frame.matrix(dung)
love$BG <- dungmt[1, 2]
love$GG <- dungmt[2, 2]
# Sau đó gán vào love:
totalLOG <- merge(love, you)
total1 <- rbind(total1, totalLOG)
# Chạy mô hình cây phân loại:
tree <- train(Class ~., data = training, method = "rpart", trControl = ctrl)
pred <- predict(tree, newdata = testing)
caypl <- confusionMatrix(data = pred, testing$Class)
# Tạo ma trận các thông tin về phẩm chất mô hình cây:
love <- caypl$overall
you <- caypl$byClass
love <- data.frame(love)
you <- data.frame(you)
love <- as.data.frame(t(love))
you <- as.data.frame(t(you))
# Tạo các thông tin về BG và GG từ mô hình cây phân loại:
dung <- caypl$table
dungmt <- as.data.frame.matrix(dung)
love$BG <- dungmt[1, 2]
love$GG <- dungmt[2, 2]
totalTREE <- merge(love,you)
total2 <- rbind(total2, totalTREE)
}
total1$Mohinh <- rep("Logistic", n)
total2$Mohinh <- rep("Tree", n)
total <- rbind(total1, total2)

Muốn biết những phẩm chất nào của mô hình được lưu trong data frame có tên total:

names(total)

## [1] "Accuracy" "Kappa" "AccuracyLower"


## [4] "AccuracyUpper" "AccuracyNull" "AccuracyPValue"
## [7] "McnemarPValue" "BG" "GG"
## [10] "Sensitivity" "Specificity" "Pos Pred Value"

Nguyễn Chí Dũng http://rpubs.com/chidungkt


427

## [13] "Neg Pred Value" "Prevalence" "Detection Rate"


## [16] "Detection Prevalence" "Balanced Accuracy" "Mohinh"

Đến đây chúng ta có thể thực hiện phân tích hình ảnh cũng như kiểm định t cho ba tiêu chí lựa chọn
là Accuracy, BG, và GG như đã làm ở mục 13.8:

library(ggplot2); library(gridExtra)
a <- ggplot(total, aes(Mohinh, Accuracy, colour = Mohinh)) + geom_boxplot()
b <- ggplot(total, aes(Accuracy, fill = Mohinh)) + geom_density(alpha = 0.3)
grid.arrange(a, b, ncol = 2, nrow = 1)

Từ hình ảnh thu được có thể nhận định rằng Logistic là mô hình có mức độ phân loại chính xác toàn
cục cao hơn. Thực hiện kiểm định t để đánh giá sự khác biệt này:
t.test(total$Accuracy ~ total$Mohinh)

##
## Welch Two Sample t-test
##
## data: total$Accuracy by total$Mohinh
## t = 3.8757, df = 192.9, p-value = 0.0001457
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## 0.002979321 0.009154012
## sample estimates:
## mean in group Logistic mean in group Tree
## 0.7057333 0.6996667

Kết quả này chỉ ra rằng Accuracy (mức độ chính xác toàn cục) của mô hình cây là kém hơn và kết luận
này có ý nghĩa thống kê do p-value là rất bé. Đáng chú ý là sự sai khác này rất bé.

Tương tự chúng ta thực hiện phân tích hình ảnh và kiểm định t cho BG và GG:

m <- ggplot(total, aes(Mohinh, BG, colour = Mohinh)) + geom_boxplot()


n <- ggplot(total, aes(BG, fill = Mohinh)) + geom_density(alpha = 0.3)
grid.arrange(m, n, ncol = 1, nrow = 2)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


428

t.test(total$BG ~ total$Mohinh)

##
## Welch Two Sample t-test
##
## data: total$BG by total$Mohinh
## t = 3.0517, df = 151.29, p-value = 0.002688
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## 0.8884666 4.1515334
## sample estimates:
## mean in group Logistic mean in group Tree
## 8.98 6.46

x <- ggplot(total, aes(Mohinh, GG, colour = Mohinh)) + geom_boxplot()


y <- ggplot(total, aes(GG, fill = Mohinh)) + geom_density(alpha = 0.3)
grid.arrange(x, y, ncol = 1, nrow = 2)

t.test(total$GG ~ total$Mohinh)

##
## Welch Two Sample t-test
##
## data: total$GG by total$Mohinh
## t = -3.0517, df = 151.29, p-value = 0.002688
## alternative hypothesis: true difference in means is not equal to 0

Nguyễn Chí Dũng http://rpubs.com/chidungkt


429

## 95 percent confidence interval:


## -4.1515334 -0.8884666
## sample estimates:
## mean in group Logistic mean in group Tree
## 201.02 203.54

Từ những kết quả này các bạn rút ra những kết luận cực kì quan trọng sau.

Thứ nhất, có sự khác biệt về khả năng dự báo hai loại hồ sơ và kết luận này có ý nghĩa thống kê. Cụ
thể là mô hình Logistic có mức độ chính xác toàn cục khi phân loại tín dụng cao hơn.

Nhưng có đúng là ngân hàng sẽ chấp nhận mô hình này? Câu trả lời hơi bất ngờ: ngược lại. Các bạn có
thể thấy ngay sau đây.

Với giả thiết rằng mỗi hồ sơ phân loại đúng mang lại lợi nhuận 10%, một hồ sơ xếp nhầm thì ngân
hàng mất trắng vốn và cứ giả định rằng mỗi một hồ sơ vay 1 USD , ta tính lợi nhuận của ngân hàng
ứng với các mô hình rồi thực hiện phân tích hình ảnh cho lợi nhuận:

total$loinhuan <- total$GG*0.1 - total$BG # Tính lợi nhuận.


u <- ggplot(total, aes(Mohinh, loinhuan, colour = Mohinh)) + geom_boxplot()
v <- ggplot(total, aes(loinhuan, fill = Mohinh)) + geom_density(alpha = 0.3)
grid.arrange(u, v, ncol = 2, nrow = 1)

Rõ ràng, hình ảnh mà cho thấy câu chuyện ngược lại: nếu ngân hàng sử dụng mô hình cây thì lợi nhuận
thu được sẽ cao hơn. Chúng ta cần đánh giá xem liệu kết luận này có ý nghĩa thống kê – tức có tính
phổ quát bằng kiểm định t:

t.test(total$loinhuan ~ total$Mohinh)

##
## Welch Two Sample t-test
##
## data: total$loinhuan by total$Mohinh
## t = -3.0517, df = 151.29, p-value = 0.002688
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -4.5666867 -0.9773133
## sample estimates:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


430

## mean in group Logistic mean in group Tree


## 11.122 13.894

Đến đây chúng ta có kết luận thứ hai rằng ngân hàng luôn luôn có lợi ích kinh tế lớn hơn khi sử
dụng mô hình cây cho phân loại bất kể là mô hình Logistic có mức độ dự báo toàn cục tốt hơn.

Nghiên cứu nhỏ này một lần nữa khẳng định rằng: một mô hình phân loại có mức độ chính xác toàn
cục cao hơn chưa phải là một mô hình tối ưu đối với ngân hàng về mặt kinh tế. Đây là sự khác biệt
giữa thực tiễn và lý thuyết.

Tất nhiên, việc chúng ta giả định rằng mỗi một hồ sơ chỉ vay 1 USD là một giả thuyết yếu. Ngoài ra,
một hồ sơ tốt được duyệt vay vẫn có thể không trả lại vốn được cho ngân hàng với một xác suất nào
đó. Còn cho vay hồ sơ xấu thì ngân hàng vẫn thu lại vốn với mức xác suất (tuy thấp) nào đó.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


431

Chương 14: Mô hình có biến bị kiểm duyệt: Tobit và hồi quy Poisson

Chương 12 chúng ta đã nghiên cứu các mô hình mà biến phụ thuộc là biến nhị phân (biến định tính hai
cấp độ), hoặc là biến định tính nhiều cấp độ. Chương này chúng ta sẽ nghiên cứu hai nhóm mô hình mà
ở đó biến phụ thuộc bị một “ràng buộc” hay “giới hạn” nào đó về giá trị. Chúng ta xét hai mô hình cụ thể
là mô hình hồi quy Tobit và Poisson.

Lý thuyết và các khía cạnh khác của hai mô hình này các bạn có thể tìm thấy ở bất kì cuốn kinh tế lượng
nhập môn nào, chẳng hạn, cuốn sách giáo trình kinh tế lượng của NEU, tại chương 10.

14.1 Mô hình Tobit


Mô hình Tobit còn gọi là mô hình hồi quy biến bị kiểm duyệt (censored regression model), theo đó
biến phụ thuộc bị kiểm duyệt phía trái (censoring from below) hoặc bị kiểm duyệt phía phải
(censoring from above) với hàm ý rằng biến phụ thuộc bị chặn dưới hoặc bị chặn trên. Với bộ số liệu
MROZ.DTA mà chúng ta đã đề cập ở các phần trước, giả sử chúng ta muốn đánh giá tác động của các
biến độc lập nwifeinc, educ, exper, exper2, age, kidslt6, và kidsge6 lên hours (số giờ làm việc) của 753
phụ nữ thì rõ ràng biến hours trong bị kiểm duyệt phía trái: biến hours > 0. Trong tình huống này,
chúng ta có thể sử dụng mô hình Tobit. Dưới đây là các lệnh trong R thực hiện mô hình hồi quy biến
bị kiểm duyệt với sự trợ giúp của gói censReg cũng như so sánh với OLS thông thường:
setwd("D:/KTLR")
library(foreign)
trang <- read.dta("MROZ.DTA")
trang <- trang[, c(2, 20, 6, 19, 5, 3, 4)]
trang$exper2 <- (trang$exper)^2
library(censReg) # Gọi gói censReg với giả sử bạn đã cài đặt gói này.
tobit <- censReg(hours ~., data = trang, left = 0) # Chạy Tobit Model.
ols <- lm(hours ~., data = trang)
library(stargazer)
stargazer(ols, tobit, title = "So sanh OLS và Tobit", type = "text")
## So sanh OLS và Tobit
## =======================================================
## Dependent variable:
## -----------------------------------
## hours
## OLS censored
## regression
## (1) (2)
## -------------------------------------------------------
## nwifeinc -3.447 -8.814**
## (2.544) (4.459)
##
## educ 28.761** 80.646***

Nguyễn Chí Dũng http://rpubs.com/chidungkt


432

## (12.955) (21.583)
##
## exper 65.673*** 131.564***
## (9.963) (17.279)
##
## age -30.512*** -54.405***
## (4.364) (7.419)
##
## kidslt6 -442.090*** -894.022***
## (58.847) (111.878)
##
## kidsge6 -32.779 -16.218
## (23.176) (38.641)
##
## exper2 -0.700** -1.864***
## (0.325) (0.538)
##
## logSigma 7.023***
## (0.037)
##
## Constant 1,330.482*** 965.305**
## (270.785) (446.436)
## -------------------------------------------------------
## Observations 753 753
## R2 0.266
## Adjusted R2 0.259
## Log Likelihood -3,819.095
## Akaike Inf. Crit. 7,656.189
## Bayesian Inf. Crit. 7,697.806
## Residual Std. Error 750.179 (df = 745)
## F Statistic 38.495*** (df = 7; 745)
## =======================================================
## Note: *p<0.1; **p<0.05; ***p<0.01

Việc diễn giải ý nghĩa của các hệ số hồi quy ở mô hình Tobit là tương tự như đối với các hệ số hồi quy
OLS tuy nhiên đó là tác động tuyến tính (linear effect) lên các biến không bị kiểm duyệt tiềm ẩn
(uncensored latent variable). Các bạn có thể tham khảo thêm McDonald & Moffitt (1980) để biết chi
tiết.

Kết quả thu được ở trên chính là kết quả được trình bày ở trang 601 cuốn sách của Wooldridge (2013)
và cũng là ví dụ được sách giáo trình NEU sử dụng ở trang 425.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


433

Kết quả này có hai điểm đáng chú ý. Thứ nhất, hệ số ước lượng thu được từ hai mô hình là có cùng
dấu. Thứ hai, chúng ta nên thận trọng khi so sánh trực tiếp các hệ số ước lượng thu được từ hai mô
hình với nhau .

14.2 Hồi quy Poisson


Mô hình hồi quy Poisson được áp dụng cho tình huống mà biến phụ thuộc là các số nguyên không âm.
Đứng trên một phương diện nào đó thì cũng có nghĩa là biến phụ thuộc bị kiểm duyệt. Ví dụ số con
mà một phụ nữ sinh hay số người bị bắt giữ trong 1 năm.

Để minh họa, chúng ta xét bộ số liệu CRIME1.DTA với biến phụ thuộc là narr86 (số lần 1 người đàn
ông bị bắt giữ trong năm 1986). Đây là bộ số liệu được sử dụng trong cuốn sách của Wooldridge
(2013) tại trang 607 và được sử dụng lại tại trang 430 của NEU. Miêu tả chi tiết các biến này các bạn
có thể tham khảo trang 430 sách của NEU. Dưới đây là các câu lệnh chạy hồi quy Poisson trong R cũng
như so sánh các kết quả với các ước lượng OLS và hồi quy bán Poisson (Quasi Poisson Regression)
nhằm hiệu chỉnh các sai lệch tiềm năng của phân phối Poisson:

yeutrang <- read.dta("CRIME1.DTA")


names(yeutrang) # Xem qua các biến số.

## [1] "narr86" "nfarr86" "nparr86" "pcnv" "avgsen" "tottime" "ptime86"


## [8] "qemp86" "inc86" "durat" "black" "hispan" "born60" "pcnvsq"
## [15] "pt86sq" "inc86sq"

ols <- lm(narr86 ~ pcnv + avgsen + tottime + ptime86 +


qemp86 + inc86 + black + hispan + born60, yeutrang)
poisson<- glm(narr86 ~ pcnv + avgsen + tottime + ptime86 + qemp86 + inc86 +
black + hispan + born60, data = yeutrang, family = poisson)
quasiPoisson <- glm(narr86 ~ pcnv + avgsen + tottime + ptime86 +
qemp86 + inc86 + black + hispan + born60,
data = yeutrang,
family = quasipoisson)
library(stargazer)
stargazer(ols, poisson, quasiPoisson,
title = "So sanh ba mo hinh", type = "text")

## So sanh ba mo hinh
## =========================================================================
## Dependent variable:
## -----------------------------------------------------
## narr86
## OLS Poisson glm: quasipoisson
## link = log
## (1) (2) (3)
## -------------------------------------------------------------------------
## pcnv -0.132*** -0.402*** -0.402***
## (0.040) (0.085) (0.105)
##
## avgsen -0.011 -0.024 -0.024

Nguyễn Chí Dũng http://rpubs.com/chidungkt


434

## (0.012) (0.020) (0.025)


##
## tottime 0.012 0.024* 0.024
## (0.009) (0.015) (0.018)
##
## ptime86 -0.041*** -0.099*** -0.099***
## (0.009) (0.021) (0.025)
##
## qemp86 -0.051*** -0.038 -0.038
## (0.014) (0.029) (0.036)
##
## inc86 -0.001*** -0.008*** -0.008***
## (0.0003) (0.001) (0.001)
##
## black 0.327*** 0.661*** 0.661***
## (0.045) (0.074) (0.091)
##
## hispan 0.194*** 0.500*** 0.500***
## (0.040) (0.074) (0.091)
##
## born60 -0.022 -0.051 -0.051
## (0.033) (0.064) (0.079)
##
## Constant 0.577*** -0.600*** -0.600***
## (0.038) (0.067) (0.083)
##
## -------------------------------------------------------------------------
## Observations 2,725 2,725 2,725
## R2 0.072
## Adjusted R2 0.069
## Log Likelihood -2,248.761
## Akaike Inf. Crit. 4,517.522
## Residual Std. Error 0.829 (df = 2715)
## F Statistic 23.572*** (df = 9; 2715)
## =========================================================================
## Note: *p<0.1; **p<0.05; ***p<0.01

Các hệ số ước lượng từ hai mô hình này không thể so sánh trực tiếp với nhau vì chúng có ý nghĩa hoàn
toàn khác biệt. Ví dụ, hệ số thu được từ OLS ứng với biến pcnv (tỉ lệ bị kết án) là -0.132 ngụ ý rằng
nếu biến này tăng lên 0.1 thì số người bị bắt giữ giảm 0.0132. Còn hệ số ước lượng từ mô hình Poisson
hàm ý rằng nếu tăng tỉ lệ bị kết án tăng 0.1 thì số người bị bắt sẽ giảm 0.1*0.402 = 4%. Hệ số của
black ngụ ý rằng số người bị bắt vơi người da màu là cao hơn100[exp(0.661) – 1]=93.7% so với người
da trắng.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


435

Nguyễn Chí Dũng http://rpubs.com/chidungkt


436

Chương 15: Phân tích nhân tố khám phá EFA

Phân tích EFA (Exploratory Factor Analysis) là một trong những kĩ thuật phân tích thống kê nhiều
chiều (Multivariate Analysis) được sử dụng ở một số lĩnh vực, nhất là cho đo lường các thang đo liên
quan đến tâm lý, nhận thức. Nó cũng có thể được sử dụng như là bước phân tích nền cho các phân sâu
hơn như phân tích hồi quy hay sử dụng cho các mô hình SEM (Structural Equation Model).

Trong chương này, tôi sẽ giới thiệu một số phân tích cho EFA cũng như các kiểm định hay sử dụng là
kiểm định KMO, kiểm định Bartlett cũng như kiểm định thang đo Cronbach Alpha.

15.1 Mô tả số liệu và các gói cần thiết cho phân tích


Chúng ta sẽ sử dụng bộ số liệu SAQ.sav (định dạng file của SPSS) nhằm khám phá và nghiên cứu để
trả lời cho câu hỏi “Những nhân tố nào làm sinh viên khiếp sợ học môn thống kê”. Đây là bộ số liệu này
được thu thập bằng việc sử dụng bảng câu hỏi với thang đo Likert 5 cho 23 câu hỏi khi phỏng vấn
2571 sinh viên và được sử dụng tại chương 17 của cuốn Discovering Statistics using SPSS của Field
(2013). Chi tiết các câu hỏi này cũng như lý thuyết về phân tích EFA các bạn có thể xem tại chương
17 (có data đi kèm) tại:

http://www.mediafire.com/download/wbxxpidlryf62u1/AndyFieldSPSS.rar

Tuy nhiên, để cho gọn và hỗ trợ thuận tiện cho các bạn nghiên cứu, tôi đã mã hóa 23 câu hỏi này bằng
các kí hiệu từ Q01 đến Q23 đồng thời đổi định dạng cho dữ liệu với tên gọi raq.dat.

Để thực hiện phân tích EFA và một số phân kĩ thuật phân tích đa biến khác chúng ta cần cài đặt một
số gói sau:

install.packages("GPArotation")
install.packages("corpcor")
install.packages("corrplot")
install.packages("grid")

Riêng gói jbryer và likert cài đặt có chút phức tạp hơn vì phải cài đặt từ Github:
library(devtools)
install_github("likert", "jbryer")

Theo Field (2013), phân tích khám phá EFA được sử dụng khi chúng ta muốn đo lường và khám phá
cấu trúc của những biến số hoặc khái niệm mà không thể đo lường trực tiếp được (các biến, khái niệm
như thế gọi là latent variables – các biến ẩn và còn có tên gọi khác là nhân tố - factor) mà chỉ có thể
đo lường gián tiếp qua các biến trung gian, chẳng hạn, một loạt các câu hỏi theo thang đo Likert 5. Để
khám phá cấu trúc và đo lường nhân tố chúng ta sử dụng một kĩ thuật phân tích đa biến gọi là phân
tích thành phần chính PCA (Principal Component Analysis) – một kĩ thuật phân tích nhằm xác định
những nhóm biến trung gian tập trung theo các cụm như thế nào dựa vào một tiêu chí thống kê gọi là
hệ số tải (factor loading). Bạn đọc quan tâm có thể xem chi tiết chương 17 cuốn sách của A. Field đã
nêu tên ở trên.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


437

15.2 Các phân tích sơ bộ cần thiết


Chúng ta cần thực hiện một số phân tích sơ bộ cho bộ dữ liệu.

15.2.1 Phân tích tương quan


Chúng ta có thể xem tương quan giữa các biến số với bảng ma trận hệ số tương quan (trích):

setwd("D:/KTLR")
love <- read.delim("raq.dat", header = TRUE)
library(psych); library(GPArotation); library(corpcor); library(corrplot)
library(factoextra); library(likert); library(tidyverse); library(grid)
you <- cor(love)
round(you, 3)

## Q01 Q02 Q03 Q04 Q05 Q06 Q07 Q08 Q09 Q10
## Q01 1.000 -0.099 -0.337 0.436 0.402 0.217 0.305 0.331 -0.092 0.214
## Q02 -0.099 1.000 0.318 -0.112 -0.119 -0.074 -0.159 -0.050 0.315 -0.084
## Q03 -0.337 0.318 1.000 -0.380 -0.310 -0.227 -0.382 -0.259 0.300 -0.193

Ma trận hệ số tương quan trong tình huống của phân tích EFA – CFA được gọi là R-matrix. Những hệ
số tương quan không thuộc đường chéo của ma trận (off-diagonal elements) chính là hệ số tương
quan của các biến trung gian. Ví dụ, giữa biến Q01 và Q04 (theo thang đo Likert 5) là 0.402. Một bộ
dữ liệu được cho là có thể thực hiện phân tích EFA – CFA khi mà các hệ số tương quan này đủ lớn về
giá trị tuyệt đối và được đánh giá thông qua một trong hai thống kê là kiểm định KMO và Bartlett mà
chúng ta sẽ nghiên cứu ở mục sau.

Chúng ta cũng có thể trình bày tương quan giữa các biến số theo một ngôn ngữ khác - ngôn ngữ của
hình ảnh và màu sắc:

corrplot(you, method = "color")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


438

Các ô vuông ở đường chéo luôn là màu xanh đậm (tương quan dương 1). Màu xanh càng nhạt thì
tương quan dương càng yếu. Tương tự, màu đỏ sậm là tương quan âm 1. Màu đỏ này càng nhạt thì
tương quan âm này càng yếu. Tất nhiên thông tin về tương quan giữa các câu hỏi chúng ta có thể có
được theo một cách thức khác như đã làm ở mục 8.3 của chương 8.

Do ma trận hệ số tương quan là đối xứng nên chúng ta có thể hiệu chỉnh bằng lệnh sau:

corrplot(you, method = "color", type = "lower")

Hoặc có thể “tập trung” những biến có tương qua dương hoặc âm lại với nhau:

corrplot(you, method = "color", order = "hclust")

15.2.2 Phân tích một số thống kê khác về các câu hỏi


Các lệnh sau đây cho ta biết bức tranh toàn cảnh về các câu hỏi:

love[] <- lapply(love[], as.factor)


love <- likert(love)
title <- "Ti le lua chon (%) cho cac cau hoi"
plot(love, type = "heat") + ggtitle(title)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


439

Ở đây chúng ta có thể thấy rằng, chẳng hạn, câu Q23 thì tỉ lệ chọn 1 (tức là rất không đồng ý là 12.45%)
và tỉ lệ chọn 2 là cao nhất với 42.43 %.Q23 có trung bình (với thang đo từ 1 đến 5) là 2.57 và độ lệch
chuẩn là 1.04.

Chúng ta cũng có thể biểu diễn các thông tin ở trên dưới dạng khác:
plot(love, centered = FALSE) + ggtitle(title)

15.3 Kiểm định KMO và Bartlett


Như đã nói ở mục 15.2, trước khi phân tích PCA - EFA chúng ta cần đảm bảo rằng bộ số liệu của chúng
ta là phù hợp cho loại phân tích này. Để thực hiện điều này chúng ta sử dụng một trong hai kiểm định
là KMO Test (1970) và Bartlett Test. Các kiểm định này sẽ chỉ ra bằng chứng có hay không các hệ số
tương quan nằm ngoài đường chéo của R – matrix là đủ lớn để bộ dữ liệu có thể sử dụng được phân
tích thành phần chính PCA.

15.3.1 Kiểm định KMO


love <- read.delim("raq.dat", header = TRUE) # Đọc lại bộ dữ liệu với tên là
love.
KMO(love)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


440

## Kaiser-Meyer-Olkin factor adequacy


## Call: KMO(r = love)
## Overall MSA = 0.93
## MSA for each item =
## Q01 Q02 Q03 Q04 Q05 Q06 Q07 Q08 Q09 Q10 Q11 Q12 Q13 Q14 Q15
## 0.93 0.87 0.95 0.96 0.96 0.89 0.94 0.87 0.83 0.95 0.91 0.95 0.95 0.97 0.94
## Q16 Q17 Q18 Q19 Q20 Q21 Q22 Q23
## 0.93 0.93 0.95 0.94 0.89 0.93 0.88 0.77

Theo Kaiser (1974), để phân tích EFA chúng ta cần giá trị KMO này tối thiểu là 0.5. Với dữ liệu của
chúng ta, KMO Test là 0.93 cho thấy có thể sử dụng phân tích EFA cho bộ dữ liệu. Hutcheson &
Sofroniou (1999) thậm chí còn đưa ra các ngưỡng cụ thể hơn như sau: nếu thống kê KMO nằm từ 0.5
đến 0.7 thì là chấp nhận được (mediocre), từ 0.7 đến 0.8 là tốt, từ 0.8 đến 0.9 là rất tốt, còn trên 0.9
là siêu tốt (superb).

15.3.2 Kiểm định Bartlett


Chúng ta cũng có thể sử dụng Bartlett Test như là một kiểm định thay thế cho KMO:

cortest.bartlett(love)

## $chisq
## [1] 19334.49
##
## $p.value
## [1] 0
##
## $df
## [1] 253

Kiểm định này có gía trị 19334.49 với 253 bậc tự do và tương ứng với p-value = 0 < 5% nên chúng ta
có kết luận rằng tương quan giữa các items là đủ lớn để sử dụng phân tích nhân tố.

15.4 Số lượng các nhân tố chính rút ra


Có hai trường phái đối về số lượng các nhân tố chính được rút ra khi căn cứ vào giá trị Eigenvalues.
Một là tiêu chuẩn Kaiser (Kaiser’s criterion). Theo tiêu chuẩn này, nhân tố chính (hay thành phần
chính) được rút ra phải đảm bảo giá trị Eigenvalues lớn hơn 1. Trong khi đó, tiêu chuẩn Jolliffe
(Jolliffe’s criterion ) thì lỏng hơn: chỉ cần lớn hơn 0.7 cũng có thể được lựa chọn. Ở đây, số lượng nhận
tố được rút ra chúng ta căn cứ vào tiêu chuẩn của Kaiser :

# Thực hiện phân tích thành phần chính PCA:


pca1 <- prcomp(love, scale = TRUE)
# Các Eigenvalues ứng với các nhân tố:
u <- get_eig(pca1)
# Xem qua kết quả:
u %>% head()

Nguyễn Chí Dũng http://rpubs.com/chidungkt


441

## eigenvalue variance.percent cumulative.variance.percent


## Dim.1 7.2900471 31.695857 31.69586
## Dim.2 1.7388287 7.560125 39.25598
## Dim.3 1.3167515 5.725007 44.98099
## Dim.4 1.2271982 5.335644 50.31663
## Dim.5 0.9878779 4.295121 54.61175
## Dim.6 0.8953304 3.892741 58.50449

# Có thể tạo ra graph như ở trang 640 sách của A. Field:


u <- u %>% mutate(ComponentNumber = 1:23)
# Eigenvalue của 6 nhân tố đầu:
u %>% head()

## eigenvalue variance.percent cumulative.variance.percent ComponentNumber


## 1 7.2900471 31.695857 31.69586 1
## 2 1.7388287 7.560125 39.25598 2
## 3 1.3167515 5.725007 44.98099 3
## 4 1.2271982 5.335644 50.31663 4
## 5 0.9878779 4.295121 54.61175 5
## 6 0.8953304 3.892741 58.50449 6

# Hình ảnh hóa eigenvalue ứn với các nhân tố:


theme_set(theme_minimal())
u %>%
ggplot(aes(ComponentNumber, eigenvalue)) +
geom_line() +
geom_point(color = "red") +
labs(title = "The number of factors (PCA) based on Kaiser’s Criterion")

Chúng ta thấy rằng sẽ có 4 nhân tố được rút ra theo tiêu chuẩn Kaiser. Nhân tố thứ 4(Dim.4) có
Eigenvalues là 1.23 tương ứng với nhân tố này giải thích cho 1.23/23 = 5.3 % tổng phương sai (total
variance). Cả 4 nhân tố này giải thích được 50.32 % tổng phương sai (chính là bằng (7.29 + 1.74 +
1.32 + 1.23)/23 ). Chúng ta có thể biểu diễn các kết quả này bằng hình ảnh như sau:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


442

# Phương sai giải thích tương ứng cho 10 nhân tố đầu tiên:
fviz_screeplot(pca1, addlabels = TRUE, n = 10)

Chúng ta cũng có thể biểu diễn Eigenvalues cho các nhân tố bằng với độ chính xác 1 chữ số sau dấu
phẩy (không hiển thị hình ảnh):

fviz_screeplot(pca1, n = 23, choice = "eigenvalue", addlabels = TRUE)


# Eigenvalues của 23 nhân tố với độ chính xác 1 chữ số sau dấu phẩy.

15.5 Các biến cấu thành nhân tố, đặt tên cho nhân tố và kiểm định Cronbach Alpha
Các phân tích trên chỉ ra rằng có 4 nhân tố chính được rút ra. Để biết các nhân tố này được cấu thành
từ các biến nào (tức là khám phá cấu trúc của nhân tố) chúng ta có thể sử dụng phép xoay Varimax.
Câu lệnh dưới đây sẽ loại bỏ (không hiển thị) bất kì biến nào có hệ sổ tải (Factor Loadings) bé hơn
0.3:

pc2 <- principal(love, nfactors = 4, rotate = "varimax")


print.psych(pc2, cut = 0.3, sort = TRUE)

## Principal Components Analysis


## Call: principal(r = love, nfactors = 4, rotate = "varimax")
## Standardized loadings (pattern matrix) based upon correlation matrix
## item PC3 PC1 PC4 PC2 h2 u2 com
## Q06 6 0.80 0.65 0.35 1.0
## Q18 18 0.68 0.33 0.60 0.40 1.5
## Q13 13 0.65 0.54 0.46 1.6
## Q07 7 0.64 0.33 0.55 0.45 1.7
## Q14 14 0.58 0.36 0.49 0.51 1.8
## Q10 10 0.55 0.33 0.67 1.2
## Q15 15 0.46 0.38 0.62 2.6

Nguyễn Chí Dũng http://rpubs.com/chidungkt


443

## Q20 20 0.68 0.48 0.52 1.1


## Q21 21 0.66 0.55 0.45 1.5
## Q03 3 -0.57 0.37 0.53 0.47 2.3
## Q12 12 0.47 0.52 0.51 0.49 2.1
## Q04 4 0.32 0.52 0.31 0.47 0.53 2.4
## Q16 16 0.33 0.51 0.31 0.49 0.51 2.6
## Q01 1 0.50 0.36 0.43 0.57 2.4
## Q05 5 0.32 0.43 0.34 0.66 2.5
## Q08 8 0.83 0.74 0.26 1.1
## Q17 17 0.75 0.68 0.32 1.5
## Q11 11 0.75 0.69 0.31 1.5
## Q09 9 0.65 0.48 0.52 1.3
## Q22 22 0.65 0.46 0.54 1.2
## Q23 23 0.59 0.41 0.59 1.4
## Q02 2 -0.34 0.54 0.41 0.59 1.7
## Q19 19 -0.37 0.43 0.34 0.66 2.2
##
## PC3 PC1 PC4 PC2
## SS loadings 3.73 3.34 2.55 1.95
## Proportion Var 0.16 0.15 0.11 0.08
## Cumulative Var 0.16 0.31 0.42 0.50
## Proportion Explained 0.32 0.29 0.22 0.17
## Cumulative Proportion 0.32 0.61 0.83 1.00
##
## Mean item complexity = 1.8
## Test of the hypothesis that 4 components are sufficient.
##
## The root mean square of the residuals (RMSR) is 0.06
## with the empirical chi square 4006.15 with prob < 0
##
## Fit based upon off diagonal values = 0.96

Chúng ta thấy với nhân tố thứ nhất (PC1), các biến cấu thành nhân tố này là từ Q06 đến Q15. Đối chiếu
với nội dung các câu hỏi tương ứng với Q06 đến Q15 chúng ta có thể thấy rằng tất cả chúng thuộc về
một nhóm nhân tố mà chúng ta có thể gọi là “kiến thức về toán học”, hay “nỗi sợ toán học”. Chúng ta
đặt tên cho các nhân tố còn lại cũng căn cứ vào nội dung của các câu hỏi (xem bảng 17.1 Sách của
Field). Chú ý rằng cách đặt tên này không giống nhau giữa các cá nhân tuy nhiên việc đặt tên cho từng
nhân tố nên cố gắng phản ánh bản chất của nhân tố đó căn cứ vào các câu hỏi (các biến) cấu thành.

Việc chọn hệ số tải (trong tình huống của chúng ta là 0.3) có liên quan đến kích cỡ mẫu của phân tích
(Janssens et al., 2008) và được cho ở bảng dưới đây:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


444

Nếu chúng ta lựa chọn một tiêu chuẩn chặt hơn, chúng ta có thể chọn ngưỡng hệ số tải là 0.4. Lúc này
kết quả là:

pc2 <- principal(love, nfactors = 4, rotate = "varimax")


print.psych(pc2, cut = 0.4, sort = TRUE)

## Principal Components Analysis


## Call: principal(r = love, nfactors = 4, rotate = "varimax")
## Standardized loadings (pattern matrix) based upon correlation matrix
## item PC3 PC1 PC4 PC2 h2 u2 com
## Q06 6 0.80 0.65 0.35 1.0
## Q18 18 0.68 0.60 0.40 1.5
## Q13 13 0.65 0.54 0.46 1.6
## Q07 7 0.64 0.55 0.45 1.7
## Q14 14 0.58 0.49 0.51 1.8
## Q10 10 0.55 0.33 0.67 1.2
## Q15 15 0.46 0.38 0.62 2.6
## Q20 20 0.68 0.48 0.52 1.1
## Q21 21 0.66 0.55 0.45 1.5
## Q03 3 -0.57 0.53 0.47 2.3
## Q12 12 0.47 0.52 0.51 0.49 2.1
## Q04 4 0.52 0.47 0.53 2.4
## Q16 16 0.51 0.49 0.51 2.6
## Q01 1 0.50 0.43 0.57 2.4
## Q05 5 0.43 0.34 0.66 2.5
## Q08 8 0.83 0.74 0.26 1.1
## Q17 17 0.75 0.68 0.32 1.5
## Q11 11 0.75 0.69 0.31 1.5
## Q09 9 0.65 0.48 0.52 1.3
## Q22 22 0.65 0.46 0.54 1.2

Nguyễn Chí Dũng http://rpubs.com/chidungkt


445

## Q23 23 0.59 0.41 0.59 1.4


## Q02 2 0.54 0.41 0.59 1.7
## Q19 19 0.43 0.34 0.66 2.2
##
## PC3 PC1 PC4 PC2
## SS loadings 3.73 3.34 2.55 1.95
## Proportion Var 0.16 0.15 0.11 0.08
## Cumulative Var 0.16 0.31 0.42 0.50
## Proportion Explained 0.32 0.29 0.22 0.17
## Cumulative Proportion 0.32 0.61 0.83 1.00
##
## Mean item complexity = 1.8
## Test of the hypothesis that 4 components are sufficient.
##
## The root mean square of the residuals (RMSR) is 0.06
## with the empirical chi square 4006.15 with prob < 0
##
## Fit based upon off diagonal values = 0.96

Chúng ta lưu tâm đến biến số Q12. Nó vừa thuộc nhân tố 3 lẫn nhân tố 1. Tuy nhiên hệ số tải của nó
với nhân tố 1 là lớn hơn (0.52 so với 0.47) nên ta có thể nói nó tương quan lớn hơn với nhân tố 1 .
Nói cách khác, căn cứ vào tiêu chí hệ số tải lớn hơn thì Q12 thuộc nhân tố 1 (PC1).

Dù chọn hệ số tải là 0.3 hay 0.4 thì các biến số cấu thành các nhân tố chính (từ PC1 đến PC4) vẫn
không thay đổi. Cụ thể, nhân tố “kiến thức về toán” được cấu thành từ các biến Q06, Q18, Q13, Q07,
Q14, Q10, và Q15. Chúng ta có thể thực hiện kiểm định Cronbach Alpha cho thang đo (hay nhân tố)
này bằng câu lệnh sau:
psych::alpha(love[, c(06, 18, 13, 07, 14, 10, 15)])
## Reliability analysis
## Call: psych::alpha(x = love[, c(6, 18, 13, 7, 14, 10, 15)])
##
## raw_alpha std.alpha G6(smc) average_r S/N ase mean sd
## 0.82 0.82 0.81 0.4 4.6 0.0094 3.4 0.71
##
## lower alpha upper 95% confidence boundaries
## 0.8 0.82 0.84
##
## Reliability if an item is dropped:
## raw_alpha std.alpha G6(smc) average_r S/N alpha se
## Q06 0.79 0.79 0.77 0.38 3.7 0.011
## Q18 0.79 0.78 0.76 0.38 3.6 0.011
## Q13 0.79 0.79 0.77 0.39 3.8 0.011

Nguyễn Chí Dũng http://rpubs.com/chidungkt


446

## Q07 0.79 0.79 0.77 0.38 3.7 0.011


## Q14 0.80 0.80 0.77 0.39 3.9 0.011
## Q10 0.82 0.82 0.80 0.44 4.7 0.010
## Q15 0.81 0.81 0.79 0.41 4.2 0.011
##
## Item statistics
## n raw.r std.r r.cor r.drop mean sd
## Q06 2571 0.75 0.74 0.68 0.62 3.8 1.12
## Q18 2571 0.76 0.76 0.72 0.65 3.4 1.05
## Q13 2571 0.72 0.73 0.67 0.61 3.6 0.95
## Q07 2571 0.75 0.73 0.68 0.62 3.1 1.10
## Q14 2571 0.70 0.70 0.64 0.58 3.1 1.00
## Q10 2571 0.54 0.57 0.44 0.40 3.7 0.88
## Q15 2571 0.64 0.64 0.54 0.49 3.2 1.01
##
## Non missing response frequency for each item
## 1 2 3 4 5 miss
## Q06 0.06 0.10 0.13 0.44 0.27 0
## Q18 0.06 0.12 0.31 0.37 0.14 0
## Q13 0.03 0.12 0.25 0.48 0.12 0
## Q07 0.09 0.24 0.26 0.34 0.07 0
## Q14 0.07 0.18 0.38 0.31 0.06 0
## Q10 0.02 0.10 0.18 0.57 0.14 0
## Q15 0.06 0.18 0.30 0.39 0.07 0

Câu lệnh trên chúng ta phải gõ cả psych:: là bởi vì gói ggplot 2 cũng có “lệnh” alpha. Dao vậy chúng ta
cần gõ psych:: để chỉ thị cho R hiểu là dùng lệnh alpha của gói psych chứ không phải của gói ggplot2.
Chúng ta đã thực hiện sử dụng theo cách thức tương tự tại mục 2.6. Nếu bạn không làm thế, R sẽ báo
lỗi.

Một thang đo là hợp lí (Reability) nếu gí trị Cronbach Alpha này lớn hơn 0.7. Kêt quả của chúng ta là
0.82 > 0.7 nên thang đo “kiến thức về toán” cấu thành từ 7 biến số (thường gọi là items) trên là hợp
lí.

Thực hiện kiểm định thanh đo một cách tương tự cho 3 nhân tố (thang đo) còn lại một cách tương tự.
Cũng có thể kết hợp phân tích EFA với phân tích hồi quy hoặc mô hình SEM (Structural equation
modeling).

15.6 Mini Project: Hình ảnh hóa dữ liệu sử dụng thang đo Likert
Một khía cạnh quan trọng ngoài thực hiện các phân tích thống kê như chúng ta vừa thực hiện thì
chúng ta còn có thể phải thực hiện hình ảnh hóa dữ liệu với thang đo Likert – một việc làm khá phổ
biến ở nhiều báo cáo của các tổ chức lớn, các công ti nghiên cứu thị trường hay báo chí. Trong mục
này chúng ta sẽ thực hành một dự án nhỏ với bộ số liệu pisaitems tích hợp cùng gói likert. Bộ số
liệu này được thu thập bởi Tổ Chức Hợp Tác Kinh Tế và Phát Triển OECD (Organization for Economic

Nguyễn Chí Dũng http://rpubs.com/chidungkt


447

Co-operation and Development) . Xem thêm về số liệu tại http://www.pisa.oecd.org/. Các quốc gia
có trong lần khảo sát này là Canada, Hoa Kì và Mexico với 80 biến số (thường gọi là 80 items):
# Xóa tất cả các object:
rm(list = ls())
# Load gói likert:
library(likert)
# Kiểm tra dữ liệu thiếu
data(pisaitems)
sapply(pisaitems, function(x) sum(is.na(x)))

## CNT ST24Q01 ST24Q02 ST24Q03 ST24Q04 ST24Q05 ST24Q06 ST24Q07 ST24Q08


## 0 1199 1134 1276 1210 1214 1300 1319 1234
## ST24Q09 ST24Q10 ST24Q11 ST25Q01 ST25Q02 ST25Q03 ST25Q04 ST25Q05 ST26Q01
## 1301 1193 1135 1081 1325 1350 1397 1108 1085

# Xem qua bộ số liệu pisaitems


?pisaitems
names(pisaitems)

## [1] "CNT" "ST24Q01" "ST24Q02" "ST24Q03" "ST24Q04" "ST24Q05" "ST24Q06"


## [71] "ST41Q01" "ST41Q02" "ST41Q03" "ST41Q04" "ST41Q05" "ST41Q06" "ST42Q01"
## [78] "ST42Q02" "ST42Q03" "ST42Q04" "ST42Q05"

str(pisaitems)

## 'data.frame': 66690 obs. of 81 variables:


## $ CNT : Factor w/ 3 levels "Canada","Mexico",..: 1 1 1 1 1 1 1 1 1 1 .
..
## $ ST24Q01: Factor w/ 4 levels "Strongly disagree",..: 2 3 4 2 1 3 2 3 3 4
...

Để minh họa chúng ta chỉ trích ra 11 câu hỏi liên quan đến thái độ của người được phỏng vấn đối
với việc đọc. Chúng là các câu hỏi có cụm kí tự ST24Q:
library(tidyverse)
# Trích ra bộ dữ liệu gồm các biến có kí tự ST24Q - thái độ với việc đọc:
reading <- select(pisaitems, contains("ST24Q"))
head(reading)

## ST24Q01 ST24Q02 ST24Q03


## 68038 Disagree Strongly agree Strongly agree
## 68039 Agree Strongly disagree Strongly disagree
## 68040 Strongly agree Strongly disagree Strongly disagree

names(reading)

## [1] "ST24Q01" "ST24Q02" "ST24Q03" "ST24Q04" "ST24Q05" "ST24Q06" "ST24Q07"


## [8] "ST24Q08" "ST24Q09" "ST24Q10" "ST24Q11"

Hình ảnh hóa cho số lượng những người được phỏng vấn đến từ ba nước trên:

Nguyễn Chí Dũng http://rpubs.com/chidungkt


448

# Data Visualization cho số lượng quan sát đến từ 3 quốc gia:


u <- data.frame(table(pisaitems$CNT))
library(ggthemes)
ggplot(u, aes(Var1, Freq, fill = Var1)) +
geom_bar(stat = "identity", show.legend = FALSE) +
labs(x = NULL,
y = NULL,
title = "Number of students interviewed by country",
subtitle = "Unit: Thousands",
caption = "Data Source: http://www.oecd.org/pisa/") +
theme_economist() +
scale_fill_economist()

Để dễ hiểu cho bạn đọc chúng ta nên đổi tên cho các items:
# Đổi tên cho các biến số:
reading <- dplyr::rename(reading,
"I read only if I have to." = ST24Q01,
"Reading is one of my favorite hobbies." = ST24Q02,
"I like talking about books with other people." = ST
24Q03,
"I find it hard to finish books." = ST24Q04,
"I feel happy if I receive a book as a present." = S
T24Q05,
"For me, reading is a waste of time." = ST24Q06,
"I enjoy going to a bookstore or a library." = ST24Q
07,
"I read only to get information that I need." = ST24
Q08,
"I cannot sit still and read for more than a few min
utes." = ST24Q09,
"I like to express my opinions about books I have re
ad." = ST24Q10,
"I like to exchange books with my friends." = ST24Q1
1)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


449

Với mục đích minh họa (và cũng để tiết kiệm giấy in) chúng ta chỉ xét 4 câu hỏi (items) đầu tiên của
bộ dữ liệu con này trước khi hình ảnh hóa dữ liệu:
# Chỉ lấy các câu hỏi (items) từ 1 đến 4:
f1_4 <- reading[, c(1:4)]
# Likert hóa các items này:
f1_4likert <- likert(f1_4)
# Tóm tắt:
summary(f1_4likert)

## Item low neutral high


## 3 I like talking about books with other people. 54.99129 0 45.00871
## 2 Reading is one of my favorite hobbies. 56.64470 0 43.35530
## 1 I read only if I have to. 58.72868 0 41.27132
## 4 I find it hard to finish books. 65.35125 0 34.64875
## mean sd
## 3 2.328049 0.9090326
## 2 2.344530 0.9277495
## 1 2.291811 0.9369023
## 4 2.178299 0.8991628

# Bar plot biểu diễn tỉ lệ lựa chọn đối với 4 items:


plot(f1_4likert)

# Thêm tiêu đề:


plot(f1_4likert) + ggtitle("Reading Attitudes")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


450

Hoặc chúng ta có thể hình ảnh hóa theo một số cách khác:
# Bar plot theo một cách khác:
plot(f1_4likert, centered = FALSE, wrap = 30)

# Hàm mật độ (xấp xỉ) ứng với 4 items này:


plot(f1_4likert, type = "density")

# Tỉ lệ người lựa chọn 4 items biểu diễn bằng heat map:


plot(f1_4likert, type = "heat")

Nguyễn Chí Dũng http://rpubs.com/chidungkt


451

##----------------------------------------------
## Đánh giá thái độ đối với reading của các
## quan sát đến từ ba quốc gia tham gia khảo sát
##----------------------------------------------
g <- likert(f1_4, grouping = pisaitems$CNT)
print(g)

## Group Item
## 1 Canada I read only if I have to.
## 2 Canada Reading is one of my favorite hobbies.
## 3 Canada I like talking about books with other people.
## 4 Canada I find it hard to finish books.
## 5 Mexico I read only if I have to.
## 6 Mexico Reading is one of my favorite hobbies.
## 7 Mexico I like talking about books with other people.
## 8 Mexico I find it hard to finish books.
## 9 United States I read only if I have to.
## 10 United States Reading is one of my favorite hobbies.
## 11 United States I like talking about books with other people.
## 12 United States I find it hard to finish books.
## Strongly disagree Disagree Agree Strongly agree
## 1 25.69810 35.12856 24.88383 14.289507
## 2 26.77758 35.18871 24.63608 13.397637
## 3 25.22917 31.68150 33.47062 9.618706
## 4 31.33106 40.44088 19.69811 8.529946
## 5 21.87500 36.76845 33.45526 7.901293
## 6 15.26451 36.42523 37.79077 10.519491
## 7 18.44410 34.78607 37.89150 8.878331
## 8 21.09309 39.92260 31.07241 7.911896
## 9 17.16996 33.00426 33.97213 15.853659
## 10 29.08282 40.51858 21.03328 9.365325
## 11 24.31646 35.13671 32.79038 7.756448
## 12 25.32455 43.61558 22.96067 8.099206

mydf <- g$results


# Cho, chẳng hạn, Canada:
filter(mydf, Group == "Canada")

## Group Item Strongly disagree


## 1 Canada I read only if I have to. 25.69810
## 2 Canada Reading is one of my favorite hobbies. 26.77758
## 3 Canada I like talking about books with other people. 25.22917
## 4 Canada I find it hard to finish books. 31.33106
## Disagree Agree Strongly agree
## 1 35.12856 24.88383 14.289507
## 2 35.18871 24.63608 13.397637
## 3 31.68150 33.47062 9.618706
## 4 40.44088 19.69811 8.529946

# Hình ảnh hóa


plot(g)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


452

plot(g, include.histogram = TRUE)

plot(g, centered = FALSE)

Nguyễn Chí Dũng http://rpubs.com/chidungkt


453

plot(g, type = "density")

Khi bạn thực hiện hình ảnh hóa dữ liệu cho bộ số liệu của mình chú ý rằng bộ dữ liệu của bạn phải có
cấu trúc tương tự như pisaitems. Nếu không giống thì việc đầu tiên bạn cần thực hiện là cần chuyển
chúng về cấu trúc dữ liệu như pisaitems.

Nguyễn Chí Dũng http://rpubs.com/chidungkt


454

15.7 Về xu hướng sử dụng phân tích EFA trong nghiên cứu hiện nay
Có nhiều công cụ phân tích và cách tiếp cận có thể sử dụng cho nghiên cứu và sử dụng EFA chỉ là một
trong số đó. Nhưng có vẻ như sử dụng EFA với thang đo Likert 5 lại được ưu tiên một cách đặc biệt ở
Việt Nam. Điều này có thể thấy qua hầu hết các sách về hướng dẫn nghiên cứu khoa học đều dành một
khối lượng đáng kể để nói về phương pháp này, cá biệt có cuốn dành xấp xỉ 30% số trang sách cho
phương pháp phân tích EFA (mà trong đó 80% số trang giấy chỉ để in số liệu). Sự ưu ái vô lý dành cho
kĩ thuật phân tích đa biến này có thể dẫn đến ngộ nhận của nhiều người rằng EFA là công cụ vạn năng,
hoặc chí ít là công cụ đầy sức mạnh cho các nghiên cứu. Hầu hế các sách về hướng dẫn nghiên cứu
khoa học bằng tiếng Anh cho kinh tế và kinh doanh, không nhiều sách viết về EFA, nhất là sử kết hợp
việc sử dụng phân tích hồi quy OLS cho các nhân tố rút ra sau khi thực hiện EFA. Các sách về nghiên
cứu Marketing, nếu có, thì cũng chỉ dành một chương cho CFA mà thôi.

Nguyên nhân có lẽ là thang đo Likert vốn là biến thứ bậc (Ordinal Variable) và có nên coi nó là biến
Interval (hay thang đo khoảng) hay không và trong những trường hợp cụ thể nào vẫn là một vấn đề
chưa nhận được sự đồng thuận vì rằng với biến thứ bậc chúng ta chỉ có quyền so sánh, ví dụ, mức độ
nghiêm trọng của người được phỏng vấn đối với một vấn đề nào đó chứ không thể thực hiện các phép
toán cho loại biến này (Keller, 2013). Còn việc thực hiện phân tích hồi quy OLS cho các nhân tố rút
ra sau khi thực hiện EFA còn gây tranh cãi hơn nữa, ít nhất là với các nghiên cứu giải thích vì rằng
các nhân tố rút ra đó là biến không có đơn vị và cũng chẳng phải là loại biến thứ bậc hay Interval.
Điều này được giải thích chi tiết hơn dưới đây.

Để đánh giá tác động của giá lên lượng tiêu thụ nước ngọt có ga chúng ta có thể thực hiện hồi quy OLS
với giá là biến độc lập. Nếu hệ số hồi quy của giá là 0.002 thì ta có thể diễn giải (hay giải thích) rằng
nếu giá tăng 1 (đơn vị là ngàn VND) thì tiêu thụ về sản phẩm này giảm 0.002 (đơn vị là ngàn chai).
Cách giải thích này đã được thừa nhận rộng rãi và được chấp nhận.

Nhưng cách giải thích này áp dụng cho hồi quy OLS với các nhân tố rút ra là vô nghĩa. Thực vậy, trong
một nghiên cứu có tên “Các nhân tố ảnh hưởng đến mức độ trung thành của nhân viên tại ngân hàng
X” với 35 câu hỏi theo thang đo Likert 5. Sau khi thực hiện EFA, 35 câu hỏi này được rút về, chẳng
hạn, chỉ còn 2 nhân tố với tên gọi là “Thăng Tiến” và “Đồng Nghiệp”. Kế tiếp tác giả thực hiện hồi quy
OLS và cho ra kết quả là:

Trung Thành = 0.34 + 1.02(Thăng Tiến) + 0.74(Đồng Nghiệp)

Kết quả này được diễn giải là khi Thăng Tiến tăng 1 thì Trung Thành tăng 1.02. Cách diễn giải như
vậy (do tác giả sử dụng OLS với các nhân tố rút ra) rõ ràng có một điểm yếu: các biến số độc lập Thăng
Tiến, Đồng Nghiệp và cả biến phụ thuộc Trung Thành là những biến không có đơn vị.

Thăng Tiến tăng 1 là 1 gì? Phải chăng là 1 Dollar hay 1 lời hứa cất nhắc lên vị trí cao hơn?

Để chốt lại xu hướng sử dụng EFA trong nghiên cứu khoa học ở Việt Nam, tôi nêu một số thực tế sau
(để đảm bảo khách quan, tôi không dịch chúng ra tiếng Việt nên bạn có thể copy cả cụm từ / câu để
tìm nguồn với sự trợ giúp của Google):

1. 36 was the number of articles ISI Web of Science shows with the topic “Factor Analsysis” for the
week ending October 11, 2003.
2. FA is not worth the time necessary to understand it and carry it out (Hills, 1977).

Nguyễn Chí Dũng http://rpubs.com/chidungkt


455

3. At the present time, factor analysis still maintains the flavor of an art, and no single strategy
should yet be "chiseled into stone" (Johnson & Wichern, 2002,).
4. Factor analysis should not be used in most practical situations (Chatfield & Collins, 1980).

Nghĩa là từ những năm của thập niên 70, giới nghiên cứu và phân tích số liệu đã không tán thành việc
lạm dụng và sử dụng phân tích nhân tố. Điều này có thể thấy rằng qua một số thực tế là cho đến tháng
10 năm 2003, trong số hàng chục ngàn nghiên cứu đăng trên ISI thì chỉ có 36 bài có cụm từ phân tích
nhân tố. Thậm chí Hills còn cực đoan hơn khi tuyên bố rằng “FA (kí hiệu của phân tích nhân tố) là
không đáng để nghiên cứu và thực hiện (các nghiên cứu sử dụng phân tích nhân tố)”. Một trong những
nguyên nhân là phân tích nhân tố là rất không ổn định và nó thiên về một nghệ thuật hơn là khoa học
như cách nói của Johnson & Wichern. Chi tiết hơn về việc chỉ trích sử dụng kĩ thuât phân tích này các
bạn có thể đọc chi tiết ở trang 159 cuốn An Introduction to Applied Multivariate Analysis with R
xuất bản bởi Springer của Brian Everitt và Torsten Hothorn.

Quan điểm của Chatfield & Collins có lẽ là đỡ khắt khe hơn (so với quan điểm có phần cực đoan của
Hills) khi hai ông cho rằng “Phân tích nhân tố không nên được sử dụng trong hầu hết các tình huống
(nghiên cứu)”.

Tại Việt Nam hiện cũng có một số tiếng nói chỉ trích phong trào lạm dụng sử dụng EFA trong nghiên
cứu. Các bạn có thể xem một loạt bài (có dẫn chứng và phân tích rõ ràng) tại:

http://vneconomist.net/newsdetail.php?f=36&t=988&sid=d3f701e15821ed7a6ee892bcca5b7b41

Nguyễn Chí Dũng http://rpubs.com/chidungkt

You might also like