2
$\begingroup$

I have set up a neural network which has a single output with a sigmoid activation function, which I understand by default is used as a binary classifier where values over 0.5 should belong to class 1 else class 0. After looking at the results of training, it would be a better balance of precision/recall for my task if I set the classification threshold at a lower number, say 0.25.

Is there a proper way to rescale around this new threshold to give a probability of being in a certain class? So for values close to 0.25, its actually around 50% probability of belonging to class 1.

from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
model.add(Dense(1, activation='sigmoid'))
...layers layers layers
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy',precision,recall,f1])
hist = model.fit(X_train.values,y_train.values, epochs=50, batch_size=64,
          verbose=1, validation_data=(X_val.values,y_val.values),
            callbacks=callbacks_list, shuffle=True)

model.predict(X_test) # ... want to use 0.25 as the cutoff threshold
# but also want the probability of belonging to class 1
$\endgroup$
2
  • $\begingroup$ The output of the network should be the value returned by the sigmoid function, which is used in the loss function directly (typically binary cross entropy). So, it should be pretty easy to lower the threshold as you please. Which library are you using? $\endgroup$
    – AndreaL
    Oct 25, 2017 at 14:46
  • $\begingroup$ Keras. Edited to include code snippet. $\endgroup$ Oct 25, 2017 at 15:13

2 Answers 2

4
$\begingroup$

model.predict will output a matrix in which each row is the probability of that input to be in class 1.

If you print it, it should look like this:

[[ 0.7310586 ]
 [ 0.26896983]]

You just need to loop through those values.

for i, predicted in enumerate(predictions):
    if predicted[0] > 0.25:
        print "bigger than 0.25"
        #assign i to class 1
    else:
        print "smaller than 0.25"
        #assign i to class 0

EDIT: It might be worth to play with the weight of the classes. If you weight the 1 class 3 times more, you might get something close to what you want, in a more elegant way.

Here is an example.

$\endgroup$
5
  • $\begingroup$ I'm interested in the probabilities that they belong to each class given I use a different threshold. Is it valid to just do a linear interpolation and call them probabilities? $\endgroup$ Oct 25, 2017 at 16:45
  • $\begingroup$ OK, I would use a logistic function with mid-point 0.25 to do that. Also, you can play with the steepness of the curve (or just leave it to 1). $\endgroup$
    – AndreaL
    Oct 25, 2017 at 16:57
  • $\begingroup$ It looks like the logistic function is what I am looking for, if you edit to include I will accept this answer. Is this common practice to tack that on at the end of a NN, which already has a sigmoid output? $\endgroup$ Oct 30, 2017 at 18:21
  • $\begingroup$ On second thought, logistic function recentered the 0.25 to 0.5, and capped the output to 1, but given the min value that can come is 0, this gives a different min output. Is there a way to have the 0 input become a 0 output as well? $\endgroup$ Oct 30, 2017 at 18:38
  • $\begingroup$ I would increase the steepness of the logistic function to control that. In principle you can also have two different values for the steepness, if the input is above or below 0.25. $\endgroup$
    – AndreaL
    Oct 30, 2017 at 23:14
4
$\begingroup$

You can also do it in simpler form as:

y_predict = model.predict(X_test) 
y_predict = (y_predict>0.25) # It will evaluate the logical expression y_predict>0.25 and return True or False 
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.