% Created 2023-03-20 Mon 12:45
% Intended LaTeX compiler: pdflatex
\documentclass[12pt]{article}

%%%% settings when exporting code %%%% 

\usepackage{listings}
\lstdefinestyle{code-small}{
backgroundcolor=\color{white}, % background color for the code block
basicstyle=\ttfamily\small, % font used to display the code
commentstyle=\color[rgb]{0.5,0,0.5}, % color used to display comments in the code
keywordstyle=\color{black}, % color used to highlight certain words in the code
numberstyle=\ttfamily\tiny\color{gray}, % color used to display the line numbers
rulecolor=\color{black}, % color of the frame
stringstyle=\color[rgb]{0,.5,0},  % color used to display strings in the code
breakatwhitespace=false, % sets if automatic breaks should only happen at whitespace
breaklines=true, % sets automatic line breaking
columns=fullflexible,
frame=single, % adds a frame around the code (non,leftline,topline,bottomline,lines,single,shadowbox)
keepspaces=true, % % keeps spaces in text, useful for keeping indentation of code
literate={~}{$\sim$}{1}, % symbol properly display via latex
numbers=none, % where to put the line-numbers; possible values are (none, left, right)
numbersep=10pt, % how far the line-numbers are from the code
showspaces=false,
showstringspaces=false,
stepnumber=1, % the step between two line-numbers. If it's 1, each line will be numbered
tabsize=1,
xleftmargin=0cm,
emph={anova,apply,class,coef,colnames,colNames,colSums,dim,dcast,for,ggplot,head,if,ifelse,is.na,lapply,list.files,library,logLik,melt,plot,require,rowSums,sapply,setcolorder,setkey,str,summary,tapply},
aboveskip = \medskipamount, % define the space above displayed listings.
belowskip = \medskipamount, % define the space above displayed listings.
lineskip = 0pt} % specifies additional space between lines in listings
\lstset{style=code-small}
%%%% packages %%%%%

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{textcomp}
\usepackage{color}
\usepackage{graphicx}
\usepackage{grffile}
\usepackage{wrapfig}
\usepackage{rotating}
\usepackage{longtable}
\usepackage{multirow}
\usepackage{multicol}
\usepackage{changes}
\usepackage{pdflscape}
\usepackage{geometry}
\usepackage[normalem]{ulem}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{dsfont}
\usepackage{array}
\usepackage{ifthen}
\usepackage{hyperref}
\usepackage{natbib}
\RequirePackage{setspace} % to modify the space between lines - incompatible with footnote in beamer
\renewcommand{\baselinestretch}{1.1}
\geometry{a4paper, left=10mm, right=10mm, top=10mm}
\usepackage{titlesec}
\usepackage{etoolbox}

\makeatletter
\patchcmd{\ttlh@hang}{\parindent\z@}{\parindent\z@\leavevmode}{}{}
\patchcmd{\ttlh@hang}{\noindent}{}{}{}
\makeatother
\RequirePackage{colortbl} % arrayrulecolor to mix colors
\definecolor{myorange}{rgb}{1,0.2,0}
\definecolor{mypurple}{rgb}{0.7,0,8}
\definecolor{mycyan}{rgb}{0,0.6,0.6}
\newcommand{\lightblue}{blue!50!white}
\newcommand{\darkblue}{blue!80!black}
\newcommand{\darkgreen}{green!50!black}
\newcommand{\darkred}{red!50!black}
\definecolor{gray}{gray}{0.5}
\hypersetup{
citecolor=[rgb]{0,0.5,0},
urlcolor=[rgb]{0,0,0.5},
linkcolor=[rgb]{0,0,0.5},
}
\newenvironment{note}{\small \color{gray}\fontfamily{lmtt}\selectfont}{\par}
\newenvironment{activity}{\color{orange}\fontfamily{qzc}\selectfont}{\par}
\RequirePackage{pifont}
\RequirePackage{relsize}
\newcommand{\Cross}{{\raisebox{-0.5ex}%
{\relsize{1.5}\ding{56}}}\hspace{1pt} }
\newcommand{\Valid}{{\raisebox{-0.5ex}%
{\relsize{1.5}\ding{52}}}\hspace{1pt} }
\newcommand{\CrossR}{ \textcolor{red}{\Cross} }
\newcommand{\ValidV}{ \textcolor{green}{\Valid} }
\usepackage{stackengine}
\usepackage{scalerel}
\newcommand\Warning[1][3ex]{%
\renewcommand\stacktype{L}%
\scaleto{\stackon[1.3pt]{\color{red}$\triangle$}{\tiny\bfseries !}}{#1}%
\xspace
}
\newcommand\Rlogo{\textbf{\textsf{R}}\xspace} %
\RequirePackage{fancyvrb}
\DefineVerbatimEnvironment{verbatim}{Verbatim}{fontsize=\small,formatcom = {\color[rgb]{0.5,0,0}}}
\RequirePackage{enumitem} % better than enumerate
\RequirePackage{epstopdf} % to be able to convert .eps to .pdf image files
\RequirePackage{capt-of} %
\RequirePackage{caption} % newlines in graphics
\RequirePackage{tikz-cd} % graph
\RequirePackage{booktabs} % for nice lines in table (e.g. toprule, bottomrule, midrule, cmidrule)
\RequirePackage{amsmath}
\RequirePackage{algorithm}
\RequirePackage[noend]{algpseudocode}
\RequirePackage{dsfont}
\RequirePackage{amsmath,stmaryrd,graphicx}
\RequirePackage{prodint} % product integral symbol (\PRODI)
\usepackage{ifthen}
\usepackage{xifthen}
\usepackage{xargs}
\usepackage{xspace}
\newcommand\defOperator[7]{%
\ifthenelse{\isempty{#2}}{
\ifthenelse{\isempty{#1}}{#7{#3}#4}{#7{#3}#4 \left#5 #1 \right#6}
}{
\ifthenelse{\isempty{#1}}{#7{#3}#4_{#2}}{#7{#3}#4_{#1}\left#5 #2 \right#6}
}
}
\newcommand\defUOperator[5]{%
\ifthenelse{\isempty{#1}}{
#5\left#3 #2 \right#4
}{
\ifthenelse{\isempty{#2}}{\underset{#1}{\operatornamewithlimits{#5}}}{
\underset{#1}{\operatornamewithlimits{#5}}\left#3 #2 \right#4}
}
}
\newcommand{\defBoldVar}[2]{
\ifthenelse{\equal{#2}{T}}{\boldsymbol{#1}}{\mathbf{#1}}
}
\newcommandx\Esp[2][1=,2=]{\defOperator{#1}{#2}{E}{}{\lbrack}{\rbrack}{\mathbb}}
\newcommandx\Prob[2][1=,2=]{\defOperator{#1}{#2}{P}{}{\lbrack}{\rbrack}{\mathbb}}
\newcommandx\Qrob[2][1=,2=]{\defOperator{#1}{#2}{Q}{}{\lbrack}{\rbrack}{\mathbb}}
\newcommandx\Var[2][1=,2=]{\defOperator{#1}{#2}{V}{ar}{\lbrack}{\rbrack}{\mathbb}}
\newcommandx\Cov[2][1=,2=]{\defOperator{#1}{#2}{C}{ov}{\lbrack}{\rbrack}{\mathbb}}
\newcommandx\Binom[2][1=,2=]{\defOperator{#1}{#2}{B}{}{(}{)}{\mathcal}}
\newcommandx\Gaus[2][1=,2=]{\defOperator{#1}{#2}{N}{}{(}{)}{\mathcal}}
\newcommandx\Wishart[2][1=,2=]{\defOperator{#1}{#2}{W}{ishart}{(}{)}{\mathcal}}
\newcommandx\Likelihood[2][1=,2=]{\defOperator{#1}{#2}{L}{}{(}{)}{\mathcal}}
\newcommandx\logLikelihood[2][1=,2=]{\defOperator{#1}{#2}{\ell}{}{(}{)}{}}
\newcommandx\Information[2][1=,2=]{\defOperator{#1}{#2}{I}{}{(}{)}{\mathcal}}
\newcommandx\Score[2][1=,2=]{\defOperator{#1}{#2}{S}{}{(}{)}{\mathcal}}
\newcommandx\Vois[2][1=,2=]{\defOperator{#1}{#2}{V}{}{(}{)}{\mathcal}}
\newcommandx\IF[2][1=,2=]{\defOperator{#1}{#2}{IF}{}{(}{)}{\mathcal}}
\newcommandx\Ind[1][1=]{\defOperator{}{#1}{1}{}{(}{)}{\mathds}}
\newcommandx\Max[2][1=,2=]{\defUOperator{#1}{#2}{(}{)}{min}}
\newcommandx\Min[2][1=,2=]{\defUOperator{#1}{#2}{(}{)}{max}}
\newcommandx\argMax[2][1=,2=]{\defUOperator{#1}{#2}{(}{)}{argmax}}
\newcommandx\argMin[2][1=,2=]{\defUOperator{#1}{#2}{(}{)}{argmin}}
\newcommandx\cvD[2][1=D,2=n \rightarrow \infty]{\xrightarrow[#2]{#1}}
\newcommandx\Hypothesis[2][1=,2=]{
\ifthenelse{\isempty{#1}}{
\mathcal{H}
}{
\ifthenelse{\isempty{#2}}{
\mathcal{H}_{#1}
}{
\mathcal{H}^{(#2)}_{#1}
}
}
}
\newcommandx\dpartial[4][1=,2=,3=,4=\partial]{
\ifthenelse{\isempty{#3}}{
\frac{#4 #1}{#4 #2}
}{
\left.\frac{#4 #1}{#4 #2}\right\rvert_{#3}
}
}
\newcommandx\dTpartial[3][1=,2=,3=]{\dpartial[#1][#2][#3][d]}
\newcommandx\ddpartial[3][1=,2=,3=]{
\ifthenelse{\isempty{#3}}{
\frac{\partial^{2} #1}{\partial #2^2}
}{
\frac{\partial^2 #1}{\partial #2\partial #3}
}
}
\newcommand\Real{\mathbb{R}}
\newcommand\Rational{\mathbb{Q}}
\newcommand\Natural{\mathbb{N}}
\newcommand\trans[1]{{#1}^\intercal}%\newcommand\trans[1]{{\vphantom{#1}}^\top{#1}}
\newcommand{\independent}{\mathrel{\text{\scalebox{1.5}{$\perp\mkern-10mu\perp$}}}}
\newcommand\half{\frac{1}{2}}
\newcommand\normMax[1]{\left|\left|#1\right|\right|_{max}}
\newcommand\normTwo[1]{\left|\left|#1\right|\right|_{2}}
\newcommand\Veta{\boldsymbol{\eta}}
\newcommand\VX{\mathbf{X}}
\author{Brice Ozenne}
\date{\today}
\title{Wilcoxon test via GPC}
\hypersetup{
 colorlinks=true,
 pdfauthor={Brice Ozenne},
 pdftitle={Wilcoxon test via GPC},
 pdfkeywords={},
 pdfsubject={},
 pdfcreator={Emacs 26.3 (Org mode 9.4.6)},
 pdflang={English}
 }
\begin{document}

\maketitle

\section{Single Wilcoxon test}
\label{sec:org00cb9cb}

Generalized Pairwise comparisons include the Wilcoxon rank sum test as
a specific case. \newline Consider the following dataset (from the example
section of \texttt{stats::wilcox.test}):
\lstset{language=r,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
x <- c(1.83,  0.50,  1.62,  2.48, 1.68, 1.88, 1.55, 3.06, 1.30)
y <- c(0.878, 0.647, 0.598, 2.05, 1.06, 1.29, 1.06, 3.14, 1.29)
df <- rbind(data.frame(value = x, group="x"),
            data.frame(value = y, group="y"))
\end{lstlisting}

We can perform a Wilcoxon test using the \texttt{wilcox.test} function:
\lstset{language=r,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
wilcox.test(value ~ group, data = df)
\end{lstlisting}

\begin{verbatim}

	Wilcoxon rank sum test with continuity correction

data:  value by group
W = 58, p-value = 0.1329
alternative hypothesis: true location shift is not equal to 0

Warning message:
In wilcox.test.default(x = DATA[[1L]], y = DATA[[2L]], ...) :
  cannot compute exact p-value with ties
\end{verbatim}

It unfortunately does not ouput any effect size (just the test
statistic and corresponding p-value). The package \emph{asht} contains an
alternative implementation:
\lstset{language=r,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
library(asht)
wmwTest(value ~ group, data = df, method = "asymptotic")
\end{lstlisting}

\begin{verbatim}

	Wilcoxon-Mann-Whitney test with continuity correction (confidence interval
	requires proportional odds assumption, but test does not)

data:  value by group
Mann-Whitney estimate = 0.28395, tie factor = 0.99794, p-value = 0.1329
alternative hypothesis: two distributions are not equal
95 percent confidence interval:
 0.1142978 0.5614097
sample estimates:
Mann-Whitney estimate 
            0.2839506
\end{verbatim}

which does output an estimate\footnote{Mann-Whitney parameter,
i.e. probability that a randomly chosen observation from one group has
higher value than a randomly chosen observation from the other
group}. It matches exactly the p.value and is based on an asymptotic
result. It is also possible to get an exact p-value \footnote{this is only
feasible in small samples - otherwise the procedure becomes
computationnally challenging}:
\lstset{language=r,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
wmwTest(value ~ group, data = df, method = "exact.ce")
\end{lstlisting}

\begin{verbatim}

	exact Wilcoxon-Man-Whitney test (confidence interval requires proportional odds
	assumption, but test does not)

data:  value by group
Mann-Whitney estimate = 0.28395, p-value = 0.1299
alternative hypothesis: two distributions are not equal
95 percent confidence interval:
 0.09721823 0.56323417
sample estimates:
Mann-Whitney estimate 
            0.2839506
\end{verbatim}

To match those results with GPC we can use a permutation test
(\Warning remember to add the argument \texttt{add.halfNeutral} to \texttt{TRUE} to
handle ties the same way as the previous tests):
\lstset{language=r,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
eperm.BT <- BuyseTest(group ~ cont(value), data = df, add.halfNeutral = TRUE,
                      method.inference = "permutation", n.resampling = 10000,
                      trace = FALSE, seed = 10)
confint(eperm.BT, statistic = "favorable")
\end{lstlisting}

\begin{verbatim}
       estimate       se  lower.ci  upper.ci null   p.value
value 0.2839506 0.140185 0.1050267 0.5725376  0.5 0.1242876
Warning message:
In .local(object, ...) :
  Confidence intervals are computed under the null hypothesis and therefore may not be valid.
\end{verbatim}


The estimate is precisely the same and the p-value approximately the
same. Instead of permutation, we could use the asymptotic theory to
obtain p-values and (valid) confidence intervals:
\lstset{language=r,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
BuyseTest.options(order.Hprojection=2)
eU.BT <- BuyseTest(group ~ cont(value), data = df,
                  method.inference = "u-statistic",
                  add.halfNeutral = TRUE, trace = FALSE)
confint(eU.BT, statistic = "favorable")
\end{lstlisting}

\begin{verbatim}
       estimate        se   lower.ci  upper.ci null   p.value
value 0.2839506 0.1401461 0.09313769 0.6049215  0.5 0.1796262
\end{verbatim}


Unsuprisingly, we get the same estimate. However the p-value seems
quite a bit different. This might be explained by the fact that this
approach does not assume iid\footnote{iid=independent and identically
distributed} observations but only iid observations within each
group. A studentised permutation, which is exactly (instead of
asymptotically) valid under the same assumption, gives a somewhat
similar p-value:
\lstset{language=r,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
etperm.BT <- BuyseTest(group ~ cont(value), data = df, add.halfNeutral = TRUE,
                      method.inference = "studentized permutation", n.resampling = 10000,
                      trace = FALSE, seed = 10)
confint(etperm.BT, statistic = "favorable")
\end{lstlisting}

\begin{verbatim}
       estimate        se  lower.ci  upper.ci null p.value
value 0.2839506 0.1401461 0.1006681 0.5809142  0.5   0.163
Warning message:
In .local(object, ...) :
  Confidence intervals are computed under the null hypothesis and therefore may not be valid.
\end{verbatim}

\section{Multiple Wilcoxon tests}
\label{sec:org3d82d86}

Consider now the case where we would like to compare one reference
group (here strata \texttt{a}) to multiple treatment groups (here strata
\texttt{b,c,d,e}). We will consider the following dataset:
\lstset{language=r,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
set.seed(35)
dt <- simBuyseTest(n.T=25, n.strata = 5)
dt$id <- paste0("id",1:NROW(dt))
dt$strata <- as.character(dt$strata) 
head(dt)
\end{lstlisting}

\begin{verbatim}
   treatment  eventtime status toxicity      score strata  id
1:         C 0.03384999      1      yes  0.4777913      b id1
2:         C 0.65039474      0       no -1.1048190      d id2
3:         C 1.00647502      1       no -0.1407630      b id3
4:         C 0.01129603      1      yes -0.5512507      a id4
5:         C 0.22249748      1       no  1.0465250      d id5
6:         C 0.07400412      0       no -2.0053855      d id6
\end{verbatim}


\clearpage

We can apply the GPC procedure to each pair of group:
\lstset{language=r,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
BuyseTest.options(order.Hprojection=1);BuyseTest.options(trace=0)

ls.BT <- list("b-a=0" = BuyseTest(strata ~ cont(score), add.halfNeutral = TRUE,
                                  data = dt[dt$strata %in% c("a","b"),],
                                  method.inference = "u-statistic"),
              "c-a=0" = BuyseTest(strata ~ cont(score), add.halfNeutral = TRUE,
                                  data = dt[dt$strata %in% c("a","c"),],
                                  method.inference = "u-statistic"),
              "d-a=0" = BuyseTest(strata ~ cont(score), add.halfNeutral = TRUE,
                                  data = dt[dt$strata %in% c("a","d"),],
                                  method.inference = "u-statistic"),
              "e-a=0" = BuyseTest(strata ~ cont(score), add.halfNeutral = TRUE,
                                  data = dt[dt$strata %in% c("a","e"),],
                                  method.inference = "u-statistic")
              )

M.confint <- do.call(rbind,lapply(ls.BT,confint, statistic = "favorable"))
cbind(M.confint,adj.p.value = p.adjust(M.confint[,"p.value"], method = "bonferroni"))
\end{lstlisting}

\begin{verbatim}
       estimate        se  lower.ci  upper.ci null    p.value adj.p.value
b-a=0 0.4090909 0.1542200 0.1654639 0.7073759  0.5 0.56434599   1.0000000
c-a=0 0.4375000 0.1465755 0.1948678 0.7142379  0.5 0.67306460   1.0000000
d-a=0 0.2500000 0.1010153 0.1039078 0.4893302  0.5 0.04143057   0.1657223
e-a=0 0.3333333 0.1360828 0.1308601 0.6241219  0.5 0.25767454   1.0000000
\end{verbatim}



Because we compare the treatment groups to the same reference, the
test statistics are correlated and a Bonferroni adjustment would not
be optimal. A better (but still not optimal adjustment) is the
max-test adjustment which can be obtained via the \texttt{BuyseMultComp} function:
\lstset{language=r,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
e.mc <- BuyseMultComp(ls.BT, statistic = "favorable", cluster = "id", global = TRUE)
print(e.mc, cols = c("estimate","se","p.value","adj.p.value"))
\end{lstlisting}

\begin{verbatim}
  - Multivariate test: p.value = 0.2645493 (df = 4)
  - Univariate tests:
       estimate        se    p.value adj.p.value
b-a=0 0.4090909 0.1542200 0.56434599   0.9289219
c-a=0 0.4375000 0.1465755 0.67306460   0.9752151
d-a=0 0.2500000 0.1010153 0.04143057   0.1223430
e-a=0 0.3333333 0.1360828 0.25767454   0.5831344
\end{verbatim}



Here the smallest p-value has been multiplied by a factor 2.64 instead
of 4. This is thanks to the rather strong correlation between the test
statistics:
\lstset{language=r,label= ,caption= ,captionpos=b,numbers=none}
\begin{lstlisting}
M.cor <- cov2cor(crossprod(e.mc$iid))
dimnames(M.cor) <- list(names(ls.BT),names(ls.BT))
M.cor
\end{lstlisting}

\begin{verbatim}
          b-a=0     c-a=0     d-a=0     e-a=0
b-a=0 1.0000000 0.6519486 0.5601058 0.7520401
c-a=0 0.6519486 1.0000000 0.4240003 0.5439927
d-a=0 0.5601058 0.4240003 1.0000000 0.5051815
e-a=0 0.7520401 0.5439927 0.5051815 1.0000000
\end{verbatim}
\end{document}