In this project, the open-source R programming language is used to examine the relationship between RPE and strength decline. R is maintained by an international team of developers who make the language available at The Comprehensive R Archive Network. Readers interested in reusing our code and reproducing our results should have R installed locally on their machines. R can be installed on a number of different operating systems (see Windows, Mac, and Linux for the installation instructions for these systems). We also recommend using the RStudio interface for R. The reader can download RStudio for free by following the instructions at the link. For non-R users, we recommend the Hands-on Programming with R for a brief overview of the software’s functionality. Hereafter, we assume that the reader has an introductory understanding of the R programming language.
In the code chunk below, we load the packages used to support our analysis. Note that the code of this and any of the code chunks can be hidden by clicking on the ‘Hide’ button to facilitate the navigation. The reader can hide all code and/or download the Rmd file associated with this document by clicking on the Code button on the top right corner of this document. Our input data file can be accessed/ downloaded from blindedResearch/corr_analysis.
rm(list = ls()) # clear global environment
graphics.off() # close all graphics
#p_load is equivalent to combining both install.packages() and library()
pacman::p_load(stringr, readxl, ggplot2, dplyr, rje, signal, stats, tibble, kableExtra, magrittr, polyreg)
In this section we first load the “Mixed_Data_Full”, the data frame including all RPE scores and Strength decline data for the whole experiment, which involves three work periods and two rest periods. Since the focus of this report is on the first two work periods, the other periods are removed for the later analysis.
setwd(dirname(rstudioapi::getActiveDocumentContext()$path))
load('Mixed_Data_Full.RData')
Mixed_Data_Full$Unique_code = paste(Mixed_Data_Full$Unique_code, Mixed_Data_Full$Period)
data_to_remove = which(Mixed_Data_Full$Period == '1st_break' | Mixed_Data_Full$Period == '2nd_break'| Mixed_Data_Full$Period == '3rd_45min')
Mixed_Data_Full = Mixed_Data_Full[-data_to_remove,]
Mixed_Data_List = split(Mixed_Data_Full, f = Mixed_Data_Full$Unique_code)
Mixed_Data = as.data.frame(do.call(rbind, Mixed_Data_List))
This section includes the process of data preparation, plotting, and correlation analysis of RPE scores and strength decline.
First, the process starts with interpolating RPE scores for the strength test’s time points using the cubic fitting for the first work period. Since the RPE scores are reported every 5 minutes and strength tests are done every 9 minutes as well as the begin and end of each period, this interpolation is needed to have RPE scores at timepoints that they are not originally reported. This interpolation is done using the function “model = lm(Y ~ stats::poly(X, 3))” to fit to current data and then using “Y_fit = predict(model, data.frame(X))” to find the fitted RPE scores for the missing data points. It can be replaced with “model = approx(X, Y, xout = X)” and “Y_fit = do.call(cbind, model)” to have the linear interpolation of the RPE scores. In this report we have proceeded with the cubic fit, however, the results of the linear fit is also provided in the paper and its results does not differ significantly from the results shown in the next steps.
Subjects = unique(Mixed_Data$ID)
Conditions = unique(Mixed_Data$Condition)
Full_Data1 = NULL
for (i in 1:length(Subjects))
{
for (j in 1:length(Conditions))
{
Subject = Subjects[i]
Condition = Conditions[j]
Data = Mixed_Data[Mixed_Data$ID == Subject &
unlist(Mixed_Data$Condition) == Condition & Mixed_Data$Period == '1st_45min',]
to_remove = which((is.na(Data$Change_in_Max_Load))& (is.na(Data$RPE)))
if (length(to_remove)>0)
{
Data = Data[-to_remove,]
}
if (dim(Data)[1]>0)
{
tryCatch({
X = Data$Time - min(Data$Time)
Y = Data$RPE
#Fitting the cubic polynomial to the RPE scores
model = lm(Y ~ stats::poly(X, 3))
Y_fit = predict(model, data.frame(X))
Data$Fitted_RPE = Y_fit
Full_Data1 = rbind(Full_Data1, Data)
}, error = function(e) {})
}
}
}
The same process is followed to obtain the interpolated values of RPE scores for the second work period of the experiment. Similarly, a cubic fit is used in this section.
Full_Data2 = NULL
for (i in 1:length(Subjects))
{
for (j in 1:length(Conditions))
{
Subject = Subjects[i]
Condition = Conditions[j]
Data = Mixed_Data[Mixed_Data$ID == Subject &
unlist(Mixed_Data$Condition) == Condition & Mixed_Data$Period == '2nd_45min',]
to_remove = which((is.na(Data$Change_in_Max_Load))& (is.na(Data$RPE)))
if (length(to_remove)>0)
{
Data = Data[-to_remove,]
}
if (dim(Data)[1]>0)
{
tryCatch({
X = Data$Time - min(Data$Time)
Y = Data$RPE
#Fitting the cubic polynomial to the RPE scores
model = lm(Y ~ stats::poly(X, 3))
Y_fit = predict(model, data.frame(X))
Data$Fitted_RPE = Y_fit
Full_Data2 = rbind(Full_Data2, Data)
}, error = function(e) {})
}
}
}
In this section, the fitted RPE scores are plotted together with the original reported RPE scores along with the original strength decline ratios. As demonstrated in these plots, the interpolation has provided us with the fitted RPE scores in the time-points where it is not originally reported (in the strength test time points). Then the correlation analysis of RPE scores and the strength decline is calculated which provides the correlation coefficients.
Corr_Matrix = matrix(data = NA, nrow = length(Conditions),
ncol = length(Subjects))
rownames(Corr_Matrix) = Conditions
colnames(Corr_Matrix) = Subjects
Full_Data = NULL
for (i in 1:length(Subjects))
{
cat('##',Subjects[i], "{.tabset .tabset-fade}", '\n')
for (j in 1:length(Conditions))
{
cat('###', as.character(Conditions[j]), "{.tabset .tabset-fade}",'\n')
Subject = Subjects[i]
Condition = as.character(Conditions[j])
Data = Mixed_Data[which(Mixed_Data$ID == Subject &
Mixed_Data$Condition == Condition & Mixed_Data$Period == "1st_45min"),]
to_remove = which((is.na(Data$Change_in_Max_Load))&
(is.na(Data$RPE)))
if(length(to_remove)==0)({
Data = Data
}) else {
Data = Data[-to_remove,]}
if (dim(Data)[1]>0)
{
tryCatch({
X = Data$Time
Y = Data$RPE
model = lm(Y ~ stats::poly(X, 3))
Y_fit = predict(model, data.frame(X))
Y_fit[Y_fit<0] = c(0)
Y_fit[Y_fit>10] = c(10)
Data$Fitted_RPE = Y_fit
Full_Data = rbind(Full_Data, Data)
#Calculate the correlation
Corr_Matrix[j, i] = cor(Data$Change_in_Max_Load,
Data$Fitted_RPE, use = "complete.obs")
gg_Data1 = Data[,c(5,6,7,9)]
colnames(gg_Data1) = c('Time', 'Y', 'Y', 'Y')
gg_Data1 = rbind(gg_Data1[,c(1,2)], gg_Data1[,c(1,3)], gg_Data1[,c(1,4)])
gg_Data1$Variable = c(rep('Strength', dim(Data)[1]),
rep('RPE', 2*dim(Data)[1]))
gg_Data1$Type = c(rep('Reported', 2*dim(Data)[1]),
rep('Fitted', dim(Data)[1]))
gg_Data1 = na.omit(gg_Data1)
gg_Data1$Y = as.numeric(gg_Data1$Y)
p = ggplot(gg_Data1, aes(Time, Y, colour = Type)) + geom_point()
# Use vars() to supply faceting variables:
p = p + facet_wrap(vars(Variable), nrow = 2, scales = "free_y")+
scale_x_continuous(breaks = scales::pretty_breaks(n=5), limits = c(0, 50))
print(p)
}, error = function(e) {})
}
cat('\n \n')
}
cat('\n \n')
}
The same approach as the previous section is followed to plot the fitted RPE scores for the second work period of the experiment and the correlation coefficients are also calculated in a similar manner.
Corr_Matrix2 = matrix(data = NA, nrow = length(Conditions),
ncol = length(Subjects))
rownames(Corr_Matrix2) = Conditions
colnames(Corr_Matrix2) = Subjects
Full_Data2 = NULL
for (i in 1:length(Subjects))
{
cat('##',Subjects[i], "{.tabset .tabset-fade}", '\n')
for (j in 1:length(Conditions))
{
cat('###', as.character(Conditions[j]), "{.tabset .tabset-fade}",'\n')
Subject = Subjects[i]
Condition = as.character(Conditions[j])
Data2 = Mixed_Data[which(Mixed_Data$ID == Subject &
Mixed_Data$Condition == Condition & Mixed_Data$Period == "2nd_45min"),]
to_remove = which((is.na(Data2$Change_in_Max_Load))&
(is.na(Data2$RPE)))
if(length(to_remove)==0)({
Data2 = Data2
}) else {
Data2 = Data2[-to_remove,]}
if (dim(Data2)[1]>0)
{
tryCatch({
X = Data2$Time
Y = Data2$RPE
model = lm(Y ~ stats::poly(X, 3))
Y_fit = predict(model, data.frame(X))
Y_fit[Y_fit<0] = c(0)
Y_fit[Y_fit>10] = c(10)
Data2$Fitted_RPE = Y_fit
Full_Data2 = rbind(Full_Data2, Data2)
#Calculate the correlation
Corr_Matrix2[j, i] = cor(Data2$Change_in_Max_Load,
Data2$Fitted_RPE, use = "complete.obs")
gg_Data1 = Data2[,c(5,6,7,9)]
colnames(gg_Data1) = c('Time', 'Y', 'Y', 'Y')
gg_Data1 = rbind(gg_Data1[,c(1,2)], gg_Data1[,c(1,3)], gg_Data1[,c(1,4)])
gg_Data1$Variable = c(rep('Strength', dim(Data2)[1]),
rep('RPE', 2*dim(Data2)[1]))
gg_Data1$Type = c(rep('Reported', 2*dim(Data2)[1]),
rep('Fitted', dim(Data2)[1]))
gg_Data1 = na.omit(gg_Data1)
gg_Data1$Y = as.numeric(gg_Data1$Y)
p = ggplot(gg_Data1, aes(Time, Y, colour = Type)) + geom_point()
# Use vars() to supply faceting variables:
p = p + facet_wrap(vars(Variable), nrow = 2, scales = "free_y")+
scale_x_continuous(breaks = scales::pretty_breaks(n=5), limits = c(min(gg_Data1$Time), max(gg_Data1$Time)))
print(p)
}, error = function(e) {})
}
cat('\n \n')
}
cat('\n \n')
}
In this section, the values of the Pearson’s correlation coefficients are reported in a table for the first work period. In the first 45 minute work period, the average correlation between RPE and strength change, across all conditions, is -0.62. When considering each individual’s correlation, in many cases the correlations exceed -0.8 for the first period. This indicates a somewhat strong negative linear relationship between RPE and strength decline. The negative sign is expected since as a participant gets fatigued, one expects the RPE value to increase and strength to decrease/decline.
# Corr_Matrix = data.frame(Corr_Matrix)
Corr_Matrix %>%
kable(format = "html", col.names = colnames(Corr_Matrix)) %>%
kable_styling() %>%
kableExtra::scroll_box(width = "100%", height = "300px")
Sub01 | Sub02 | Sub03 | Sub04 | Sub05 | Sub06 | Sub07 | Sub08 | Sub09 | Sub10 | Sub13 | Sub15 | Sub16 | Sub17 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Condition 2.5-15 | -0.6803455 | -0.0470419 | -0.9917536 | -0.7335948 | 0.5569103 | -0.8016492 | -0.5306839 | -0.7817394 | -0.9212997 | -0.8048402 | -0.9542397 | -0.8017957 | -0.9451933 | 0.6200871 |
Condition 2.5-10 | -0.9207853 | -0.4409184 | -0.5007067 | -0.8156772 | -0.3920030 | -0.5754893 | -0.0195457 | -0.8657196 | -0.6834956 | -0.8720612 | -0.8386104 | -0.9132669 | -0.5565792 | -0.6428274 |
Condition 2.5-5 | -0.3633217 | -0.8366559 | -0.9129173 | -0.8592127 | -0.4760247 | -0.2293649 | -0.7431481 | -0.4529402 | -0.3027686 | -0.0339077 | -0.9640506 | -0.7636875 | -0.7820622 | -0.8152096 |
Condition 1.5-15 | -0.3350294 | -0.9204215 | -0.9061243 | -0.7140332 | -0.6381683 | -0.9446565 | -0.9229072 | -0.7302866 | -0.8297332 | 0.2679715 | -0.9989992 | -0.5138187 | -0.8148924 | -0.7354459 |
Average_Corr_1st = mean(na.omit(Corr_Matrix))
Average_Corr_1st
[1] -0.6272622
Similar to the previous section, the values of the Pearson’s correlation coefficients are reported in a table for the second work period. In the second period, the average correlation between RPE and strength change, across all conditions, is -0.43, which shows the negative relationship between RPE and strength decline, however, it is less stronger than the first work period.
# Corr_Matrix = data.frame(Corr_Matrix)
Corr_Matrix2 %>%
kable(format = "html", col.names = colnames(Corr_Matrix2)) %>%
kable_styling() %>%
kableExtra::scroll_box(width = "100%", height = "300px")
Sub01 | Sub02 | Sub03 | Sub04 | Sub05 | Sub06 | Sub07 | Sub08 | Sub09 | Sub10 | Sub13 | Sub15 | Sub16 | Sub17 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Condition 2.5-15 | 0.3582046 | -0.5990801 | -0.9523749 | -0.6112975 | -0.2032299 | -0.9950105 | -0.2239527 | -0.7561728 | -0.9977609 | -0.5933673 | -0.8860376 | -0.6849213 | -0.8483693 | -0.6888065 |
Condition 2.5-10 | -0.3149191 | -0.2125776 | -0.7896680 | -0.8680324 | -0.8056649 | -0.9781610 | 0.8236219 | -0.5626364 | -0.2578060 | -0.8891650 | -0.5598962 | -0.6438110 | -0.7273062 | 0.4103357 |
Condition 2.5-5 | 0.6249696 | -0.3193794 | -0.7233387 | -0.0087296 | -0.1922238 | -0.7439048 | -0.9143338 | -0.1691954 | 0.9252212 | -0.5140405 | -0.7553018 | -0.9679565 | 0.4597668 | 0.2086452 |
Condition 1.5-15 | -0.0186620 | 0.0337413 | -0.6188169 | 0.1016194 | 0.7543394 | -0.9317877 | 0.5833613 | NA | -0.1777579 | 0.2265232 | -0.7941124 | -0.9140903 | -0.4027939 | -0.7283759 |
Average_Corr_2nd = mean(na.omit(Corr_Matrix2))
Average_Corr_2nd
[1] -0.4320872
In this section the box plots of correlation coefficients of RPE scores and strength decline are plotted for each condition type (combination of work loads and task paces) for the first work period.The conditions with higher paces (Condition 2.5-15, and 1.5-15) indicate stronger correlation between the RPE scores and Strength decline.
gg_Data2 = data.frame(as.vector(Corr_Matrix), rep(unlist(Conditions), length(Subjects)))
colnames(gg_Data2) = c('Correlation', 'Condition')
p = ggplot(gg_Data2, aes(x= Condition, y= Correlation)) +
geom_boxplot()
print(p)
Similar to the previous section, the box plots of correlation coefficients of RPE scores and strength decline are plotted for each condition type (combination of work loads and task paces) for the second work period. The condition with highest pace and load (condition 2.5-15), has the strongest correlation coefficients among other conditions.
gg_Data3 = data.frame(as.vector(Corr_Matrix2), rep(unlist(Conditions), length(Subjects)))
colnames(gg_Data3) = c('Correlation', 'Condition')
p = ggplot(gg_Data3, aes(x= Condition, y= Correlation)) +
geom_boxplot()
print(p)