Database
# Load required libraries
library(readxl)
library(dplyr)
library(tidyr)
library(rstatix)
library(ggplot2)
library(FactoMineR)
library(factoextra)
library(reshape2)
library(fmsb)
library(knitr)
library(DT)
library(lubridate)
library(moments)
data <- read_excel("C:/Users/lenovo/Downloads/Data_Sport Science.xlsx")
# Mengubah format kolom tanggal dan jam
data <- data %>%
mutate(
Tanggal = format(as.Date(Tanggal, format = "%Y-%m-%dT%H:%M:%S"), "%d/%m/%y"),
Jam = format(hms::as_hms(Jam), "%H:%M")
)
datatable(data)
Descriptive & Comparassion Analysis
# Load additional libraries
# Define parameters to be analyzed
parameters <- c("Systolic", "Diastolic", "Heart.Rate", "SPO2", "Temperature")
param_names <- c("Systolic Blood Pressure", "Diastolic Blood Pressure", "Heart Rate", "Oxygen Saturation (SPO2)", "Body Temperature")
# Function to perform Shapiro-Wilk normality test
perform_normality_test <- function(data, col) {
test <- shapiro.test(data[[col]][!is.na(data[[col]])])
list(is_normal = test$p.value > 0.05, p_value = test$p.value) # Returns TRUE if data is normal, FALSE otherwise
}
# Function to calculate comprehensive descriptive statistics (mean, SD, IQR, skewness, kurtosis)
calculate_comprehensive_stats <- function(data, param, device) {
col_name <- paste(device, param, sep = "_")
data %>%
summarise(
Parameter = param,
Mean = mean(.data[[col_name]], na.rm = TRUE),
Min = min(.data[[col_name]], na.rm = TRUE),
Max = max(.data[[col_name]], na.rm = TRUE),
SD = sd(.data[[col_name]], na.rm = TRUE),
Median = median(.data[[col_name]], na.rm = TRUE),
Q1 = quantile(.data[[col_name]], 0.25, na.rm = TRUE),
Q3 = quantile(.data[[col_name]], 0.75, na.rm = TRUE),
IQR = IQR(.data[[col_name]], na.rm = TRUE),
Skewness = skewness(.data[[col_name]], na.rm = TRUE),
Kurtosis = kurtosis(.data[[col_name]], na.rm = TRUE),
Missing = sum(is.na(.data[[col_name]])),
Present = sum(!is.na(.data[[col_name]]))
)
}
# Function for comparative tests and advanced statistical measures
perform_comparative_tests <- function(data, param) {
col1 <- paste("SmartLife", param, sep = "_")
col2 <- paste("Covwatch", param, sep = "_")
# Normality checks
normal1 <- perform_normality_test(data, col1)
normal2 <- perform_normality_test(data, col2)
# SEM and SDC calculations
SEM1 <- sd(data[[col1]], na.rm = TRUE) / sqrt(sum(!is.na(data[[col1]])))
SDC1 <- SEM1 * 1.96 * sqrt(2)
SEM2 <- sd(data[[col2]], na.rm = TRUE) / sqrt(sum(!is.na(data[[col2]])))
SDC2 <- SEM2 * 1.96 * sqrt(2)
# Distribution comparison (t-test or Wilcoxon test)
if (normal1$is_normal && normal2$is_normal) {
distribution_test <- t.test(data[[col1]], data[[col2]], paired = TRUE, na.action = na.omit)
test_type <- "t-test"
} else {
distribution_test <- wilcox.test(data[[col1]], data[[col2]], paired = TRUE, na.action = na.omit)
test_type <- "Wilcoxon"
}
# Chi-squared tests for missing and present data
chisq_missing <- chisq.test(table(is.na(data[[col1]]), is.na(data[[col2]])))
chisq_present <- chisq.test(table(!is.na(data[[col1]]), !is.na(data[[col2]])))
tibble(
Parameter = param,
SEM_SmartLife = SEM1,
SEM_Covwatch = SEM2,
SDC_SmartLife = SDC1,
SDC_Covwatch = SDC2,
Chi_Squared_Missing = chisq_missing$statistic,
p_value_Missing = chisq_missing$p.value,
Chi_Squared_Present = chisq_present$statistic,
p_value_Present = chisq_present$p.value,
Test_Type = test_type,
Test_Statistic = distribution_test$statistic,
p_Value = distribution_test$p.value
)
}
# Generate comprehensive descriptive statistics for each device and parameter
smartlife_stats <- bind_rows(lapply(parameters, function(p) calculate_comprehensive_stats(data, p, "SmartLife")))
covwatch_stats <- bind_rows(lapply(parameters, function(p) calculate_comprehensive_stats(data, p, "Covwatch")))
# Apply the comparative tests function to each parameter
comparison_results <- bind_rows(lapply(parameters, function(p) perform_comparative_tests(data, p)))
# Round the results to 3 decimal places
smartlife_stats_rounded <- smartlife_stats %>% mutate(across(where(is.numeric), round, 3))
covwatch_stats_rounded <- covwatch_stats %>% mutate(across(where(is.numeric), round, 3))
comparison_results_rounded <- comparison_results %>% mutate(across(where(is.numeric), round, 3))
# Print the results using kable with 3 decimal points
print("SmartLife Comprehensive Descriptive Statistics")
## [1] "SmartLife Comprehensive Descriptive Statistics"
kable(smartlife_stats_rounded, caption = "SmartLife Comprehensive Descriptive Statistics")
SmartLife Comprehensive Descriptive Statistics
| Systolic |
117.800 |
99.0 |
137.0 |
7.739 |
118.0 |
115.00 |
124.0 |
9.00 |
-0.484 |
2.926 |
46 |
95 |
| Diastolic |
78.768 |
67.0 |
90.0 |
5.911 |
78.0 |
74.00 |
84.0 |
10.00 |
-0.077 |
1.934 |
46 |
95 |
| Heart.Rate |
104.159 |
70.0 |
175.0 |
21.514 |
102.5 |
89.00 |
110.0 |
21.00 |
1.278 |
4.994 |
53 |
88 |
| SPO2 |
97.185 |
93.0 |
98.0 |
1.442 |
98.0 |
97.00 |
98.0 |
1.00 |
-1.741 |
4.862 |
114 |
27 |
| Temperature |
36.515 |
36.2 |
36.9 |
0.191 |
36.5 |
36.35 |
36.7 |
0.35 |
-0.361 |
1.972 |
38 |
103 |
print("Covwatch Comprehensive Descriptive Statistics")
## [1] "Covwatch Comprehensive Descriptive Statistics"
kable(covwatch_stats_rounded, caption = "Covwatch Comprehensive Descriptive Statistics")
Covwatch Comprehensive Descriptive Statistics
| Systolic |
84.828 |
60.0 |
121.0 |
18.955 |
88.0 |
65.00 |
92.00 |
27.00 |
0.329 |
2.000 |
112 |
29 |
| Diastolic |
71.250 |
67.0 |
80.0 |
5.909 |
69.0 |
68.50 |
71.75 |
3.25 |
1.064 |
2.275 |
137 |
4 |
| Heart.Rate |
91.774 |
52.0 |
155.0 |
20.987 |
89.5 |
78.25 |
107.75 |
29.50 |
0.315 |
2.924 |
79 |
62 |
| SPO2 |
98.000 |
97.0 |
99.0 |
0.577 |
98.0 |
98.00 |
98.00 |
0.00 |
0.000 |
3.500 |
134 |
7 |
| Temperature |
36.325 |
35.8 |
36.8 |
0.216 |
36.4 |
36.20 |
36.50 |
0.30 |
-0.330 |
2.459 |
31 |
110 |
print("Comparison Results")
## [1] "Comparison Results"
kable(comparison_results_rounded, caption = "Comparison Results")
Comparison Results
| Systolic |
0.794 |
3.520 |
2.201 |
9.757 |
0.182 |
0.669 |
0.182 |
0.669 |
Wilcoxon |
221.0 |
0.00 |
| Diastolic |
0.607 |
2.955 |
1.681 |
8.190 |
0.000 |
1.000 |
0.000 |
1.000 |
Wilcoxon |
4.0 |
0.75 |
| Heart.Rate |
2.293 |
2.665 |
6.357 |
7.388 |
5.682 |
0.017 |
5.682 |
0.017 |
Wilcoxon |
775.5 |
0.01 |
| SPO2 |
0.278 |
0.218 |
0.769 |
0.605 |
0.025 |
0.875 |
0.025 |
0.875 |
Wilcoxon |
0.0 |
NaN |
| Temperature |
0.019 |
0.021 |
0.052 |
0.057 |
3.609 |
0.057 |
3.609 |
0.057 |
Wilcoxon |
1920.0 |
0.00 |
Comparassion Analysis - histogram density &
boxplot
# Transform data into a long format
data <- data[, -c(1, 2)]
data_long <- data %>%
pivot_longer(
cols = -Nama, # Excluding the identifier column 'Nama'
names_to = c("name", "Parameter"),
names_pattern = "([^_]+)_(.+)"
)
# Visualization of histograms, density plots and boxplots
# Creating one combined plot with histograms and boxplots
# Histograms and Density Plots
hist_density_plot <- ggplot(data_long, aes(x = value, fill = name)) +
geom_histogram(aes(y = ..density..), position = "identity", alpha = 0.5, bins = 30) +
geom_density(alpha = 0.7, adjust = 1.5) +
facet_wrap(~Parameter, scales = "free") +
labs(title = "Distribution of Measurements by Device", x = "Value", y = "Density") +
theme_minimal()
# Boxplots showing distribution differences
boxplot_comparison <- ggplot(data_long, aes(x = Parameter, y = value, fill = name)) +
geom_boxplot() +
labs(title = "Boxplot Comparison of Parameters by Device", x = "Parameter", y = "Value") +
theme_minimal()
# Print the plots
print(hist_density_plot)

print(boxplot_comparison)

Bland-Altman
# Aggregate the data by averaging values
aggregated_data <- data_long %>%
group_by(Nama, Parameter, name) %>%
summarise(value = mean(value, na.rm = TRUE), .groups = "drop")
# Pivot data to wide format without dropping NAs
wide_data <- aggregated_data %>%
pivot_wider(names_from = name, values_from = value)
# Pastikan untuk memuat library yang diperlukan
library(dplyr)
library(DT) # Untuk fungsi datatable()
# Pastikan semua kolom yang diperlukan memiliki angka 3 digit di belakang koma
wide_data <- wide_data %>%
mutate(across(where(is.numeric), ~ round(., 3)))
# Menampilkan hasil tabel dengan datatable dan memastikan bahwa semua baris ditampilkan
datatable(wide_data, options = list(pageLength = 90))
# Optionally handle missing values or proceed to plot with available data
wide_data <- wide_data %>%
drop_na() # or use another method to handle NAs
# Visualize data, separated by parameter
plot_list <- lapply(unique(wide_data$Parameter), function(param) {
data_subset <- wide_data %>%
filter(Parameter == param)
ggplot(data_subset, aes(x = SmartLife, y = Covwatch)) +
geom_point() +
geom_smooth(method = "lm", color = "black") +
labs(title = paste("Scatter plot for", param), x = "SmartLife", y = "Covwatch") +
theme_minimal()
})
# Print all plots for each parameter
invisible(lapply(plot_list, print))





PCA
# Load necessary libraries
# Convert relevant columns to numeric (ignoring 'Nama')
data <- data %>%
mutate(across(starts_with("SmartLife"), as.numeric),
across(starts_with("Covwatch"), as.numeric))
# Prepare data for PCA with parameters as variables (and SmartLife, Covwatch as vectors)
pca_data <- data.frame(
Systolic = c(mean(data$SmartLife_Systolic, na.rm = TRUE), mean(data$Covwatch_Systolic, na.rm = TRUE)),
Diastolic = c(mean(data$SmartLife_Diastolic, na.rm = TRUE), mean(data$Covwatch_Diastolic, na.rm = TRUE)),
Heart_Rate = c(mean(data$SmartLife_Heart.Rate, na.rm = TRUE), mean(data$Covwatch_Heart.Rate, na.rm = TRUE)),
SPO2 = c(mean(data$SmartLife_SPO2, na.rm = TRUE), mean(data$Covwatch_SPO2, na.rm = TRUE)),
Temperature = c(mean(data$SmartLife_Temperature, na.rm = TRUE), mean(data$Covwatch_Temperature, na.rm = TRUE))
)
# Set row names as SmartLife and Covwatch
rownames(pca_data) <- c("SmartLife", "Covwatch")
# Transpose the data so that parameters become the points and devices become the vectors
pca_data <- t(pca_data)
# Perform PCA
pca_results <- PCA(pca_data, scale.unit = TRUE, graph = FALSE)
# Add parameter names as labels for the points
parameter_labels <- rownames(pca_data)
# Visualize the PCA results using a biplot
fviz_pca_biplot(pca_results,
geom_ind = "point", # Points for the individuals (parameters)
geom_var = "arrow", # Arrows for the variables (SmartLife and Covwatch)
label = "var", # Label variables (devices SmartLife, Covwatch)
repel = TRUE, # Avoid overlapping of text labels
title = "PCA Biplot: Parameters vs Devices"
) +
geom_text(aes(label = parameter_labels), vjust = 1.5, color = "black") # Add parameter labels to the points

Diagram & Radar Analysis
# Create data for summary plot with error bars
summary_data <- data.frame(
Parameter = rep(c("Systolic", "Diastolic", "Heart Rate", "SPO2", "Temperature"), each = 2),
Device = rep(c("SmartLife", "Covwatch"), times = 5),
Mean = c(mean(data$SmartLife_Systolic, na.rm = TRUE), mean(data$Covwatch_Systolic, na.rm = TRUE),
mean(data$SmartLife_Diastolic, na.rm = TRUE), mean(data$Covwatch_Diastolic, na.rm = TRUE),
mean(data$SmartLife_Heart.Rate, na.rm = TRUE), mean(data$Covwatch_Heart.Rate, na.rm = TRUE),
mean(data$SmartLife_SPO2, na.rm = TRUE), mean(data$Covwatch_SPO2, na.rm = TRUE),
mean(data$SmartLife_Temperature, na.rm = TRUE), mean(data$Covwatch_Temperature, na.rm = TRUE)),
SD = c(sd(data$SmartLife_Systolic, na.rm = TRUE), sd(data$Covwatch_Systolic, na.rm = TRUE),
sd(data$SmartLife_Diastolic, na.rm = TRUE), sd(data$Covwatch_Diastolic, na.rm = TRUE),
sd(data$SmartLife_Heart.Rate, na.rm = TRUE), sd(data$Covwatch_Heart.Rate, na.rm = TRUE),
sd(data$SmartLife_SPO2, na.rm = TRUE), sd(data$Covwatch_SPO2, na.rm = TRUE),
sd(data$SmartLife_Temperature, na.rm = TRUE), sd(data$Covwatch_Temperature, na.rm = TRUE))
)
# Create a bar plot with error bars (representing standard deviation)
ggplot(summary_data, aes(x = Parameter, y = Mean, fill = Device)) +
geom_bar(stat = "identity", position = position_dodge(width = 0.8)) +
geom_errorbar(aes(ymin = Mean - SD, ymax = Mean + SD), position = position_dodge(width = 0.8), width = 0.25) +
labs(title = "Comparison of SmartLife vs Covwatch Performance Across Parameters",
y = "Mean Value", x = "Parameters") +
scale_fill_manual(values = c("#00BFC4", "#F8766D")) +
theme_minimal()

# Create a scoring system (1-5 scale based on performance)
summary_data$Score <- with(summary_data, ifelse(Device == "SmartLife",
scale(Mean, center = TRUE, scale = TRUE) + 3,
scale(Mean, center = TRUE, scale = TRUE) + 3))
# Load necessary libraries
# Prepare data for the radar chart by using the mean values of each parameter for both devices
pca_data <- data.frame(
Systolic = c(mean(data$SmartLife_Systolic, na.rm = TRUE),
mean(data$Covwatch_Systolic, na.rm = TRUE)),
Diastolic = c(mean(data$SmartLife_Diastolic, na.rm = TRUE),
mean(data$Covwatch_Diastolic, na.rm = TRUE)),
Heart_Rate = c(mean(data$SmartLife_Heart.Rate, na.rm = TRUE),
mean(data$Covwatch_Heart.Rate, na.rm = TRUE)),
SPO2 = c(mean(data$SmartLife_SPO2, na.rm = TRUE),
mean(data$Covwatch_SPO2, na.rm = TRUE)),
Temperature = c(mean(data$SmartLife_Temperature, na.rm = TRUE),
mean(data$Covwatch_Temperature, na.rm = TRUE))
)
# Add row names to distinguish between devices
rownames(pca_data) <- c("SmartLife", "Covwatch")
# Create a max-min range to compare both devices properly
max_min <- data.frame(
Systolic = c(150, 50), # Arbitrary max and min for scaling
Diastolic = c(100, 40), # Adjust max and min values as per actual data range
Heart_Rate = c(180, 0),
SPO2 = c(100, 0),
Temperature = c(50, 30)
)
# Combine the max/min values with device data for radar chart
radar_data <- rbind(max_min, pca_data)
# Create radar chart
radarchart(radar_data, axistype = 1,
# Customize the plot colors
pcol = c("#00BFC4", "#F8766D"), # Colors for lines (SmartLife=blue, Covwatch=red)
pfcol = c(rgb(0.2, 0.5, 0.5, 0.5), rgb(1, 0.2, 0.2, 0.5)), # Transparency for filled areas
plwd = 2, # Line width
cglcol = "grey", # Color for grid lines
cglty = 1, # Line type for grid
axislabcol = "grey", # Axis label color
caxislabels = seq(0, 100, 25), # Axis labels
cglwd = 0.8, # Grid line width
vlcex = 1.2) # Font size for labels
# Add title
title(main = "Radar Chart: Comparison of SmartLife vs Covwatch Parameters")
# Add a better-positioned legend to avoid overlap
legend("bottomright", legend = c("SmartLife", "Covwatch"),
col = c("#00BFC4", "#F8766D"), lty = 1, lwd = 2, bty = "n", inset = c(0.7, 0.79), cex = 0.8)

Close
library(magick)
# Baca gambar dari path lokal
img <- image_read("C:/Users/lenovo/Downloads/WhatsApp Image 2024-10-25 at 17.38.16.jpeg")
# Ubah gambar menjadi hitam putih (grayscale)
img_bw <- image_convert(img, colorspace = "gray")
# Tampilkan gambar hasil hitam putih
print(img_bw)
## # A tibble: 1 × 7
## format width height colorspace matte filesize density
## <chr> <int> <int> <chr> <lgl> <int> <chr>
## 1 JPEG 4032 3024 Gray FALSE 0 72x72

# Jika ingin menyimpan hasilnya
image_write(img_bw, "C:/Users/lenovo/Downloads/WhatsApp_Image_bw.jpeg")
Thank you, runners, for your passion and resilience. Your
strides inspire us all to keep moving forward! 🌟🏃♂️🏃♀️