How to construct a confusion matrix in LaTeX?

Here is some LaTeX code I used to produce related tables for a tutorial. It might get you close to what you're looking for, although you'll probably want to change the layout.

\begin{tabular}{l|l|c|c|c}
\multicolumn{2}{c}{}&\multicolumn{2}{c}{True diagnosis}&\\
\cline{3-4}
\multicolumn{2}{c|}{}&Positive&Negative&\multicolumn{1}{c}{Total}\\
\cline{2-4}
\multirow{2}{*}{Screening test}& Positive & $a$ & $b$ & $a+b$\\
\cline{2-4}
& Negative & $c$ & $d$ & $c+d$\\
\cline{2-4}
\multicolumn{1}{c}{} & \multicolumn{1}{c}{Total} & \multicolumn{1}{c}{$a+c$} & \multicolumn{    1}{c}{$b+d$} & \multicolumn{1}{c}{$N$}\\
\end{tabular}

enter image description here

% need the pifont package
\begin{tabular}{l|l|>{\columncolor{gray!20}}l|l|l}
%\begin{tabular}{l|l|l|l|l}                                                                  
\multicolumn{2}{c}{}&\multicolumn{2}{c}{True diagnosis}&\\
\cline{3-4}
\multicolumn{2}{c|}{}&\multicolumn{1}{c|}{Positive}&\multicolumn{1}{c|}{Negative}&\multicolu    mn{1}{c}{}\\
%\cline{2-4}                                                                                 
\hhline{~|---}
\multirow{2}{*}{Screening test}& Positive & TP & FP ($\alpha$) &\ding{214} PPV\\
%\cline{2-4}                                                                                 
\hhline{~|---}
& Negative & FN ($\beta$) & TN & \ding{214} NPV\\
%\cline{2-4}                                                                                 
\hhline{~|---}
\multicolumn{1}{c}{} & \multicolumn{1}{c}{} &
\multicolumn{1}{c}{\multirow{2}{*}{\parbox{2em}{\vskip1ex\ding{215}\\ Se}}} & \multicolumn{1    }{c}{\multirow{2}{*}{\parbox{2em}{\vskip1ex\ding{215}\\ Sp}}} &\multicolumn{1}{c}{}\\
\end{tabular}

enter image description here


Here's a solution without TikZ:

\documentclass{article}
\usepackage{array}
\usepackage{multirow}

\newcommand\MyBox[2]{
  \fbox{\lower0.75cm
    \vbox to 1.7cm{\vfil
      \hbox to 1.7cm{\hfil\parbox{1.4cm}{#1\\#2}\hfil}
      \vfil}%
  }%
}

\begin{document}

\noindent
\renewcommand\arraystretch{1.5}
\setlength\tabcolsep{0pt}
\begin{tabular}{c >{\bfseries}r @{\hspace{0.7em}}c @{\hspace{0.4em}}c @{\hspace{0.7em}}l}
  \multirow{10}{*}{\parbox{1.1cm}{\bfseries\raggedleft actual\\ value}} & 
    & \multicolumn{2}{c}{\bfseries Prediction outcome} & \\
  & & \bfseries p & \bfseries n & \bfseries total \\
  & p$'$ & \MyBox{True}{Positive} & \MyBox{False}{Negative} & P$'$ \\[2.4em]
  & n$'$ & \MyBox{False}{Positive} & \MyBox{True}{Negative} & N$'$ \\
  & total & P & N &
\end{tabular}

\end{document}

In a comment it has been requested to rotate one of the labels; this can be easily done using \rotatebox from graphicx:

\documentclass{article}
\usepackage{array}
\usepackage{graphicx}
\usepackage{multirow}

\newcommand\MyBox[2]{
  \fbox{\lower0.75cm
    \vbox to 1.7cm{\vfil
      \hbox to 1.7cm{\hfil\parbox{1.4cm}{#1\\#2}\hfil}
      \vfil}%
  }%
}

\begin{document}

\noindent
\renewcommand\arraystretch{1.5}
\setlength\tabcolsep{0pt}
\begin{tabular}{c >{\bfseries}r @{\hspace{0.7em}}c @{\hspace{0.4em}}c @{\hspace{0.7em}}l}
  \multirow{10}{*}{\rotatebox{90}{\parbox{1.1cm}{\bfseries\centering actual\\ value}}} & 
    & \multicolumn{2}{c}{\bfseries Prediction outcome} & \\
  & & \bfseries p & \bfseries n & \bfseries total \\
  & p$'$ & \MyBox{True}{Positive} & \MyBox{False}{Negative} & P$'$ \\[2.4em]
  & n$'$ & \MyBox{False}{Positive} & \MyBox{True}{Negative} & N$'$ \\
  & total & P & N &
\end{tabular}

\end{document}

enter image description here


It's quite easy making such a thing with TikZ, once you get the hang of it.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}[
box/.style={draw,rectangle,minimum size=2cm,text width=1.5cm,align=left}]
\matrix (conmat) [row sep=.1cm,column sep=.1cm] {
\node (tpos) [box,
    label=left:\( \mathbf{p'} \),
    label=above:\( \mathbf{p} \),
    ] {True \\ positive};
&
\node (fneg) [box,
    label=above:\textbf{n},
    label=above right:\textbf{total},
    label=right:\( \mathrm{P}' \)] {False \\ negative};
\\
\node (fpos) [box,
    label=left:\( \mathbf{n'} \),
    label=below left:\textbf{total},
    label=below:P] {False \\ positive};
&
\node (tneg) [box,
    label=right:\( \mathrm{N}' \),
    label=below:N] {True \\ negative};
\\
};
\node [left=.05cm of conmat,text width=1.5cm,align=right] {\textbf{actual \\ value}};
\node [above=.05cm of conmat] {\textbf{prediction outcome}};
\end{tikzpicture}
\end{document}

To rotate actual value you can replace

\node [left=.05cm of conmat,text width=1.5cm,align=right] {\textbf{actual \\ value}};

with

 \node [rotate=90,left=.05cm of conmat,anchor=center,text width=1.5cm,align=center] {\textbf{actual \\ value}};

result