Giới thiệu tổng quát
Bộ dữ liệu này bao gồm 100.000 quan sát và 11 biến, thu thập thông tin liên quan đến các đặc điểm sinh học và sức khỏe cơ bản của sinh viên.
Mục tiêu của bộ dữ liệu là mô tả mối quan hệ giữa các yếu tố nhân khẩu học (tuổi, giới tính, chiều cao, cân nặng, nhóm máu) và các chỉ số sức khỏe (BMI, nhiệt độ cơ thể, nhịp tim, huyết áp, cholesterol).
library(readxl)
## Warning: package 'readxl' was built under R version 4.5.1
data <- read_excel("D:/DuLieuThayTuongST3.xlsx")
head(data)
## # A tibble: 6 × 11
## Student.ID Age Gender Height Weight Blood.Type BMI Temperature Heart.Rate
## <dbl> <dbl> <chr> <dbl> <dbl> <chr> <dbl> <dbl> <dbl>
## 1 1 18 Female 162. 72.4 O 27.6 99.1 95
## 2 2 30 Male 152. 47.6 B 21.6 98.7 93
## 3 3 32 Female 183. 55.7 A 16.7 98.3 76
## 4 4 30 Male 182. 63.3 B 19.1 98.8 99
## 5 5 23 Female 164. 46.2 O 18.8 98.5 95
## 6 6 32 Male 151. 68.6 B 29.9 99.7 70
## # ℹ 2 more variables: Blood.Pressure <dbl>, Cholesterol <dbl>
Hàm head() giúp xem nhanh 6 dòng đầu tiên của bảng dữ liệu data.
tail(data)
## # A tibble: 6 × 11
## Student.ID Age Gender Height Weight Blood.Type BMI Temperature Heart.Rate
## <dbl> <dbl> <chr> <dbl> <dbl> <chr> <dbl> <dbl> <dbl>
## 1 99995 22 Male 161. 70.3 O 27.6 99.0 86
## 2 99996 24 Male 177. 95.8 B 30.7 98.5 65
## 3 99997 29 Female 164. 45.2 O 16.8 97.9 62
## 4 99998 34 Male 173. 99.6 B 33.2 98.8 60
## 5 99999 30 Female 156. 50.1 A 20.5 99.0 86
## 6 100000 20 Female 154. 99.9 O 42.2 98.6 95
## # ℹ 2 more variables: Blood.Pressure <dbl>, Cholesterol <dbl>
Hàm tail() giúp xem nhanh 6 dòng cuối cùng của bảng dữ liệu data.
dim(data)
## [1] 100000 11
Hàm dim() (dimension) trả về kích thước của đối tượng dữ liệu Bộ dữ liệu gồm 100000 dòng và 11 biến.
names(data)
## [1] "Student.ID" "Age" "Gender" "Height"
## [5] "Weight" "Blood.Type" "BMI" "Temperature"
## [9] "Heart.Rate" "Blood.Pressure" "Cholesterol"
Hàm names() dùng để: Liệt kê hoặc xem tên các biến (tên cột) trong một data frame
sum(duplicated(data))
## [1] 0
Giải thích: duplicated(data): Kiểm tra dòng nào bị trùng trong toàn bộ bảng dữ liệu → trả về một vector logic (TRUE hoặc FALSE) cho từng dòng. sum(…): Cộng tất cả giá trị TRUE (vì TRUE = 1, FALSE = 0) → cho ra số lượng dòng trùng. Kết quả 0 cho thấy bộ dữ liệu không có bất kỳ quan sát nào bị trùng lặp.
sum(is.na(data))
## [1] 0
Giải thích: Hàm is.na() dùng để kiểm tra giá trị bị thiếu (NA) trong dữ liệu. sum() sẽ đếm tổng số giá trị bị thiếu (NA) trong toàn bộ bảng dữ liệu data. Kết quả 0 cho thấy bộ dữ liệu không có bất kỳ giá trị nào bị thiếu.
variable_meaning <- data.frame(
Variable = c("Student.ID", "Age", "Gender", "Height", "Weight", "Blood.Type", "BMI", "Temperature", "Heart.Rate", "Blood.Pressure", "Cholesterol"),
Meaning = c(
"Ma so benh nhan",
"Tuoi (nam)",
"Gioi tinh (Nam/Nu)",
"Chieu cao (cm)",
"Can nang (kg)",
"Nhom mau (A, B, AB, O)",
"Chi so BMI (khoi luong co the)",
"Nhiet do co the",
"Nhip tim (bpm)",
"Huyet ap (mmHg)",
"Cholesterol (mg/dL)"
),
stringsAsFactors = FALSE
)
library(knitr)
## Warning: package 'knitr' was built under R version 4.5.1
kable(variable_meaning, booktabs = TRUE)
| Variable | Meaning |
|---|---|
| Student.ID | Ma so benh nhan |
| Age | Tuoi (nam) |
| Gender | Gioi tinh (Nam/Nu) |
| Height | Chieu cao (cm) |
| Weight | Can nang (kg) |
| Blood.Type | Nhom mau (A, B, AB, O) |
| BMI | Chi so BMI (khoi luong co the) |
| Temperature | Nhiet do co the |
| Heart.Rate | Nhip tim (bpm) |
| Blood.Pressure | Huyet ap (mmHg) |
| Cholesterol | Cholesterol (mg/dL) |
Giải thích: Hàm Variable: chứa tên các biến trong bộ dữ liệu.
Meaning: mô tả ý nghĩa của từng biến.
stringsAsFactors = FALSE Thông số này giúp giữ nguyên kiểu dữ liệu chữ (character). Nếu không viết stringsAsFactors = FALSE, R (trong phiên bản cũ) sẽ tự động chuyển cột ký tự sang factor (kiểu phân loại), điều này không cần thiết trong bảng mô tả.
knitr là một thư viện dùng trong R Markdown để hiển thị kết quả đẹp, đặc biệt là bảng (table).
Hàm kable() thuộc gói knitr, dùng để hiển thị bảng dữ liệu (data frame) dưới dạng bảng trình bày đẹp trong R Markdown.
booktabs = TRUE giúp bảng xuất ra đẹp hơn, có đường kẻ mảnh và gọn, phù hợp với tiêu chuẩn xuất bản (LaTeX style). Nhận xét: Đoạn code này tạo và trình bày một bảng mô tả biến trong dữ liệu, giúp người đọc nắm rõ ý nghĩa của từng cột.
sum(sapply(data, is.numeric))
## [1] 9
Giải thích: - is.numeric: Đây là hàm kiểm tra kiểu dữ liệu trong R xem có phải dạng số hay không.
Hàm sapply() áp dụng hàm is.numeric lên từng cột của data. Kết quả trả về là một vector logic (TRUE/FALSE) cho biết cột nào là số.
sum(…): Trong R, khi cộng các giá trị TRUE/FALSE, R tự hiểu TRUE = 1 và FALSE = 0. Sẽ đếm số lượng cột TRUE, tức là số biến có kiểu numeric.
names(data)[sapply(data, is.numeric)]
## [1] "Student.ID" "Age" "Height" "Weight"
## [5] "BMI" "Temperature" "Heart.Rate" "Blood.Pressure"
## [9] "Cholesterol"
Nhận xét: Bộ dữ liệu gồm 9 biến định lượng
sum(sapply(data, function(x) is.factor(x) | is.character(x)))
## [1] 2
Giải thích:
sapply() sẽ lặp qua từng cột của data
Hàm function(x) is.factor(x) | is.character(x) sẽ: Kiểm tra xem cột đó có phải là factor hay character. Dấu | nghĩa là “hoặc”. Nếu cột là factor hoặc character → trả về TRUE (tức 1). Nếu không → trả về FALSE( tức 0).
names(data)[sapply(data, function(x) is.factor(x) | is.character(x))]
## [1] "Gender" "Blood.Type"
Nhận xét: Bộ dữ liệu gồm 2 biến định tính.
table(sapply(data, class))
##
## character numeric
## 2 9
nrow(data)
## [1] 100000
Hàm nrow(data) sẽ trả về một số nguyên (integer) — chính là số dòng. Kết quả cho thấy bộ dữ liệu có 100000 dòng.
ncol(data)
## [1] 11
Hàm ncol(data) sẽ trả về một số nguyên (integer) — chính là số lượng cột. Kết quả cho thấy bộ dữ liệu có 11 cột.
sapply(data, class)
## Student.ID Age Gender Height Weight
## "numeric" "numeric" "character" "numeric" "numeric"
## Blood.Type BMI Temperature Heart.Rate Blood.Pressure
## "character" "numeric" "numeric" "numeric" "numeric"
## Cholesterol
## "numeric"
Giải thích:
sapply() = “simplified apply”: áp dụng một hàm cho từng cột trong data
class() = hàm kiểm tra kiểu dữ liệu (class) của đối tượng.
Nhận xét:
Kết quả cho thấy có 9 biến kiểu numeric (Age, Height, Weight, BMI, Temperature, Heart.Rate, Blood.Pressure, Cholesterol, Student.ID). Có 2 biến kiểu character (Gender, Blood.Type).
colSums(is.na(data))
## Student.ID Age Gender Height Weight
## 0 0 0 0 0
## Blood.Type BMI Temperature Heart.Rate Blood.Pressure
## 0 0 0 0 0
## Cholesterol
## 0
Kết quả cho thấy các cột đều không có giá trị bị thiếu.
data$Weight[is.na(data$Weight)] <- mean(data$Weight, na.rm = TRUE)
Giải thích:
is.na(data$Weight): Tạo một vector logic cho biết vị trí nào trong cột Weight bị thiếu (NA). Mỗi phần tử: TRUE → là giá trị bị thiếu, FALSE → có giá trị hợp lệ.
mean(data$Weight, na.rm = TRUE): Tính giá trị trung bình của cột Weight, bỏ qua các NA (na.rm = TRUE có nghĩa là remove NAs)
data\(Weight[is.na(data\)Weight)] <- … : Tại các vị trí mà Weight bị thiếu (TRUE trong is.na()), gán lại bằng giá trị trung bình. Sau khi chạy, cột Weight không còn giá trị NA
data$Gender <- tools::toTitleCase(data$Gender)
Giải thích:
data$Gender: là cột Gender trong bộ dữ liệu data.
tools::toTitleCase(): là hàm trong package tools, dùng để viết hoa chữ cái đầu tiên của mỗi từ (title case).
=> Hàm này sẽ chuẩn hóa lại giá trị trong cột Gender
data$Gender <- as.factor(data$Gender)
data$Blood.Type <- as.factor(data$Blood.Type)
as.factor(): Hàm chuyển kiểu dữ liệu sang factor (biến phân loại). Giúp R hiểu đây không phải là dữ liệu dạng số hay text thông thường, mà là biến phân loại, dễ dàng trong việc thực hiện vẽ biểu đồ, tóm tắt dữ liệu.
data$Gender_num <- ifelse(data$Gender == "Male", 1, 0)
ifelse() là hàm điều kiện trong R. Cú pháp: ifelse(điều_kiện, giá_trị_nếu_đúng, giá_trị_nếu_sai)
data$Gender == “Male”: kiểm tra từng dòng trong cột Gender xem có bằng “Male” không.
→ Nếu đúng → trả về 1. Nếu sai → trả về 0
Kết quả được gán vào cột mới Gender_num.
data$BMI_Level <- cut(data$BMI,
breaks = c(0, 18.5, 24.9, 29.9, Inf),
labels = c("Underweight", "Normal", "Overweight", "Obese"))
data$BMI Cột dữ liệu BMI (Body Mass Index), dạng số thực (numeric).
cut() Hàm phân loại (chia khoảng) trong R. Nó cắt biến liên tục thành các nhóm.
breaks = c(0, 18.5, 24.9, 29.9, Inf) Các ranh giới (ngưỡng) để chia BMI thành các nhóm:
0 → 18.5 → Underweight: Thiếu cân
18.5 → 24.9 → Normal: Cân đối
24.9 → 29.9 → Overweight: Thừa cân
≥ 30 (Inf = vô cùng) → Obese: Béo phì
labels = c(“Underweight”, “Normal”, “Overweight”, “Obese”) Tên nhóm tương ứng với từng khoảng.
data$BMI_Level Cột mới được tạo ra để lưu kết quả phân loại.
data$Temperature_C <- (data$Temperature - 32) * 5/9
Giải thích:
data$Temperature Cột nhiệt độ hiện tại trong dữ liệu (đơn vị °F).
32: Trừ đi 32 — bước đầu tiên trong công thức chuyển đổi
5/9: Nhân với 5/9 để ra đơn vị °C
data$Temperature_C Cột mới được tạo ra để lưu giá trị nhiệt độ đã đổi sang °C.
library(knitr)
kable(head(data[, c("Gender", "Gender_num", "BMI", "BMI_Level", "Temperature", "Temperature_C")]),
caption = "Bảng minh họa sau khi chuẩn hóa dữ liệu")
| Gender | Gender_num | BMI | BMI_Level | Temperature | Temperature_C |
|---|---|---|---|---|---|
| Female | 0 | 27.64584 | Overweight | 99.09644 | 37.27580 |
| Male | 1 | 21.63422 | Normal | 98.71498 | 37.06388 |
| Female | 0 | 16.72902 | Underweight | 98.26029 | 36.81127 |
| Male | 1 | 19.09604 | Normal | 98.83960 | 37.13311 |
| Female | 0 | 18.76571 | Normal | 98.48001 | 36.93334 |
| Male | 1 | 29.91240 | Obese | 99.66837 | 37.59354 |
Giải thích:
library(knitr): Gọi thư viện knitr, dùng để hiển thị bảng và kết quả đẹp hơn trong RMarkdown.
data[, c(“Gender”, “Gender_num”, “BMI”, “BMI_Level”, “Temperature”, “Temperature_C”)] Chọn 6 cột cụ thể từ dataset data.
head(…) Lấy 6 dòng đầu tiên để minh họa (tránh bảng quá dài).
kable() Hàm trong knitr, dùng để tạo bảng đẹp trong file HTML, PDF, hoặc Word xuất ra từ RMarkdown.
caption = “…” Gắn tên bảng (chú thích) hiển thị bên dưới bảng.
Nhận xét về bảng dữ liệu sau khi chuẩn hóa:
Bảng trên thể hiện một phần dữ liệu sau khi đã chuẩn hóa và xử lý các biến liên quan đến giới tính, chỉ số cơ thể và nhiệt độ.
Cột Gender hiển thị giá trị dạng chữ (“Male”, “Female”),
Trong khi Gender_num là dạng mã hóa nhị phân tương ứng (Male = 1, Female = 0).
-> Việc mã hóa này giúp thuận tiện cho các mô hình phân tích định lượng.
BMI là chỉ số khối cơ thể (Body Mass Index) – biến định lượng.
BMI_Level là biến phân loại, được chia thành 4 nhóm: Underweight, Normal, Overweight, Obese.
-> Trong mẫu minh họa, ta thấy có đủ các nhóm từ thiếu cân đến béo phì, cho thấy dữ liệu đa dạng và cân bằng.
Temperature được ghi nhận theo đơn vị Fahrenheit,
Còn Temperature_C là kết quả chuyển đổi sang Celsius theo công thức
-> Nhiệt độ sau khi chuyển đổi dao động quanh 36.8°C – 37.6°C, tương ứng với mức bình thường của cơ thể con người.
Kết luận: Các biến định tính như Gender và Blood.Type đã được mã hóa và chuẩn hóa cách viết, trong khi các biến định lượng như BMI và Temperature đã được xử lý và chuyển đổi đơn vị thích hợp. Việc chuẩn hóa giúp đảm bảo tính nhất quán và sẵn sàng cho các bước phân tích tiếp theo.
sapply(data, class)
## Student.ID Age Gender Height Weight
## "numeric" "numeric" "factor" "numeric" "numeric"
## Blood.Type BMI Temperature Heart.Rate Blood.Pressure
## "factor" "numeric" "numeric" "numeric" "numeric"
## Cholesterol Gender_num BMI_Level Temperature_C
## "numeric" "numeric" "factor" "numeric"
sapply() là hàm trong R giúp áp dụng một hàm nào đó cho từng cột (hoặc từng phần tử) trong một data frame.
Áp dụng hàm class, tức là yêu cầu R cho biết kiểu dữ liệu của mỗi cột.
Kết quả trả về là một vector, trong đó tên của mỗi phần tử là tên cột, và giá trị là kiểu dữ liệu của cột đó.
-> Việc kiểm tra kiểu dữ liệu bằng sapply(data, class) giúp đảm bảo rằng tất cả các biến đã ở đúng định dạng sau khi chuẩn hóa dữ liệu.
Qua kết quả có thể thấy biến Gender và Blood.Type đã thành factor.
library(psych)
## Warning: package 'psych' was built under R version 4.5.1
library(moments)
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.5.1
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
Hàm Mô tả: describe(data) Tóm tắt thống kê (mean, sd, median, min, max, skewness, kurtosis, v.v.)
skewness(x) Độ lệch (mức độ phân bố nghiêng trái hay phải)
kurtosis(x) Độ nhọn (mức độ phân bố tập trung hay trải rộng)
select() Chọn cột
filter() Lọc dòng
mutate() Tạo biến mới
arrange() Sắp xếp
summarise() Tóm tắt dữ liệu
group_by() Nhóm dữ liệu để tính trung bình, đếm,…
str(data)
## tibble [100,000 × 14] (S3: tbl_df/tbl/data.frame)
## $ Student.ID : num [1:100000] 1 2 3 4 5 6 7 8 9 10 ...
## $ Age : num [1:100000] 18 30 32 30 23 32 21 28 21 32 ...
## $ Gender : Factor w/ 2 levels "Female","Male": 1 2 1 2 1 2 2 2 2 2 ...
## $ Height : num [1:100000] 162 152 183 182 164 ...
## $ Weight : num [1:100000] 72.4 47.6 55.7 63.3 46.2 ...
## $ Blood.Type : Factor w/ 4 levels "A","AB","B","O": 4 3 1 3 4 3 2 2 3 3 ...
## $ BMI : num [1:100000] 27.6 21.6 16.7 19.1 18.8 ...
## $ Temperature : num [1:100000] 99.1 98.7 98.3 98.8 98.5 ...
## $ Heart.Rate : num [1:100000] 95 93 76 99 95 70 66 85 75 61 ...
## $ Blood.Pressure: num [1:100000] 109 104 130 112 105 128 134 123 111 94 ...
## $ Cholesterol : num [1:100000] 203 163 216 141 231 183 247 128 243 166 ...
## $ Gender_num : num [1:100000] 0 1 0 1 0 1 1 1 1 1 ...
## $ BMI_Level : Factor w/ 4 levels "Underweight",..: 3 2 1 2 2 4 1 1 2 1 ...
## $ Temperature_C : num [1:100000] 37.3 37.1 36.8 37.1 36.9 ...
Giải thích: Hàm str(data) hiển thị cấu trúc tổng quát của đối tượng data. Cho biết:
Loại đối tượng (data.frame, tibble, v.v.)
Số hàng, số cột
Tên và kiểu dữ liệu của từng cột
Một vài giá trị mẫu trong mỗi cột
Nhận xét: Đối tượng: tibble [100,000 × 11], tức có 100.000 quan sát (observations) và 11 biến (variables).
describe(data[, c("Age", "Height", "Weight", "BMI", "Temperature_C" , "Cholesterol" , "Heart.Rate" , "Blood.Pressure")])
## vars n mean sd median trimmed mad min max
## Age 1 1e+05 26.02 4.89 26.00 26.02 5.93 18.00 34.00
## Height 2 1e+05 174.91 14.47 174.79 174.89 18.59 150.00 200.00
## Weight 3 1e+05 69.89 17.35 69.84 69.86 22.28 40.00 100.00
## BMI 4 1e+05 23.32 7.03 22.62 22.93 7.42 10.07 44.31
## Temperature_C 5 1e+05 37.00 0.28 37.00 37.00 0.28 35.78 38.24
## Cholesterol 6 1e+05 184.56 37.57 184.00 184.57 48.93 120.00 249.00
## Heart.Rate 7 1e+05 79.51 11.55 79.00 79.52 14.83 60.00 99.00
## Blood.Pressure 8 1e+05 114.52 14.41 115.00 114.52 17.79 90.00 139.00
## range skew kurtosis se
## Age 16.00 0.00 -1.20 0.02
## Height 50.00 0.01 -1.20 0.05
## Weight 60.00 0.01 -1.20 0.05
## BMI 34.24 0.45 -0.41 0.02
## Temperature_C 2.46 0.01 0.01 0.00
## Cholesterol 129.00 0.00 -1.20 0.12
## Heart.Rate 39.00 0.00 -1.20 0.04
## Blood.Pressure 49.00 0.00 -1.20 0.05
Giải thích:
Hàm describe() thường nằm trong gói psych, được dùng để tính toán các chỉ số thống kê mô tả cho từng biến (cột) trong bộ dữ liệu, xuất ra
các chỉ số như:
mean (trung bình)
sd (độ lệch chuẩn)
median (trung vị)
trimmed mean (trung bình cắt tỉa)
mad (độ lệch tuyệt đối trung vị)
min, max, range
skew (độ lệch): Skew > 0: lệch phải (đuôi dài bên phải). Skew < 0: lệch trái. Skew ≈ 0: đối xứng.
kurtosis (độ nhọn): > 0: nhọn (dữ liệu tập trung nhiều ở trung tâm); < 0: bẹt (phân tán rộng hơn).
se (sai số chuẩn)
Nhận xét:
Tuổi trung bình của mẫu là 26,02, trung vị 26,00 và độ lệch chuẩn 4,89 → dữ liệu phân bố khá đồng đều, không bị lệch. Khoảng tuổi dao động từ 18 đến 34 tuổi, phạm vi hẹp. Độ lệch (Skew = 0) và độ nhọn (Kurtosis = -1,2) cho thấy phân bố chuẩn, hơi bẹt. Sai số chuẩn (SE = 0,02) rất nhỏ, chứng tỏ trung bình đáng tin cậy.
Chiều cao trung bình 174,91 cm, trung vị 174,79 cm, độ lệch chuẩn 14,47 cm, dao động 150–200 cm → dữ liệu phân tán vừa phải. Skew ≈ 0 và Kurtosis = -1,2 cho thấy phân bố cân đối, hơi bẹt, không có giá trị ngoại lai rõ rệt.
Cân nặng trung bình 69,89 kg, trung vị 69,84 kg, độ lệch chuẩn 17,35 kg → dữ liệu phân tán khá rộng. Khoảng dao động từ 40 đến 100 kg, cho thấy sự khác biệt rõ giữa các cá nhân. Skew ≈ 0, Kurtosis = -1,2 → phân bố gần chuẩn.
Giá trị trung bình 23,32, trung vị 22,62, độ lệch chuẩn 7,03, dao động từ 10,07 đến 44,31 → dữ liệu phân tán cao, có thể gồm cả người gầy và béo phì. Skew = 0,45 và Kurtosis = -0,41 → phân bố hơi lệch phải, có một số giá trị cao hơn mức trung bình.
Trung bình 37,00°C, trung vị 37,00°C, độ lệch chuẩn 0,28°C, phạm vi 35,78–38,24°C → dữ liệu rất ổn định, gần như không biến động. Skew ≈ 0, Kurtosis = 0 → phân bố chuẩn hoàn hảo
Giá trị trung bình 184,56 mg/dL, trung vị 184,00 mg/dL, độ lệch chuẩn 37,57 → dữ liệu phân tán vừa phải quanh mức trung bình. Khoảng dao động từ 120 đến 249 mg/dL, cho thấy một số người có cholesterol cao. Độ lệch Skew = 0,01 và Kurtosis = -1,20 → phân bố gần chuẩn, hơi bẹt, không có ngoại lệ rõ rệt. Cholesterol chủ yếu nằm trong mức bình thường, nhưng có sự khác biệt nhỏ giữa các cá nhân.
Trung bình 79,51 nhịp/phút, trung vị 79,00, độ lệch chuẩn 11,55, dao động 60–99 nhịp/phút → dữ liệu ổn định và tập trung quanh mức trung bình. Giá trị Skew = 0, Kurtosis = -1,20 → phân bố chuẩn, hơi bẹt, thể hiện sự đồng đều giữa các cá nhân. Nhịp tim trung bình nằm trong khoảng bình thường của người trưởng thành (khoảng 60–100 nhịp/phút), không có dấu hiệu bất thường.
Trung bình 114,52 mmHg, trung vị 115,00, độ lệch chuẩn 14,41, dao động 90–139 mmHg → phần lớn mẫu nằm trong ngưỡng huyết áp bình thường. Độ lệch Skew = 0,00, Kurtosis = -1,20 → phân bố đối xứng, hơi bẹt. Huyết áp của các cá nhân trong mẫu khá ổn định, không có giá trị ngoại lệ cao hoặc thấp đáng kể.
mean(data$Height)
## [1] 174.9051
median(data$Height)
## [1] 174.7908
sd(data$Height)
## [1] 14.4696
sd(data$Weight)
## [1] 17.34591
var(data$Weight)
## [1] 300.8804
cv_height <- sd(data$Height) / mean(data$Height)
cv_height
## [1] 0.08272829
Hệ số biến thiên (CV) của biến Height là khoảng 8.28%, cho thấy chiều cao giữa các sinh viên có sự biến động thấp và khá đồng nhất trong toàn bộ mẫu quan sát
min(data$BMI)
## [1] 10.07484
max(data$BMI)
## [1] 44.31407
range(data$BMI)
## [1] 10.07484 44.31407
quantile(data$BMI)
## 0% 25% 50% 75% 100%
## 10.07484 17.84263 22.62432 27.96283 44.31407
quantile(data$BMI) tính các phân vị (quantiles) của biến BMI trong bộ dữ liệu.
0% (Min): Giá trị nhỏ nhất BMI thấp nhất trong mẫu 25% (1st Qu.):
Phân vị thứ nhất
50% (Median): Trung vị BMI ở giữa tập dữ liệu 75% (3rd Qu.): Phân vị thứ
ba
100% (Max): Giá trị lớn nhất
Kết quả: Giá trị BMI của các sinh viên dao động từ 10.07 đến 44.29. 25% sinh viên có chỉ số BMI thấp hơn 17.86, trong khi 25% sinh viên có BMI cao hơn 27.93. Trung vị BMI là 22.66, cho thấy phần lớn sinh viên có chỉ số BMI nằm trong khoảng từ 18 đến 28, tương ứng với nhóm cân nặng bình thường đến hơi thừa cân theo phân loại thông thường của WHO.
hist(data$BMI, main="Phan phoi chi so BMI", xlab="BMI", col="lightblue", breaks=30)
Hàm hist() dùng để vẽ biểu đồ tần suất (Histogram): giúp ta quan sát phân phối của một biến định lượng (numeric variable). main = “Phân phối chỉ số BMI” : Tiêu đề biểu đồ xlab = “BMI”, : Nhãn trục hoành col = “lightblue”, : Màu cột histogram breaks = 30) : Số lượng cột chia
Nhận xét: Biểu đồ tần suất cho thấy chỉ số BMI của sinh viên phân bố theo dạng gần đối xứng, tập trung chủ yếu quanh giá trị từ 18 đến 28. Điều này phù hợp với nhận định rằng phần lớn sinh viên có mức BMI nằm trong phạm vi bình thường đến hơi thừa cân. Một số ít sinh viên có BMI thấp (<18) hoặc cao (>30), thể hiện các trường hợp gầy hoặc béo phì.
sapply(data, function(x) length(unique(x)))
## Student.ID Age Gender Height Weight
## 100000 17 2 89924 90041
## Blood.Type BMI Temperature Heart.Rate Blood.Pressure
## 4 89952 89953 40 50
## Cholesterol Gender_num BMI_Level Temperature_C
## 130 2 4 89953
sapply() → áp dụng hàm cho mỗi cột trong data.
function(x) length(unique(x)) → đếm số lượng giá trị duy nhất trong từng cột.
Kết quả sẽ là một vector, trong đó:
Tên là tên biến
Giá trị là số lượng giá trị khác nhau của biến đó
table(data$Gender, data$BMI_Level)
##
## Underweight Normal Overweight Obese
## Female 12777 15004 8900 8347
## Male 15718 18123 10910 10221
prop.table(table(data$Gender, data$BMI_Level), 1) * 100
##
## Underweight Normal Overweight Obese
## Female 28.37568 33.32149 19.76548 18.53735
## Male 28.59274 32.96769 19.84647 18.59310
Giới tính (Gender): Male, Female
Mức BMI (BMI_Level): Underweight, Normal, Overweight, Obese
Tham số “, 1”: nghĩa là tính theo hàng (tức theo từng giới tính).
” * 100”: để chuyển sang phần trăm (%).
aggregate(Weight ~ Gender, data = data, FUN = mean)
## Gender Weight
## 1 Female 69.89192
## 2 Male 69.88608
aggregate() là hàm dùng để tính toán thống kê theo nhóm (grouped summary) trong R.
Weight ~ Gender nghĩa là bạn tính trung bình của biến Weight theo từng nhóm Gender (giới tính).
data = data chỉ rõ rằng bạn đang làm việc với bộ dữ liệu data.
FUN = mean nghĩa là bạn muốn tính giá trị trung bình.
Nhận xét: Trọng lượng trung bình của sinh viên nữ là 69.98 kg, trong khi sinh viên nam có trọng lượng trung bình là 69.77 kg. Sự chênh lệch giữa hai giới rất nhỏ (chỉ khoảng 0.21 kg), cho thấy cân nặng trung bình của nam và nữ trong mẫu dữ liệu gần như tương đương nhau. Điều này có thể phản ánh rằng trong bộ dữ liệu này, sự khác biệt giới tính về cân nặng không đáng kể, có thể do chiều cao, thói quen ăn uống hoặc đặc điểm dân số tương đồng.
aggregate(BMI ~ Blood.Type, data = data, mean)
## Blood.Type BMI
## 1 A 23.39142
## 2 AB 23.33637
## 3 B 23.29708
## 4 O 23.28116
aggregate(): Dùng để tính toán thống kê theo nhóm.
BMI là biến cần tính trung bình,
Blood.Type là biến nhóm (phân loại theo nhóm máu),
mean là hàm dùng để tính giá trị trung bình BMI của từng nhóm máu.
Nhận xét:
Giá trị trung bình BMI của các nhóm máu dao động từ 23.27 đến 23.39, cho thấy sự khác biệt giữa các nhóm là rất nhỏ. Nhóm máu A có BMI trung bình cao nhất (23.39), trong khi nhóm O có BMI trung bình thấp nhất (23.27). Tuy nhiên, chênh lệch giữa các nhóm chỉ khoảng 0.12 đơn vị, cho thấy nhóm máu không phải là yếu tố có ảnh hưởng đáng kể đến chỉ số BMI của sinh viên trong bộ dữ liệu này.
data %>%
group_by(Gender) %>%
summarise(Mean_BMI = mean(BMI), SD_BMI = sd(BMI))
## # A tibble: 2 × 3
## Gender Mean_BMI SD_BMI
## <fct> <dbl> <dbl>
## 1 Female 23.3 7.04
## 2 Male 23.3 7.03
group_by(Gender): chia bộ dữ liệu thành các nhóm theo giới tính (nam và nữ).
summarise(…): tính toán các giá trị thống kê cho từng nhóm.
Mean_BMI = mean(BMI) → tính giá trị trung bình BMI của từng giới.
SD_BMI = sd(BMI) → tính độ lệch chuẩn BMI của từng giới.
Nhận xét: Kết quả cho thấy BMI trung bình của sinh viên nữ là 23.37, cao hơn một chút so với sinh viên nam (23.28). Độ lệch chuẩn của hai nhóm khá tương đồng (khoảng 7.0), cho thấy mức độ phân tán BMI giữa các cá nhân trong mỗi nhóm là tương đương. Nhìn chung, sự khác biệt giữa nam và nữ về chỉ số BMI là rất nhỏ, cho thấy giới tính không phải yếu tố ảnh hưởng đáng kể đến BMI trong bộ dữ liệu này.
tanso1 <- table(data$Gender)
bang_tanso1 <- data.frame(Gender = names(tanso1), TanSo = as.numeric(tanso1), TanSoTichLuy = cumsum(as.numeric(tanso1)))
print(bang_tanso1)
## Gender TanSo TanSoTichLuy
## 1 Female 45028 45028
## 2 Male 54972 100000
Tạo bảng tần số (frequency table) của biến Gender.
names(tanso1): Trả về tên các nhóm trong bảng tần số.
as.numeric(tanso1): Chuyển giá trị tần số từ dạng bảng (table) sang dạng số (numeric vector) để có thể tính toán dễ dàng. Đây chính là số lượng quan sát (TanSo) của từng giới.
cumsum(as.numeric(tanso1)): Hàm cumsum() nghĩa là cumulative sum → tính tổng cộng dồn. Từng phần tử sau bằng tổng của tất cả các phần tử trước đó. Kết quả thể hiện tần số tích lũy (TanSoTichLuy).
data.frame(…): Dùng để kết hợp các cột trên thành một bảng dữ liệu hoàn chỉnh (data frame).
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.5.1
##
## Attaching package: 'ggplot2'
## The following objects are masked from 'package:psych':
##
## %+%, alpha
ggplot(data, aes(x = Gender, fill = Gender)) +
geom_bar(color = "white", width = 0.6) +
geom_text(stat = "count", aes(label = after_stat(count)), vjust = -0.3, size = 3.5, fontface = "bold") +
labs(title = "Biểu đồ cột tần số theo giới tính", x = "Giới tính", y = "Tần số") +
theme_minimal() +
scale_fill_manual(values = c("Male" = "#5DADE2", "Female" = "#F5B7B1")) +
theme(plot.title = element_text(size = 15, face = "bold", hjust = 0.5),
axis.title = element_text(face = "bold"),
axis.text = element_text(size = 11),
legend.position = "none")
Giải thích:
Gọi hàm ggplot() để bắt đầu tạo biểu đồ từ bộ dữ liệu data.
aes() xác định biến thẩm mỹ (aesthetic mapping):
x = Gender: trục hoành là giới tính.
fill = Gender: tô màu các cột khác nhau theo giới tính.
Tạo biểu đồ cột (bar chart).
color = “white”: viền cột màu trắng.
width = 0.6: điều chỉnh độ rộng của các cột (nhỏ hơn 1 để các cột tách nhau nhẹ nhàng).
Hiển thị số lượng (tần số) trên đầu mỗi cột.
after_stat(count): lấy giá trị đếm tự động từ geom_bar.
vjust = -0.3: nâng chữ lên một chút trên cột.
size = 3.5, fontface = “bold”: chỉnh kích thước và kiểu chữ in đậm.
Thêm tiêu đề và nhãn trục:
title: tiêu đề biểu đồ.
x, y: nhãn trục hoành và trục tung.
Áp dụng giao diện tối giản, sạch đẹp, phù hợp cho báo cáo.
Tùy chỉnh màu sắc thủ công:
Nam: xanh (#5DADE2)
Nữ: hồng nhạt (#F5B7B1) → Giúp biểu đồ trực quan và dễ phân biệt giới tính.
Tùy chỉnh giao diện biểu đồ:
plot.title: căn giữa, in đậm, tăng kích thước.
axis.title: chữ đậm cho nhãn trục.
axis.text: tăng kích thước chữ trục.
legend.position = “none”: ẩn chú giải (vì màu đã thể hiện rõ giới tính rồi).
Nhận xét:
Biến Gender gồm hai nhóm là Female và Male.
Kết quả cho thấy có 45,028 sinh viên nữ (chiếm 45.03%) và 54,972 sinh viên nam (chiếm 54.97%) trong tổng số 100,000 quan sát.
Như vậy, tỷ lệ sinh viên nam cao hơn nữ khoảng 10%, cho thấy mẫu dữ liệu có sự cân đối tương đối giữa hai giới, tuy nhiên nam vẫn chiếm ưu thế nhẹ.
Tần số tích lũy đạt 100,000, khẳng định tính đầy đủ của bộ dữ liệu.
tansuat1 <- prop.table(tanso1) * 100
bang_tansuat1 <- data.frame(Gender = names(tansuat1), TanSuat = round(as.numeric(tansuat1), 2), TanSuatTichLuy = round(cumsum(as.numeric(tansuat1)), 2))
print(bang_tansuat1)
## Gender TanSuat TanSuatTichLuy
## 1 Female 45.03 45.03
## 2 Male 54.97 100.00
tanso1 là bảng tần số (số lượng từng giới tính) đã tạo ở bước trước bằng table(data$Gender).
prop.table(tanso1) tính tỷ lệ phần trăm của mỗi nhóm (tức là tần suất tương đối).
Nhân với 100 để chuyển sang đơn vị phần trăm (%).
names(tansuat1) → lấy tên các nhóm (ở đây là “Female”, “Male”).
as.numeric(tansuat1) → chuyển tần suất từ dạng bảng sang dạng số.
round(…, 2) → làm tròn 2 chữ số thập phân.
cumsum() → tính tần suất tích lũy (cộng dồn tỉ lệ phần trăm từ trên xuống).
data.frame() → gom lại thành bảng dữ liệu có 3 cột: Gender, TanSuat, TanSuatTichLuy.
library(ggplot2)
ggplot(bang_tansuat1, aes(x = "", y = TanSuat, fill = Gender)) +
geom_bar(width = 1, stat = "identity", color = "white", linewidth = 0.5) + coord_polar("y", start = 0) + geom_text(aes(label = paste0(TanSuat, "%")), position = position_stack(vjust = 0.55),
color = "gray10", size = 4, fontface = "bold") + scale_fill_manual(values = c(
"#A8DADC",
"#F6BD60",
"#F28482",
"#84A59D",
"#B9FBC0"
)) + labs(title = "Biểu đồ tròn tần suất theo giới tính",
fill = "Giới tính") + theme_void() + theme(
plot.title = element_text(size = 15, face = "bold", hjust = 0.5, color = "#333333"),
legend.title = element_text(size = 12, face = "bold"),
legend.text = element_text(size = 11),
legend.position = "right")
Giải thích:
Dữ liệu đầu vào là bang_tansuat1.
x = ““: dùng giá trị rỗng để gom tất cả các phần tử thành một vòng tròn duy nhất.
y = TanSuat: biểu diễn phần trăm tần suất.
fill = Gender: tô màu khác nhau cho từng giới tính.
_ geom_bar(width = 1, stat = “identity”, color = “white”, linewidth = 0.5)
Tạo các thanh bar (mỗi thanh đại diện cho 1 giới tính).
stat = “identity” → sử dụng giá trị thật (TanSuat) thay vì đếm số lượng.
width = 1 → thanh đầy đủ, tạo nên hình tròn sau khi chuyển đổi.
color = “white” → đường viền trắng giữa các phần.
linewidth = 0.5 → độ dày của viền.
Chuyển biểu đồ cột thành biểu đồ tròn (pie chart).
“y” → chuyển trục y thành góc quay quanh tâm.
start = 0 → điểm bắt đầu từ trục 0 độ (tùy chỉnh vị trí đầu tiên).
Thêm nhãn phần trăm ngay trên từng phần của hình tròn.
position_stack(vjust = 0.55) → căn giữa các nhãn theo chiều dọc.
paste0(TanSuat, “%”) → nối giá trị và ký hiệu “%”.
color, size, fontface → tùy chỉnh kiểu chữ.
Tùy chỉnh bảng màu thủ công.
Ở đây có 5 màu (dư thừa, ggplot chỉ dùng 2 màu đầu vì chỉ có 2 giới tính).
Thêm tiêu đề cho biểu đồ và nhãn chú thích (legend).
theme_void() → loại bỏ toàn bộ trục, nền, khung (đặc trưng của biểu đồ tròn).
Tùy chỉnh font và vị trí của tiêu đề và chú thích để biểu đồ trông gọn, chuyên nghiệp.
Nhận xét:
Nam giới chiếm 55,54%, là nhóm có tỷ lệ cao hơn trong tổng số người khảo sát.
Nữ giới chiếm 44,46%, thấp hơn nhưng vẫn chiếm gần một nửa mẫu.
Sự chênh lệch giữa hai giới không quá lớn, thể hiện phân bố giới tính tương đối cân bằng trong dữ liệu.
Kết luận: Cơ cấu giới tính cho thấy nam giới chiếm ưu thế nhẹ, nhưng mức độ cân đối giữa hai giới được duy trì tốt, phản ánh tính đa dạng và công bằng giới trong mẫu nghiên cứu.
tanso2 <- table(data$Blood.Type)
bang_tanso2 <- data.frame(NhomMau = names(tanso2), TanSo = as.numeric(tanso2), TanSoTichLuy = cumsum(as.numeric(tanso2)))
print(bang_tanso2)
## NhomMau TanSo TanSoTichLuy
## 1 A 22236 22236
## 2 AB 22183 44419
## 3 B 22781 67200
## 4 O 32800 100000
library(ggplot2)
library(RColorBrewer)
my_colors <- brewer.pal(n = 6, name = "Set2")
ggplot(bang_tanso2, aes(x = NhomMau, y = TanSo, fill = NhomMau)) +
geom_col() +
geom_text(aes(label = TanSo), vjust = -0.5, size = 4) +
scale_fill_manual(values = my_colors) +
labs(title = "Biểu đồ cột tần số theo nhóm máu",
x = "Nhóm máu",
y = "Tần số") +
theme_minimal() +
theme(legend.position = "none")
Giải thích
RColorBrewer là thư viện chuyên dùng để lấy bảng màu phối sẵn (đẹp, hài hòa, dễ nhìn).
brewer.pal(n = 6, name = “Set2”): → Lấy 6 màu từ bảng Set2 (tông pastel nhẹ, thường dùng trong biểu đồ định tính — như nhóm máu, giới tính…). → my_colors là vector chứa 6 màu, ví dụ: “#66C2A5” “#FC8D62” “#8DA0CB” “#E78AC3” “#A6D854” “#FFD92F”
Khởi tạo ggplot với dữ liệu đầu vào là bang_tanso2.
aes(…) định nghĩa:
x = NhomMau: trục hoành (tên nhóm máu).
y = TanSo: trục tung (tần số).
fill = NhomMau: mỗi cột có màu khác nhau tương ứng từng nhóm máu.
geom_col() Vẽ biểu đồ cột với chiều cao cột tương ứng với giá trị thực của TanSo (khác với geom_bar() – vốn tự đếm số lượng).
geom_text(aes(label = TanSo), vjust = -0.5, size = 4) Thêm nhãn số liệu trên đầu mỗi cột.
label = TanSo → hiện số tần số.
vjust = -0.5 → đẩy chữ lên một chút so với đỉnh cột.
size = 4 → cỡ chữ vừa phải, dễ đọc.
Giúp biểu đồ sinh động hơn, tránh bị trùng màu khi nhiều nhóm máu.
Thêm tiêu đề và nhãn trục.
theme_minimal() → làm biểu đồ sáng, đơn giản, chuyên nghiệp.
legend.position = “none” → ẩn chú thích (legend), vì tên nhóm máu đã hiển thị rõ trên trục X nên không cần nữa.
Nhận xét:
Trong bốn nhóm máu, nhóm O có tần số cao nhất với 32800 người, chiếm tỷ trọng lớn trong mẫu khảo sát.
Ba nhóm máu còn lại (A, B, AB) có số lượng xấp xỉ nhau, dao động từ 22183 đến 22781 người, cho thấy sự phân bố khá đồng đều giữa các nhóm này.
Sự chênh lệch rõ rệt chỉ xuất hiện giữa nhóm O và các nhóm còn lại.
Kết luận:Phân bố nhóm máu trong mẫu cho thấy nhóm O phổ biến nhất, phản ánh xu hướng tương tự như nhiều quần thể dân số khác. Các nhóm A, B và AB có tỷ lệ tương đương, cho thấy sự đa dạng nhóm máu nhưng không có khác biệt lớn giữa các nhóm nhỏ.
tansuat2 <- prop.table(tanso2) * 100
bang_tansuat2 <- data.frame(NhomMau = names(tansuat2), TanSuat = round(as.numeric(tansuat2), 2), TanSuatTichLuy = round(cumsum(as.numeric(tansuat2)), 2))
print(bang_tansuat2)
## NhomMau TanSuat TanSuatTichLuy
## 1 A 22.24 22.24
## 2 AB 22.18 44.42
## 3 B 22.78 67.20
## 4 O 32.80 100.00
Sys.setlocale("LC_ALL", "Vietnamese")
## Warning in Sys.setlocale("LC_ALL", "Vietnamese"): using locale code page other
## than 65001 ("UTF-8") may cause problems
## [1] "LC_COLLATE=Vietnamese_Vietnam.1258;LC_CTYPE=Vietnamese_Vietnam.1258;LC_MONETARY=Vietnamese_Vietnam.1258;LC_NUMERIC=C;LC_TIME=Vietnamese_Vietnam.1258"
library(ggplot2)
ggplot(bang_tansuat2, aes(x = "", y = TanSuat, fill = NhomMau)) +
geom_bar(width = 1, stat = "identity", color = "white", linewidth = 0.5) +
coord_polar("y", start = 0) +
geom_text(aes(label = paste0(TanSuat, "%")),
position = position_stack(vjust = 0.55),
color = "gray10", size = 4, fontface = "bold") +
scale_fill_manual(values = c(
"#A8DADC",
"#F6BD60",
"#F28482",
"#84A59D",
"#B9FBC0",
"#FFD6A5"
)) +
labs(
title = "Biểu đồ tròn tần suất theo nhóm máu",
fill = "Nhóm máu"
) +
theme_void() +
theme(
plot.title = element_text(size = 15, face = "bold", hjust = 0.5, color = "#333333"),
legend.title = element_text(size = 12, face = "bold"),
legend.text = element_text(size = 11),
legend.position = "right"
)
Nhận xét:
Biểu đồ cho thấy sự phân bố tần suất các nhóm máu trong tập dữ liệu có sự khác biệt rõ ràng giữa các nhóm.
Cụ thể, nhóm máu O chiếm tỷ lệ cao nhất (32,53%), thể hiện đây là nhóm máu phổ biến nhất trong mẫu khảo sát.
Ba nhóm máu còn lại gồm A (22,5%), AB (22,36%) và B (22,61%) có tỷ lệ gần tương đương nhau, dao động quanh mức 22%, cho thấy sự phân bố khá đồng đều giữa các nhóm này.
Kết luận: Nhóm máu O chiếm ưu thế trong tập dữ liệu, trong khi các nhóm A, B, AB có tỷ lệ tương đối cân bằng. Điều này phản ánh xu hướng chung trong dân số, khi nhóm máu O thường phổ biến nhất so với các nhóm khác.
Thống kê mô tả biến Cholesterol:
Chol_stats <- c(Min = min(data$Cholesterol, na.rm = TRUE), Max = max(data$Cholesterol, na.rm = TRUE), Mean = mean(data$Cholesterol, na.rm = TRUE), Median = median(data$Cholesterol, na.rm = TRUE), SD = sd(data$Cholesterol, na.rm = TRUE), Var = var(data$Cholesterol, na.rm = TRUE))
Chol_stats
## Min Max Mean Median SD Var
## 120.00000 249.00000 184.56104 184.00000 37.57068 1411.55567
Nhận xét:
Mức cholesterol của các cá nhân trong tập dữ liệu dao động từ 120 mg/dL đến 249 mg/dL, cho thấy sự khác biệt tương đối lớn giữa những người có chỉ số mỡ máu thấp và cao.
Giá trị trung bình (Mean) đạt 184.56 mg/dL, rất gần với trung vị (Median = 184 mg/dL), phản ánh phân phối dữ liệu cân đối, không có dấu hiệu lệch phải hay lệch trái rõ rệt.
Độ lệch chuẩn (SD = 37.57) và phương sai (Var = 1411.56) cho thấy mức độ phân tán tương đối lớn — nghĩa là nồng độ cholesterol giữa các cá nhân có sự dao động đáng kể, có thể do khác biệt về chế độ ăn uống, thể trạng hoặc thói quen sinh hoạt.
Giá trị tối đa 249 mg/dL nằm gần ngưỡng cholesterol cao theo khuyến nghị y tế (≥240 mg/dL), trong khi giá trị tối thiểu 120 mg/dL lại nằm trong vùng cholesterol lý tưởng. Điều này phản ánh sự đa dạng trong tình trạng sức khỏe tim mạch của các cá nhân được khảo sát.
Kết luận: Phân bố cholesterol có xu hướng ổn định quanh mức trung bình 185 mg/dL, với phần lớn cá nhân nằm trong vùng cholesterol bình thường đến hơi cao, cho thấy tình trạng sức khỏe nhìn chung là tốt, song vẫn có một nhóm nhỏ có nguy cơ cao về tim mạch cần được chú ý theo dõi.
library(ggplot2)
ggplot(data, aes(x = Cholesterol)) +
geom_histogram(
bins = 10,
fill = "lightblue",
color = "white"
) +
geom_text(
stat = "bin",
bins = 10,
aes(label = ..count..),
vjust = -0.3,
size = 3,
color = "black"
) +
scale_x_continuous(
breaks = seq(floor(min(data$Cholesterol)),
ceiling(max(data$Cholesterol)),
by = 20)
) +
labs(
title = "Bieu do cot phan to muc Cholesterol",
x = "Cholesterol (mg/dL)",
y = "Tan so"
) +
theme_minimal()
## Warning: The dot-dot notation (`..count..`) was deprecated in ggplot2 3.4.0.
## i Please use `after_stat(count)` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
Giải thích: Khởi tạo biểu đồ ggplot, dùng dữ liệu data
và gán trục hoành (x) là biến Cholesterol.
geom_histogram() tạo biểu đồ tần số (histogram).
bins = 10 → chia trục X thành 10 khoảng giá trị để nhóm các quan sát (càng nhiều bins, biểu đồ càng chi tiết).
fill = “lightblue” → tô màu xanh nhạt cho các cột.
color = “white” → viền trắng giữa các cột, giúp tách biệt rõ hơn.
Thêm nhãn số liệu lên trên mỗi cột.
..count.. là tần số của từng khoảng (được ggplot tự tính).
vjust = -0.3 → đẩy nhãn lên trên đầu cột.
size = 3 và color = “black” → kích thước và màu chữ.
Tùy chỉnh thang chia trục X (mỗi 20 đơn vị mg/dL).
floor() và ceiling() giúp làm tròn giá trị min–max của cholesterol về số nguyên gần nhất.
Nhận xét:
Phân bố tương đối đồng đều, các cột có chiều cao khá gần nhau, cho thấy mức cholesterol của người trong mẫu không quá chênh lệch giữa các khoảng giá trị.
Khoảng cholesterol 160–180 mg/dL có tần số cao nhất (≈ 2944 người), cho thấy đây là mức cholesterol phổ biến nhất trong mẫu.
Các khoảng từ 140–220 mg/dL có tần số cao và ổn định, chiếm phần lớn dân số khảo sát → phần lớn người có mức cholesterol nằm trong vùng bình thường.
Hai đầu phân bố (<130 mg/dL và >240 mg/dL) có tần số thấp hơn rõ rệt → số người có cholesterol quá thấp hoặc quá cao là thiểu số.
Kết luận: Phân bố cholesterol của người trong mẫu có dạng gần như đối xứng, hơi lệch trái nhẹ, tập trung chủ yếu ở mức 140–220 mg/dL, thể hiện đa số người có mức Cholesterol trong giới hạn an toàn, chỉ có ít người có mức quá cao hoặc quá thấp.
library(ggplot2)
ggplot(data, aes(x = factor(0), y = Cholesterol)) +
geom_boxplot(fill = "pink", color = "black", outlier.color = "lightpink", outlier.shape = 16) +
labs(title = "Boxplot cua Cholesterol", x = "", y = "Cholesterol") +
theme_minimal() +
stat_summary(fun = mean, geom = "point", shape = 20, size = 5, color = "black")
Nhận xét:
Biểu đồ Boxplot thể hiện giá trị trung vị (Median) của mức cholesterol vào khoảng 190–200 mg/dL, cho thấy phần lớn người có mức cholesterol nằm gần giá trị này.
Khoảng tứ phân vị (IQR) trải từ khoảng 150 mg/dL (Q1) đến 220 mg/dL (Q3), phản ánh rằng đa số người trong mẫu có mức cholesterol nằm trong phạm vi bình thường.
Dữ liệu phân bố cân đối và không xuất hiện giá trị ngoại lai, chứng tỏ không có cá thể nào có mức cholesterol bất thường quá cao hay quá thấp.
Độ phân tán vừa phải, cho thấy sự ổn định trong chỉ số cholesterol giữa các cá nhân được khảo sát.
Kết luận: Phân bố mức cholesterol tương đối ổn định và tập trung quanh mức trung bình, phản ánh tình trạng sức khỏe tim mạch của mẫu dữ liệu nhìn chung là bình thường, không có dấu hiệu bất thường nổi bật.
Thống kê mô tả biến Heart.Rate:
Heart.Rate_stats <- c(
Min = min(data$Heart.Rate, na.rm = TRUE),
Max = max(data$Heart.Rate, na.rm = TRUE),
Mean = mean(data$Heart.Rate, na.rm = TRUE),
Median = median(data$Heart.Rate, na.rm = TRUE),
SD = sd(data$Heart.Rate, na.rm = TRUE),
Var = var(data$Heart.Rate, na.rm = TRUE)
)
Heart.Rate_stats
## Min Max Mean Median SD Var
## 60.00000 99.00000 79.51322 79.00000 11.54908 133.38134
Nhận xét:
Nhịp tim của các cá nhân trong tập dữ liệu dao động từ 60 nhịp/phút đến 99 nhịp/phút, thể hiện sự chênh lệch nhất định giữa những người có nhịp tim chậm và những người có nhịp tim cao hơn mức trung bình.
Trung vị (Median) đạt 79 nhịp/phút, gần tương đương với giá trị trung bình (Mean = 79.51 nhịp/phút), cho thấy phân phối dữ liệu khá đối xứng và không có hiện tượng lệch rõ rệt.
Độ lệch chuẩn (SD = 11.55) và phương sai (Var = 133.38) cho thấy mức độ phân tán trung bình, tức là nhịp tim giữa các cá nhân có sự dao động nhưng không quá lớn, phần lớn vẫn nằm trong giới hạn bình thường.
Nhịp tim tối đa 99 nhịp/phút tuy cao hơn mức trung bình, nhưng vẫn nằm trong ngưỡng sinh lý an toàn đối với người trưởng thành, trong khi mức tối thiểu 60 nhịp/phút phản ánh nhóm có nhịp tim ổn định, thể lực tốt hoặc ít căng thẳng.
Kết luận: Phân bố nhịp tim của các đối tượng khảo sát khá ổn định, tập trung quanh mức 79 nhịp/phút, đặc trưng cho tình trạng sức khỏe tim mạch bình thường. Điều này cho thấy mẫu dữ liệu phản ánh tốt trạng thái thể chất ổn định và không có sự xuất hiện của các giá trị bất thường
library(ggplot2)
ggplot(data, aes(x = Heart.Rate)) +
geom_histogram(
bins = 10,
fill = "lightpink",
color = "white"
) +
geom_text(
stat = "bin",
bins = 10,
aes(label = ..count..),
vjust = -0.5,
size = 3,
color = "black"
) +
scale_x_continuous(
breaks = seq(
floor(min(data$Heart.Rate, na.rm = TRUE)),
ceiling(max(data$Heart.Rate, na.rm = TRUE)),
by = 10
)
) +
labs(
title = "Bieu do cot phan to Heart.Rate",
x = "Nhip tim (lan/phut)",
y = "Tan so"
) +
theme_minimal()
Nhận xét:
Biểu đồ cột trên mô tả phân bố nhịp tim (Heart Rate) của người trong mẫu dữ liệu.
Tần số ở các nhóm nhịp tim dao động quanh mức 2.400–2.500 người, cho thấy phân bố khá đồng đều giữa các khoảng giá trị.
Không có nhóm nào chiếm ưu thế vượt trội, phản ánh rằng hầu hết người tham gia khảo sát có nhịp tim nằm trong vùng bình thường và ổn định.
Sự chênh lệch nhỏ giữa các cột (dao động khoảng ±150 người) cho thấy độ phân tán thấp, đồng nghĩa nhịp tim trung bình tương đối đồng nhất trong tập dữ liệu.
Kết luận: Phân bố nhịp tim khá cân bằng, không có giá trị bất thường, phản ánh tình trạng sức khỏe ổn định và mức độ tương đồng sinh lý giữa các cá nhân trong mẫu.
library(ggplot2)
ggplot(data, aes(x = factor(0), y = Heart.Rate)) +
geom_boxplot(fill = "lightcoral", color = "black", outlier.color = "red", outlier.shape = 16) +
labs(title = "Boxplot cua Heart.Rate", x = "", y = "Heart Rate (nhip/phut)") +
theme_minimal() +
stat_summary(fun = mean, geom = "point", shape = 20, size = 5, color = "black")
Nhận xét:
Biểu đồ Boxplot cho thấy giá trị trung vị (Median) của nhịp tim nằm khoảng 64 nhịp/phút, thể hiện mức nhịp tim trung bình ổn định trong mẫu dữ liệu.
Khoảng tứ phân vị (IQR) kéo dài từ 62 nhịp/phút (Q1) đến 67 nhịp/phút (Q3), nghĩa là 50% số người có nhịp tim nằm trong khoảng này. Khoảng biến thiên này tương đối hẹp, cho thấy sự đồng đều cao trong nhịp tim giữa các cá nhân.
Phân bố dữ liệu khá cân đối quanh trung vị, không xuất hiện giá trị ngoại lai (outliers), phản ánh rằng không có trường hợp bất thường về nhịp tim trong tập dữ liệu.
Kết luận: Biểu đồ Boxplot cho thấy phân bố nhịp tim ổn định và tập trung quanh mức trung bình 64 nhịp/phút, phù hợp với mức nhịp tim nghỉ bình thường của người trưởng thành khỏe mạnh. Điều này gợi ý rằng tình trạng sức khỏe tim mạch của nhóm đối tượng khảo sát tương đối tốt và cân bằng.
Thống kê mô tả biến Blood.Pressure:
BloodPressure_stats <- c(
Min = min(data$Blood.Pressure, na.rm = TRUE),
Max = max(data$Blood.Pressure, na.rm = TRUE),
Mean = mean(data$Blood.Pressure, na.rm = TRUE),
Median = median(data$Blood.Pressure, na.rm = TRUE),
SD = sd(data$Blood.Pressure, na.rm = TRUE),
Var = var(data$Blood.Pressure, na.rm = TRUE)
)
BloodPressure_stats
## Min Max Mean Median SD Var
## 90.00000 139.00000 114.51856 115.00000 14.40634 207.54275
Nhận xét:
Huyết áp của các cá nhân trong tập dữ liệu dao động từ 90 mmHg đến 139 mmHg, thể hiện phạm vi khá rộng giữa những người có huyết áp thấp và cao.
Giá trị trung bình (Mean) đạt 114.52 mmHg, gần bằng trung vị (Median = 115 mmHg), cho thấy phân bố dữ liệu cân đối, không bị lệch nhiều về phía nào. Điều này phản ánh rằng phần lớn cá nhân có huyết áp xung quanh mức bình thường.
Độ lệch chuẩn (SD = 14.41) và phương sai (Var = 207.54) cho thấy mức độ dao động vừa phải, nghĩa là sự khác biệt về huyết áp giữa các cá nhân không quá lớn — điều này có thể liên quan đến việc đa số bệnh nhân có tình trạng sức khỏe ổn định và lối sống tương đối đồng nhất.
Giá trị tối đa 139 mmHg tiệm cận ngưỡng tiền tăng huyết áp theo phân loại y tế (≥140 mmHg), trong khi mức tối thiểu 90 mmHg thuộc ngưỡng huyết áp thấp nhưng vẫn trong giới hạn an toàn.
Kết luận: Biến Blood Pressure cho thấy phân bố tương đối cân đối quanh mức trung bình 115 mmHg, phần lớn cá nhân duy trì huyết áp ở mức bình thường, phản ánh sức khỏe tim mạch ổn định trong tập nhân viên khảo sát. Tuy nhiên, một số ít trường hợp cận ngưỡng cao có thể cần được theo dõi để phòng ngừa nguy cơ tăng huyết áp trong tương lai.
library(ggplot2)
ggplot(data, aes(x = Blood.Pressure)) +
geom_histogram(
bins = 10,
fill = "purple",
color = "white"
) +
geom_text(
stat = "bin",
bins = 10,
aes(label = ..count..),
vjust = -0.3,
size = 3,
color = "black"
) +
scale_x_continuous(
breaks = seq(floor(min(data$Blood.Pressure, na.rm = TRUE)),
ceiling(max(data$Blood.Pressure, na.rm = TRUE)),
by = 10)
) +
labs(
title = "Bieu do cot phan to Blood.Pressure",
x = "Blood Pressure (mmHg)",
y = "Tan so"
) +
theme_minimal()
Nhận xét:
Biểu đồ thể hiện phân bố huyết áp của các bệnh nhân, với giá trị dao động chủ yếu trong khoảng 90 – 139 mmHg. Ta có thể quan sát thấy phân bố khá đều giữa các nhóm huyết áp, tuy có sự chênh lệch nhẹ giữa các khoảng.
Cụ thể, các nhóm từ 100 – 110 mmHg và 130 mmHg có tần số cao nhất, lần lượt đạt 3059 và 3048 cá nhân, cho thấy phần lớn nhân viên có huyết áp trong mức bình thường hoặc hơi cao nhẹ. Trong khi đó, nhóm dưới 90 mmHg chỉ có 1522 cá nhân, chiếm tỷ lệ thấp hơn, phản ánh ít trường hợp huyết áp thấp.
Nhìn chung, phân bố không bị lệch rõ rệt mà có xu hướng gần đối xứng quanh trung tâm, tương ứng với giá trị trung bình khoảng 115 mmHg. Điều này gợi ý rằng phần lớn bệnh nhân có huyết áp ổn định, nằm trong ngưỡng an toàn theo tiêu chuẩn y tế.
Kết luận: Dữ liệu huyết áp của bệnh nhân có phân bố tương đối đồng đều và cân đối, cho thấy sức khỏe tim mạch nhìn chung tốt, song một số ít trường hợp cận ngưỡng cao (130–139 mmHg) vẫn cần được theo dõi thường xuyên để tránh nguy cơ tăng huyết áp trong tương lai.
library(ggplot2)
ggplot(data, aes(x = factor(0), y = Blood.Pressure)) +
geom_boxplot(fill = "purple", color = "black", outlier.color = "red", outlier.shape = 16) +
labs(title = "Boxplot cua Blood Pressure", x = "", y = "Blood Pressure (mmHg)") +
theme_minimal() +
stat_summary(fun = mean, geom = "point", shape = 20, size = 5, color = "black")
tanso <- table(data$Gender, data$Heart.Rate)
bang_tanso5 <- as.data.frame(tanso)
colnames(bang_tanso5) <- c("Gender", "Heart.Rate", "TanSo")
library(dplyr)
bang_tanso5 <- bang_tanso5 %>%
group_by(Gender) %>%
arrange(Heart.Rate) %>%
mutate(TanSoTichLuy = cumsum(TanSo))
print(bang_tanso5)
## # A tibble: 80 x 4
## # Groups: Gender [2]
## Gender Heart.Rate TanSo TanSoTichLuy
## <fct> <fct> <int> <int>
## 1 Female 60 1096 1096
## 2 Male 60 1390 1390
## 3 Female 61 1140 2236
## 4 Male 61 1432 2822
## 5 Female 62 1081 3317
## 6 Male 62 1401 4223
## 7 Female 63 1092 4409
## 8 Male 63 1439 5662
## 9 Female 64 1141 5550
## 10 Male 64 1382 7044
## # i 70 more rows
library(ggplot2)
library(dplyr)
library(viridis)
## Warning: package 'viridis' was built under R version 4.5.1
## Loading required package: viridisLite
data <- data %>%
mutate(Heart.Rate.Group = cut(
Heart.Rate,
breaks = seq(floor(min(Heart.Rate, na.rm = TRUE)),
ceiling(max(Heart.Rate, na.rm = TRUE)),
by = 10),
right = FALSE
)) %>%
filter(!is.na(Heart.Rate.Group))
long_HR <- data %>%
group_by(Gender, Heart.Rate.Group) %>%
summarise(Count = n(), .groups = "drop")
ggplot(long_HR, aes(x = Gender, y = Count, fill = Heart.Rate.Group)) +
geom_col(position = position_dodge(width = 0.8), width = 0.7) +
geom_text(aes(label = Count),
position = position_dodge(width = 0.8),
vjust = -0.5, size = 3) +
scale_fill_viridis(discrete = TRUE, option = "A", name = "Heart Rate (nhip/phut)") +
labs(title = "Phan bo Heart Rate theo Gender",
x = "Gender",
y = "So luong") +
theme_minimal() +
theme(
legend.position = "top",
axis.text.x = element_text(angle = 0, hjust = 0.5),
plot.title = element_text(size = 16, face = "bold", hjust = 0.5)
)
library(ggplot2)
library(dplyr)
library(viridis)
data <- data %>%
filter(!is.na(Heart.Rate)) %>%
mutate(Heart.Rate.Group = cut_number(Heart.Rate, n = 6, labels = paste0("Nhóm ", 1:6)))
df_pie_HR <- data %>%
group_by(Gender, Heart.Rate.Group) %>%
summarise(Count = n(), .groups = "drop") %>%
group_by(Gender) %>%
mutate(Percent = round(Count / sum(Count) * 100, 1))
ggplot(df_pie_HR, aes(x = "", y = Percent, fill = Heart.Rate.Group)) +
geom_col(color = "white", width = 1) +
coord_polar(theta = "y") +
facet_wrap(~ Gender) +
geom_text(aes(label = paste0(Percent, "%")),
position = position_stack(vjust = 0.5),
size = 3) +
scale_fill_viridis(discrete = TRUE, option = "C", name = "Heart Rate") +
labs(title = "Ty le Heart Rate theo Gender") +
theme_void() +
theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
strip.text = element_text(face = "bold", size = 12),
legend.position = "bottom"
)
tanso6 <- table(data$Gender, data$Blood.Type)
bang_tanso6 <- as.data.frame(tanso6)
colnames(bang_tanso6) <- c("Gender", "Blood.Type", "Count")
print(bang_tanso6)
## Gender Blood.Type Count
## 1 Female A 7529
## 2 Male A 9102
## 3 Female AB 7377
## 4 Male AB 9250
## 5 Female B 7727
## 6 Male B 9363
## 7 Female O 11096
## 8 Male O 13446
library(ggplot2)
library(dplyr)
library(viridis)
long_BT <- data %>%
filter(!is.na(Blood.Type)) %>%
group_by(Gender, Blood.Type) %>%
summarise(Count = n(), .groups = "drop")
ggplot(long_BT, aes(x = Gender, y = Count, fill = Blood.Type)) +
geom_col(position = position_dodge(width = 0.8), width = 0.7) +
geom_text(aes(label = Count),
position = position_dodge(width = 0.8),
vjust = -0.5, size = 3) +
scale_fill_viridis(discrete = TRUE, option = "D", name = "Nhóm máu") +
labs(title = "Phan bo nhom mau theo Gender",
x = "Gender",
y = "So luong") +
theme_minimal() +
theme(
legend.position = "top",
axis.text.x = element_text(angle = 0, hjust = 0.5),
plot.title = element_text(size = 16, face = "bold", hjust = 0.5)
)
library(ggplot2)
library(dplyr)
library(viridis)
df_pie_BT <- data %>%
filter(!is.na(Blood.Type)) %>%
group_by(Gender, Blood.Type) %>%
summarise(Count = n(), .groups = "drop") %>%
group_by(Gender) %>%
mutate(Percent = round(Count / sum(Count) * 100, 1))
ggplot(df_pie_BT, aes(x = "", y = Percent, fill = Blood.Type)) +
geom_col(color = "white", width = 1) +
coord_polar(theta = "y") +
facet_wrap(~ Gender) +
geom_text(aes(label = paste0(Percent, "%")),
position = position_stack(vjust = 0.5),
size = 3) +
scale_fill_viridis(discrete = TRUE, option = "F", name = "Nhom mau") +
labs(title = "Ty le nhom mau theo Gender") +
theme_void() +
theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
strip.text = element_text(face = "bold", size = 12),
legend.position = "bottom"
)
data <- data %>%
filter(!is.na(Cholesterol)) %>%
mutate(Chol.Group = cut(
Cholesterol,
breaks = seq(floor(min(Cholesterol)), ceiling(max(Cholesterol)), by = 10),
right = FALSE
))
tanso_chol <- table(data$Gender, data$Chol.Group)
bang_tanso_chol <- as.data.frame(tanso_chol)
colnames(bang_tanso_chol) <- c("Gender", "Chol.Group", "Count")
print(bang_tanso_chol)
## Gender Chol.Group Count
## 1 Female [120,130) 2574
## 2 Male [120,130) 3153
## 3 Female [130,140) 2487
## 4 Male [130,140) 3238
## 5 Female [140,150) 2593
## 6 Male [140,150) 3219
## 7 Female [150,160) 2696
## 8 Male [150,160) 3208
## 9 Female [160,170) 2608
## 10 Male [160,170) 3129
## 11 Female [170,180) 2640
## 12 Male [170,180) 3185
## 13 Female [180,190) 2522
## 14 Male [180,190) 3099
## 15 Female [190,200) 2612
## 16 Male [190,200) 3044
## 17 Female [200,210) 2495
## 18 Male [200,210) 3170
## 19 Female [210,220) 2624
## 20 Male [210,220) 3170
## 21 Female [220,230) 2574
## 22 Male [220,230) 3190
## 23 Female [230,240) 2669
## 24 Male [230,240) 3154
library(ggplot2)
library(dplyr)
library(viridis)
long_Chol <- data %>%
filter(!is.na(Cholesterol)) %>%
mutate(Chol.Group = cut(Cholesterol, breaks = 10, right = FALSE)) %>%
group_by(Gender, Chol.Group) %>%
summarise(Count = n(), .groups = "drop")
ggplot(long_Chol, aes(x = Gender, y = Count, fill = Chol.Group)) +
geom_col(position = position_dodge(width = 0.8), width = 0.7) +
geom_text(aes(label = Count),
position = position_dodge(width = 0.8),
vjust = -0.5, size = 3) +
scale_fill_viridis(discrete = TRUE, option = "H", name = "Cholesterol (mg/dL)") +
labs(title = "Phan bo Cholesterol theo Gender",
x = "Gender",
y = "So luong") +
theme_minimal() +
theme(
legend.position = "top",
axis.text.x = element_text(angle = 0, hjust = 0.5),
plot.title = element_text(size = 16, face = "bold", hjust = 0.5)
)
library(ggplot2)
library(dplyr)
library(viridis)
df_pie_Chol <- data %>%
filter(!is.na(Cholesterol)) %>%
mutate(Chol.Group = cut(Cholesterol, breaks = 10, right = FALSE)) %>%
group_by(Gender, Chol.Group) %>%
summarise(Count = n(), .groups = "drop") %>%
group_by(Gender) %>%
mutate(Percent = round(Count / sum(Count) * 100, 1))
ggplot(df_pie_Chol, aes(x = "", y = Percent, fill = Chol.Group)) +
geom_col(color = "white", width = 1) +
coord_polar(theta = "y") +
facet_wrap(~ Gender) +
geom_text(aes(label = paste0(Percent, "%")),
position = position_stack(vjust = 0.5),
size = 3) +
scale_fill_viridis(discrete = TRUE, option = "F", name = "Cholesterol (mg/dL)") +
labs(title = "Ty le Cholesterol theo Gender") +
theme_void() +
theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
strip.text = element_text(face = "bold", size = 12),
legend.position = "bottom"
)
library(dplyr)
data %>%
group_by(Gender) %>%
summarise(SoLuong = n(), BMI_TB = mean(BMI, na.rm = TRUE), BP_TB = mean(Blood.Pressure, na.rm = TRUE), Chol_TB = mean(Cholesterol, na.rm = TRUE))
## # A tibble: 2 x 5
## Gender SoLuong BMI_TB BP_TB Chol_TB
## <fct> <int> <dbl> <dbl> <dbl>
## 1 Female 33729 23.3 115. 185.
## 2 Male 41161 23.3 114. 184.
Nhận xét:
Cơ cấu giới tính: Gồm 54.972 nam và 45.028 nữ, cho thấy tỷ lệ nam giới chiếm ưu thế nhẹ trong bộ dữ liệu. Cơ cấu này khá cân bằng, đảm bảo độ tin cậy khi so sánh giữa hai nhóm giới tính.
Chỉ số BMI trung bình: Cả hai giới có BMI trung bình xấp xỉ nhau. Chênh lệch không đáng kể (< 0.01), cho thấy mức độ thể trọng trung bình giữa hai giới tương đối tương đồng. Theo phân loại của WHO, cả hai nhóm đều thuộc ngưỡng “bình thường (18.5-24.9). .
Chỉ số BP trung bình: Nữ giới có huyết áp trung bình cao hơn nam giới nhưng không đáng kể. Tuy nhiên, sự khác biệt rất nhỏ nên không mang ý nghĩa lâm sàng rõ rệt, cho thấy huyết áp của hai nhóm tương đối ổn định.
Mức Cholesterol trung bình: Nữ giới có mức cholesterol trung bình nhỉnh hơn nam giới. Cả hai đều ở ngưỡng bình thường (< 200 mg/dL), cho thấy tình trạng mỡ máu ổn định.
Kết luận: Các chỉ tiêu sức khỏe trung bình (BMI, BP, Chol) không có sự khác biệt đáng kể giữa hai giới. Điều này cho thấy sức khỏe tổng quát của nhóm nam và nữ trong bộ dữ liệu khá tương đồng, không có dấu hiệu chênh lệch đáng kể về thể trạng hoặc yếu tố tim mạch.
data <- data %>%
mutate(NhomTuoi = case_when(Age < 18 ~ "Duoi 18", Age <= 30 ~ "18-30", Age <= 45 ~ "31-45", Age <= 60 ~ "46-60", TRUE ~ "Tren 60", TRUE ~ NA_character_))
library(dplyr)
data %>%
group_by(NhomTuoi) %>%
summarise(BMI_TB = mean(BMI), BP_TB = mean(Blood.Pressure), Chol_TB = mean(Cholesterol))
## # A tibble: 2 x 4
## NhomTuoi BMI_TB BP_TB Chol_TB
## <chr> <dbl> <dbl> <dbl>
## 1 18-30 23.3 115. 185.
## 2 31-45 23.3 114. 185.
Nhận xét:
Chỉ số BMI trung bình: Gần như không thay đổi giữa hai nhóm, cho thấy thể trạng trung bình tương đương, đều nằm trong ngưỡng “bình thường” (18.5–24.9).
Chỉ số BP trung bình: Nhóm 31–45 có huyết áp thấp hơn nhẹ (114.4 so với 114.6), chênh lệch rất nhỏ không đáng kể.
Mức Cholesterol trung bình: Giảm nhẹ ở nhóm 31–45 (184.50 so với 184.58), sự khác biệt không đáng kể về mặt thực tiễn.
Kết luận: Các chỉ tiêu sức khỏe trung bình (BMI, BP, Chol) giữa hai nhóm tuổi 18–30 và 31–45 gần như tương đồng. Điều này cho thấy tình trạng sức khỏe tổng quát ổn định và không thay đổi rõ rệt theo độ tuổi trong khoảng 18–45 tuổi.
table(data$Gender, data$Blood.Type)
##
## A AB B O
## Female 7529 7377 7727 11096
## Male 9102 9250 9363 13446
prop.table(table(data$Gender, data$Blood.Type), 1) * 100
##
## A AB B O
## Female 22.32204 21.87139 22.90907 32.89751
## Male 22.11317 22.47273 22.74726 32.66684
prop.table(table(data$Gender, data$Blood.Type), 2) * 100
##
## A AB B O
## Female 45.27088 44.36759 45.21358 45.21229
## Male 54.72912 55.63241 54.78642 54.78771
library(dplyr)
data %>%
group_by(Gender, Blood.Type) %>%
summarise(SoLuong = n()) %>%
mutate(TyLe = round(100 * SoLuong / sum(SoLuong), 2))
## `summarise()` has grouped output by 'Gender'. You can override using the
## `.groups` argument.
## # A tibble: 8 x 4
## # Groups: Gender [2]
## Gender Blood.Type SoLuong TyLe
## <fct> <fct> <int> <dbl>
## 1 Female A 7529 22.3
## 2 Female AB 7377 21.9
## 3 Female B 7727 22.9
## 4 Female O 11096 32.9
## 5 Male A 9102 22.1
## 6 Male AB 9250 22.5
## 7 Male B 9363 22.8
## 8 Male O 13446 32.7
library(ggplot2)
ggplot(data, aes(x = Blood.Type, fill = Gender)) + geom_bar(position = "dodge") + labs(title = "Phan to nhom mau theo gioi tinh", x = "Nhom mau", y = "So luong") + theme_minimal()
Nhận xét: Ở cả hai giới, nhóm máu O chiếm tỷ lệ cao nhất (khoảng 33%),
trong khi nhóm máu AB chiếm tỷ lệ thấp nhất (khoảng 22%). Phân bố nhóm
máu giữa nam và nữ khá tương đồng, không có sự khác biệt lớn về tỷ lệ.
Số lượng mẫu ở nam nhìn chung cao hơn nữ ở tất cả các nhóm máu.
Kết luận: Cơ cấu nhóm máu giữa nam và nữ tương đối giống nhau, với nhóm O phổ biến nhất và nhóm AB ít gặp nhất, cho thấy không có sự khác biệt đáng kể về phân bố nhóm máu theo giới tính.
table(data$NhomTuoi, data$Blood.Type)
##
## A AB B O
## 18-30 12682 12731 13110 18826
## 31-45 3949 3896 3980 5716
prop.table(table(data$NhomTuoi, data$Blood.Type), 1) * 100
##
## A AB B O
## 18-30 22.11372 22.19917 22.86003 32.82708
## 31-45 22.51297 22.21082 22.68970 32.58651
prop.table(table(data$NhomTuoi, data$Blood.Type), 2) * 100
##
## A AB B O
## 18-30 76.25519 76.56823 76.71153 76.70931
## 31-45 23.74481 23.43177 23.28847 23.29069
library(dplyr)
data %>%
group_by(NhomTuoi, Blood.Type) %>%
summarise(SoLuong = n()) %>%
mutate(TyLe = round(100 * SoLuong / sum(SoLuong), 2))
## `summarise()` has grouped output by 'NhomTuoi'. You can override using the
## `.groups` argument.
## # A tibble: 8 x 4
## # Groups: NhomTuoi [2]
## NhomTuoi Blood.Type SoLuong TyLe
## <chr> <fct> <int> <dbl>
## 1 18-30 A 12682 22.1
## 2 18-30 AB 12731 22.2
## 3 18-30 B 13110 22.9
## 4 18-30 O 18826 32.8
## 5 31-45 A 3949 22.5
## 6 31-45 AB 3896 22.2
## 7 31-45 B 3980 22.7
## 8 31-45 O 5716 32.6
library(ggplot2)
ggplot(data, aes(x = Blood.Type, fill = NhomTuoi)) + geom_bar(position = "dodge") + labs(title = "Phan to nhom mau theo nhom tuoi", x = "Nhom mau", y = "So luong") + theme_minimal()
Nhận xét: Trong cả hai nhóm tuổi 18–30 và 31–45, nhóm máu O chiếm tỷ lệ
cao nhất (khoảng 33%), trong khi nhóm máu AB có tỷ lệ thấp nhất (khoảng
22%). Tỷ trọng các nhóm máu A, B, AB khá cân bằng, chỉ dao động quanh
mức 22–23%. Cấu trúc phân bố nhóm máu gần như tương đồng giữa hai nhóm
tuổi, không có sự khác biệt đáng kể. Nhìn chung, các nhóm tuổi trẻ hơn
(18–30) có số lượng mẫu lớn hơn, nhưng tỷ lệ giữa các nhóm máu vẫn ổn
định.
Kết luận: Phân bố nhóm máu không có mối liên hệ rõ ràng với nhóm tuổi, xu hướng chung là nhóm máu O phổ biến nhất, tiếp theo là B và A, còn AB ít gặp nhất. Điều này cho thấy tính ổn định trong cơ cấu nhóm máu giữa các nhóm tuổi.