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
Parameter Mean Min Max SD Median Q1 Q3 IQR Skewness Kurtosis Missing Present
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
Parameter Mean Min Max SD Median Q1 Q3 IQR Skewness Kurtosis Missing Present
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
Parameter SEM_SmartLife SEM_Covwatch SDC_SmartLife SDC_Covwatch Chi_Squared_Missing p_value_Missing Chi_Squared_Present p_value_Present Test_Type Test_Statistic p_Value
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! 🌟🏃‍♂️🏃‍♀️