Reputation: 3939
I'm getting this weird error:
classification.py:1113: UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 in labels with no predicted samples.
'precision', 'predicted', average, warn_for)`
but then it also prints the f-score the first time I run:
metrics.f1_score(y_test, y_pred, average='weighted')
The second time I run, it provides the score without error. Why is that?
>>> y_pred = test.predict(X_test)
>>> y_test
array([ 1, 10, 35, 9, 7, 29, 26, 3, 8, 23, 39, 11, 20, 2, 5, 23, 28,
30, 32, 18, 5, 34, 4, 25, 12, 24, 13, 21, 38, 19, 33, 33, 16, 20,
18, 27, 39, 20, 37, 17, 31, 29, 36, 7, 6, 24, 37, 22, 30, 0, 22,
11, 35, 30, 31, 14, 32, 21, 34, 38, 5, 11, 10, 6, 1, 14, 12, 36,
25, 8, 30, 3, 12, 7, 4, 10, 15, 12, 34, 25, 26, 29, 14, 37, 23,
12, 19, 19, 3, 2, 31, 30, 11, 2, 24, 19, 27, 22, 13, 6, 18, 20,
6, 34, 33, 2, 37, 17, 30, 24, 2, 36, 9, 36, 19, 33, 35, 0, 4,
1])
>>> y_pred
array([ 1, 10, 35, 7, 7, 29, 26, 3, 8, 23, 39, 11, 20, 4, 5, 23, 28,
30, 32, 18, 5, 39, 4, 25, 0, 24, 13, 21, 38, 19, 33, 33, 16, 20,
18, 27, 39, 20, 37, 17, 31, 29, 36, 7, 6, 24, 37, 22, 30, 0, 22,
11, 35, 30, 31, 14, 32, 21, 34, 38, 5, 11, 10, 6, 1, 14, 30, 36,
25, 8, 30, 3, 12, 7, 4, 10, 15, 12, 4, 22, 26, 29, 14, 37, 23,
12, 19, 19, 3, 25, 31, 30, 11, 25, 24, 19, 27, 22, 13, 6, 18, 20,
6, 39, 33, 9, 37, 17, 30, 24, 9, 36, 39, 36, 19, 33, 35, 0, 4,
1])
>>> metrics.f1_score(y_test, y_pred, average='weighted')
C:\Users\Michael\Miniconda3\envs\snowflakes\lib\site-packages\sklearn\metrics\classification.py:1113: UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 in labels with no predicted samples.
'precision', 'predicted', average, warn_for)
0.87282051282051276
>>> metrics.f1_score(y_test, y_pred, average='weighted')
0.87282051282051276
>>> metrics.f1_score(y_test, y_pred, average='weighted')
0.87282051282051276
Also, why is there a trailing 'precision', 'predicted', average, warn_for)
error message? There is no open parenthesis so why does it end with a closing parenthesis? I am running sklearn 0.18.1 using Python 3.6.0 in a conda environment on Windows 10.
I also looked at here and I don't know if it's the same bug. This SO post doesn't have solution either.
Upvotes: 145
Views: 324563
Reputation: 565
The error you're encountering is due to some labels in used_actions not having any true samples in the y_true list. When calculating recall (or other metrics) for these labels, it becomes undefined because the denominator in the recall calculation (the number of true samples for that label) is zero.
To resolve this, you can use the zero_division parameter in the classification_report function to control this behavior. Setting zero_division to 1 or 0 will avoid the warning by explicitly defining what to do when a zero division occurs.
class_report = classification_report(y_true, y_pred, labels=used_actions, zero_division=1)```
Upvotes: 0
Reputation: 441
I got a similar problem when using Seqeval pakcage to compute metrics. It turned out that when I used mono-character labels like 'U' or '0' for NER, the seqeval/metrics/sequence_labeling.py
script truncates a letter during processing, so the labels taken for comparison are empty. Changing the labels to 'UU' and '00' solved the problem.
Upvotes: 0
Reputation: 55
I checked, as Shovalt suggested, the difference between the sets of truth values and predictions in a multilabel case but it did not help me to solve my problem.
So, I searched into sklearn.metrics.precision_recall_fscore_support source code (which is called by f1_score) to check how it works.
The code triggering the warning is the following :
precision = _prf_divide(
tp_sum, pred_sum, "precision", "predicted", average, warn_for, zero_division
)
recall = _prf_divide(
tp_sum, true_sum, "recall", "true", average, warn_for, zero_division
)
tpsum
corresponds to TP (True Positives)pred_sum
corresponds to TP + FP (False Positives)true_sum
corresponds to TP + FN (False Negatives)_prf_divide
is numerator of division_prf_divide
is denominator of divisionAs soon as pred_sum or true_sum is equal to 0, it triggers the warning because division by 0 is not allowed.
In order to get these different values, use sklearn.metrics.multilabel_confusion_matrix. The result is a 3-dimensional array. You can see it as a list of 2x2 matrixes where each matrix represents the True Negatives (TN), False Positives (FP), False Negatives (FP) and the True Positives (TP) for each of your labels, structured as follow :
In my case, the problem came from the model unability to predict some labels due to bad training or lack of samples.
Upvotes: 1
Reputation: 2281
This command works for me
sklearn.metrics.f1_score(y_true, y_pred,average='weighted',zero_division=0)
Upvotes: -1
Reputation: 71
As I have noticed this error occurs under two circumstances,
so, either use np.array(y_test) for y_true in scores
or y_test.reset_index(drop=True)
Hope this helps.
Upvotes: 6
Reputation: 6766
As mentioned in the comments, some labels in y_test
don't appear in y_pred
. Specifically in this case, label '2' is never predicted:
>>> set(y_test) - set(y_pred)
{2}
This means that there is no F-score to calculate for this label, and thus the F-score for this case is considered to be 0.0. Since you requested an average of the score, you must take into account that a score of 0 was included in the calculation, and this is why scikit-learn is showing you that warning.
This brings me to you not seeing the error a second time. As I mentioned, this is a warning, which is treated differently from an error in python. The default behavior in most environments is to show a specific warning only once. This behavior can be changed:
import warnings
warnings.filterwarnings('always') # "error", "ignore", "always", "default", "module" or "once"
If you set this before importing the other modules, you will see the warning every time you run the code.
There is no way to avoid seeing this warning the first time, aside for setting warnings.filterwarnings('ignore')
. What you can do, is decide that you are not interested in the scores of labels that were not predicted, and then explicitly specify the labels you are interested in (which are labels that were predicted at least once):
>>> metrics.f1_score(y_test, y_pred, average='weighted', labels=np.unique(y_pred))
0.91076923076923078
The warning will be gone.
Upvotes: 191
Reputation: 79
I ended up here with the same error but after reading @Shovalt's answer, I realized I was quite low in my test/train split. I had a large data set to start with but had split it down and one group was quite small. By making the sample size bigger, this warning went away and I got my f1 score. From this
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=0)
to this
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
Upvotes: 7
Reputation: 151
the same problem also happened to me when i training my classification model. the reason caused this problem is as what the warning message said "in labels with no predicated samples", it will caused the zero-division when compute f1-score. I found another solution when i read sklearn.metrics.f1_score doc, there is a note as follows:
When true positive + false positive == 0, precision is undefined; When true positive + false negative == 0, recall is undefined. In such cases, by default the metric will be set to 0, as will f-score, and UndefinedMetricWarning will be raised. This behavior can be modified with zero_division
the zero_division
default value is "warn"
, you could set it to 0
or 1
to avoid UndefinedMetricWarning
.
it works for me ;) oh wait, there is another problem when i using zero_division
, my sklearn report that no such keyword argument by using scikit-learn 0.21.3. Just update your sklearn to the latest version by running pip install scikit-learn -U
Upvotes: 15
Reputation: 9762
The accepted answer explains already well why the warning occurs. If you simply want to control the warnings, one could use precision_recall_fscore_support
. It offers a (semi-official) argument warn_for
that could be used to mute the warnings.
(_, _, f1, _) = metrics.precision_recall_fscore_support(y_test, y_pred,
average='weighted',
warn_for=tuple())
As mentioned already in some comments, use this with care.
Upvotes: 3
Reputation: 1721
As the error message states, the method used to get the F score is from the "Classification" part of sklearn - thus the talking about "labels".
Do you have a regression problem? Sklearn provides a "F score" method for regression under the "feature selection" group: http://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.f_regression.html
In case you do have a classification problem, @Shovalt's answer seems correct to me.
Upvotes: 0