library(janitor)
library(kableExtra)
library(tidyverse)
library(readxl)
library(scales)
library(epitools)
library(nortest)
library(pROC)
library(caret)
library(ggplot2)

Chương 1 Giới thiệu đề tài

1.1 Lý do chọn đề tài

Đột quỵ là một bệnh lý nguy hiểm và phổ biến, được Tổ chức Y tế Thế giới (WHO) xếp vào nhóm nguyên nhân gây tử vong và tàn tật hàng đầu trên toàn cầu. Bản chất của đột quỵ là tình trạng rối loạn cấp tính tuần hoàn não, gây chết tế bào não do thiếu oxy và dưỡng chất. Bệnh có thể khởi phát đột ngột với nhiều biểu hiện như liệt nửa người, mất khả năng nói, giảm thị lực hoặc chóng mặt, và để lại di chứng nặng nề về thể chất lẫn tinh thần nếu không được điều trị kịp thời. Đặc biệt, những yếu tố nguy cơ như tăng huyết áp, tiểu đường, mức đường huyết, hút thuốc lá, béo phì đã được chứng minh có mối liên hệ chặt chẽ với khả năng xuất hiện đột quỵ. Vì vậy, việc phân tích các tác động của các yếu tố nguy cơ là điều kiện để xây dựng kế hoạch phòng và phác đồ hiệu quả.

Trong thời đại dữ liệu lớn và khoa học dữ liệu phát triển mạnh mẽ, việc ứng dụng các kỹ thuật phân tích định lượng để khai thác dữ liệu y tế đang mở ra nhiều cơ hội trong lĩnh vực chăm sóc sức khỏe. Bộ dữ liệu được sử dụng trong nghiên cứu này bao gồm các thông tin y học quan trọng như tuổi, giới tính, chỉ số BMI, mức đường huyết trung bình, tiền sử bệnh lý và hành vi sức khỏe của bệnh nhân. Việc phân tích bộ dữ liệu này sẽ giúp khám phá các mối quan hệ tiềm ẩn giữa các yếu tố nguy cơ và khả năng mắc đột quỵ, đồng thời hỗ trợ xây dựng các mô hình dự đoán có giá trị ứng dụng thực tiễn trong nghiên cứu lâm sàng và quản lý y tế cộng đồng. Chính vì vậy, đề tài “Phân tích các nguy cơ ảnh hưởng đến đột quỵ” được lựa chọn nhằm đáp ứng nhu cầu cấp thiết về dự báo và phòng ngừa căn bệnh này trong bối cảnh hiện nay.

1.2 Mục tiêu nghiên cứu

Nghiên cứu này nhằm xác định và phân tích các yếu tố nguy cơ có liên quan đến khả năng mắc đột quỵ thông qua dữ liệu bệnh nhân thực tế. Mục tiêu trọng tâm là nhận diện những yếu tố có tác động dương mạnh nhất đến xác suất xảy ra đột quỵ, từ đó đề xuất các giải pháp phòng ngừa và can thiệp hiệu quả. Đồng thời, nghiên cứu cũng hướng đến việc phát hiện những yếu tố có tác động âm – tức là làm giảm nguy cơ – nhằm khai thác và tăng cường các yếu tố bảo vệ sức khỏe. Bên cạnh đó, nghiên cứu còn so sánh mức độ ảnh hưởng tương đối giữa các nguy cơ, từ các đặc điểm nhân khẩu học (tuổi, giới tính) đến hành vi sức khỏe (hút thuốc, béo phì) và bệnh lý nền (tăng huyết áp, tiểu đường, bệnh tim). Thông qua mô hình hồi quy nhị phân (Logit và Probit), nghiên cứu kỳ vọng cung cấp bằng chứng định lượng hỗ trợ công tác sàng lọc, dự báo nguy cơ và xây dựng chiến lược kiểm soát đột quỵ trong cộng đồng.

1.3 Đối tượng nghiên cứu

Đối tượng nghiên cứu của đề tài là các cá nhân có hồ sơ sức khỏe được ghi nhận trong bộ dữ liệu liên quan đến đột quỵ. Mỗi cá nhân được mô tả thông qua các biến đặc trưng về nhân khẩu học, chỉ số sinh học, bệnh lý nền và hành vi sức khỏe như tuổi, giới tính, mức đường huyết trung bình, BMI, tình trạng tăng huyết áp, tiểu đường, hút thuốc và địa vị xã hội. Những thông tin này được sử dụng để phân tích mối liên hệ giữa các yếu tố nguy cơ và khả năng mắc đột quỵ.

1.4 Phương pháp nghiên cứu

Nghiên cứu sử dụng phương pháp phân tích định lượng trên bộ dữ liệu bệnh nhân nhằm khám phá mối liên hệ giữa các yếu tố nguy cơ và khả năng mắc đột quỵ. Ở phân tích đơn biến, các biến định tính được phân tích thông qua bảng tần số, bảng tỷ lệ và biểu đồ cột, trong khi các biến định lượng được mô tả bằng thống kê mô tả (trung bình, trung vị, độ lệch chuẩn, tứ phân vị),biểu đồ histogram kết hợp mật độ ,biểu đồ boxplot và kiểm định phân phối chuẩn là Anderson-Darling.

Ở phân tích hai biến, các cặp biến định tính–định tính được trình bày qua bảng chéo tần số, biểu đồ cột chồng theo tỷ lệ, và kiểm định Chi-squared đồng thời tính toán Odds Ratio (OR) và Relative Risk (RR) nhằm sự tác động. Với cặp biến định tính–định lượng, nghiên cứu sử dụng biểu đồ histogram kết hợp mật độ, boxplot phân nhóm theo biến định tính, và kiểm định sự khác biệt trung bình giữa hai nhóm bằng t-test (nếu phân phối chuẩn) hoặc Wilcoxon rank-sum test (nếu không chuẩn).

Cuối cùng, mô hình hồi quy nhị phân Logit và Probit được ước lượng nhằm xác định các yếu tố nguy cơ ảnh hưởng có ý nghĩa đến xác suất xảy ra đột quỵ, đồng thời so sánh mức độ tác động tương đối của từng biến giải thích trong việc dự báo biến phụ thuộc.

Chương 2 Giới thiệu dữ liệu

df <- readxl::read_xlsx("stroke_data.xlsx")
str(df)
## tibble [10,000 × 10] (S3: tbl_df/tbl/data.frame)
##  $ Age           : num [1:10000] 66.8 86.4 76.2 72.5 59.9 ...
##  $ Gender        : chr [1:10000] "Male" "Female" "Female" "Female" ...
##  $ SES           : chr [1:10000] "Medium" "Medium" "Medium" "Low" ...
##  $ Hypertension  : num [1:10000] 1 1 1 0 0 1 1 1 1 1 ...
##  $ Heart_Disease : num [1:10000] 0 1 0 1 0 0 0 0 0 0 ...
##  $ BMI           : num [1:10000] 25.8 32.5 40.7 33 26.1 ...
##  $ Avg_Glucose   : num [1:10000] 96.4 133.4 111.5 125.7 123.2 ...
##  $ Diabetes      : num [1:10000] 1 0 0 0 1 0 0 0 0 0 ...
##  $ Smoking_Status: chr [1:10000] "Current" "Never" "Never" "Former" ...
##  $ Stroke        : num [1:10000] 1 1 0 0 1 0 1 1 0 0 ...

Đây là bộ dữ liệu tập hợp hồ sơ sức khoẻ của các bệnh nhân dùng để phân tích các yếu tố liên quan đến đột quỵ. Bộ dữ liệu này bao gồm các chỉ số về tình trạng y tế, thói quen sinh hoạt và các thông tin cá nhân.Mục tiêu chính của bộ dữ liệu là xây dựng lên mô hình có thể dự đoán đột quỵ và nghiên cứu mối tương quan giữa các yếu tố lối sống, sinh trắc học với nguy cơ mắc bệnh.

Trong bộ dữ liệu bao gồm các biến như sau:

Biến định lượng

  • Age: Tuổi của bệnh nhân
  • BMI: Chỉ số khối cơ thể, phản ánh tình trạng cân nặng của bệnh nhana
  • Avg_Glucose: Nồng độ glucose trung bình

Biến định tính

  • Gender: Giới tính của bệnh nhân
  • SES: Tình trạng kinh tế xã hội của bệnh nhân
  • Hypertension: Tình trạng cao huyết áp (1: có, 0: không)
  • Heart_Disease: Tình trạng bệnh tim (1: có, 0: không)
  • Diabetes: Tình trạng bệnh tiểu đường (1: có, 0: không)
  • Smoking_Status: Tình trạng hút thuốc được phân loại thành “Chưa bao giờ”, “Đã từng” và “Đang hút”

Biến phụ thuộc

  • Stroke: Kết quả bị đột quỵ (1: có, 0: không)

Chương 3 Phương pháp nghiên cứu

3.1 Relative Risk

Relative Risk là một chỉ số thống kê dùng để so sánh xác suất xảy ra một sự kiện giữa hai nhóm khác nhau, thường là nhóm phơi nhiễm và nhóm không phơi nhiễm. Trong nghiên cứu y sinh học và dịch tễ học, RR thường được sử dụng để đánh giá mức độ liên quan giữa một yếu tố nguy cơ và khả năng xảy ra bệnh. RR được tính bằng tỷ số giữa xác suất xảy ra sự kiện trong phạm trù đang xét chia cho xác suất xảy ra sự kiện trong phạm trù cơ sở, theo công thức:

\[ RR=\frac{P(Y=1|X=x_1)}{P(Y=1|X=x_0)}\]

Trong đó:

  • \(Y=1\): Sự kiện xảy ra. Trong nghiên cứu này là bị đột quỵ
  • \(X\): Biến phân loại
  • \(x_1\): Phạm trù đang xét
  • \(x_0\): Phạm trù cơ sở

Diễn giải và ý nghĩa của Relative Risk

Relative Risk được diễn giải như sau: Tỷ lệ sự kiện xảy ra ở phạm trù đang xét gấp RR lần tỷ lệ sự kiện xảy ra ở phạm trù cơ sở.

  • Nếu \(RR=1\): Không có sự khác biệt về tỷ lệ sự kiện xảy ra của 2 nhóm có nghĩa yếu tố đang xét không có liên hệ với sự kiện.
  • Nếu \(RR>1\): Phạm trù đang xét có tỷ lệ sự kiện xảy ra cao hơn so với phạm trù cơ sở.
  • Nếu \(RR>1\): Phạm trù đang xét có tỷ lệ sự kiện xảy ra thấp hơn so với phạm trù cơ sở.

3.2 Odds ratio

3.2.1 Khái niệm về odds

Odds còn gọi là tỷ lệ cược một cách khác đo lường tỷ lệ xảy ra của một sự kiện là một chỉ số đo lường tỷ lệ tương đối của một sự kiện xảy ra so với không xảy ra.

\[ Odds = \frac{P(Y=1)}{1-P(Y=1)}\]

3.2.2 Odds ratio

Odds Ratio (OR) là tỷ số giữa odds của một sự kiện xảy ra trong phạm trù đang xét và odds của sự kiện đó trong phạm trù cơ sở, được tính theo công thức:

\[ OR=\frac{Odds(Y=1|X=x_1)}{Odds(Y=1|X=x_0)}\] Diễn giải và ý nghĩa của Odds ratio

Odds ratio được diễn giải như sau: Odds ở phạm trù đang xét gấp OR lần Odds ở phạm trù cơ sở.

  • \(OR=1\): Không có mối liên hệ giữa yếu tố và sự kiện
  • \(OR>1\): Phạm trù đang xét có odds cao hơn
  • \(OR<1\): Phạm trù đang xét có odds thấp hơn

3.3 Kiểm định Chi-squared

Kiểm định Chi-squared được sử dụng với mục tiêu kiểm tra tính độc lập hai biến định tính trong tổng thể. Ý nghĩa của kiểm định này là giúp xác định xem sự phân bố của một biến có bị ảnh hưởng bởi biến còn lại hay không, từ đó hỗ trợ việc khám phá các mối quan hệ tiềm ẩn giữa các yếu tố định tính trong dữ liệu. Ngược lại, nếu không có bằng chứng đủ mạnh để bác bỏ giả thuyết độc lập, ta coi hai biến là độc lập với nhau. Giả thuyết kiểm định được phát biểu như sau:

\(H_0\): Hai biến định tính độc lập với nhau

\(H_1\): Hai biến định tính có mối quan hệ với nhau.

3.4 Kiểm định phân phối chuẩn Anderson-Darling

Kiểm định Anderson-Darling là kiểm định thống kê được sử dụng để đánh giá xem một mẫu dữ liệu có tuân theo một phân phối lý thuyết, cụ thể trong bài là phân phối chuẩn (normality test). Đây là một kiểm định phi tham số, có độ nhạy cao ở cả phần đuôi của phân phối, do đó thường được ưu tiên khi muốn kiểm tra sự phù hợp với phân phối chuẩn một cách nghiêm ngặt hơn so với kiểm định Shapiro-Wilk. Giá trị thống kê càng lớn cho thấy dữ liệu càng lệch khỏi phân phối chuẩn. Mục tiêu của kiểm định này là giúp cho việc lựa chọn phương pháp kiểm định mối quan hệ giữa định tính và định lượng phù hợp hơn, nếu như dữ liệu tuân theo phân phối chuẩn thì sử dụng t.test và nếu không tuân theo phân phối chuẩn thì sử dụng Wilcoxon test. Giả thuyết kiểm định như sau:

\(H_0\): Dữ liệu tuân theo phân phối chuẩn

\(H_1\): Dữ liệu không tuân theo phân phối chuẩn

3.5 Kiểm định t

Kiểm định t (t-test) là một phương pháp thống kê dùng để so sánh trung bình của hai nhóm độc lập nhằm đánh giá xem sự khác biệt giữa chúng có ý nghĩa thống kê hay không. T-test thường được sử dụng trong các tình huống mà biến phản hồi là định lượng, và biến phân nhóm là định tính nhị phân. Một giả định quan trọng của kiểm định t là dữ liệu trong mỗi nhóm phải tuân theo phân phối chuẩn và có phương sai đồng đều (trong trường hợp t-test chuẩn). Khi giả định phân phối chuẩn không thỏa mãn, nên sử dụng kiểm định phi tham số thay thế như Wilcoxon rank-sum test. Giả thuyết kiểm định như sau:

\(H_0\): Trung bình hai nhóm bằng nhau (\(\mu_1=\mu_2\))

\(H_1\): Trung bình hai nhóm khác nhau (\(\mu_1 \neq \mu_2\))

3.6 Kiểm định Wilcoxon

Kiểm định Wilcoxon rank-sum test là một kiểm định phi tham số được sử dụng để so sánh phân phối trung tâm của hai nhóm độc lập khi giả định phân phối chuẩn không được thỏa mãn. Thay vì so sánh trung bình như kiểm định t, Wilcoxon so sánh thứ hạng của các giá trị giữa hai nhóm, do đó phù hợp với dữ liệu định lượng không chuẩn hoặc có ngoại lệ. Đây là một phương pháp mạnh mẽ và phổ biến trong các tình huống thực nghiệm với mẫu nhỏ hoặc dữ liệu lệch.

\(H_0\): Hai nhóm có trung vị giống nhau

\(H_1\): Hai nhóm có trung vị khác nhau

3.7 Hồi quy Logit

Hồi quy Logistic (Logit) là một mô hình hồi quy nhị phân được sử dụng để phân tích mối quan hệ giữa một biến phụ thuộc dạng nhị phân (binary outcome) và một hoặc nhiều biến độc lập (có thể là định tính hoặc định lượng). Mô hình này đặc biệt hữu ích trong các lĩnh vực như y học, khoa học xã hội và tài chính, nơi mà biến phụ thuộc chỉ có hai trạng thái.

3.7.1 Hàm liên kết

Trong hồi quy Logistic, xác suất xảy ra sự kiện \(Y=1\) được mô hình hóa thông qua hàm logit , là log của tỷ số odds. Hàm liên kết logit đảm bảo xác suất đầu ra luôn nằm trong khoảng \((0,1)\). \[ logit(p)=log(\frac{p}{1-p})=\beta_0 + \beta_1X_1 + \beta_2X_2 +... + \beta_nX_n \] Trong đây thì \(p = P(Y=1|X)\).

3.7.2 Diễn giải hệ số

Hệ số hồi quy \(\beta_j\) đại diện cho sự thay đổi của log-odds của biến phụ thuộc khi biến độc lập tương ứng thay đổi một đơn vị. Vì \(\beta_j\) không thể diễn giải trực tiếp, chúng ta cần chuyển đổi nó bằng cách lấy lũy thừa \(e^{\beta_j}\) để nhận được Odds Ratio.Do đó, giá trị \(e^{\beta_j}\) cho biết tỷ lệ cược của sự kiện tăng (hoặc giảm) \(e^{\beta_j}\) lần khi biến độc lập \(X_j\) tăng thêm một đơn vị, với giả định các biến độc lập khác được giữ nguyên.

3.8 Hồi quy Probit

3.8.1 Hàm liên kết

Trong mô hình Probit, xác suất xảy ra sự kiện được liên kết với tổ hợp tuyến tính của các biến độc lập thông qua hàm phân phối tích lũy chuẩn (standard normal cumulative distribution function – CDF): \[ P(Y=1|X)=\Phi(\beta_0 + \beta_1X_1 + \beta_2X_2 +... + \beta_nX_n) \] Mô hình Probit giả định rằng một biến liên tục không thể quan sát được tuân theo phân phối chuẩn. Sự kiện mà ta quan sát xảy ra khi biến tiềm ẩn này vượt qua một ngưỡng cố định. Do đó, hàm Probit liên kết xác suất của kết quả nhị phân với một biến liên tục ẩn, thông qua hàm phân phối tích lũy chuẩn.

3.8.2 Diễn giải hệ số

Hệ số hồi quy trong mô hình Probit cho biết mức độ thay đổi của Z-score (hay biến tiềm ẩn) khi biến độc lập tương ứng tăng thêm một đơn vị. Cụ thể,\(\beta_j\) đại diện cho sự thay đổi về độ lệch chuẩn trong biến tiềm ẩn, từ đó làm tăng hoặc giảm xác suất sự kiện xảy ra. Vì không có cách diễn giải đơn giản về tỷ lệ cược như Logit, chúng ta thường sử dụng \(\beta_j\) để xác định hướng và mức độ ảnh hưởng của biến độc lập đối với xác suất, thay vì diễn giải trực tiếp dưới dạng “lần”.

3.9 Tiêu chí lựa chọn: AIC

AIC (Akaike Information Criterion) là một tiêu chí thống kê dùng để so sánh và lựa chọn mô hình trong trường hợp có nhiều mô hình dự đoán cùng một biến phụ thuộc. AIC đánh giá sự cân bằng giữa độ phù hợp của mô hình (goodness of fit) và độ phức tạp của mô hình (số lượng tham số). Công thức của AIC là: \[ AIC =-2log(L)+2k \] trong đó \(L\) là hàm hợp lý và \(k\) là số tham số ước lượng. Mô hình có AIC nhỏ hơn được ưu tiên chọn, vì nó cho thấy mô hình vừa khớp tốt với dữ liệu, vừa tránh được tình trạng overfitting.

3.10 Tiêu chí đánh giá

3.10.1 ROC (Receiver Operating Characteristic Curve)

Đường cong ROC là đồ thị thể hiện mối quan hệ giữa tỷ lệ dương tính thật (True Positive Rate) và tỷ lệ dương tính giả (False Positive Rate) tại các ngưỡng phân loại khác nhau. ROC cho phép đánh giá khả năng phân biệt giữa hai lớp của mô hình. Đường cong càng lệch về phía góc trên bên trái thì mô hình càng tốt.

3.10.2 AUC (Area Under the ROC Curve)

AUC là diện tích dưới đường cong ROC, đại diện cho khả năng phân biệt đúng giữa hai lớp. Giá trị AUC nằm trong khoảng từ 0 đến 1, trong đó AUC = 0.5 tương đương với mô hình ngẫu nhiên, và AUC gần 1 cho thấy mô hình phân loại rất tốt. AUC giúp so sánh hiệu quả giữa nhiều mô hình.

3.10.3 Ma trận nhầm lẫn

Ma trận nhầm lẫn là bảng 2x2 thể hiện số lượng dự đoán đúng và sai của mô hình, chia theo từng lớp (Positive/Negative). Nó bao gồm: True Positive, True Negative, False Positive và False Negative. Từ đó có thể tính các chỉ số đánh giá như: Độ chính xác (Accuracy), Độ nhạy (Sensitivity), Độ đặc hiệu (Specificity) và F1-score, giúp hiểu rõ hiệu quả mô hình trên từng mặt.

Chương 4 Kết quả nghiên cứu

4.1 Phân tích đơn biến

4.1.1 Biến Stroke

df$Stroke <- factor(df$Stroke,levels = c(0,1),labels = c("No","Yes"))

tab_result <- tabyl(df$Stroke)
colnames(tab_result) <- c("Tình trạng đột quỵ", "Tần số", "Tỷ lệ (%)")


kable(tab_result, caption = "Bảng tần số và tỷ lệ của biến Stroke", align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, # Bảng chiếm toàn bộ chiều ngang
    font_size = 14,
    position = "center" # Căn giữa bảng
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;")
Bảng tần số và tỷ lệ của biến Stroke
Tình trạng đột quỵ Tần số Tỷ lệ (%)
No 7022 0.7022
Yes 2978 0.2978
plot_data <- df %>%
    count(Stroke) %>%
    mutate(
        percentage = n / sum(n),
        label = scales::percent(percentage,accuracy = 0.001)
    )
ggplot(plot_data, aes(x = as.factor(Stroke), y = percentage, fill = Stroke)) +
    geom_bar(stat = "identity") +
    geom_text(aes(label = label), vjust = 1, size = 5) +
    labs(
        title = "Tỷ lệ bệnh nhân bị đột quỵ và không bị đột quỵ",
        x = "Bị Đột Quỵ",
        y = "Tỷ lệ",
        fill = "Bị Đột Quỵ"
    )  +
    theme_minimal() + 
    theme(
        plot.title = element_text(hjust = 0.5, face = "bold"),
        legend.position = "none" 
    )

Dữ liệu cho thấy có sự mất cân bằng giữa hai nhóm cụ thể thì bệnh nhân chưa từng bị đột quỵ chiếm 70.22%, trong khi nhóm đã bị đột quỵ là 29.78% cho thấy rằng số bệnh nhân bị đột quỵ chỉ gần một nửa số bệnh nhân không bị đột quỵ . Mặc dù đây là một bộ dữ liệu không cân bằng, nhưng số lượng ca bị đột quỵ là 2,978 vẫn đủ lớn để kết quả phân tích có ý nghĩa thống kê.

4.1.2 Biến Age

tab_summary <- df %>%
  summarise(
    Min = min(Age, na.rm = TRUE),
    Q1 = quantile(Age, 0.25, na.rm = TRUE),
    Median = median(Age, na.rm = TRUE),
    Mean = mean(Age, na.rm = TRUE),
    Q3 = quantile(Age, 0.75, na.rm = TRUE),
    Max = max(Age, na.rm = TRUE),
    SD = sd(Age, na.rm = TRUE)
  )

# Hiển thị bảng thống kê
knitr::kable(tab_summary, caption = "Bảng mô tả thống kê biến độ tuổi", align = "c")
Bảng mô tả thống kê biến độ tuổi
Min Q1 Median Mean Q3 Max SD
27.70656 63.12857 69.79604 69.75785 76.40288 99.41745 9.869468
ggplot(df, aes(x = Age)) +
    geom_histogram(aes(y = after_stat(density)), binwidth = 1, fill = "skyblue", color = "white", alpha = 0.7) +
    geom_density(color = "blue", linewidth = 1) +
    labs(
        title = "Phân phối tuổi của bệnh nhân",
        x = "Tuổi (năm)",
        y = "Mật độ"
    ) +
    theme_minimal() +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"))

ad.test(df$Age)
## 
##  Anderson-Darling normality test
## 
## data:  df$Age
## A = 0.29563, p-value = 0.5952

Kết quả phân tích thống kê mô tả cho thấy độ tuổi của bệnh nhân có phân phối gần đối xứng, với giá trị trung vị (69.79) và trung bình (69.76) gần như tương đương. Độ lệch chuẩn (9.87) và khoảng tứ phân vị là 13.27 tương đối nhỏ, cho thấy phần lớn dữ liệu tuổi tập trung chặt chẽ quanh giá trị trung bình. Mặc dù độ biến thiên khá rộng từ 27.71 đến 99.42, điều này không làm sai lệch đáng kể phân phối tổng thể. Hơn nữa, với kết quả kiểm định Anderson-Darling cho p-value là 0.5952>0.05 chúng ta có thể kết luẩn rằng Age tuân theo phân phối chuẩn. Vì thế sẽ dùng kiểm định t đối với Age

ggplot(df, aes(y = Age)) +
    geom_boxplot(fill = "lightgreen", color = "darkgreen") +
    labs(
        title = "Boxplot của tuổi",
        y = "Tuổi (năm)"
    ) +
    theme_minimal() +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"))

count_outliers <- function(x, side = c("both", "upper", "lower")) {
  side <- match.arg(side)  # Kiểm tra đối số hợp lệ
  
  # Loại bỏ NA
  x <- x[!is.na(x)]
  
  # Tính IQR
  Q1 <- quantile(x, 0.25)
  Q3 <- quantile(x, 0.75)
  IQR_value <- Q3 - Q1
  
  # Ngưỡng dưới và trên
  lower_bound <- Q1 - 1.5 * IQR_value
  upper_bound <- Q3 + 1.5 * IQR_value
  
  # Đếm số lượng theo hướng
  if (side == "lower") {
    return(sum(x < lower_bound))
  } else if (side == "upper") {
    return(sum(x > upper_bound))
  } else if (side == "both") {
    return(sum(x < lower_bound | x > upper_bound))
  }
}

cat("Giá trị ngoại lai phía trên: ", count_outliers(df$Age,"upper"),"\n")
## Giá trị ngoại lai phía trên:  23
cat("Giá trị ngoại lai phía dưới: ", count_outliers(df$Age,"lower"))
## Giá trị ngoại lai phía dưới:  29

Ở đây thì cho thấy có 23 giá trị ngoại lai ở phía trên và 29 giá trị ngoại lai ở phía dưới, nhưng các giá trị này không làm thay đổi đáng kể phân phối tổng thể. Sự hiện diện của chúng cho thấy có một số ít bệnh nhân rất trẻ cụ thế là dưới 40 hoặc rất già cụ thế là hơn 95 tuổi xuất hiện trong mẫu, tuy nhiên kết quả kiểm định chuẩn vẫn cho phép chúng ta coi biến Age tuân theo phân phối chuẩn.

4.1.3 Biến Gender

df$Gender <- factor(df$Gender,levels = c("Female","Male"))
tab_result <- tabyl(df$Gender)
colnames(tab_result) <- c("Giới tính", "Tần số", "Tỷ lệ (%)")


kable(tab_result, caption = "Bảng tần số và tỷ lệ giới tính ", align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, # Bảng chiếm toàn bộ chiều ngang
    font_size = 14,
    position = "center" # Căn giữa bảng
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;") 
Bảng tần số và tỷ lệ giới tính
Giới tính Tần số Tỷ lệ (%)
Female 5037 0.5037
Male 4963 0.4963
plot_data <- df %>%
    count(Gender) %>%
    mutate(
        percentage = n / sum(n),
        label = scales::percent(percentage,accuracy = 0.001)
    )
ggplot(plot_data, aes(x = as.factor(Gender), y = percentage, fill = Gender)) +
    geom_bar(stat = "identity") +
    geom_text(aes(label = label), vjust = 1, size = 5) +
    labs(
        title = "Tỷ lệ giới tính bệnh nhân ",
        x = "Giới tính",
        y = "Tỷ lệ"
    )  +
    theme_minimal() + 
    theme(
        plot.title = element_text(hjust = 0.5, face = "bold"),
        legend.position = "none" 
    )

Kết quả phân tích cho thấy sự cân bằng gần như hoàn hảo về giới tính trong bộ dữ liệu, với 50.37% là nữ và 49.63% là nam. Tỷ lệ này rất lý tưởng để tiến hành phân tích, đảm bảo rằng mọi kết quả liên quan đến giới tính sẽ không bị sai lệch do sự mất cân bằng trong mẫu.

4.1.4 Biến SES

df$SES <- factor(df$SES,levels = c("Low","Medium","High"))

tab_result <- tabyl(df$SES)
colnames(tab_result) <- c("Địa vị", "Tần số", "Tỷ lệ (%)")


kable(tab_result, caption = "Bảng tần số và tỷ lệ địa vị xã hội ", align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, # Bảng chiếm toàn bộ chiều ngang
    font_size = 14,
    position = "center" # Căn giữa bảng
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;") 
Bảng tần số và tỷ lệ địa vị xã hội
Địa vị Tần số Tỷ lệ (%)
Low 2870 0.2870
Medium 5106 0.5106
High 2024 0.2024
plot_data <- df %>%
    count(SES) %>%
    mutate(
        percentage = n / sum(n),
        label = scales::percent(percentage,accuracy = 0.001)
    )
ggplot(plot_data, aes(x = as.factor(SES), y = percentage, fill = SES)) +
    geom_bar(stat = "identity") +
    geom_text(aes(label = label), vjust = 1, size = 5) +
    labs(
        title = "Tỷ lệ địa vị xã hội của bệnh nhân ",
        x = "Địa vị",
        y = "Tỷ lệ"
    )  +
    theme_minimal() + 
    theme(
        plot.title = element_text(hjust = 0.5, face = "bold"),
        legend.position = "none" 
    )

Kết quả cho thấy hơn một nửa bệnh nhân thuộc nhóm có địa vị xã hội Trung bình (51.06%). Trong khi đó, nhóm Thấp và Cao lần lượt chiếm 28.70% và 20.24%. Sự phân bố này cho phép chúng ta khám phá mối liên hệ tiềm tàng giữa tình trạng kinh tế xã hội và nguy cơ đột quỵ, đặc biệt là so sánh nhóm có địa vị xã hội thấp hơn với các nhóm còn lại.

4.1.5 Biến Hypertension

df$Hypertension <- factor(df$Hypertension,levels = c(0,1),labels = c("No","Yes"))
tab_result <- tabyl(df$Hypertension)
colnames(tab_result) <- c("Tình trạng", "Tần số", "Tỷ lệ (%)")


kable(tab_result, caption = "Bảng tần số và tỷ lệ cao huyết áp ", align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, # Bảng chiếm toàn bộ chiều ngang
    font_size = 14,
    position = "center" # Căn giữa bảng
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;") 
Bảng tần số và tỷ lệ cao huyết áp
Tình trạng Tần số Tỷ lệ (%)
No 3942 0.3942
Yes 6058 0.6058
plot_data <- df %>%
    count(Hypertension) %>%
    mutate(
        percentage = n / sum(n),
        label = scales::percent(percentage,accuracy = 0.001)
    )
ggplot(plot_data, aes(x = as.factor(Hypertension), y = percentage, fill = Hypertension)) +
    geom_bar(stat = "identity") +
    geom_text(aes(label = label), vjust = 1, size = 5) +
    labs(
        title = "Tỷ lệ cao huyết áp của bệnh nhân ",
        x = "Tình trạng",
        y = "Tỷ lệ"
    )  +
    theme_minimal() + 
    theme(
        plot.title = element_text(hjust = 0.5, face = "bold"),
        legend.position = "none" 
    )

Kết quả phân tích cho thấy phần lớn bệnh nhân trong mẫu nghiên cứu có tiền sử cao huyết áp, chiếm 60.58%. Đây là một phát hiện quan trọng, cho thấy huyết áp cao là một yếu tố phổ biến và có thể đóng vai trò then chốt trong việc giải thích mối liên hệ với đột quỵ. Tỷ lệ này cũng giúp củng cố giả thuyết rằng bệnh cao huyết áp là một yếu tố nguy cơ đáng kể trong quần thể này.

4.1.6 Biến Heart_Disease

df$Heart_Disease <- factor(df$Heart_Disease,levels = c(0,1),labels = c("No","Yes"))

tab_result <- tabyl(df$Heart_Disease)
colnames(tab_result) <- c("Tình trạng", "Tần số", "Tỷ lệ (%)")


kable(tab_result, caption = "Bảng tần số và tỷ lệ bệnh tim ", align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, # Bảng chiếm toàn bộ chiều ngang
    font_size = 14,
    position = "center" # Căn giữa bảng
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;") 
Bảng tần số và tỷ lệ bệnh tim
Tình trạng Tần số Tỷ lệ (%)
No 6972 0.6972
Yes 3028 0.3028
plot_data <- df %>%
    count(Heart_Disease) %>%
    mutate(
        percentage = n / sum(n),
        label = scales::percent(percentage,accuracy = 0.001)
    )
ggplot(plot_data, aes(x = as.factor(Heart_Disease), y = percentage, fill = Heart_Disease)) +
    geom_bar(stat = "identity") +
    geom_text(aes(label = label), vjust = 1, size = 5) +
    labs(
        title = "Tỷ lệ bệnh tim của bệnh nhân ",
        x = "Tình trạng",
        y = "Tỷ lệ"
    )  +
    theme_minimal() + 
    theme(
        plot.title = element_text(hjust = 0.5, face = "bold"),
        legend.position = "none" 
    )

Kết quả cho thấy có 30.28% bệnh nhân trong mẫu nghiên cứu mắc bệnh tim, một tỷ lệ gần tương đương với tỷ lệ bệnh nhân bị đột quỵ (29.78%). Điều này gợi mở rằng có thể có một mối liên hệ chặt chẽ giữa hai tình trạng này. Tỷ lệ cao của cả bệnh tim và đột quỵ trong cùng một quần thể củng cố giả thuyết rằng bệnh tim mạch là một yếu tố nguy cơ đáng kể gây ra đột quỵ.

4.1.7 Biến BMI

tab_summary <- df %>%
  summarise(
    Min = min(BMI, na.rm = TRUE),
    Q1 = quantile(BMI, 0.25, na.rm = TRUE),
    Median = median(BMI, na.rm = TRUE),
    Mean = mean(BMI, na.rm = TRUE),
    Q3 = quantile(BMI, 0.75, na.rm = TRUE),
    Max = max(BMI, na.rm = TRUE),
    SD = sd(BMI, na.rm = TRUE)
  )

# Hiển thị bảng thống kê
knitr::kable(tab_summary, caption = "Bảng mô tả thống kê biến độ chỉ số khối", align = "c")
Bảng mô tả thống kê biến độ chỉ số khối
Min Q1 Median Mean Q3 Max SD
15.03799 24.66079 28.06693 28.04225 31.39017 47.49596 4.901424
ggplot(df, aes(x = BMI)) +
    geom_histogram(aes(y = after_stat(density)), binwidth = 1, fill = "blue", color = "white", alpha = 0.7) +
    geom_density(color = "green", linewidth = 1) +
    labs(
        title = "Phân phối chỉ số khối của bệnh nhân",
        x = "Tuổi (năm)",
        y = "Mật độ"
    ) +
    theme_minimal() +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"))

ad.test(df$BMI)
## 
##  Anderson-Darling normality test
## 
## data:  df$BMI
## A = 0.81573, p-value = 0.03504

Phân tích cho thấy chỉ số BMI có giá trị trung bình là 28.04 và trung vị là 28.07 gần bằng nhau, nhưng kết quả kiểm định Anderson-Darling lại cho p-value là 0.03504<0.05, bác bỏ giả thuyết phân phối chuẩn. Với khoảng tứ phân vị 6.73 tương đối rộng và độ lệch chuẩn là 4.90, dữ liệu BMI có vẻ phân bố không hoàn toàn đối xứng. Do không tuân theo phân phối chuẩn, các phân tích sau sẽ sử dụng các kiểm định phi tham số, chẳng hạn như kiểm định Wilcoxon, để so sánh BMI giữa các nhóm.

ggplot(df, aes(y = BMI)) +
    geom_boxplot(fill = "lightgreen", color = "darkgreen") +
    labs(
        title = "Boxplot của chỉ số khối",
        y = "BMI "
    ) +
    theme_minimal() +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"))

cat(" Giá trị ngoại lai phía trên: ",count_outliers(df$BMI,side = "upper"),"\n",
    "Giá trị ngoại lai phía dưới: ",count_outliers(df$BMI,side = "lower"))
##  Giá trị ngoại lai phía trên:  25 
##  Giá trị ngoại lai phía dưới:  0

Boxplot cho thấy có 25 giá trị ngoại lai ở phía trên, đại diện cho những bệnh nhân có chỉ số BMI rất cao, nằm ngoài phạm vi bình thường. Không có sự hiện diện của các giá trị ngoại lai ở phía dưới cho thấy không có bệnh nhân nào có chỉ số BMI quá thấp bất thường.

4.1.8 Avg_Glucose

age_summary <- df %>%
  summarise(
    Min = min(Avg_Glucose, na.rm = TRUE),
    Q1 = quantile(Avg_Glucose, 0.25, na.rm = TRUE),
    Median = median(Avg_Glucose, na.rm = TRUE),
    Mean = mean(Avg_Glucose, na.rm = TRUE),
    Q3 = quantile(Avg_Glucose, 0.75, na.rm = TRUE),
    Max = max(Avg_Glucose, na.rm = TRUE),
    SD = sd(Avg_Glucose, na.rm = TRUE)
  )

# Hiển thị bảng thống kê
knitr::kable(age_summary, caption = "Bảng mô tả thống kê đường huyết trung bình", align = "c")
Bảng mô tả thống kê đường huyết trung bình
Min Q1 Median Mean Q3 Max SD
45.56914 98.18835 109.0222 109.1159 120.3412 176.1807 16.42114
ggplot(df, aes(x = Avg_Glucose)) +
    geom_histogram(aes(y = after_stat(density)), binwidth = 1, fill = "blue", color = "white", alpha = 0.7) +
    geom_density(color = "green", linewidth = 1) +
    labs(
        title = "Phân phối đường huyết trung bình của bệnh nhân",
        x = "Tuổi (năm)",
        y = "Mật độ"
    ) +
    theme_minimal() +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"))

ad.test(df$Avg_Glucose)
## 
##  Anderson-Darling normality test
## 
## data:  df$Avg_Glucose
## A = 0.24306, p-value = 0.767

Phân tích cho thấy chỉ số đường huyết trung bình có phân phối đối xứng, với giá trị trung bình 109.12 và trung vị 109.02 rất gần nhau. Với độ lệch chuẩn 16.42 và khoảng tứ phân vị 22.15 tương đối nhỏ, phần lớn dữ liệu tập trung chặt chẽ quanh giá trị trung bình. Hơn nữa, kết quả kiểm định Anderson-Darling cho p-value là 0.767>0.05, cho thấy chúng ta có đủ cơ sở để kết luận rằng biến Avg_Glucose tuân theo phân phối chuẩn.

ggplot(df, aes(y = Avg_Glucose)) +
    geom_boxplot(fill = "lightgreen", color = "darkgreen") +
    labs(
        title = "Boxplot của đường huyết trung bình",
        y = "Avg_Glucose "
    ) +
    theme_minimal() +
    theme(plot.title = element_text(hjust = 0.5, face = "bold"))

cat(" Giá trị ngoại lai phía trên: ",count_outliers(df$Avg_Glucose,side = "upper"),"\n",
    "Giá trị ngoại lai phía dưới: ",count_outliers(df$Avg_Glucose,side = "lower"))
##  Giá trị ngoại lai phía trên:  28 
##  Giá trị ngoại lai phía dưới:  41

Biểu đồ boxplot cho thấy chỉ số đường huyết trung bình có 28 giá trị ngoại lai ở phía trên và 41 giá trị ngoại lai ở phía dưới. Sự hiện diện của những giá trị này cho thấy có một số lượng đáng kể bệnh nhân có chỉ số đường huyết bất thường, bao gồm cả những người có đường huyết rất thấp hoặc rất cao. Đường huyết bất thường là một dấu hiệu cảnh báo sức khỏe nghiêm trọng. Đường huyết quá cao là nguyên nhân chính gây ra bệnh tiểu đường và các biến chứng tim mạch. Ngược lại, đường huyết quá thấp có thể dẫn đến các vấn đề nghiêm trọng như chóng mặt, ngất xỉu, và thậm chí là hôn mê.

4.1.9 Diabetes

df$Diabetes <- factor(df$Diabetes,levels = c(0,1),labels = c("No","Yes"))

tab_result <- tabyl(df$Diabetes)
colnames(tab_result) <- c("Tình trạng", "Tần số", "Tỷ lệ (%)")


kable(tab_result, caption = "Bảng tần số và tỷ lệ tình trạng tiểu đường", align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, # Bảng chiếm toàn bộ chiều ngang
    font_size = 14,
    position = "center" # Căn giữa bảng
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;") 
Bảng tần số và tỷ lệ tình trạng tiểu đường
Tình trạng Tần số Tỷ lệ (%)
No 8040 0.804
Yes 1960 0.196
plot_data <- df %>%
    count(Diabetes) %>%
    mutate(
        percentage = n / sum(n),
        label = scales::percent(percentage,accuracy = 0.001)
    )
ggplot(plot_data, aes(x = as.factor(Diabetes), y = percentage, fill = Diabetes)) +
    geom_bar(stat = "identity") +
    geom_text(aes(label = label), vjust = 1, size = 5) +
    labs(
        title = "Tỷ lệ tình trạng tiểu đường của bệnh nhân ",
        x = "Tình trạng",
        y = "Tỷ lệ"
    )  +
    theme_minimal() + 
    theme(
        plot.title = element_text(hjust = 0.5, face = "bold"),
        legend.position = "none" 
    )

Dựa trên phân tích, phần lớn bệnh nhân trong mẫu nghiên cứu không mắc bệnh tiểu đường, chiếm 80.4%. Tuy nhiên, tỷ lệ bệnh nhân có tiểu đường cũng chiếm một phần năm trong mẫu cụ thế là 19.6%. Tỷ lệ này cho thấy tiểu đường là một vấn đề sức khỏe phổ biến trong nhóm mẫu, củng cố giả thuyết rằng đây có thể là một trong những yếu tố nguy cơ quan trọng cần được xem xét trong mô hình dự đoán đột quỵ.

4.1.10 Biến Smoking_Status

df$Smoking_Status <- factor(df$Smoking_Status,levels = c("Never","Current","Former"))

tab_result <- tabyl(df$Smoking_Status)
colnames(tab_result) <- c("Tình trạng", "Tần số", "Tỷ lệ (%)")


kable(tab_result, caption = "Bảng tần số và tỷ lệ tình trạng hút thuốc", align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, # Bảng chiếm toàn bộ chiều ngang
    font_size = 14,
    position = "center" # Căn giữa bảng
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;") 
Bảng tần số và tỷ lệ tình trạng hút thuốc
Tình trạng Tần số Tỷ lệ (%)
Never 5951 0.5951
Current 2062 0.2062
Former 1987 0.1987
plot_data <- df %>%
    count(Smoking_Status) %>%
    mutate(
        percentage = n / sum(n),
        label = scales::percent(percentage,accuracy = 0.001)
    )
ggplot(plot_data, aes(x = as.factor(Smoking_Status), y = percentage, fill = Smoking_Status)) +
    geom_bar(stat = "identity") +
    geom_text(aes(label = label), vjust = 1, size = 5) +
    labs(
        title = "Tỷ lệ tình trạng hút thuốc của bệnh nhân ",
        x = "Tình trạng",
        y = "Tỷ lệ"
    )  +
    theme_minimal() + 
    theme(
        plot.title = element_text(hjust = 0.5, face = "bold"),
        legend.position = "none" 
    )

Phân tích cho thấy phần lớn bệnh nhân trong mẫu nghiên cứu chưa bao giờ hút thuốc, chiếm tỷ lệ cao nhất là 59.51%. Trong khi đó, nhóm đang hút thuốc và đã từng hút thuốc có tỷ lệ gần tương đương nhau, lần lượt là 20.62% và 19.87%. Sự phân bố này cho phép chúng ta so sánh rõ ràng nguy cơ đột quỵ giữa ba nhóm thói quen hút thuốc khác nhau.

4.2 Phân tích hai biến

Sau khi khám phá đặc điểm của từng biến riêng lẻ, chúng ta sẽ đi sâu vào mối quan hệ giữa các biến độc lập và biến phụ thuộc (Stroke). Phần phân tích này nhằm mục đích xác định các yếu tố nguy cơ tiềm năng, lựa chọn những biến phù hợp cho việc xây dựng các mô hình dự đoán.

4.2.1 Biến Age

table_summary <- df %>%
  group_by(Stroke) %>%
  summarise(
    Min = min(Age, na.rm = TRUE),
    Q1 = quantile(Age, 0.25, na.rm = TRUE),
    Median = median(Age, na.rm = TRUE),
    Mean = mean(Age, na.rm = TRUE),
    Q3 = quantile(Age, 0.75, na.rm = TRUE),
    Max = max(Age, na.rm = TRUE),
    SD = sd(Age, na.rm = TRUE)
  )

# Hiển thị bảng đẹp
kable(table_summary,
      caption = "Bảng mô tả thống kê tuổi theo tình trạng đột quỵ", 
      align = "c",
      digits = 2)%>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, # Bảng chiếm toàn bộ chiều ngang
    font_size = 14,
    position = "center" # Căn giữa bảng
  ) %>%
  column_spec(1:ncol(table_summary), bold = TRUE, extra_css = "text-align: center;") 
Bảng mô tả thống kê tuổi theo tình trạng đột quỵ
Stroke Min Q1 Median Mean Q3 Max SD
No 27.71 61.22 67.60 67.43 73.70 99.04 9.27
Yes 44.47 69.07 75.28 75.25 81.53 99.42 9.04

Dựa trên bảng thống kê, có sự khác biệt rõ rệt về độ tuổi trung bình giữa hai nhóm. Bệnh nhân bị đột quỵ có độ tuổi trung bình 75.25 cao hơn so với nhóm không bị đột quỵ 67.43. Cả hai nhóm đều có phân phối độ tuổi tương đối đối xứng, với giá trị trung vị gần bằng trung bình. Điều này cho thấy tuổi tác là một yếu tố có mối liên hệ chặt chẽ với nguy cơ đột quỵ, củng cố giả thuyết rằng tuổi cao làm tăng nguy cơ mắc bệnh.

ggplot(df, aes(x = Stroke, y = Age, fill = Stroke)) +
  geom_boxplot(outlier.colour = "red", outlier.shape = 16, outlier.size = 2) +
  labs(
    title = "Biểu đồ Boxplot tuổi theo tình trạng đột quỵ",
    x = "Tình trạng đột quỵ ",
    y = "Tuổi"
  ) +
  theme_minimal() +
  scale_fill_discrete(name = "Đột quỵ")

mean_line <- df %>%
  group_by(Stroke) %>%
  summarise(mean_line = mean(Age, na.rm = TRUE)) %>%
  mutate(Stroke = as.factor(Stroke))  # đảm bảo khớp kiểu dữ liệu

ggplot(df, aes(x = Age, color = as.factor(Stroke), fill = as.factor(Stroke))) +
    geom_density(alpha = 0.5) +
    geom_vline(data = mean_line,
             aes(xintercept = mean_line, color = Stroke),
             linetype = "dashed", size = 1) +
  labs(
    title = "Biểu đồ mật độ của tuổi theo tình trạng đột quỵ",
    x = "Tuổi",
    fill = "Đột quỵ",
    color = "Đột quỵ"
  ) +
  theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

df %>%
  group_by(Stroke) %>%
  summarise(
    ad_statistic = ad.test(Age)$statistic,
    p_value = ad.test(Age)$p.value
  )
## # A tibble: 2 × 3
##   Stroke ad_statistic p_value
##   <fct>         <dbl>   <dbl>
## 1 No            0.497  0.213 
## 2 Yes           0.682  0.0750
t.test(Age~Stroke,df)
## 
##  Welch Two Sample t-test
## 
## data:  Age by Stroke
## t = -39.291, df = 5740.5, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group No and group Yes is not equal to 0
## 95 percent confidence interval:
##  -8.213907 -7.433220
## sample estimates:
##  mean in group No mean in group Yes 
##          67.42799          75.25155

Kết quả kiểm định t cho thấy một sự khác biệt có ý nghĩa thống kê về độ tuổi trung bình giữa nhóm bệnh nhân bị đột quỵ và không bị đột quỵ. Cụ thể, với p-value rất nhỏ (<2.2e−16), chúng ta có thể bác bỏ giả thuyết không có sự khác biệt. Khoảng tin cậy 95% ([−8.21,−7.43]) không chứa số 0, xác nhận rằng tuổi trung bình của nhóm đột quỵ (75.25) cao hơn đáng kể so với nhóm không đột quỵ (67.43). Phân tích boxplot cho thấy có giá trị ngoại lai ở cả hai đầu của nhóm không đột quỵ, nhưng chỉ có ở phía dưới đối với nhóm đột quỵ. Điều này cho thấy có một số ít bệnh nhân rất trẻ bị đột quỵ, nhưng đa số bệnh nhân đột quỵ lại ở độ tuổi cao.

4.2.2 Biến Gender

tab <-  table(df$Gender,df$Stroke)
proptab <- prop.table(tab, margin = 1)
freq_df <- as.data.frame.matrix(tab)
prop_df <- as.data.frame.matrix(proptab)
colnames(freq_df) <- paste("Tần số", colnames(freq_df))
colnames(prop_df) <- paste("Tỷ lệ", colnames(prop_df))
tab_result <- cbind(freq_df, prop_df)
tab_result <- tab_result %>%
  mutate(across(starts_with("Tỷ lệ"), ~ percent(.x, 0.01)))
tab_result <- tab_result %>%
  rownames_to_column("Giới tính")


kable(tab_result, caption = "Bảng tần số và tỷ lệ giới tính theo tình trạng đột quỵ", align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, 
    font_size = 14,
    position = "center" 
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;") 
Bảng tần số và tỷ lệ giới tính theo tình trạng đột quỵ
Giới tính Tần số No Tần số Yes Tỷ lệ No Tỷ lệ Yes
Female 3548 1489 70.44% 29.56%
Male 3474 1489 70.00% 30.00%
df_percent <- df %>%
    group_by(Stroke, Smoking_Status) %>%
    summarise(Count = n(), .groups = "drop") %>%
    group_by(Smoking_Status) %>%
    mutate(Percent = Count / sum(Count))

ggplot(df_percent, aes(x = Smoking_Status, y = Percent, fill = Stroke)) +
    geom_col(position = "stack") +
    geom_text(aes(label = scales::percent(Percent, accuracy = 0.01)),
              position = position_stack(vjust = 0.5), color = "white") +
    scale_y_continuous(labels = scales::percent_format()) +
    labs(
        title = "Tỷ lệ bị đột quỵ theo tình trạng hút thuốc",
        y = "Tỷ lệ (%)", x = "Hút thuốc", fill = "Tình trạng"
    ) +
    theme_minimal()

riskratio(tab)$measure
##         risk ratio with 95% C.I.
##          estimate     lower    upper
##   Female  1.00000        NA       NA
##   Male    1.01491 0.9556228 1.077876
riskratio(tab)$p.value
##         two-sided
##          midp.exact fisher.exact chi.square
##   Female         NA           NA         NA
##   Male    0.6299362    0.6305196  0.6298623
oddsratio(tab)$measure
##         odds ratio with 95% C.I.
##          estimate     lower    upper
##   Female 1.000000        NA       NA
##   Male   1.021299 0.9373929 1.112752
oddsratio(tab)$p.value
##         two-sided
##          midp.exact fisher.exact chi.square
##   Female         NA           NA         NA
##   Male    0.6299362    0.6305196  0.6298623
chisq.test(tab)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tab
## X-squared = 0.21165, df = 1, p-value = 0.6455

Kết quả phân tích cho thấy không có sự khác biệt nào về tỷ lệ đột quỵ giữa nam và nữ. Cụ thể, tỷ lệ đột quỵ ở nam giới là 30.00%, chỉ cao hơn một chút so với nữ giới là 29.56%. Tương ứng, Relative Risk (RR) cho thấy nguy cơ đột quỵ ở nam giới cao hơn nữ giới khoảng 1.5%, nhưng giá trị này không có ý nghĩa thống kê. Điều này được xác nhận bởi cả kiểm định Chi-squared và các kiểm định khác, với p-value >0.6 đều lớn hơn nhiều so với ngưỡng 0.05. Tương tự, Odds Ratio (OR) cũng cho thấy tỷ lệ cược đột quỵ ở nam giới cao hơn 2.1% so với nữ, nhưng khoảng tin cậy của OR [0.937,1.113] chứa số 1, khẳng định sự khác biệt này không có ý nghĩa thống kê.

4.2.3 SES

tab <-  table(df$SES,df$Stroke)
proptab <- prop.table(tab, margin = 1)
freq_df <- as.data.frame.matrix(tab)
prop_df <- as.data.frame.matrix(proptab)
colnames(freq_df) <- paste("Tần số", colnames(freq_df))
colnames(prop_df) <- paste("Tỷ lệ", colnames(prop_df))
tab_result <- cbind(freq_df, prop_df)
tab_result <- tab_result %>%
  mutate(across(starts_with("Tỷ lệ"), ~ percent(.x, 0.01)))
tab_result <- tab_result %>%
  rownames_to_column("Địa vị")


kable(tab_result, caption = "Bảng tần số và tỷ lệ tình trạng đột quỵ theo địa vị xã hội", align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, 
    font_size = 14,
    position = "center" 
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;") 
Bảng tần số và tỷ lệ tình trạng đột quỵ theo địa vị xã hội
Địa vị Tần số No Tần số Yes Tỷ lệ No Tỷ lệ Yes
Low 2071 799 72.16% 27.84%
Medium 3543 1563 69.39% 30.61%
High 1408 616 69.57% 30.43%
df_percent <- df %>%
    group_by(Stroke, SES) %>%
    summarise(Count = n(), .groups = "drop") %>%
    group_by(SES) %>%
    mutate(Percent = Count / sum(Count))

ggplot(df_percent, aes(x = SES, y = Percent, fill = Stroke)) +
    geom_col(position = "stack") +
    geom_text(aes(label = scales::percent(Percent, accuracy = 0.01)),
              position = position_stack(vjust = 0.5), color = "white") +
    scale_y_continuous(labels = scales::percent_format()) +
    labs(
        title = "Tỷ lệ bị đột quỵ theo địa vị xã hội",
        y = "Tỷ lệ (%)", x = "Địa vị", fill = "Tình trạng"
    ) +
    theme_minimal()

riskratio(tab)$measure
##         risk ratio with 95% C.I.
##          estimate    lower    upper
##   Low    1.000000       NA       NA
##   Medium 1.099546 1.023227 1.181557
##   High   1.093214 1.000762 1.194207
riskratio(tab)$p.value
##         two-sided
##           midp.exact fisher.exact  chi.square
##   Low             NA           NA          NA
##   Medium 0.009133705  0.009854671 0.009271768
##   High   0.048951886  0.050848363 0.048602625
oddsratio(tab)$measure
##         odds ratio with 95% C.I.
##          estimate    lower    upper
##   Low    1.000000       NA       NA
##   Medium 1.143370 1.033766 1.265201
##   High   1.133997 1.000563 1.284896
oddsratio(tab)$p.value
##         two-sided
##           midp.exact fisher.exact  chi.square
##   Low             NA           NA          NA
##   Medium 0.009133705  0.009854671 0.009271768
##   High   0.048951886  0.050848363 0.048602625
chisq.test(tab)
## 
##  Pearson's Chi-squared test
## 
## data:  tab
## X-squared = 7.2681, df = 2, p-value = 0.02641

Kết quả phân tích cho thấy có sự khác biệt có ý nghĩa thống kê về tỷ lệ đột quỵ giữa các nhóm địa vị xã hội. Cụ thể, kiểm định Chi-squared có p-value = 0.02641, nhỏ hơn ngưỡng 0.05, cho phép chúng ta bác bỏ giả thuyết không có mối liên hệ. Phân tích RR và OR cho thấy nguy cơ và tỷ lệ cược đột quỵ của nhóm địa vị Trung bình và Cao đều cao hơn so với nhóm Thấp. Cụ thể, nguy cơ đột quỵ ở nhóm Trung bình cao hơn 1.1 lần (RR = 1.099) và nhóm Cao cao hơn 1.09 lần (RR = 1.093) so với nhóm Thấp. Tương tự, tỷ số chênh (OR) của hai nhóm này cũng cao hơn đáng kể so với nhóm tham chiếu. Mặc dù sự khác biệt này có ý nghĩa thống kê, nhưng nó không cho thấy một xu hướng tăng tuyến tính, khi mà nhóm có địa vị cao không có nguy cơ lớn hơn nhóm trung bình.

4.2.4 Biến Hypertension

tab <-  table(df$Hypertension,df$Stroke)
proptab <- prop.table(tab, margin = 1)
freq_df <- as.data.frame.matrix(tab)
prop_df <- as.data.frame.matrix(proptab)
colnames(freq_df) <- paste("Tần số", colnames(freq_df))
colnames(prop_df) <- paste("Tỷ lệ", colnames(prop_df))
tab_result <- cbind(freq_df, prop_df)
tab_result <- tab_result %>%
  mutate(across(starts_with("Tỷ lệ"), ~ percent(.x, 0.01)))
tab_result <- tab_result %>%
  rownames_to_column("Cao huyết áp")


kable(tab_result, caption = "Bảng tần số và tỷ lệ tình trạng đột quỵ theo tình trạng cao huyết áp",
      align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, 
    font_size = 14,
    position = "center" 
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;") 
Bảng tần số và tỷ lệ tình trạng đột quỵ theo tình trạng cao huyết áp
Cao huyết áp Tần số No Tần số Yes Tỷ lệ No Tỷ lệ Yes
No 3637 305 92.26% 7.74%
Yes 3385 2673 55.88% 44.12%
df_percent <- df %>%
    group_by(Stroke, Hypertension) %>%
    summarise(Count = n(), .groups = "drop") %>%
    group_by(Hypertension) %>%
    mutate(Percent = Count / sum(Count))

ggplot(df_percent, aes(x = Hypertension, y = Percent, fill = Stroke)) +
    geom_col(position = "stack") +
    geom_text(aes(label = scales::percent(Percent, accuracy = 0.01)),
              position = position_stack(vjust = 0.5), color = "white") +
    scale_y_continuous(labels = scales::percent_format()) +
    labs(
        title = "Tỷ lệ đột quỵ theo tình trạng cao huyết áp ",
        y = "Tỷ lệ (%)", x = "Tình trạng", fill = "Tình trạng"
    ) +
    theme_minimal()

riskratio(tab)$measure
##      risk ratio with 95% C.I.
##       estimate    lower    upper
##   No  1.000000       NA       NA
##   Yes 5.702778 5.101287 6.375191
riskratio(tab)$p.value
##      two-sided
##       midp.exact fisher.exact chi.square
##   No          NA           NA         NA
##   Yes          0            0          0
oddsratio(tab)$measure
##      odds ratio with 95% C.I.
##       estimate    lower    upper
##   No  1.000000       NA       NA
##   Yes 9.410503 8.297965 10.70661
oddsratio(tab)$p.value
##      two-sided
##       midp.exact fisher.exact chi.square
##   No          NA           NA         NA
##   Yes          0            0          0
chisq.test(tab)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tab
## X-squared = 1510.2, df = 1, p-value < 2.2e-16

Kết quả cho thấy mối liên hệ mạnh mẽ và có ý nghĩa thống kê giữa tình trạng cao huyết áp và đột quỵ. Cụ thể, kiểm định Chi-squared có p-value rất nhỏ (<2.2e−16), cho phép chúng ta bác bỏ giả thuyết không và khẳng định có mối liên hệ. Tỷ lệ đột quỵ ở nhóm có cao huyết áp là 44.12%, cao hơn rất nhiều so với nhóm không có cao huyết áp chỉ 7.74%. Phân tích Relative Risk (RR = 5.70) cho thấy nguy cơ đột quỵ ở bệnh nhân có cao huyết áp cao gấp 5.7 lần so với nhóm không có. Tương tự, Odds Ratio (OR = 9.41) khẳng định tỷ lệ cược đột quỵ ở nhóm có cao huyết áp cao gấp 9.4 lần. Cả hai chỉ số này đều có khoảng tin cậy không chứa số 1, cùng với p-value rất nhỏ, xác nhận rằng cao huyết áp là một trong những yếu tố nguy cơ quan trọng nhất gây ra đột quỵ trong bộ dữ liệu này.

4.2.5 Biến Heart_Disease

tab <-  table(df$Heart_Disease,df$Stroke)
proptab <- prop.table(tab, margin = 1)
freq_df <- as.data.frame.matrix(tab)
prop_df <- as.data.frame.matrix(proptab)
colnames(freq_df) <- paste("Tần số", colnames(freq_df))
colnames(prop_df) <- paste("Tỷ lệ", colnames(prop_df))
tab_result <- cbind(freq_df, prop_df)
tab_result <- tab_result %>%
  mutate(across(starts_with("Tỷ lệ"), ~ percent(.x, 0.01)))
tab_result <- tab_result %>%
  rownames_to_column("Tình trạng")


kable(tab_result, caption = "Bảng tần số và tỷ lệ tình trạng đột quỵ theo tình trạng bệnh tim", align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, 
    font_size = 14,
    position = "center" 
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;") 
Bảng tần số và tỷ lệ tình trạng đột quỵ theo tình trạng bệnh tim
Tình trạng Tần số No Tần số Yes Tỷ lệ No Tỷ lệ Yes
No 5472 1500 78.49% 21.51%
Yes 1550 1478 51.19% 48.81%
df_percent <- df %>%
    group_by(Stroke, Heart_Disease) %>%
    summarise(Count = n(), .groups = "drop") %>%
    group_by(Heart_Disease) %>%
    mutate(Percent = Count / sum(Count))

ggplot(df_percent, aes(x = Heart_Disease, y = Percent, fill = Stroke)) +
    geom_col(position = "stack") +
    geom_text(aes(label = scales::percent(Percent, accuracy = 0.01)),
              position = position_stack(vjust = 0.5), color = "white") +
    scale_y_continuous(labels = scales::percent_format()) +
    labs(
        title = "Tỷ lệ tình trạng đột quỵ theo tình trạng bệnh tim",
        y = "Tỷ lệ (%)", x = "Tình trạng", fill = "Tình trạng"
    ) +
    theme_minimal()

riskratio(tab)$measure
##      risk ratio with 95% C.I.
##       estimate    lower    upper
##   No   1.00000       NA       NA
##   Yes  2.26874 2.141332 2.403728
cat("\n")
riskratio(tab)$p.value
##      two-sided
##       midp.exact  fisher.exact    chi.square
##   No          NA            NA            NA
##   Yes          0 3.731689e-159 1.325279e-165
cat("\n")
oddsratio(tab)$measure
##      odds ratio with 95% C.I.
##       estimate   lower    upper
##   No  1.000000      NA       NA
##   Yes 3.477951 3.17468 3.811347
cat("\n")
oddsratio(tab)$p.value
##      two-sided
##       midp.exact  fisher.exact    chi.square
##   No          NA            NA            NA
##   Yes          0 3.731689e-159 1.325279e-165
cat("\n")
chisq.test(tab)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tab
## X-squared = 750.91, df = 1, p-value < 2.2e-16

Kết quả phân tích cho thấy một mối liên hệ mạnh mẽ và có ý nghĩa thống kê giữa việc mắc bệnh tim và nguy cơ đột quỵ. Kiểm định Chi-squared có p-value rất nhỏ (<2.2e−16), cho phép chúng ta bác bỏ giả thuyết không và khẳng định có mối liên hệ như phân tích ở đơn biến. Tỷ lệ đột quỵ ở bệnh nhân có bệnh tim là 48.81%, cao hơn gấp đôi so với nhóm không có bệnh tim chỉ 21.51%. Phân tích Relative Risk (RR = 2.27) cho thấy nguy cơ đột quỵ ở bệnh nhân có bệnh tim cao gấp 2.27 lần so với nhóm không mắc. Tương tự, Odds Ratio (OR = 3.48) cho thấy tỷ lệ cược đột quỵ của nhóm có bệnh tim cao gấp 3.48 lần. Cả hai chỉ số này đều có khoảng tin cậy không chứa số 1 và p-value cực nhỏ, khẳng định rằng bệnh tim là một yếu tố nguy cơ rất đáng kể đối với đột quỵ.

4.2.6 biến BMI

table_summary <- df %>%
    group_by(Stroke) %>%
    summarise(
        Min = min(BMI, na.rm = TRUE),
        Q1 = quantile(BMI, 0.25, na.rm = TRUE),
        Median = median(BMI, na.rm = TRUE),
        Mean = mean(BMI, na.rm = TRUE),
        Q3 = quantile(BMI, 0.75, na.rm = TRUE),
        Max = max(BMI, na.rm = TRUE),
        SD = sd(BMI, na.rm = TRUE)
    )

# Hiển thị bảng đẹp
kable(table_summary,
      caption = "Bảng mô tả thống kê chỉ số khối theo tình trạng đột quỵ", 
      align = "c",
      digits = 2)%>%
    kable_styling(
        bootstrap_options = c("striped", "hover", "condensed", "responsive"),
        full_width = TRUE, # Bảng chiếm toàn bộ chiều ngang
        font_size = 14,
        position = "center" # Căn giữa bảng
    ) %>%
    column_spec(1:ncol(table_summary), bold = TRUE, extra_css = "text-align: center;") 
Bảng mô tả thống kê chỉ số khối theo tình trạng đột quỵ
Stroke Min Q1 Median Mean Q3 Max SD
No 15.04 24.47 27.79 27.78 31.06 47.50 4.86
Yes 15.22 25.21 28.80 28.67 32.03 45.97 4.93

Dựa trên bảng thống kê, có sự khác biệt rõ ràng về chỉ số BMI trung bình giữa hai nhóm. Nhóm bệnh nhân bị đột quỵ (Yes) có BMI trung bình (28.67) cao hơn một chút so với nhóm không bị đột quỵ (No) (27.78). Cả hai nhóm đều có giá trị trung bình và trung vị gần bằng nhau, cho thấy phân phối không bị lệch nhiều. Tuy nhiên, chỉ số BMI của nhóm đột quỵ có vẻ cao hơn, gợi ý rằng béo phì có thể là một yếu tố nguy cơ.

ggplot(df, aes(x = Stroke, y = BMI, fill = Stroke)) +
    geom_boxplot(outlier.colour = "red", outlier.shape = 16, outlier.size = 2) +
    labs(
        title = "Biểu đồ Boxplot chỉ số khối theo tình trạng đột quỵ",
        x = "Tình trạng đột quỵ ",
        y = "Chỉ số khối"
    ) +
    theme_minimal() +
    scale_fill_discrete(name = "Đột quỵ")

median_line <- df %>%
    group_by(Stroke) %>%
    summarise(median_line = median(BMI, na.rm = TRUE)) %>%
    mutate(Stroke = as.factor(Stroke))  # đảm bảo khớp kiểu dữ liệu

ggplot(df, aes(x = BMI, color = as.factor(Stroke), fill = as.factor(Stroke))) +
    geom_density(alpha = 0.5) +
    geom_vline(data = median_line,
               aes(xintercept = median_line, color = Stroke),
               linetype = "dashed", size = 1) +
    labs(
        title = "Biểu đồ mật độ của chỉ số khối theo tình trạng đột quỵ",
        x = "Chỉ số khối",
        fill = "Đột quỵ",
        color = "Đột quỵ"
    ) +
    theme_minimal()

df %>%
  group_by(Stroke) %>%
  summarise(
    ad_statistic = ad.test(BMI)$statistic,
    p_value = ad.test(BMI)$p.value
  )
## # A tibble: 2 × 3
##   Stroke ad_statistic p_value
##   <fct>         <dbl>   <dbl>
## 1 No            0.520   0.186
## 2 Yes           0.596   0.120
t.test(BMI~ Stroke,df)
## 
##  Welch Two Sample t-test
## 
## data:  BMI by Stroke
## t = -8.3041, df = 5536.1, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group No and group Yes is not equal to 0
## 95 percent confidence interval:
##  -1.1029266 -0.6816343
## sample estimates:
##  mean in group No mean in group Yes 
##          27.77653          28.66881

Kết quả kiểm định Wilcoxon cho thấy sự khác biệt có ý nghĩa thống kê về chỉ số BMI giữa hai nhóm bệnh nhân. Với p-value rất nhỏ (9.546e−16), chúng ta có thể bác bỏ giả thuyết không và khẳng định có sự khác biệt. Điều này xác nhận rằng chỉ số BMI của nhóm đột quỵ cao hơn đáng kể so với nhóm không đột quỵ. Phân tích boxplot cho thấy cả hai nhóm đều có giá trị ngoại lai phía trên, cho thấy cả hai nhóm đều có những cá nhân béo phì. Tuy nhiên, sự khác biệt về BMI trung vị vẫn đủ lớn để khẳng định BMI là một yếu tố nguy cơ ảnh hưởng đến đột quỵ.

4.2.7 Biến Avg_Glucose

table_summary <- df %>%
    group_by(Stroke) %>%
    summarise(
        Min = min(Avg_Glucose, na.rm = TRUE),
        Q1 = quantile(Avg_Glucose, 0.25, na.rm = TRUE),
        Median = median(Avg_Glucose, na.rm = TRUE),
        Mean = mean(Avg_Glucose, na.rm = TRUE),
        Q3 = quantile(Avg_Glucose, 0.75, na.rm = TRUE),
        Max = max(Avg_Glucose, na.rm = TRUE),
        SD = sd(Avg_Glucose, na.rm = TRUE)
    )

# Hiển thị bảng đẹp
kable(table_summary,
      caption = "Bảng mô tả thống kê đường huyết trung bình theo tình trạng đột quỵ", 
      align = "c",
      digits = 2)%>%
    kable_styling(
        bootstrap_options = c("striped", "hover", "condensed", "responsive"),
        full_width = TRUE, # Bảng chiếm toàn bộ chiều ngang
        font_size = 14,
        position = "center" # Căn giữa bảng
    ) %>%
    column_spec(1:ncol(table_summary), bold = TRUE, extra_css = "text-align: center;") 
Bảng mô tả thống kê đường huyết trung bình theo tình trạng đột quỵ
Stroke Min Q1 Median Mean Q3 Max SD
No 45.57 95.91 106.80 106.76 117.57 161.03 16.04
Yes 61.03 103.69 114.82 114.68 125.69 176.18 15.97

Dựa trên bảng thống kê, có sự khác biệt rõ rệt về mức đường huyết trung bình giữa hai nhóm. Bệnh nhân bị đột quỵ có đường huyết trung bình (114.68) và trung vị (114.82) cao hơn nhiều so với nhóm không bị đột quỵ (106.76 và 106.80). Độ lệch chuẩn của cả hai nhóm đều tương đối thấp, cho thấy dữ liệu tập trung chặt chẽ quanh giá trị trung bình. Sự khác biệt này gợi ý rằng đường huyết cao là một yếu tố nguy cơ đáng kể của đột quỵ.

ggplot(df, aes(x = Stroke, y = Avg_Glucose, fill = Stroke)) +
    geom_boxplot(outlier.colour = "red", outlier.shape = 16, outlier.size = 2) +
    labs(
        title = "Biểu đồ Boxplot đường huyết trung bình theo tình trạng đột quỵ",
        x = "Tình trạng đột quỵ ",
        y = "Đường huyết trung bình"
    ) +
    theme_minimal() +
    scale_fill_discrete(name = "Đột quỵ")

mean_line <- df %>%
    group_by(Stroke) %>%
    summarise(mean_line = mean(Avg_Glucose, na.rm = TRUE)) %>%
    mutate(Stroke = as.factor(Stroke))  

ggplot(df, aes(x = Avg_Glucose, color = as.factor(Stroke), fill = as.factor(Stroke))) +
    geom_density(alpha = 0.5) +
    geom_vline(data = mean_line,
               aes(xintercept = mean_line, color = Stroke),
               linetype = "dashed", size = 1) +
    labs(
        title = "Biểu đồ mật độ đường huyết trung bình  theo tình trạng đột quỵ",
        x = "Tuổi",
        fill = "Đột quỵ",
        color = "Đột quỵ"
    ) +
    theme_minimal()

df %>%
  group_by(Stroke) %>%
  summarise(
    ad_statistic = ad.test(Avg_Glucose)$statistic,
    p_value = ad.test(Avg_Glucose)$p.value
  )
## # A tibble: 2 × 3
##   Stroke ad_statistic p_value
##   <fct>         <dbl>   <dbl>
## 1 No            0.182   0.912
## 2 Yes           0.487   0.224
t.test(Avg_Glucose~Stroke,df)
## 
##  Welch Two Sample t-test
## 
## data:  Avg_Glucose by Stroke
## t = -22.658, df = 5632.3, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group No and group Yes is not equal to 0
## 95 percent confidence interval:
##  -8.607533 -7.236683
## sample estimates:
##  mean in group No mean in group Yes 
##          106.7567          114.6788

Kết quả kiểm định t cho thấy sự khác biệt có ý nghĩa thống kê về đường huyết trung bình giữa hai nhóm bệnh nhân. Với p-value rất nhỏ (<2.2e−16), chúng ta bác bỏ giả thuyết không và khẳng định có sự khác biệt. Khoảng tin cậy 95% không chứa số 0, xác nhận rằng đường huyết trung bình của nhóm đột quỵ (114.68) cao hơn đáng kể so với nhóm không đột quỵ (106.76). Phân tích boxplot cho thấy cả hai nhóm đều có giá trị ngoại lai ở cả hai đầu, nhưng đáng chú ý là giá trị ngoại lai phía dưới của nhóm đột quỵ lại cao hơn nhóm không đột quỵ. Điều này củng cố giả thuyết rằng đường huyết cao là một yếu tố nguy cơ của đột quỵ.

4.2.8 Diabetes

tab <-  table(df$Diabetes,df$Stroke)
proptab <- prop.table(tab, margin = 1)
freq_df <- as.data.frame.matrix(tab)
prop_df <- as.data.frame.matrix(proptab)
colnames(freq_df) <- paste("Tần số", colnames(freq_df))
colnames(prop_df) <- paste("Tỷ lệ", colnames(prop_df))
tab_result <- cbind(freq_df, prop_df)
tab_result <- tab_result %>%
  mutate(across(starts_with("Tỷ lệ"), ~ percent(.x, 0.01)))
tab_result <- tab_result %>%
  rownames_to_column("Tình trạng tiểu đường")


kable(tab_result, caption = "Bảng tần số và tỷ lệ tình trạng đột quỵ theo tình trạng tiểu đường", align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, 
    font_size = 14,
    position = "center" 
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;") 
Bảng tần số và tỷ lệ tình trạng đột quỵ theo tình trạng tiểu đường
Tình trạng tiểu đường Tần số No Tần số Yes Tỷ lệ No Tỷ lệ Yes
No 6096 1944 75.82% 24.18%
Yes 926 1034 47.24% 52.76%
df_percent <- df %>%
    group_by(Stroke, Diabetes) %>%
    summarise(Count = n(), .groups = "drop") %>%
    group_by(Diabetes) %>%
    mutate(Percent = Count / sum(Count))

ggplot(df_percent, aes(x = Diabetes, y = Percent, fill = Stroke)) +
    geom_col(position = "stack") +
    geom_text(aes(label = scales::percent(Percent, accuracy = 0.01)),
              position = position_stack(vjust = 0.5), color = "white") +
    scale_y_continuous(labels = scales::percent_format()) +
    labs(
        title = "Tỷ lệ bị đột quỵ theo tình trạng tiểu đường",
        y = "Tỷ lệ (%)", x = "Tình trạng tiểu đường", fill = "Tình trạng"
    ) +
    theme_minimal()

riskratio(tab)$measure
##      risk ratio with 95% C.I.
##       estimate    lower    upper
##   No  1.000000       NA       NA
##   Yes 2.181847 2.060879 2.309916
cat("\n")
riskratio(tab)$p.value
##      two-sided
##       midp.exact  fisher.exact    chi.square
##   No          NA            NA            NA
##   Yes          0 9.202261e-127 7.636659e-136
cat("\n")
oddsratio(tab)$measure
##      odds ratio with 95% C.I.
##       estimate    lower    upper
##   No  1.000000       NA       NA
##   Yes 3.500922 3.160691 3.878516
cat("\n")
oddsratio(tab)$p.value
##      two-sided
##       midp.exact  fisher.exact    chi.square
##   No          NA            NA            NA
##   Yes          0 9.202261e-127 7.636659e-136
cat("\n")
chisq.test(tab)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tab
## X-squared = 613.99, df = 1, p-value < 2.2e-16

Kết quả phân tích cho thấy một mối liên hệ mạnh mẽ và có ý nghĩa thống kê giữa tình trạng tiểu đường và đột quỵ. Kiểm định Chi-squared có p-value cực nhỏ (<2.2e−16), cho phép chúng ta bác bỏ giả thuyết không có mối liên hệ. Tỷ lệ đột quỵ ở bệnh nhân tiểu đường là 52.76%, cao hơn gấp đôi so với nhóm không mắc bệnh tiểu đường chỉ 24.18%. Phân tích Relative Risk (RR = 2.18) cho thấy nguy cơ đột quỵ ở bệnh nhân tiểu đường cao gấp 2.18 lần so với nhóm không mắc bệnh. Tương tự, Odds Ratio (OR = 3.50) cho thấy tỷ lệ cược đột quỵ của nhóm có bệnh tiểu đường cao gấp 3.5 lần. Cả hai chỉ số này đều có khoảng tin cậy không chứa số 1 và p-value rất nhỏ, khẳng định rằng tiểu đường là một yếu tố nguy cơ đáng kể của đột quỵ.

4.2.9 Smoking_Status

tab <-  table(df$Smoking_Status,df$Stroke)
proptab <- prop.table(tab, margin = 1)
freq_df <- as.data.frame.matrix(tab)
prop_df <- as.data.frame.matrix(proptab)
colnames(freq_df) <- paste("Tần số", colnames(freq_df))
colnames(prop_df) <- paste("Tỷ lệ", colnames(prop_df))
tab_result <- cbind(freq_df, prop_df)
tab_result <- tab_result %>%
  mutate(across(starts_with("Tỷ lệ"), ~ percent(.x, 0.01)))
tab_result <- tab_result %>%
  rownames_to_column("Tình trạng hút thuốc")


kable(tab_result, caption = "Bảng tần số và tỷ lệ tình trạng đột quỵ theo tình trạng hút thuốc", align = "c") %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    full_width = TRUE, 
    font_size = 14,
    position = "center" 
  ) %>%
  column_spec(1:ncol(tab_result), bold = TRUE, extra_css = "text-align: center;") 
Bảng tần số và tỷ lệ tình trạng đột quỵ theo tình trạng hút thuốc
Tình trạng hút thuốc Tần số No Tần số Yes Tỷ lệ No Tỷ lệ Yes
Never 4263 1688 71.64% 28.36%
Current 1300 762 63.05% 36.95%
Former 1459 528 73.43% 26.57%
df_percent <- df %>%
    group_by(Stroke, Smoking_Status) %>%
    summarise(Count = n(), .groups = "drop") %>%
    group_by(Smoking_Status) %>%
    mutate(Percent = Count / sum(Count))

ggplot(df_percent, aes(x = Smoking_Status, y = Percent, fill = Stroke)) +
    geom_col(position = "stack") +
    geom_text(aes(label = scales::percent(Percent, accuracy = 0.01)),
              position = position_stack(vjust = 0.5), color = "white") +
    scale_y_continuous(labels = scales::percent_format()) +
    labs(
        title = "Tỷ lệ bị đột quỵ theo tình trạng hút thuốc",
        y = "Tỷ lệ (%)", x = "Tình trạng hút thuốc", fill = "Tình trạng"
    ) +
    theme_minimal()

riskratio(tab)$measure
##          risk ratio with 95% C.I.
##            estimate     lower    upper
##   Never   1.0000000        NA       NA
##   Current 1.3028182 1.2155372 1.396366
##   Former  0.9368144 0.8617663 1.018398
cat("\n")
riskratio(tab)$p.value
##          two-sided
##             midp.exact fisher.exact   chi.square
##   Never             NA           NA           NA
##   Current 5.382361e-13 6.267566e-13 2.972286e-13
##   Former  1.224893e-01 1.259125e-01 1.230677e-01
cat("\n")
oddsratio(tab)$measure
##          odds ratio with 95% C.I.
##            estimate     lower    upper
##   Never   1.0000000        NA       NA
##   Current 1.4803110 1.3315383 1.645093
##   Former  0.9140847 0.8148156 1.024357
cat("\n")
oddsratio(tab)$p.value
##          two-sided
##             midp.exact fisher.exact   chi.square
##   Never             NA           NA           NA
##   Current 5.382361e-13 6.267566e-13 2.972286e-13
##   Former  1.224893e-01 1.259125e-01 1.230677e-01
cat("\n")
chisq.test(tab)
## 
##  Pearson's Chi-squared test
## 
## data:  tab
## X-squared = 66.227, df = 2, p-value = 4.159e-15

Kết quả phân tích cho thấy có một mối liên hệ có ý nghĩa thống kê giữa tình trạng hút thuốc và nguy cơ đột quỵ, được xác nhận bởi kiểm định Chi-squared với p-value rất nhỏ (4.159e−15). Tỷ lệ đột quỵ ở nhóm đang hút thuốc là 36.95%, cao hơn đáng kể so với nhóm chưa bao giờ hút thuốc (28.36%) và nhóm đã từng hút thuốc (26.57%). Phân tích Relative Risk (RR) cho thấy nguy cơ đột quỵ ở nhóm đang hút thuốc cao hơn 1.3 lần (RR = 1.30) so với nhóm chưa bao giờ hút. Tương tự, Odds Ratio (OR) cho thấy tỷ lệ cược đột quỵ của nhóm này cao hơn 1.48 lần (OR = 1.48). Ngược lại, nhóm đã từng hút thuốc có nguy cơ và tỷ lệ cược đột quỵ gần như không khác biệt so với nhóm chưa bao giờ hút thuốc, với RR và OR đều xấp xỉ 1 và p-value không có ý nghĩa thống kê (>0.1). Do không có sự khác biệt có ý nghĩa thống kê về nguy cơ đột quỵ giữa nhóm chưa bao giờ hút thuốc và nhóm đã từng hút thuốc, chúng ta có thể gộp hai nhóm này lại thành một nhóm mới là “Không hút thuốc” để đơn giản hóa phân tích. Việc gộp nhóm sẽ giúp tạo ra một biến nhị phân rõ ràng, có hoặc không có yếu tố nguy cơ, phục vụ tốt hơn cho các mô hình phân tích sau này.

df$Smoking_Status <- ifelse(df$Smoking_Status == "Current","Smoking","No_Smoking")
df$Smoking_Status <-  factor(df$Smoking_Status,levels = c( "No_Smoking", "Smoking"))

4.3 Mô hình Logit

Mô hình Logit cần ước lượng: \[ \begin{aligned} \log\left(\frac{P(Y=1)}{1 - P(Y=1)}\right) &= \beta_0 + \beta_1 \cdot Age + \beta_2 \cdot SES \\ &\quad + \beta_3 \cdot AvgGlucose + \beta_4 \cdot HeartDisease \\ &\quad + \beta_5 \cdot Hypertension + \beta_6 \cdot Diabetes \\ &\quad + \beta_7 \cdot BMI + \beta_8 \cdot Smoking\_Status \end{aligned} \]

model_logit <- glm(Stroke ~ Age+SES+Avg_Glucose+Heart_Disease+Hypertension+Diabetes+BMI+Smoking_Status, 
             data = df , 
             family = binomial(link = "logit"))
summary(model_logit)
## 
## Call:
## glm(formula = Stroke ~ Age + SES + Avg_Glucose + Heart_Disease + 
##     Hypertension + Diabetes + BMI + Smoking_Status, family = binomial(link = "logit"), 
##     data = df)
## 
## Coefficients:
##                         Estimate Std. Error z value Pr(>|z|)    
## (Intercept)           -10.365051   0.354694 -29.223  < 2e-16 ***
## Age                     0.063385   0.003195  19.839  < 2e-16 ***
## SESMedium               0.072004   0.063341   1.137    0.256    
## SESHigh                 0.042428   0.078453   0.541    0.589    
## Avg_Glucose             0.007995   0.001808   4.422 9.78e-06 ***
## Heart_DiseaseYes        1.400393   0.059938  23.364  < 2e-16 ***
## HypertensionYes         2.011297   0.076337  26.348  < 2e-16 ***
## DiabetesYes             1.434903   0.065151  22.024  < 2e-16 ***
## BMI                     0.057735   0.005556  10.391  < 2e-16 ***
## Smoking_StatusSmoking   0.584676   0.064811   9.021  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 12179.8  on 9999  degrees of freedom
## Residual deviance:  8509.2  on 9990  degrees of freedom
## AIC: 8529.2
## 
## Number of Fisher Scoring iterations: 5

Kết quả từ mô hình hồi quy logistic cho thấy hầu hết các biến độc lập đều có mối liên hệ có ý nghĩa thống kê với khả năng bị đột quỵ. Các biến Age, Avg_Glucose, Heart_Disease, Hypertension, Diabetes, BMI và Smoking_Status đều có p-value rất nhỏ (<0.05), cho thấy chúng có tác động đáng kể lên tỷ lệ cược đột quỵ. Cụ thể:

  • Đối với hệ số chặn thì ở mức tuổi(70 tuổi), BMI(28) và chỉ số đường huyết(109) ở mức trung bình ở trong mẫu với địa vị xã hội là thấp, không bệnh tim, không tiểu đường, không cao huyết áp và không hút thuốc thì xác suất đột quỵ của người này là: \[ P(Stroke=1)= \frac{1}{1+exp[-(-10.365051+0.0633\times70+0.0577\times28+0.00799\times109)]} \] = 3.0842277%. Mặc dù tuổi đã cao và BMI tiệm cận ngưỡng béo phì, xác suất này vẫn ở mức tương đối thấp khi không có các yếu tố rủi ro đi kèm. Điều này nhấn mạnh tầm quan trọng của việc kiểm soát bệnh nền và lối sống. Do đó, chiến lược y tế công cộng nên tập trung vào phòng ngừa tích cực bệnh mạn tính và nâng cao nhận thức về lối sống lành mạnh, hơn là chỉ can thiệp khi biến cố đã xảy ra

  • Age: Khi tuổi tăng thêm 1 đơn vị, tỷ lệ cược đột quỵ tăng lên 1.0650268 lần.

  • Hypertension: Bệnh nhân có cao huyết áp có tỷ lệ cược đột quỵ cao gấp 7.4707844 lần đối với người không có cao huyết áp. Điều này phản ánh rõ xu hướng nguy cơ đột quỵ gia tăng theo thời gian sinh học, phù hợp với cơ chế suy giảm chức năng sinh lý ở người cao tuổi. Do đó, các biện pháp can thiệp phòng ngừa cần được ưu tiên triển khai cho nhóm dân số lão niên. Thông tin này đặc biệt hữu ích trong việc lập kế hoạch y tế cộng đồng và sàng lọc đối tượng nguy cơ cao.

  • Heart_Disease: Tỷ lệ cược đột quỵ ở người có bệnh tim cao gấp 4.0552 lần đối với người không có bệnh về tim mạch.Điều này hoàn toàn phù hợp với cơ sở sinh lý bệnh khi tổn thương tim làm suy giảm khả năng điều hòa huyết áp và lưu lượng máu não. Sự gia tăng đáng kể này nhấn mạnh vai trò then chốt của việc kiểm soát và điều trị bệnh tim trong chiến lược phòng chống đột quỵ.

  • Diabetes: Bệnh nhân tiểu đường có tỷ lệ cược đột quỵ cao gấp 4.199645 lần đối với người không có tiểu đường. Điều này phản ánh cơ chế bệnh sinh khi tình trạng tăng đường huyết mạn tính dẫn đến tổn thương thành mạch máu, xơ vữa động mạch và rối loạn tuần hoàn não. Bên cạnh đó, bệnh tiểu đường thường đi kèm với các yếu tố nguy cơ khác như cao huyết áp và béo phì, làm cộng hưởng tác động tiêu cực đến hệ tim mạch và não bộ.

  • BMI và Avg_Glucose: Cả hai biến này đều có tác động làm tăng nguy cơ và có ý nghĩa, với mỗi đơn vị tăng lên, tỷ lệ cược đột quỵ cũng tăng theo. Điều này phản ánh mối liên hệ giữa béo phì, rối loạn chuyển hóa và nguy cơ tổn thương mạch máu não. Do đó, kiểm soát cân nặng hợp lý thông qua chế độ ăn cân đối, hạn chế thực phẩm nhiều đường tinh luyện (như bánh kẹo, nước ngọt) và chất béo bão hòa (như đồ chiên rán, thịt đỏ), đồng thời tăng cường rau xanh, ngũ cốc nguyên hạt và hoạt động thể chất đều đặn là những biện pháp quan trọng để giảm thiểu nguy cơ đột quỵ.

  • Smoking_Status: Bệnh nhân nào có hút thuốc thì sẽ có tỷ lệ cược đột quỵ cao gấp 1.7942731 so với người không hút thuốc. Điều này phản ánh tác động tiêu cực rõ rệt của thuốc lá đối với hệ tim mạch và thần kinh. Do đó, việc triển khai các chương trình cai thuốc lá, tăng thuế thuốc lá, kết hợp truyền thông cộng đồng về tác hại của hút thuốc là chiến lược y tế công cộng thiết yếu. Đồng thời, lồng ghép tư vấn cai thuốc vào hệ thống chăm sóc sức khỏe ban đầu sẽ góp phần làm giảm tỷ lệ đột quỵ trong dân số.

Tuy nhiên, các biến về địa vị xã hội (SES) không có ý nghĩa thống kê (p-value >0.05), cho thấy sau khi kiểm soát các yếu tố sức khỏe khác, địa vị xã hội không phải là yếu tố dự đoán đáng kể cho đột quỵ trong mô hình này.

Kết luận từ mô hình hồi quy logistic cho thấy các yếu tố lâm sàng như tuổi tác, chỉ số đường huyết, BMI, tình trạng bệnh tim, cao huyết áp, tiểu đường và thói quen hút thuốc có ảnh hưởng đáng kể đến xác suất xảy ra đột quỵ. Điều này cho thấy nguy cơ đột quỵ chịu tác động mạnh từ tình trạng sức khỏe nền và thói quen sinh hoạt hơn là từ các yếu tố nhân khẩu học hoặc địa vị xã hội. Việc các biến xã hội không có ý nghĩa thống kê gợi ý rằng, trong bối cảnh dữ liệu nghiên cứu này, yếu tố sinh lý và bệnh lý đóng vai trò quyết định.

4.4 Mô hình Probit

Mô hình Probit cần ước lượng:

\[ \begin{aligned} \left(\Phi^{-1}(P(Y=1))}\right) &= \beta_0 + \beta_1 \cdot Age + \beta_2 \cdot SES \\ &\quad + \beta_3 \cdot AvgGlucose + \beta_4 \cdot HeartDisease \\ &\quad + \beta_5 \cdot Hypertension + \beta_6 \cdot Diabetes \\ &\quad + \beta_7 \cdot BMI + \beta_8 \cdot Smoking\_Status \end{aligned} \]

model_probit <- glm(Stroke ~ Age+SES+Avg_Glucose+Heart_Disease+Hypertension+Diabetes+BMI+Smoking_Status, 
             data = df , 
             family = binomial(link = "probit"))
summary(model_probit)
## 
## Call:
## glm(formula = Stroke ~ Age + SES + Avg_Glucose + Heart_Disease + 
##     Hypertension + Diabetes + BMI + Smoking_Status, family = binomial(link = "probit"), 
##     data = df)
## 
## Coefficients:
##                        Estimate Std. Error z value Pr(>|z|)    
## (Intercept)           -5.921066   0.197542 -29.974  < 2e-16 ***
## Age                    0.036073   0.001812  19.909  < 2e-16 ***
## SESMedium              0.035441   0.036392   0.974    0.330    
## SESHigh                0.014073   0.045108   0.312    0.755    
## Avg_Glucose            0.004883   0.001041   4.692  2.7e-06 ***
## Heart_DiseaseYes       0.802634   0.034313  23.391  < 2e-16 ***
## HypertensionYes        1.109029   0.040571  27.335  < 2e-16 ***
## DiabetesYes            0.829931   0.037307  22.246  < 2e-16 ***
## BMI                    0.033344   0.003187  10.463  < 2e-16 ***
## Smoking_StatusSmoking  0.337988   0.037369   9.045  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 12179.8  on 9999  degrees of freedom
## Residual deviance:  8535.6  on 9990  degrees of freedom
## AIC: 8555.6
## 
## Number of Fisher Scoring iterations: 5

Các hệ số hồi quy trong mô hình Probit cho biết được mức độ thay đổi của Z-score (đại diện cho “nguy cơ tiềm ẩn” đột quỵ) khi một biến độc lập thay đổi. Z-score càng cao, xác suất đột quỵ càng lớn.

  • Về hệ số chặn thì khi bệnh nhân ở mức tuổi(70 tuổi), BMI(28) và chỉ số đường huyết(109) ở mức trung bình ở trong mẫu với địa vị xã hội là thấp, không bệnh tim, không tiểu đường, không cao huyết áp và không hút thuốc thì xác suất đột quỵ của người này là: \[ P(Y=1) = \Phi(-5.921066 + 0.036073\times 70 + 0.004883\times 109 + 0.033344\times28 ) \] = 2.6798649%

Cho thấy rằng những người ở trạng thái bình thường thì xác suất đột quỵ rất thấp. Mặc dù ở mức BMI là mức có thể được xem như là béo phì. Tuy nhiên, không nên chủ quan với yếu tố cân nặng, bởi vì BMI cao có thể trở thành yếu tố nguy cơ khi kết hợp với các rối loạn chuyển hóa khác như tăng đường huyết hoặc huyết áp.

  • Age: Với mỗi năm tuổi tăng lên, Z-score của nguy cơ đột quỵ tăng 0.036 đơn vị. Điều này có nghĩa là tuổi tác là một yếu tố nguy cơ tích cực, làm tăng xác suất đột quỵ.
  • Hypertension: Việc có tiền sử cao huyết áp làm tăng Z-score của nguy cơ đột quỵ thêm 1.109 đơn vị so với nhóm không có. Đây là một tác động rất lớn và có ý nghĩa thống kê.
  • Heart_Disease: Tương tự, bệnh nhân có bệnh tim có Z-score của nguy cơ đột quỵ cao hơn 0.803 đơn vị so với người không có.
  • Diabetes: Bệnh nhân tiểu đường có Z-score nguy cơ đột quỵ cao hơn 0.830 đơn vị so với người không có.
  • Chỉ số khối BMI: Với mỗi đơn vị BMI tăng thêm, Z-score của nguy cơ đột quỵ tăng thêm 0.033 đơn vị.
  • Avg_Glucose: Khi đường huyết trung bình tăng thêm 1 đơn vị, Z-score của nguy cơ đột quỵ tăng thêm 0.005 đơn vị.

Điều đáng chú ý là các biến về Địa vị xã hội (SES) không có ý nghĩa thống kê (p-value >0.05), cho thấy sau khi kiểm soát các yếu tố sức khỏe khác, địa vị xã hội không phải là một yếu tố dự đoán đáng tin cậy trong mô hình này.

Kết quả từ mô hình Probit cho thấy các yếu tố lâm sàng như tuổi tác, huyết áp, bệnh tim, tiểu đường, chỉ số BMI và đường huyết trung bình đều góp phần làm tăng Z-score nghĩa là làm gia tăng xác suất tiềm ẩn bị đột quỵ. Đặc biệt, các biến Hypertension, Heart_Disease và Diabetes có hệ số rất lớn, phản ánh mức độ ảnh hưởng mạnh mẽ và rõ rệt đến nguy cơ đột quỵ. Trong khi đó, các yếu tố liên quan đến địa vị xã hội không cho thấy ý nghĩa thống kê, cho thấy vai trò thứ yếu khi đã kiểm soát các yếu tố sức khỏe. Điều này nhấn mạnh rằng các yếu tố sinh lý có sức ảnh hưởng lớn hơn đến xác suất đột quỵ trong mô hình Probit.

4.5 Lựa chọn và đánh giá mô hình

model_names <- c("Logit", "Probit")
aic_values <- c(AIC(model_logit), AIC(model_probit))
table_aic <- data.frame(
  "Mô hình" = model_names,
  "Giá trị AIC" = round(aic_values, 2) # Làm tròn cho đẹp
)

# Trình bày bảng đẹp bằng kableExtra
kable(table_aic, 
      caption = "Bảng so sánh tiêu chí AIC giữa mô hình Logit và Probit", 
      align = "c", 
      booktabs = TRUE) %>%
  kable_styling(latex_options = c("striped", "hold_position"), 
                full_width = TRUE, 
                font_size = 12)
Bảng so sánh tiêu chí AIC giữa mô hình Logit và Probit
Mô.hình Giá.trị.AIC
Logit 8529.16
Probit 8555.63

Dựa trên chỉ số AIC, mô hình Logit được lựa chọn vì có giá trị AIC thấp hơn so với Probit . Chỉ số AIC thấp cho thấy mô hình Logit có khả năng giải thích dữ liệu tốt hơn với các biến đã chọn, đồng thời cũng ít phức tạp hơn. Hơn nữa, việc diễn giải kết quả của mô hình Logit (dưới dạng Odds Ratio) trực quan và dễ hiểu hơn, giúp người đọc nắm bắt ý nghĩa của các hệ số một cách rõ ràng. Do đó, đây là mô hình được lựa chọn để phân tích đột quỵ.

df$predicted_prob <- predict(model_logit ,type = "response")
roc_obj <- roc(df$Stroke, df$predicted_prob, levels = c("No", "Yes"))
plot(roc_obj, col = "blue", print.auc = TRUE, main = "ROC Curve - logit model")

auc(roc_obj)
## Area under the curve: 0.8506
cat("Ngưỡng để phân loại: ", as.numeric(coords(roc_obj, "best", ret = "threshold")))
## Ngưỡng để phân loại:  0.3024846
df$predicted_class <- ifelse(df$predicted_prob >= as.numeric(coords(roc_obj, "best", ret = "threshold")),
                             "Yes", "No")
confusionMatrix(factor(df$predicted_class), 
                factor(df$Stroke), 
                positive = "Yes")
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   No  Yes
##        No  5332  667
##        Yes 1690 2311
##                                           
##                Accuracy : 0.7643          
##                  95% CI : (0.7559, 0.7726)
##     No Information Rate : 0.7022          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.4872          
##                                           
##  Mcnemar's Test P-Value : < 2.2e-16       
##                                           
##             Sensitivity : 0.7760          
##             Specificity : 0.7593          
##          Pos Pred Value : 0.5776          
##          Neg Pred Value : 0.8888          
##              Prevalence : 0.2978          
##          Detection Rate : 0.2311          
##    Detection Prevalence : 0.4001          
##       Balanced Accuracy : 0.7677          
##                                           
##        'Positive' Class : Yes             
## 

Kết quả đánh giá mô hình cho thấy hiệu suất tương đối tốt. Chỉ số AUC đạt 0.8508, cho thấy khả năng phân biệt giữa hai nhóm đột quỵ và không đột quỵ của mô hình là khá cao. Dựa trên ma trận nhầm lẫn, mô hình có độ chính xác Accuracy là 76.23%, vượt trội đáng kể so với mức cơ sở là 70.22%, được xác nhận bởi p-value nhỏ hơn 2.2e-16.Mô hình có khả năng nhận diện các trường hợp đột quỵ là 78.01%, và khả năng nhận diện các trường hợp không đột quỵ là 75.48%. Mặc dù có độ chính xác cao khi dự đoán không đột quỵ (Negative Predictive Value = 89.00%), khả năng dự đoán đúng một trường hợp là đột quỵ khi mô hình dự đoán là đột quỵ (Positive Predictive Value) chỉ đạt 57.43%. Cụ thể, vì số lượng bệnh nhân không bị đột quỵ (70.22%) chiếm ưu thế lớn so với số bệnh nhân bị đột quỵ (29.78%), mô hình có xu hướng dự đoán phần lớn các trường hợp là “không đột quỵ” để tối đa hóa độ chính xác tổng thể. Điều này cho thấy mô hình đôi khi dự đoán sai một số trường hợp không đột quỵ thành đột quỵ, nhưng khả năng dự đoán đúng người không bị đột quỵ là rất tốt.

Chương 5 Kết luận

Nghiên cứu này đã thành công trong việc xác định các yếu tố nguy cơ chính liên quan đến đột quỵ thông qua khai thác dữ liệu lâm sàng và hành vi sức khỏe. Dựa trên mô hình hồi quy Logit được lựa chọn vì có chỉ số AIC thấp hơn so với mô hình Probit. Các yếu tố như tuổi tác, cao huyết áp, bệnh tim, tiểu đường, chỉ số BMI, mức đường huyết trung bình, và tình trạng hút thuốc đều cho thấy ảnh hưởng đáng kể đến xác suất xảy ra đột quỵ. Kết quả cho thấy rằng, mỗi yếu tố nguy cơ đều góp phần làm tăng khả năng mắc đột quỵ, với hai yếu tố có sức tác động mạnh nhất là cao huyết áp và bệnh tim, phản ánh vai trò trung tâm của bệnh lý nền trong quá trình hình thành bệnh. Ngược lại, yếu tố liên quan đến địa vị xã hội lại không có ý nghĩa thống kê trong mô hình, hàm ý rằng các điều kiện sinh học và thói quen sinh hoạt có vai trò quyết định hơn so với đặc điểm kinh tế xã hội trong việc dự báo nguy cơ mắc bệnh. Những phát hiện này không chỉ mang lại bằng chứng định lượng có giá trị mà còn củng cố thêm nền tảng lý luận cho công tác sàng lọc nguy cơ và can thiệp dự phòng sớm trong cộng đồng.

Từ các phát hiện trên, nghiên cứu đề xuất một số chiến lược phòng ngừa và điều trị có trọng tâm. Theo đó, công tác sàng lọc và kiểm soát nguy cơ đột quỵ nên được tập trung vào các nhóm dân số có yếu tố nguy cơ cao, đặc biệt là người cao tuổi, người mắc bệnh lý nền mạn tính và những người có lối sống không lành mạnh. Cần xây dựng các chương trình can thiệp cụ thể như theo dõi huyết áp thường xuyên, kiểm soát đường huyết, điều chỉnh chế độ dinh dưỡng để duy trì BMI hợp lý, và đẩy mạnh tư vấn bỏ thuốc lá. Những biện pháp này không chỉ giúp giảm xác suất khởi phát đột quỵ mà còn góp phần nâng cao chất lượng cuộc sống nói chung. Mặc dù mô hình đã đạt được độ chính xác phân loại khá tốt, vẫn còn dư địa để nâng cao khả năng nhận diện đúng các trường hợp đột quỵ. Do vậy, các kỹ thuật nâng cao như xử lý mất cân bằng dữ liệu hoặc áp dụng các mô hình phi tuyến có thể được xem xét trong các nghiên cứu tiếp theo nhằm tối ưu hóa hiệu năng dự báo.