Replication of Inter-limb asymmetries versus performance in elite team sports athletes

Fort-Vanmeerhaeghe, A., Bishop, C., Buscà, B., Aguilera-Castells, J., Vicens-Bordas, J., & Gonzalo-Skok, O. (2020). Inter-limb asymmetries are associated with decrements in physical performance in youth elite team sports athletes. PloS one, 15(3), e0229440. https://doi.org/10.1371/journal.pone.0229440

Introduction

The paper explored whether there were relationships between inter-limb asymmetries and athletic performance in youth elite team sports. A secondary goal was to establish whether sex influenced inter-limb asymmetries.

The authors performed a cross-sectional study. Eighty-one elite youth team sport athletes were recruited. Athletes were assessed in the anterior star excursion balance test, single-leg countermovement jump, single leg broad jump, 30 m sprint, and a change-of-direction V-cut test.

Original paper can be found here: [Link]


.


Data Analysis

Data can be downloaded by following this link: [Link]

Inter-limb asymmetries were calculated as:

\[ asymmetry = \frac{(high – low)}{low} * 100 \]

The authors performed several analyses:

Data was checked for normality using the Kolmogorov-Smirnov test, and within-session reliability was measured using a two-way random ICC with absolute agreement and coefficient of variation.

Student t-tests were run to identify potential differences in asymmetries between the group and each sex. Independent sample t-tests were also run to identify potential differences in asymmetries between sexes.

Cohen’s d was used to assess the magnitude of the difference of effect size for the asymmetries between the sexes. Effect size was interpreted as suggested by Hopkins et al. (2009).

Finally, relationships between asymmetry scores and physical performance were assessed using the Pearson correlation coefficient. Relationships were established for the whole group and for each sex. Strength of the correlation was interpreted as suggested by Hopkins et al. (2009).

The authors did not state whether outliers were removed. Therefore, the analyses performed on the data includes all observations.

Code

Some of the analyses cannot be completed with the data set that was made public.

Set-Up

library(readxl) # to read in data
library(tidyverse, quietly = TRUE) # for tidy code
library(janitor) # clean variable names
library(skimr) # for easy exploratory analyses
library(correlation) # correlation matrices
library(report) # automate reporting of results
library(parameters) # supplemental reporting fns
library(knitr) # clean reporting

Original Data Set

asym <- read_excel("Data asymmetries vs performance.xlsx")

asym <- asym %>% 
  clean_names() %>%  # clean column names
  mutate_if(Negate(is.numeric), as.numeric) %>%  # convert non-numeric to numeric
  mutate(sex = case_when(
    sex == 0 ~ "male",
    sex == 1 ~ "female"
  ))
Code
knitr::kable(head(asym))
codi age phv height weight experience bmi sex cmj x30m_sprint v_cut_test olht_skillfull olhte_non_skillfull percent_asi_olht cmj_skillfull cmj_nonskillfull percent_asi_cmj sebt_ant_skillful sebt_ant_non_skillfull percent_asi_sebt_ant
1 17.01 NA 1.78 70.5 8 22.25 female 0.25 5.092 7.353 1.73 1.54 10.75 0.18 0.15 16.41 0.0 76.0 2.56
2 17.29 3.49 1.68 59.0 10 20.90 female 0.27 4.507 7.612 1.56 1.41 9.73 0.20 0.17 17.45 62.3 62.3 0.00
3 15.98 3.54 1.78 59.0 9 18.62 female 0.28 4.644 7.523 1.61 1.55 3.85 0.18 0.14 24.61 76.3 76.3 2.62
4 16.56 3.14 1.65 59.0 10 21.67 female 0.27 4.884 7.459 1.50 1.41 6.13 0.16 0.13 15.96 70.7 70.7 3.30
5 16.18 3.07 1.67 60.0 8 21.51 female 0.28 4.747 7.713 1.54 1.50 2.98 0.18 0.14 21.81 73.0 73.0 36.07
6 16.68 3.92 1.75 74.0 7 24.16 female 0.16 NA NA 1.22 0.67 44.90 0.11 0.09 13.00 57.5 57.5 3.63

Descriptive Statistics

skim.asym <- skim(asym)
skim.asym <- cbind(skim.asym,
                   tibble(kolmogorov.smirnov = sapply(asym, FUN = function(x) if(is.numeric(x)) round(ks.test(x, "pnorm")$p.value, 2))))
skim.asym <- skim.asym[, c(-1, -4:-9, -12:-16)]
skim.asym <- as.data.frame(sapply(skim.asym, FUN = function(x) if(is.double(x)) round(x, 3) else as.character(x)))
Code
kable(skim.asym)
skim_variable n_missing numeric.mean numeric.sd numeric.hist kolmogorov.smirnov
sex 0 NA NA NA 0
codi 0 41 23.527 ▇▇▇▇▇ 0
age 0 15.905 1.127 ▆▇▆▇▇ 0
phv 2 2.733 1.795 ▁▂▇▆▁ 0
height 0 1.79 0.2 ▁▁▁▁▇ 0
weight 0 69.91 11.785 ▅▇▃▂▁ 0
experience 0 6.089 3.008 ▃▃▇▆▂ 0
bmi 0 20.228 5.242 ▁▁▁▇▂ NULL
cmj 0 0.285 0.073 ▆▇▁▁▁ 0
x30m_sprint 5 5.146 4.175 ▇▁▁▁▁ 0
v_cut_test 2 7.181 0.949 ▁▁▁▁▇ 0
olht_skillfull 1 1.684 0.248 ▃▇▆▅▂ 0
olhte_non_skillfull 1 1.586 0.258 ▁▂▇▆▅ 0
percent_asi_olht 1 5.919 6.227 ▇▁▁▁▁ 0
cmj_skillfull 0 0.161 0.039 ▃▇▆▂▁ 0
cmj_nonskillfull 0 0.142 0.035 ▂▇▆▁▁ 0
percent_asi_cmj 0 11.331 8.327 ▇▆▂▁▁ 0
sebt_ant_skillful 1 68.265 9.771 ▁▁▁▅▇ 0
sebt_ant_non_skillfull 1 69.172 7.009 ▃▆▇▂▁ 0
percent_asi_sebt_ant 1 12.848 15.312 ▇▁▂▁▁ 0
skim.asym.by.sex <- skim(asym %>% 
                    group_by(sex))

skim.asym.by.sex <- skim.asym.by.sex[, c(-1, -8:-12)]
skim.asym.by.sex <- as.data.frame(sapply(skim.asym.by.sex, FUN = function(x) if(is.double(x)) round(x, 3) else as.character(x)))
Code
kable(skim.asym.by.sex %>% 
              filter(sex == "male"))
skim_variable sex n_missing complete_rate numeric.mean numeric.sd numeric.hist
codi male 0 1 60.724 14.619 ▇▅▁▅▇
age male 0 1 16.125 1.078 ▇▅▆▇▇
phv male 0 1 1.561 2.257 ▃▆▇▃▁
height male 0 1 1.803 0.322 ▁▁▁▁▇
weight male 0 1 75.421 13.827 ▆▇▃▅▁
experience male 0 1 4.731 3.474 ▆▇▂▂▅
bmi male 0 1 21.132 5.036 ▁▁▁▇▃
cmj male 0 1 0.348 0.077 ▆▇▁▁▁
x30m_sprint male 1 0.966 5.64 6.918 ▇▁▁▁▁
v_cut_test male 0 1 6.561 1.306 ▁▁▁▁▇
olht_skillfull male 0 1 1.941 0.155 ▆▆▇▇▂
olhte_non_skillfull male 0 1 1.83 0.175 ▂▅▇▇▃
percent_asi_olht male 0 1 5.719 4.661 ▇▇▃▂▁
cmj_skillfull male 0 1 0.193 0.037 ▃▆▇▆▁
cmj_nonskillfull male 0 1 0.168 0.036 ▁▅▇▃▁
percent_asi_cmj male 0 1 12.647 10.327 ▇▆▂▁▁
sebt_ant_skillful male 1 0.966 69.732 6.07 ▂▇▇▅▂
sebt_ant_non_skillfull male 1 0.966 69.625 8.003 ▃▆▇▃▁
percent_asi_sebt_ant male 1 0.966 15.271 18.869 ▇▁▂▁▁
skim.asym.by.sex <- skim(asym %>% 
                    group_by(sex))

skim.asym.by.sex <- skim.asym.by.sex[, c(-1, -8:-12)]
skim.asym.by.sex <- as.data.frame(sapply(skim.asym.by.sex, FUN = function(x) if(is.double(x)) round(x, 3) else as.character(x)))
Code
kable(skim.asym.by.sex %>% 
              filter(sex == "female"))
skim_variable sex n_missing complete_rate numeric.mean numeric.sd numeric.hist
codi female 0 1 30 20.157 ▇▇▇▁▇
age female 0 1 15.783 1.145 ▇▆▇▇▇
phv female 2 0.962 3.412 0.967 ▁▁▆▇▆
height female 0 1 1.783 0.077 ▅▇▇▇▁
weight female 0 1 66.837 9.274 ▂▇▅▂▂
experience female 0 1 6.846 2.437 ▁▁▇▆▂
bmi female 0 1 19.724 5.335 ▁▁▁▇▇
cmj female 0 1 0.25 0.04 ▃▇▇▆▁
x30m_sprint female 4 0.923 4.858 0.293 ▁▇▆▁▁
v_cut_test female 2 0.962 7.541 0.315 ▃▅▇▅▂
olht_skillfull female 1 0.981 1.538 0.153 ▃▂▇▆▅
olhte_non_skillfull female 1 0.981 1.447 0.184 ▁▁▃▆▇
percent_asi_olht female 1 0.981 6.033 7.005 ▇▁▁▁▁
cmj_skillfull female 0 1 0.143 0.026 ▅▇▇▇▃
cmj_nonskillfull female 0 1 0.127 0.023 ▂▆▇▇▂
percent_asi_cmj female 0 1 10.597 6.977 ▇▅▅▁▁
sebt_ant_skillful female 0 1 67.475 11.25 ▁▁▁▆▇
sebt_ant_non_skillfull female 0 1 68.929 6.482 ▃▆▇▅▁
percent_asi_sebt_ant female 0 1 11.544 13.028 ▇▂▁▁▃

Statistical Analysis

The authors report that they assessed limbs as strong and weak. The following code separates the limb values by strength for further analyses.

asym.stats <- asym %>% 
  mutate(sebt.high = ifelse(sebt_ant_skillful > sebt_ant_non_skillfull, sebt_ant_skillful, sebt_ant_non_skillfull),
         sebt.low = ifelse(sebt_ant_skillful < sebt_ant_non_skillfull, sebt_ant_skillful, sebt_ant_non_skillfull),
         
         olht.high = ifelse(olht_skillfull > olhte_non_skillfull, olht_skillfull, olhte_non_skillfull),
         olht.low = ifelse(olht_skillfull < olhte_non_skillfull, olht_skillfull, olhte_non_skillfull),
         
         cmj.high = ifelse(cmj_skillfull > cmj_nonskillfull, cmj_skillfull, cmj_nonskillfull),
         cmj.low = ifelse(cmj_skillfull < cmj_nonskillfull, cmj_skillfull, cmj_nonskillfull)) 

t-tests

Asymmetries by Group vs by Sex

percent.asi.cmj <- asym.stats$percent_asi_cmj
percent.asi.cmj.male <- subset(asym.stats, sex == "male")$percent_asi_cmj
percent.asi.cmj.female <- subset(asym.stats, sex == "female")$percent_asi_cmj

grp.v.male.cmj <- t.test(percent.asi.cmj, percent.asi.cmj.male)
grp.v.female.cmj <- t.test(percent.asi.cmj, percent.asi.cmj.female)
Code
report(grp.v.male.cmj)
Effect sizes were labelled following Cohen's (1988) recommendations.

The Welch Two Sample t-test testing the difference between percent.asi.cmj and
percent.asi.cmj.male (mean of x = 11.33, mean of y = 12.65) suggests that the
effect is negative, statistically not significant, and very small (difference =
-1.32, 95% CI [-5.61, 2.98], t(41.76) = -0.62, p = 0.540; Cohen's d = -0.14,
95% CI [-0.59, 0.31])
Code
report(grp.v.female.cmj)
Effect sizes were labelled following Cohen's (1988) recommendations.

The Welch Two Sample t-test testing the difference between percent.asi.cmj and
percent.asi.cmj.female (mean of x = 11.33, mean of y = 10.60) suggests that the
effect is positive, statistically not significant, and very small (difference =
0.73, 95% CI [-1.92, 3.38], t(121.93) = 0.55, p = 0.585; Cohen's d = 0.10, 95%
CI [-0.25, 0.44])
percent.asi.sebt <- asym.stats$percent_asi_sebt_ant
percent.asi.sebt.male <- subset(asym.stats, sex == "male")$percent_asi_sebt_ant
percent.asi.sebt.female <- subset(asym.stats, sex == "female")$percent_asi_sebt_ant


grp.v.male.sebt <- t.test(percent.asi.sebt, percent.asi.sebt.male)
grp.v.female.sebt <- t.test(percent.asi.sebt, percent.asi.sebt.female)
Code
report(grp.v.male.sebt)
Warning: Missing values detected. NAs dropped.
Effect sizes were labelled following Cohen's (1988) recommendations.

The Welch Two Sample t-test testing the difference between percent.asi.sebt and
percent.asi.sebt.male (mean of x = 12.85, mean of y = 15.27) suggests that the
effect is negative, statistically not significant, and very small (difference =
-2.42, 95% CI [-10.42, 5.57], t(40.15) = -0.61, p = 0.544; Cohen's d = -0.14,
95% CI [-0.59, 0.31])
Code
report(grp.v.female.sebt)
Warning: Missing values detected. NAs dropped.
Effect sizes were labelled following Cohen's (1988) recommendations.

The Welch Two Sample t-test testing the difference between percent.asi.sebt and
percent.asi.sebt.female (mean of x = 12.85, mean of y = 11.54) suggests that
the effect is positive, statistically not significant, and very small
(difference = 1.30, 95% CI [-3.62, 6.23], t(120.82) = 0.52, p = 0.601; Cohen's
d = 0.09, 95% CI [-0.25, 0.43])
percent.asi.olht <- asym.stats$percent_asi_olht
percent.asi.olht.male <- subset(asym.stats, sex == "male")$percent_asi_olht
percent.asi.olht.female <- subset(asym.stats, sex == "female")$percent_asi_olht

grp.v.male.olht <- t.test(percent.asi.olht, percent.asi.olht.male)
grp.v.female.olht <- t.test(percent.asi.olht, percent.asi.olht.female)
Code
report(grp.v.female.olht)
Warning: Missing values detected. NAs dropped.
Effect sizes were labelled following Cohen's (1988) recommendations.

The Welch Two Sample t-test testing the difference between percent.asi.olht and
percent.asi.olht.female (mean of x = 5.92, mean of y = 6.03) suggests that the
effect is negative, statistically not significant, and very small (difference =
-0.11, 95% CI [-2.50, 2.27], t(97.42) = -0.09, p = 0.925; Cohen's d = -0.02,
95% CI [-0.37, 0.34])
Code
report(grp.v.male.olht)
Warning: Missing values detected. NAs dropped.
Effect sizes were labelled following Cohen's (1988) recommendations.

The Welch Two Sample t-test testing the difference between percent.asi.olht and
percent.asi.olht.male (mean of x = 5.92, mean of y = 5.72) suggests that the
effect is positive, statistically not significant, and very small (difference =
0.20, 95% CI [-2.02, 2.42], t(66.14) = 0.18, p = 0.858; Cohen's d = 0.04, 95%
CI [-0.36, 0.43])

Asymmetries by Sex

male.v.female.cmj <- t.test(percent.asi.cmj.male, percent.asi.cmj.female)
Code
report(male.v.female.cmj)
Warning: Missing values detected. NAs dropped.
Effect sizes were labelled following Cohen's (1988) recommendations.

The Welch Two Sample t-test testing the difference between percent.asi.cmj.male
and percent.asi.cmj.female (mean of x = 12.65, mean of y = 10.60) suggests that
the effect is positive, statistically not significant, and small (difference =
2.05, 95% CI [-2.28, 6.38], t(42.55) = 0.95, p = 0.345; Cohen's d = 0.23, 95%
CI [-0.25, 0.71])
male.v.female.sebt <- t.test(percent.asi.sebt.male, percent.asi.sebt.female)
Code
report(male.v.female.sebt)
Warning: Missing values detected. NAs dropped.
Effect sizes were labelled following Cohen's (1988) recommendations.

The Welch Two Sample t-test testing the difference between
percent.asi.sebt.male and percent.asi.sebt.female (mean of x = 15.27, mean of y
= 11.54) suggests that the effect is positive, statistically not significant,
and small (difference = 3.73, 95% CI [-4.34, 11.80], t(41.20) = 0.93, p =
0.357; Cohen's d = 0.23, 95% CI [-0.26, 0.71])
male.v.female.olht <- t.test(percent.asi.olht.male, percent.asi.olht.female)
Code
report(male.v.female.olht)
Warning: Missing values detected. NAs dropped.
Effect sizes were labelled following Cohen's (1988) recommendations.

The Welch Two Sample t-test testing the difference between
percent.asi.olht.male and percent.asi.olht.female (mean of x = 5.72, mean of y
= 6.03) suggests that the effect is negative, statistically not significant,
and very small (difference = -0.31, 95% CI [-2.92, 2.29], t(75.95) = -0.24, p =
0.811; Cohen's d = -0.05, 95% CI [-0.48, 0.38])

Correlations

cor.group <- correlation(asym.stats,
                            select = c("percent_asi_sebt_ant",
                                       "percent_asi_olht",
                                       "percent_asi_cmj"),
                            select2 = c("x30m_sprint",
                                        "v_cut_test",
                                        "olht.high",
                                        "olht.low",
                                        "cmj.high",
                                        "cmj.low",
                                        "sebt.high",
                                        "sebt.low")) 
Code
print_md(
  summary(cor.group, 
          stars = TRUE,
          include_significance = FALSE)
)
Correlation Matrix (pearson-method)
Parameter x30m_sprint v_cut_test olht.high olht.low cmj.high cmj.low sebt.high sebt.low
percent_asi_sebt_ant -0.08 0.01 0.16 0.20 0.03 -0.01 0.05 0.06
percent_asi_olht -0.08 0.06 -0.10 -0.44** -0.09 -0.12 -0.16 -0.16
percent_asi_cmj 0.26 0.01 0.16 0.12 0.11 -0.25 0.15 0.09

p-value adjustment method: Holm (1979)

cor.male <- correlation(asym.stats %>% 
                              filter(sex == "male"),
                            select = c("percent_asi_sebt_ant",
                                       "percent_asi_olht",
                                       "percent_asi_cmj"),
                            select2 = c("x30m_sprint",
                                        "v_cut_test",
                                        "olht.high",
                                        "olht.low",
                                        "cmj.high",
                                        "cmj.low",
                                        "sebt.high",
                                        "sebt.low")) 
Code
print_md(
  summary(cor.male, 
          stars = TRUE,
          include_significance = FALSE)
)
Correlation Matrix (pearson-method)
Parameter x30m_sprint v_cut_test olht.high olht.low cmj.high cmj.low sebt.high sebt.low
percent_asi_sebt_ant -0.13 0.05 0.14 0.27 -0.17 -0.27 0.07 0.10
percent_asi_olht -0.13 0.15 -0.04 -0.56* 0.12 0.08 -5.24e-03 -0.05
percent_asi_cmj 0.36 0.10 0.16 0.17 0.03 -0.47 0.27 0.29

p-value adjustment method: Holm (1979)

cor.female <- correlation(asym.stats %>% 
                              filter(sex == "female"),
                            select = c("percent_asi_sebt_ant",
                                       "percent_asi_olht",
                                       "percent_asi_cmj"),
                            select2 = c("x30m_sprint",
                                        "v_cut_test",
                                        "olht.high",
                                        "olht.low",
                                        "cmj.high",
                                        "cmj.low",
                                        "sebt.high",
                                        "sebt.low")) 
Code
print_md(
  summary(cor.female, 
          stars = TRUE,
          include_significance = FALSE)
)
Correlation Matrix (pearson-method)
Parameter x30m_sprint v_cut_test olht.high olht.low cmj.high cmj.low sebt.high sebt.low
percent_asi_sebt_ant 0.11 0.19 0.08 0.08 0.06 0.11 -1.43e-03 0.05
percent_asi_olht -5.85e-03 0.02 -0.17 -0.64*** -0.22 -0.28 -0.23 -0.18
percent_asi_cmj 0.14 0.10 0.08 -0.02 0.06 -0.30 0.02 8.83e-03

p-value adjustment method: Holm (1979)

Discussion

The results from the paper resemble those that were assessed in this post. Although, there are some key differences that should be addressed.

Primarily, the number of male and female participants in the provided data set do not match the reported number of males and females. This could be a typo in either the publication or the data set during anonymization. Moreover, there are missing observations in the data set that were not accounted for. This can be seen in the Descriptive Statistics section.

There are marked differences in mean and SD values. Although a significance test was not performed between the two, the results in this post should not differ from the publication. If issues arose from the misclassification of a participant, there shouldn’t be stark contrasts between the results here and the original publication. Rather, the individual’s results should have a minimal impact on the outcomes here.

Although the data was tested for normality, the histograms reveal that much of the data was not actually normally distributed. This is due to various issues like outliers remaining in the data set. Subsequent analyses showed that some parameters included values that exceeded five SDs. Since these values exceed three SDs, rationale dictates that the values are either improperly recorded or are not representative of the sample size, and should be removed.

Finally, the majority of the significance values (p-values) for the t-tests and correlations do not coincide between these results and the publication.

It is unclear why the results in this post do not match those in the original publication. It is prudent to say that the analyses in this post were completed incorrectly. Unfortunately, there is enough evidence suggesting that many of the analyses were completed correctly and that the results in the publication are subject to various typos or that statistical analyses were misinterpreted.

Further analyses should be completed that remove outliers and transform data to ensure that the data is normally distributed prior to completing statistical analyses. Many of the distributions returned to the user (see above) can be either log-transformed or a Box-Cox transformation, both of which can be easily back-transformed.



.