This script describes variables collected at baseline (visit day: 0, visit_number: 1) conditioned on sensory neuropathy (SN) status (i.e., whether SN developed at any point during the follow-up period).

For descriptive statistics of baseline variables for the whole cohort, see: suppl-01-descriptive-whole-cohort.[Rmd/html/md/pdf]

The following data columns were not analysed:

  • pain and pain score: related to SN only, therefore not relevant at baseline when everyone was free from SN.

  • *_record: inconsistent patient records.

  • hba1c_percent/diabetic_hba1c and vitaminB12_pmol.l/vitaminB12_deficiency: Zero and one participant had diabetes mellitus or vitamin B12 deficiency, respectively, so these data were not analysed.

  • ID, visit_day, hivsn_present, visit_months: provide sorting and grouping information only.


Define bootstrap functions

Functions calculate the 95% confidence interval of the mean/median difference between SN:yes and SN:no, or the 95% confidence interval for the odds ratio between the two groups.

# Difference between means
## d = dataframe object
## i = boot index
## data_column = data column (character vector of length 1)
## grouping_column = grouping variable column (character vector of length 1)
boot_deltaMean <- function(d, i, data_column = NULL, grouping_column = NULL){
    # Sample
    df <- d[i, c(data_column, grouping_column)]
    # Rename columns
    colnames(df) <- c('x', 'y')
    # Calculate means
    df <- df %>% 
        filter(!is.na(x)) %>% 
        group_by(y) %>% 
        summarise(mean = mean(x)) %>% 
        ungroup()
    # Calculate difference in means
    df$mean[1] - df$mean[2]
}

# Difference between medians
## d = dataframe object
## i = boot index
## data_column = data column (character vector of length 1)
## grouping_column = grouping variable column (character vector of length 1)
boot_deltaMedian <- function(d, i, data_column = NULL, grouping_column = NULL){
    # Sample
    df <- d[i, c(data_column, grouping_column)]
    # Rename columns
    colnames(df) <- c('x', 'y')
    # Calculate means
    df <- df %>% 
        filter(!is.na(x)) %>% 
        group_by(y) %>% 
        summarise(median = median(x)) %>% 
        ungroup()
    # Calculate difference in means
    df$median[1] - df$median[2]
}

# Odds ratio
## d = dataframe object
## i = boot index
## data_column = data column (character vector of length 1)
## grouping_column = grouping variable column (character vector of length 1)
boot_OR <- function(d, i, data_column = NULL, grouping_column = NULL){
    # Sample
    df <- d[i, c(data_column, grouping_column)]
    # Rename columns
    colnames(df) <- c('x', 'y')
    # xtabulate
    x_tab <- xtabs(~ x + y,
                  data = df)
    # Calculate odds ratio
    fisher.test(x_tab)$estimate
}

Inspect data

## [1] 120  17
##  [1] "ID"                     "visit_number"          
##  [3] "visit_day"              "age_years"             
##  [5] "mass_kg"                "height_m"              
##  [7] "sex"                    "hivsn_present"         
##  [9] "CD4_cell.ul"            "viral_load_copies.ml"  
## [11] "consumes_alcohol"       "alcohol_units.week"    
## [13] "TB_current"             "pyridoxine_prophylaxis"
## [15] "rifafour_treatment"     "ARV_regimen"           
## [17] "sn_present"
## # A tibble: 6 x 17
##   ID    visit_number visit_day age_years mass_kg height_m sex  
##   <chr>        <int>     <int>     <dbl>   <dbl>    <dbl> <fct>
## 1 001              1         0        59    41.4     1.56 F    
## 2 002              1         0        23    70.2     1.56 F    
## 3 003              1         0        27    75       1.64 M    
## 4 004              1         0        26    68.8     1.74 M    
## 5 005              1         0        37   107       1.6  F    
## 6 006              1         0        34    85.5     1.53 F    
## # … with 10 more variables: hivsn_present <fct>, CD4_cell.ul <dbl>,
## #   viral_load_copies.ml <dbl>, consumes_alcohol <fct>,
## #   alcohol_units.week <int>, TB_current <fct>,
## #   pyridoxine_prophylaxis <fct>, rifafour_treatment <fct>,
## #   ARV_regimen <fct>, sn_present <ord>
## # A tibble: 6 x 17
##   ID    visit_number visit_day age_years mass_kg height_m sex  
##   <chr>        <int>     <int>     <dbl>   <dbl>    <dbl> <fct>
## 1 115              1         0        29    55.1     1.66 M    
## 2 116              1         0        30    93.7     1.55 F    
## 3 117              1         0        30    58.2     1.6  F    
## 4 118              1         0        30    61.2     1.64 F    
## 5 119              1         0        22    62.7     1.63 F    
## 6 120              1         0        58    71.2     1.74 M    
## # … with 10 more variables: hivsn_present <fct>, CD4_cell.ul <dbl>,
## #   viral_load_copies.ml <dbl>, consumes_alcohol <fct>,
## #   alcohol_units.week <int>, TB_current <fct>,
## #   pyridoxine_prophylaxis <fct>, rifafour_treatment <fct>,
## #   ARV_regimen <fct>, sn_present <ord>
## Observations: 120
## Variables: 17
## $ ID                     <chr> "001", "002", "003", "004", "005", "006",…
## $ visit_number           <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
## $ visit_day              <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ age_years              <dbl> 59, 23, 27, 26, 37, 34, 44, 34, 32, 29, 2…
## $ mass_kg                <dbl> 41.4, 70.2, 75.0, 68.8, 107.0, 85.5, 121.…
## $ height_m               <dbl> 1.56, 1.56, 1.64, 1.74, 1.60, 1.53, 1.69,…
## $ sex                    <fct> F, F, M, M, F, F, F, F, F, M, M, M, M, F,…
## $ hivsn_present          <fct> no, no, no, no, no, no, no, no, no, no, n…
## $ CD4_cell.ul            <dbl> 35, 285, 28, 270, 310, 247, 439, 311, 130…
## $ viral_load_copies.ml   <dbl> 6.103804, 5.041393, 5.181844, 2.484300, 3…
## $ consumes_alcohol       <fct> no, no, no, no, yes, no, no, no, no, no, …
## $ alcohol_units.week     <int> 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 6, 9, 0…
## $ TB_current             <fct> no, no, yes, no, no, no, no, no, no, no, …
## $ pyridoxine_prophylaxis <fct> no, no, yes, no, no, no, no, no, no, no, …
## $ rifafour_treatment     <fct> no, no, yes, no, no, no, no, no, no, no, …
## $ ARV_regimen            <fct> TDF_FTC_EFV, TDF_FTC_EFV, TDF_FTC_EFV, TD…
## $ sn_present             <ord> no, no, no, no, no, yes, yes, no, no, no,…

Analyses

Age

## Skim summary statistics
##  n obs: 120 
##  n variables: 2 
##  group variables: sn_present 
## 
## ── Variable type:numeric ────────────────────────────────────────────────────────────────────────────────────
##  sn_present  variable missing complete   n  mean   sd p0   p25  p50   p75
##         yes age_years       0       20  20 41.8  8.47 26 36.5  40.5 46.75
##          no age_years       0      100 100 36.96 9.36 21 29.75 36   43   
##  p100     hist
##    59 ▂▅▅▇▅▂▃▃
##    59 ▃▆▇▅▇▂▂▂
##   sn_present   n Mean Conf.level Bca.lower Bca.upper
## 1        yes  20 41.8       0.95      38.0      45.4
## 2         no 100 37.0       0.95      35.2      38.8

##     n Mean.difference Conf.level Bca.lower Bca.upper Includes.zero
## 1 120            4.84       0.95     1.062     9.135            no

Body mass

## Skim summary statistics
##  n obs: 120 
##  n variables: 2 
##  group variables: sn_present 
## 
## ── Variable type:numeric ────────────────────────────────────────────────────────────────────────────────────
##  sn_present variable missing complete   n  mean    sd   p0   p25   p50
##         yes  mass_kg       0       20  20 72.97 18.05 47.6 59.48 69.45
##          no  mass_kg       0      100 100 63.43 13.5  41.4 53.98 62.1 
##    p75  p100     hist
##  84.15 121.4 ▇▅▆▅▅▂▁▂
##  71.58 107   ▆▇▇▆▃▂▁▁
##   sn_present   n Mean Conf.level Bca.lower Bca.upper
## 1        yes  20 73.0       0.95      66.2      82.2
## 2         no 100 63.4       0.95      60.8      66.1

##     n Mean.difference Conf.level Bca.lower Bca.upper Includes.zero
## 1 120           9.535       0.95     2.401    19.008            no

Height

Expect height to show sex difference, so analyse separately for males and females.

## Skim summary statistics
##  n obs: 120 
##  n variables: 3 
##  group variables: sn_present, sex 
## 
## ── Variable type:numeric ────────────────────────────────────────────────────────────────────────────────────
##  sn_present sex variable missing complete  n mean    sd   p0  p25  p50
##         yes   F height_m       0        8  8 1.64 0.087 1.53 1.58 1.66
##         yes   M height_m       0       12 12 1.72 0.045 1.65 1.69 1.73
##          no   F height_m       0       58 58 1.57 0.056 1.46 1.53 1.57
##          no   M height_m       0       42 42 1.7  0.051 1.58 1.66 1.7 
##   p75 p100     hist
##  1.7  1.76 ▇▁▃▃▁▇▃▃
##  1.75 1.79 ▇▃▃▇▃▇▇▃
##  1.62 1.68 ▂▆▇▆▅▇▆▃
##  1.72 1.82 ▁▅▂▇▅▅▁▁
##   sn_present sex  n Boot.mean Conf.level Bca.lower Bca.upper
## 1        yes   F  8      1.64       0.95      1.58      1.70
## 2        yes   M 12      1.72       0.95      1.69      1.74
## 3         no   F 58      1.57       0.95      1.56      1.59
## 4         no   M 42      1.70       0.95      1.68      1.71

##     n Mean.difference Conf.level Bca.lower Bca.upper Includes.zero
## 1 120           0.066       0.95     0.028     0.099            no

##    n Mean.difference Conf.level Bca.lower Bca.upper Includes.zero
## 1 54           0.025       0.95    -0.007     0.052           yes

##    n Mean.difference Conf.level Bca.lower Bca.upper Includes.zero
## 1 66           0.072       0.95     0.005     0.133            no

Sex

## Skim summary statistics
##  n obs: 120 
##  n variables: 2 
##  group variables: sn_present 
## 
## ── Variable type:factor ─────────────────────────────────────────────────────────────────────────────────────
##  sn_present variable missing complete   n n_unique          top_counts
##         yes      sex       0       20  20        2  M: 12, F: 8, NA: 0
##          no      sex       0      100 100        2 F: 58, M: 42, NA: 0
##  ordered
##    FALSE
##    FALSE
##   sn_present  n Proportion Conf.level Bca.lower Bca.upper
## 1        yes 20       0.40       0.95      0.15      0.55
## 2         no 20       0.58       0.95      0.47      0.66

##     n Odds.ratio Conf.level Bca.lower Bca.upper Includes.one
## 1 120      0.486       0.95     0.168     1.371          yes

CD4 T-cell count

## Skim summary statistics
##  n obs: 120 
##  n variables: 2 
##  group variables: sn_present 
## 
## ── Variable type:numeric ────────────────────────────────────────────────────────────────────────────────────
##  sn_present    variable missing complete   n   mean     sd p0   p25   p50
##         yes CD4_cell.ul       0       20  20 223.55 176.37  4  71.5 200.5
##          no CD4_cell.ul       1       99 100 274.41 233.13  1 123   234  
##     p75 p100     hist
##  308.25  673 ▇▃▃▃▂▂▁▁
##  345    1347 ▇▇▃▁▁▁▁▁
##   sn_present  n Median Conf.level Bca.lower Bca.upper
## 1        yes 20    200       0.95        82       290
## 2         no 99    234       0.95       163       285

##     n Median.difference Conf.level Bca.lower Bca.upper Includes.zero
## 1 119             -33.5       0.95  -188.279    93.716           yes

Viral load

## Skim summary statistics
##  n obs: 120 
##  n variables: 2 
##  group variables: sn_present 
## 
## ── Variable type:numeric ────────────────────────────────────────────────────────────────────────────────────
##  sn_present             variable missing complete   n mean   sd   p0  p25
##         yes viral_load_copies.ml       1       19  20 3.59 1.59 1.83 2.22
##          no viral_load_copies.ml      11       89 100 3.45 1.26 1.7  2.63
##   p50  p75 p100     hist
##  3    4.73 6.45 ▇▃▂▃▁▁▂▃
##  3.16 4.26 6.51 ▇▆▇▂▅▅▁▂
##   sn_present  n Median Conf.level Bca.lower Bca.upper
## 1        yes 19   3.00       0.95      2.08      4.08
## 2         no 89   3.16       0.95      2.90      3.50

##     n Median.difference Conf.level Bca.lower Bca.upper Includes.zero
## 1 108             -0.16       0.95    -1.073     1.044           yes

Alcohol

## Skim summary statistics
##  n obs: 120 
##  n variables: 3 
##  group variables: sn_present, drinks_alcohol 
## 
## ── Variable type:integer ────────────────────────────────────────────────────────────────────────────────────
##  sn_present drinks_alcohol           variable missing complete  n  mean
##         yes             No alcohol_units.week       0       18 18  0   
##         yes            Yes alcohol_units.week       0        2  2  7.5 
##          no             No alcohol_units.week       0       75 75  0   
##          no            Yes alcohol_units.week       0       25 25 24.96
##     sd p0  p25  p50   p75 p100     hist
##   0     0 0     0    0       0 ▁▁▁▇▁▁▁▁
##   4.95  4 5.75  7.5  9.25   11 ▇▁▁▁▁▁▁▇
##   0     0 0     0    0       0 ▁▁▁▇▁▁▁▁
##  26     3 9    15   29      95 ▇▆▂▁▁▁▁▂
##   sn_present  n Median Conf.level Bca.lower Bca.upper
## 1        yes  2    7.5       0.95         4       7.5
## 2         no 25   15.0       0.95         6      15.0

TB

Note: Treatment policy was to start some patients, irrespective of TB diagnosis, on TB treatment. Therefore current TB infection and treatment for TB analysed separately.

Currently infected with TB

## Skim summary statistics
##  n obs: 120 
##  n variables: 2 
##  group variables: sn_present 
## 
## ── Variable type:factor ─────────────────────────────────────────────────────────────────────────────────────
##  sn_present   variable missing complete   n n_unique
##         yes TB_current       0       20  20        2
##          no TB_current       0      100 100        2
##              top_counts ordered
##   no: 11, yes: 9, NA: 0   FALSE
##  no: 89, yes: 11, NA: 0   FALSE
##   sn_present   n Proportion Conf.level Bca.lower Bca.upper
## 1        yes  20       0.45       0.95      0.20     0.603
## 2         no 100       0.11       0.95      0.05     0.170

##     n Odds.ratio Conf.level Bca.lower Bca.upper Includes.zero
## 1 120      0.155       0.95     0.048     0.472            no

Currently receiving TB treatment?

Treatment consisted of rifafour and pyridoxine (prophylaxis). Therefore only need to analyse rifafour data. Data coded as ‘No’ (not being treated), ‘Yes’ (being treated for active TB), and ‘Prophylaxis’ (being treated prophylactically for TB).

## [1] TRUE
## Skim summary statistics
##  n obs: 120 
##  n variables: 3 
##  group variables: pyridoxine_prophylaxis, sn_present 
## 
## ── Variable type:factor ─────────────────────────────────────────────────────────────────────────────────────
##  pyridoxine_prophylaxis sn_present           variable missing complete  n
##                      no        yes rifafour_treatment       0       12 12
##                      no         no rifafour_treatment       0       75 75
##                     yes        yes rifafour_treatment       0        8  8
##                     yes         no rifafour_treatment       0       11 11
##             prophylaxis         no rifafour_treatment       0       14 14
##  n_unique                    top_counts ordered
##         1 no: 12, yes: 0, pro: 0, NA: 0   FALSE
##         1 no: 75, yes: 0, pro: 0, NA: 0   FALSE
##         1  yes: 8, no: 0, pro: 0, NA: 0   FALSE
##         1 yes: 11, no: 0, pro: 0, NA: 0   FALSE
##         1 pro: 14, no: 0, yes: 0, NA: 0   FALSE
## [1] 0.117
##   sn_present   n Proportion Conf.level Bca.lower Bca.upper
## 1        yes  20       0.40       0.95     0.150      0.60
## 2         no 100       0.25       0.95     0.163      0.33

##     n Odds.ratio Conf.level Bca.lower Bca.upper Includes.zero
## 1 120      0.503       0.95     0.166      1.59           yes


Session information

## R version 3.6.0 (2019-04-26)
## Platform: x86_64-apple-darwin15.6.0 (64-bit)
## Running under: macOS Mojave 10.14.5
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] patchwork_0.0.1  skimr_1.0.7      rcompanion_2.2.1 boot_1.3-22     
##  [5] forcats_0.4.0    stringr_1.4.0    dplyr_0.8.2      purrr_0.3.2     
##  [9] readr_1.3.1      tidyr_0.8.3      tibble_2.1.3     ggplot2_3.2.0   
## [13] tidyverse_1.2.1  magrittr_1.5    
## 
## loaded via a namespace (and not attached):
##  [1] httr_1.4.0         jsonlite_1.6       splines_3.6.0     
##  [4] modelr_0.1.4       assertthat_0.2.1   expm_0.999-4      
##  [7] stats4_3.6.0       coin_1.3-0         cellranger_1.1.0  
## [10] yaml_2.2.0         pillar_1.4.2       backports_1.1.4   
## [13] lattice_0.20-38    glue_1.3.1         digest_0.6.19     
## [16] rvest_0.3.4        colorspace_1.4-1   sandwich_2.5-1    
## [19] htmltools_0.3.6    Matrix_1.2-17      plyr_1.8.4        
## [22] pkgconfig_2.0.2    broom_0.5.2        haven_2.1.0       
## [25] EMT_1.1            mvtnorm_1.0-11     scales_1.0.0      
## [28] manipulate_1.0.1   generics_0.0.2     TH.data_1.0-10    
## [31] withr_2.1.2.9000   lazyeval_0.2.2     cli_1.1.0         
## [34] survival_2.44-1.1  crayon_1.3.4       readxl_1.3.1      
## [37] evaluate_0.14      fansi_0.4.0        nlme_3.1-140      
## [40] MASS_7.3-51.4      xml2_1.2.0         foreign_0.8-71    
## [43] tools_3.6.0        hms_0.4.2          matrixStats_0.54.0
## [46] multcomp_1.4-10    munsell_0.5.0      compiler_3.6.0    
## [49] multcompView_0.1-7 rlang_0.4.0        grid_3.6.0        
## [52] rstudioapi_0.10    labeling_0.3       rmarkdown_1.13    
## [55] DescTools_0.99.28  gtable_0.3.0       codetools_0.2-16  
## [58] R6_2.4.0           zoo_1.8-6          lubridate_1.7.4   
## [61] knitr_1.23         zeallot_0.1.0      utf8_1.1.4        
## [64] nortest_1.0-4      libcoin_1.0-4      modeltools_0.2-22 
## [67] stringi_1.4.3      parallel_3.6.0     Rcpp_1.0.1        
## [70] vctrs_0.1.0        tidyselect_0.2.5   xfun_0.8          
## [73] lmtest_0.9-37