1. Tiền xử lý số liệu

# Gọi thư viện readxl để đọc file excel
library(readxl)

# Đọc dữ liệu từ file excel vào biến printer_data và in ra 3 dòng đầu tiên
printer_data <- read_excel("D:/HCMUT/HK252/BTL XSTK/data.csv.xlsx")
head(printer_data, 3)
## # A tibble: 3 × 12
##   layer_height wall_thickness infill_density infill_pattern nozzle_temperature
##          <dbl>          <dbl>          <dbl> <chr>                       <dbl>
## 1         0.02              8             90 grid                          220
## 2         0.02              7             90 honeycomb                     225
## 3         0.02              1             80 grid                          230
## # ℹ 7 more variables: bed_temperature <dbl>, print_speed <dbl>, material <chr>,
## #   fan_speed <dbl>, roughness <dbl>, tension_strenght <dbl>, elongation <dbl>
# Trích xuất một dataframe mới (new_DF) chỉ giữ lại các biến cần thiết cho phân tích
new_DF <- printer_data[, c("layer_height", "wall_thickness", "infill_density", 
                           "infill_pattern", "nozzle_temperature", "bed_temperature", 
                           "print_speed", "material", "fan_speed", "tension_strenght")]

# In ra 3 dòng đầu tiên của dataframe mới
head(new_DF, 3)
## # A tibble: 3 × 10
##   layer_height wall_thickness infill_density infill_pattern nozzle_temperature
##          <dbl>          <dbl>          <dbl> <chr>                       <dbl>
## 1         0.02              8             90 grid                          220
## 2         0.02              7             90 honeycomb                     225
## 3         0.02              1             80 grid                          230
## # ℹ 5 more variables: bed_temperature <dbl>, print_speed <dbl>, material <chr>,
## #   fan_speed <dbl>, tension_strenght <dbl>
# Gọi thư viện questionr để tính toán và thống kê tỷ lệ dữ liệu bị khuyết (missing values)
library(questionr)
freq.na(new_DF)
##                    missing %
## layer_height             0 0
## wall_thickness           0 0
## infill_density           0 0
## infill_pattern           0 0
## nozzle_temperature       0 0
## bed_temperature          0 0
## print_speed              0 0
## material                 0 0
## fan_speed                0 0
## tension_strenght         0 0

2. Thống kê mô tả

# Xây dựng hàm tùy chỉnh (new_function) để tính toán nhanh các giá trị thống kê mô tả
new_function <- function(x){
  c(n = length(x), xtb = mean(x), sd = sd(x), Q1 = quantile(x, probs = 0.25),
    Q2 = median(x), Q3 = quantile(x, probs = 0.75), min = min(x), max = max(x))
}

# Lọc ra nhóm các biến liên tục (định lượng) để đưa vào hàm thống kê
continous_data <- new_DF[, c("layer_height", "wall_thickness", "infill_density",
                             "nozzle_temperature", "bed_temperature", "print_speed",
                             "fan_speed", "tension_strenght")]

# Áp dụng hàm thống kê vừa tạo cho toàn bộ các cột của tập dữ liệu liên tục
apply(continous_data, 2, new_function)
##        layer_height wall_thickness infill_density nozzle_temperature
## n       50.00000000      50.000000       50.00000           50.00000
## xtb      0.10600000       5.220000       53.40000          221.50000
## sd       0.06439673       2.922747       25.36348           14.82035
## Q1.25%   0.06000000       3.000000       40.00000          210.00000
## Q2       0.10000000       5.000000       50.00000          220.00000
## Q3.75%   0.15000000       7.000000       80.00000          230.00000
## min      0.02000000       1.000000       10.00000          200.00000
## max      0.20000000      10.000000       90.00000          250.00000
##        bed_temperature print_speed fan_speed tension_strenght
## n            50.000000     50.0000  50.00000        50.000000
## xtb          70.000000     64.0000  50.00000        20.080000
## sd            7.142857     29.6923  35.71429         8.925634
## Q1.25%       65.000000     40.0000  25.00000        12.000000
## Q2           70.000000     60.0000  50.00000        19.000000
## Q3.75%       75.000000     60.0000  75.00000        27.000000
## min          60.000000     40.0000   0.00000         4.000000
## max          80.000000    120.0000 100.00000        37.000000
# Lập bảng tần số để đếm số lượng cho các biến phân loại (định tính)
table(new_DF$infill_pattern)
## 
##      grid honeycomb 
##        25        25
table(new_DF$material)
## 
## abs pla 
##  25  25

3. Trực quan hóa dữ liệu

# Vẽ biểu đồ phân bố tần số Histogram để xem hình dáng phân phối của biến sức bền kéo
hist(new_DF$tension_strenght, xlab = "tension_strenght", main = "Histogram of tension_strenght", 
     col = "blue", labels = T, ylim = c(0, 15))

# Vẽ biểu đồ Boxplot nhằm so sánh khoảng giá trị sức bền kéo theo các dạng lưới in
boxplot(tension_strenght ~ infill_pattern, data = new_DF, col = c("red", "blue"), 
        main = "tension_strenght and infill_pattern")

# Vẽ biểu đồ Boxplot nhằm so sánh khoảng giá trị sức bền kéo theo loại vật liệu in
boxplot(tension_strenght ~ material, data = new_DF, col = c("red", "blue"), 
        main = "tension_strenght and material")

# Thiết lập khung đồ thị hiển thị 2 hàng 4 cột để vẽ hàng loạt biểu đồ phân tán cùng lúc
par(mfrow = c(2, 4))

# Nhóm lệnh vẽ đồ thị phân tán (Scatter plot) để nhận xét sơ bộ mối quan hệ tuyến tính
plot(new_DF$layer_height, new_DF$tension_strenght, xlab = "layer_height", ylab = "tension_strenght", main = "layer_height & tension_strenght")
plot(new_DF$wall_thickness, new_DF$tension_strenght, xlab = "wall_thickness", ylab = "tension_strenght", main = "wall_thickness & tension_strenght")
plot(new_DF$infill_density, new_DF$tension_strenght, xlab = "infill_density", ylab = "tension_strenght", main = "infill_density & tension_strenght")
plot(new_DF$nozzle_temperature, new_DF$tension_strenght, xlab = "nozzle_temperature", ylab = "tension_strenght", main = "nozzle_temperature & tension_strenght")
plot(new_DF$bed_temperature, new_DF$tension_strenght, xlab = "bed_temperature", ylab = "tension_strenght", main = "bed_temperature & tension_strenght")
plot(new_DF$print_speed, new_DF$tension_strenght, xlab = "print_speed", ylab = "tension_strenght", main = "print_speed & tension_strenght")
plot(new_DF$fan_speed, new_DF$tension_strenght, xlab = "fan_speed", ylab = "tension_strenght", main = "fan_speed & tension_strenght")

# Gọi thư viện corrplot để vẽ ma trận tương quan, giúp phát hiện sớm hiện tượng đa cộng tuyến
library(corrplot)
## corrplot 0.95 loaded
corrplot(cor(continous_data), method = "number")

4. Thống kê suy diễn - Bài toán 1 mẫu và 2 mẫu

# --- BÀI TOÁN MỘT MẪU (Ước lượng khoảng tin cậy 95%) ---
# Tính cỡ mẫu (n), trung bình mẫu (xtb) và độ lệch chuẩn (s) của biến sức bền kéo
n <- length(new_DF$tension_strenght)
xtb <- mean(new_DF$tension_strenght)
s <- sd(new_DF$tension_strenght)
data.frame(n, xtb, s)
##    n   xtb        s
## 1 50 20.08 8.925634
# Kiểm tra giả định phân phối chuẩn thông qua biểu đồ QQ-plot và kiểm định Shapiro-Wilk
qqnorm(new_DF$tension_strenght)
qqline(new_DF$tension_strenght)

shapiro.test(new_DF$tension_strenght)
## 
##  Shapiro-Wilk normality test
## 
## data:  new_DF$tension_strenght
## W = 0.9566, p-value = 0.06404
# Tính ngưỡng sai số ước lượng (epsilon) dựa trên phân phối Student (t) do chưa biết phương sai tổng thể
epsilon <- qt(p = 0.05/2, df = n-1, lower.tail = FALSE) * s / sqrt(n)
print(epsilon)
## [1] 2.536637
# Xây dựng và in ra khoảng ước lượng tin cậy: giới hạn dưới (u1) và giới hạn trên (u2)
data.frame(u1 = xtb - epsilon, u2 = xtb + epsilon)
##         u1       u2
## 1 17.54336 22.61664
# --- BÀI TOÁN HAI MẪU (So sánh 2 nhóm vật liệu) ---
# Trích xuất dữ liệu riêng cho nhóm vật liệu "abs" và kiểm tra phân phối chuẩn
abs_data <- subset(new_DF, material == "abs")
qqnorm(abs_data$tension_strenght)
qqline(abs_data$tension_strenght)

shapiro.test(abs_data$tension_strenght)
## 
##  Shapiro-Wilk normality test
## 
## data:  abs_data$tension_strenght
## W = 0.90604, p-value = 0.02489
# Trích xuất dữ liệu riêng cho nhóm vật liệu "pla" và kiểm tra phân phối chuẩn
pla_data <- subset(new_DF, material == "pla")
qqnorm(pla_data$tension_strenght)
qqline(pla_data$tension_strenght)

shapiro.test(pla_data$tension_strenght)
## 
##  Shapiro-Wilk normality test
## 
## data:  pla_data$tension_strenght
## W = 0.92466, p-value = 0.06547
# Kiểm định F (F-test) để so sánh sự bằng nhau của 2 phương sai trước khi chạy kiểm định T-test
var.test(tension_strenght ~ material, data = new_DF, alternative = "greater")
## 
##  F test to compare two variances
## 
## data:  tension_strenght by material
## F = 1.3045, num df = 24, denom df = 24, p-value = 0.26
## alternative hypothesis: true ratio of variances is greater than 1
## 95 percent confidence interval:
##  0.6575797       Inf
## sample estimates:
## ratio of variances 
##            1.30448
# Thực hiện kiểm định T-test hai mẫu độc lập (giả định phương sai 2 nhóm bằng nhau)
t.test(tension_strenght ~ material, data = new_DF, var.equal = T)
## 
##  Two Sample t-test
## 
## data:  tension_strenght by material
## t = -2.0972, df = 48, p-value = 0.04126
## alternative hypothesis: true difference in means between group abs and group pla is not equal to 0
## 95 percent confidence interval:
##  -10.028585  -0.211415
## sample estimates:
## mean in group abs mean in group pla 
##             17.52             22.64

5. Phân tích phương sai một nhân tố (ANOVA)

# Tạo biến phân loại mới, chia nhóm nhiệt độ mũi in (nozzle_temperature) thành 3 mức độ
new_DF$nozzle_temperature_2 <- ifelse(new_DF$nozzle_temperature < 220, "Group_1",
                               ifelse(new_DF$nozzle_temperature > 230, "Group_3", "Group_2"))

# Lọc dữ liệu và kiểm tra giả định phân phối chuẩn cho sức bền kéo ở từng nhóm
Group_1 <- subset(new_DF, new_DF$nozzle_temperature_2 == "Group_1")
qqnorm(Group_1$tension_strenght)
qqline(Group_1$tension_strenght)

shapiro.test(Group_1$tension_strenght)
## 
##  Shapiro-Wilk normality test
## 
## data:  Group_1$tension_strenght
## W = 0.91815, p-value = 0.09128
Group_2 <- subset(new_DF, new_DF$nozzle_temperature_2 == "Group_2")
qqnorm(Group_2$tension_strenght)
qqline(Group_2$tension_strenght)

shapiro.test(Group_2$tension_strenght)
## 
##  Shapiro-Wilk normality test
## 
## data:  Group_2$tension_strenght
## W = 0.95684, p-value = 0.4829
Group_3 <- subset(new_DF, new_DF$nozzle_temperature_2 == "Group_3")
qqnorm(Group_3$tension_strenght)
qqline(Group_3$tension_strenght)

shapiro.test(Group_3$tension_strenght)
## 
##  Shapiro-Wilk normality test
## 
## data:  Group_3$tension_strenght
## W = 0.87204, p-value = 0.1056
# Gọi thư viện car và chạy kiểm định Levene để đánh giá sự đồng nhất của phương sai giữa 3 nhóm
library(car)
## Loading required package: carData
leveneTest(tension_strenght ~ as.factor(nozzle_temperature_2), data = new_DF)
## Levene's Test for Homogeneity of Variance (center = median)
##       Df F value Pr(>F)
## group  2  0.9575 0.3912
##       47
# Xây dựng mô hình phân tích phương sai ANOVA một nhân tố và trích xuất bảng kết quả
ANOVA_model <- aov(tension_strenght ~ as.factor(nozzle_temperature_2), data = new_DF)
summary(ANOVA_model)
##                                 Df Sum Sq Mean Sq F value Pr(>F)  
## as.factor(nozzle_temperature_2)  2    688   343.9   5.026 0.0105 *
## Residuals                       47   3216    68.4                 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Thực hiện so sánh bội Tukey để xác định cụ thể cặp nhóm nào có sự khác biệt về trung bình
TukeyHSD(ANOVA_model)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = tension_strenght ~ as.factor(nozzle_temperature_2), data = new_DF)
## 
## $`as.factor(nozzle_temperature_2)`
##                   diff        lwr        upr     p adj
## Group_2-Group_1  -3.10  -9.430522  3.2305221 0.4678313
## Group_3-Group_1 -10.15 -17.903275 -2.3967255 0.0074607
## Group_3-Group_2  -7.05 -14.803275  0.7032745 0.0814970
# Vẽ đồ thị so sánh bội để dễ hình dung các khoảng tin cậy
plot(TukeyHSD(ANOVA_model))

6. Hồi quy tuyến tính đa biến

# Xây dựng mô hình hồi quy đa biến ban đầu (model_1) bao gồm tất cả các biến dự báo
model_1 <- lm(tension_strenght ~ layer_height + wall_thickness + infill_density + 
              infill_pattern + nozzle_temperature + bed_temperature + print_speed + 
              material, data = new_DF)
summary(model_1)
## 
## Call:
## lm(formula = tension_strenght ~ layer_height + wall_thickness + 
##     infill_density + infill_pattern + nozzle_temperature + bed_temperature + 
##     print_speed + material, data = new_DF)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -9.4101 -3.8491  0.0338  3.9073 13.5086 
## 
## Coefficients:
##                          Estimate Std. Error t value Pr(>|t|)    
## (Intercept)             171.62809   54.21779   3.166  0.00292 ** 
## layer_height             55.59721   12.78771   4.348 8.87e-05 ***
## wall_thickness            1.06871    0.31942   3.346  0.00176 ** 
## infill_density            0.16286    0.03415   4.769 2.35e-05 ***
## infill_patternhoneycomb  -1.14271    1.64581  -0.694  0.49140    
## nozzle_temperature       -1.04681    0.36901  -2.837  0.00705 ** 
## bed_temperature           1.00534    0.47426   2.120  0.04012 *  
## print_speed              -0.01559    0.03006  -0.519  0.60679    
## materialpla             -17.30508    8.51530  -2.032  0.04864 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 5.58 on 41 degrees of freedom
## Multiple R-squared:  0.673,  Adjusted R-squared:  0.6092 
## F-statistic: 10.55 on 8 and 41 DF,  p-value: 6.91e-08
# Xây dựng mô hình tối ưu hơn (model_2) bằng cách loại bỏ các biến không có ý nghĩa thống kê
model_2 <- lm(tension_strenght ~ layer_height + wall_thickness + infill_density + 
              nozzle_temperature + bed_temperature + material, data = new_DF)
summary(model_2)
## 
## Call:
## lm(formula = tension_strenght ~ layer_height + wall_thickness + 
##     infill_density + nozzle_temperature + bed_temperature + material, 
##     data = new_DF)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -9.4717 -4.1695  0.0914  3.8586 13.9581 
## 
## Coefficients:
##                     Estimate Std. Error t value Pr(>|t|)    
## (Intercept)        167.02463   53.19880   3.140 0.003055 ** 
## layer_height        56.36695   12.44845   4.528 4.67e-05 ***
## wall_thickness       1.11169    0.28024   3.967 0.000271 ***
## infill_density       0.16643    0.03339   4.985 1.06e-05 ***
## nozzle_temperature  -1.02890    0.36321  -2.833 0.006996 ** 
## bed_temperature      0.98346    0.46685   2.107 0.041026 *  
## materialpla        -17.10365    8.39202  -2.038 0.047722 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 5.501 on 43 degrees of freedom
## Multiple R-squared:  0.6667, Adjusted R-squared:  0.6201 
## F-statistic: 14.33 on 6 and 43 DF,  p-value: 6.783e-09
# Thiết lập khung đồ thị 2x2 để vẽ 4 đồ thị kiểm tra các giả định của sai số ngẫu nhiên
par(mfrow = c(2, 2))
plot(model_2)

# Kiểm tra giả định sai số có phân phối chuẩn
shapiro.test(model_2$residuals)
## 
##  Shapiro-Wilk normality test
## 
## data:  model_2$residuals
## W = 0.97458, p-value = 0.3517
# Kiểm tra giả định sai số có kỳ vọng bằng 0 thông qua T-test một mẫu
t.test(model_2$residuals)
## 
##  One Sample t-test
## 
## data:  model_2$residuals
## t = -7.5559e-16, df = 49, p-value = 1
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
##  -1.464546  1.464546
## sample estimates:
##     mean of x 
## -5.506598e-16
# Gọi thư viện lmtest và dùng Breusch-Pagan test để kiểm tra giả định phương sai các sai số là hằng số
library(lmtest)
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
bptest(model_2)
## 
##  studentized Breusch-Pagan test
## 
## data:  model_2
## BP = 6.6773, df = 6, p-value = 0.3517
# Sử dụng Durbin-Watson test để kiểm tra xem các sai số có độc lập với nhau hay không
dwtest(model_2)
## 
##  Durbin-Watson test
## 
## data:  model_2
## DW = 1.5005, p-value = 0.01575
## alternative hypothesis: true autocorrelation is greater than 0