After running my code ,I get the values of accuracy, precision and recall and I want t determine the values of FP FN TP and TN from these metrics. I tried to calculate it using the formula of each metric but I couldn't. Is there any way to do this?
4 Answers
You should modify the code to produce the confusion matrix itself. But assuming that's impossible for some reason...
A bit of linear algebra helps here. @n1k31t4 is right that given only accuracy, precision, and recall, you can't expect to reproduce the confusion matrix: you have three equations in four unknowns, and the equations can be expressed as linear equations (in the unknowns; see below), so there are definitely infinitely many solutions (but made finite by the non-negativity requirement, and in odd cases made few or even unique by the integer requirement).
If you happen to also know the total number of samples (or perhaps some other confusion-matrix measurement), you can recover everything. You don't need both P and N as @BenjiAlbert uses (although that produces more pleasing formulas IMO). Below I've done it by putting everything else in terms of $TP$, but there are sure to be several routes to the answer.
From $\text{recall}=\frac{TP}{TP+FN}$, we get $\frac{1}{\text{recall}} = 1+\frac{FN}{TP}$ and so
- $FN = (\frac{1}{\text{recall}}-1)TP$.
Similarly, from $\text{precision}=\frac{TP}{TP+FP}$ we obtain
- $FP = (\frac{1}{\text{precision}}-1)TP$.
Finally,
- $TN = \text{accuracy}\cdot\text{count} - TP$,
so
$$\begin{align*} \text{count} &= TP+TN+FP+FN \\ &= \text{accuracy}\cdot\text{count} + (\frac{1}{\text{precision}}-1)TP + (\frac{1}{\text{recall}}-1)TP, \end{align*} $$ and now you can solve for TP:
$$TP = \frac{(1 - \text{accuracy})\cdot(\text{count})}{\frac{1}{\text{precision}}+\frac{1}{\text{recall}}-2}$$
Plugging that back into the above formulas gives the values for all the others.
You can!
The trick is that you actually know two other critical variables: the number of positive and negative examples (P and N). You can then use them to algebraically solve for the confusion matrix:
$ recall=\frac{TP}{TP+FN}=1-\frac{FN}{P}\Rightarrow $
- $ FN = P(1-recall) $
$ recall=\frac{TP}{TP+FN}\Rightarrow (recall)(TP+FN)=TP\Rightarrow TP(1-recall)=FN\Rightarrow$
- $ TP=\frac{FN}{1-recall} $
- or simply: $ TP=P-FN $
$ accuracy = \frac{TP+TN}{P+N}\Rightarrow (accuracy)(P+N)=TP+TN\Rightarrow $
- $ TN=(accuracy)(P+N)-TP $
$ accuracy = \frac{TP+TN}{TP+TN+FP+FN}\Rightarrow (accuracy)(TP+TN+FP+FN)=TP+TN\Rightarrow $
- $ FP=\frac{TP+FN}{accuracy}-TP-TN-FN $
- or simply: $ FP=N-TN $
As others have pointed out, you could retrospectively compute those values if you know enough about the data.
If you literally only know the accuracy, precision and recall then it wouldn't be possible. It would be like someone telling you the answer is 0.79, and asking how it was computed... there are infinitely many ways.
I would suggest looking into the code where those metrics are computed and intercept the raw predictions and labels. You could sum up the values in the confusion matrix (TP, FP, FN) during inference, then just use something like the sklearn.metrics.precision_recall_fscore_support function from Sci-kit Learn.
Depending on what method you are using to get the metrics, there might even already be an argument to the function that will also return the full confusion matrix.
# Calculating FP, FN, TP, and TN using accuracy, precision, and recall
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix
y_true = [0, 1, 0, 0, 1, 1, 1, 1]
y_pred = [0, 0, 1, 0, 0, 1, 1, 1]
num_values = len(y_true)
print("Number of observations: {}".format(num_values))
# Calculate Precision
# The precision is the ratio tp / (tp + fp)
precision = precision_score(y_true, y_pred)
print("Precision Score: {}".format(precision))
# Calculate Recall
# The recall is the ratio tp / (tp + fn)
recall = recall_score(y_true, y_pred)
print("Recall Score: {}".format(recall))
# Calculate Accuracy
# The accuracy is the ratio (TP + TN)/(TP + TN + FP + FN)
accuracy = accuracy_score(y_true, y_pred)
print("Accuracy Score: {}".format(accuracy))
# Calculate the number of positive predictions
num_pos_preds = accuracy * num_values
num_neg_preds = num_values - num_pos_preds
print("Number of Positive Predictions: {0} \n"
"Number of Negative Predictions: {1}".format(num_pos_preds, num_neg_preds))
# Calculate the False Negatives
FN = num_pos_preds * (1 - recall)
print("FN: {0}".format(FN))
# Calculate the True Positives
TP = num_pos_preds - FN
print("TP: {0}".format(TP))
# Calculate the True Negatives
TN = num_pos_preds - TP
print("TN: {0}".format(TN))
# Calculate the False Positives
FP = num_neg_preds - TN
print("FP: {0}".format(FP))
# Verify the results
sk_tn, sk_fp, sk_fn, sk_tp = confusion_matrix(y_true, y_pred).ravel()
print("Verify our results using Sklearn confusion matrix values\n"
"FN: {0}\n"
"TP: {1}\n"
"TN: {2}\n"
"FP: {3}".format(sk_fn, sk_tp, sk_tn, sk_fp,))
Output:
Number of observations: 8
Precision Score: 0.75
Recall Score: 0.6
Accuracy Score: 0.625
Number of Positive Predictions: 5.0
Number of Negative Predictions: 3.0
FN: 2.0
TP: 3.0
TN: 2.0
FP: 1.0
Sklearn values
FN: 2
TP: 3
TN: 2
FP: 1