Learning Weka - Precision and Recall - Wiki example to .Arff file - machine-learning

I'm new to WEKA and advanced statistics, starting from scratch to understand the WEKA measures. I've done all the #rushdi-shams examples, which are great resources.
On Wikipedia the http://en.wikipedia.org/wiki/Precision_and_recall examples explains with an simple example about a video software recognition of 7 dogs detection in a group of 9 real dogs and some cats.
I perfectly understand the example, and the recall calculation.
So my first step, let see in Weka how to reproduce with this data.
How do I create such a .ARFF file?
With this file I have a wrong Confusion Matrix, and the wrong Accuracy By Class
Recall is not 1, it should be 4/9 (0.4444)
#relation 'dogs and cat detection'
#attribute 'realanimal' {dog,cat}
#attribute 'detected' {dog,cat}
#attribute 'class' {correct,wrong}
#data
dog,dog,correct
dog,dog,correct
dog,dog,correct
dog,dog,correct
cat,dog,wrong
cat,dog,wrong
cat,dog,wrong
dog,?,?
dog,?,?
dog,?,?
dog,?,?
dog,?,?
cat,?,?
cat,?,?
Output Weka (without filters)
=== Run information ===
Scheme:weka.classifiers.rules.ZeroR
Relation: dogs and cat detection
Instances: 14
Attributes: 3
realanimal
detected
class
Test mode:10-fold cross-validation
=== Classifier model (full training set) ===
ZeroR predicts class value: correct
Time taken to build model: 0 seconds
=== Stratified cross-validation ===
=== Summary ===
Correctly Classified Instances 4 57.1429 %
Incorrectly Classified Instances 3 42.8571 %
Kappa statistic 0
Mean absolute error 0.5
Root mean squared error 0.5044
Relative absolute error 100 %
Root relative squared error 100 %
Total Number of Instances 7
Ignored Class Unknown Instances 7
=== Detailed Accuracy By Class ===
TP Rate FP Rate Precision Recall F-Measure ROC Area Class
1 1 0.571 1 0.727 0.65 correct
0 0 0 0 0 0.136 wrong
Weighted Avg. 0.571 0.571 0.327 0.571 0.416 0.43
=== Confusion Matrix ===
a b <-- classified as
4 0 | a = correct
3 0 | b = wrong
There must be something wrong with the False Negative dogs,
or is my ARFF approach totally wrong and do I need another kind of attributes?
Thanks

Lets start with the basic definition of Precision and Recall.
Precision = TP/(TP+FP)
Recall = TP/(TP+FN)
Where TP is True Positive, FP is False Positive, and FN is False Negative.
In the above dog.arff file, Weka took into account only the first 7 tuples, it ignored the remaining 7. It can be seen from the above output that it has classified all the 7 tuples as correct(4 correct tuples + 3 wrong tuples).
Lets calculate the precision for correct and wrong class.
First for the correct class:
Prec = 4/(4+3) = 0.571428571
Recall = 4/(4+0) = 1.
For wrong class:
Prec = 0/(0+0)= 0
recall =0/(0+3) = 0

Related

Is there a reason why a feature only present in a given class is not being predicted strongly into that class?

Summary & Questions
I'm using liblinear 2.30 - I noticed a similar issue in prod, so I tried to isolate it through a simple reduced training with 2 classes, 1 train doc per class, 5 features with same weight in my vocabulary and 1 simple test doc containing only one feature which is present only in class 2.
a) what's the feature value being used for?
b) I wanted to understand why this test document containing a single feature which is only present in one class is not being strongly predicted into that class?
c) I'm not expecting to have different values per features. Is there any other implications by increasing each feature value from 1 to something-else? How can I determine that number?
d) Could my changes affect other more complex trainings in a bad way?
What I tried
Below you will find data related to a simple training (please focus on feature 5):
> cat train.txt
1 1:1 2:1 3:1
2 2:1 4:1 5:1
> train -s 0 -c 1 -p 0.1 -e 0.01 -B 0 train.txt model.bin
iter 1 act 3.353e-01 pre 3.333e-01 delta 6.715e-01 f 1.386e+00 |g| 1.000e+00 CG 1
iter 2 act 4.825e-05 pre 4.824e-05 delta 6.715e-01 f 1.051e+00 |g| 1.182e-02 CG 1
> cat model.bin
solver_type L2R_LR
nr_class 2
label 1 2
nr_feature 5
bias 0
w
0.3374141436539016
0
0.3374141436539016
-0.3374141436539016
-0.3374141436539016
0
And this is the output of the model:
solver_type L2R_LR
nr_class 2
label 1 2
nr_feature 5
bias 0
w
0.3374141436539016
0
0.3374141436539016
-0.3374141436539016
-0.3374141436539016
0
1 5:10
Below you will find my model's prediction:
> cat test.txt
1 5:1
> predict -b 1 test.txt model.bin test.out
Accuracy = 0% (0/1)
> cat test.out
labels 1 2
2 0.416438 0.583562
And here is where I'm a bit surprised because of the predictions being just [0.42, 0.58] as the feature 5 is only present in class 2. Why?
So I just tried with increasing the feature value for the test doc from 1 to 10:
> cat newtest.txt
1 5:10
> predict -b 1 newtest.txt model.bin newtest.out
Accuracy = 0% (0/1)
> cat newtest.out
labels 1 2
2 0.0331135 0.966887
And now I get a better prediction [0.03, 0.97]. Thus, I tried re-compiling my training again with all features set to 10:
> cat newtrain.txt
1 1:10 2:10 3:10
2 2:10 4:10 5:10
> train -s 0 -c 1 -p 0.1 -e 0.01 -B 0 newtrain.txt newmodel.bin
iter 1 act 1.104e+00 pre 9.804e-01 delta 2.508e-01 f 1.386e+00 |g| 1.000e+01 CG 1
iter 2 act 1.381e-01 pre 1.140e-01 delta 2.508e-01 f 2.826e-01 |g| 2.272e+00 CG 1
iter 3 act 2.627e-02 pre 2.269e-02 delta 2.508e-01 f 1.445e-01 |g| 6.847e-01 CG 1
iter 4 act 2.121e-03 pre 1.994e-03 delta 2.508e-01 f 1.183e-01 |g| 1.553e-01 CG 1
> cat newmodel.bin
solver_type L2R_LR
nr_class 2
label 1 2
nr_feature 5
bias 0
w
0.19420510395364846
0
0.19420510395364846
-0.19420510395364846
-0.19420510395364846
0
> predict -b 1 newtest.txt newmodel.bin newtest.out
Accuracy = 0% (0/1)
> cat newtest.out
labels 1 2
2 0.125423 0.874577
And again predictions were still ok for class 2: 0.87
a) what's the feature value being used for?
Each instance of n features is considered as a point in an n-dimensional space, attached with a given label, say +1 or -1 (in your case 1 or 2). A linear SVM tries to find the best hyperplane to separate those instance into two sets, say SetA and SetB. A hyperplane is considered better than other roughly when SetA contains more instances labeled with +1 and SetB contains more those with -1. i.e., more accurate. The best hyperplane is saved as the model. In your case, the hyperplane has formulation:
f(x)=w^T x
where w is the model, e.g (0.33741,0,0.33741,-0.33741,-0.33741) in your first case.
Probability (for LR) formulation:
prob(x)=1/(1+exp(-y*f(x))
where y=+1 or -1. See Appendix L of LIBLINEAR paper.
b) I wanted to understand why this test document containing a single feature which is only present in one class is not being strongly predicted into that class?
Not only 1 5:1 gives weak probability such as [0.42,0.58], if you predict 2 2:1 4:1 5:1 you will get [0.337417,0.662583] which seems that the solver is also not very confident about the result, even the input is exactly the same as the training data set.
The fundamental reason is the value of f(x), or can be simply seen as the distance between x and the hyperplane. It can be 100% confident x belongs to a certain class only if the distance is infinite large (see prob(x)).
c) I'm not expecting to have different values per features. Is there any other implications by increasing each feature value from 1 to something-else? How can I determine that number?
TL;DR
Enlarging both training and test set is like having a larger penalty parameter C (the -c option). Because larger C means a more strict penalty on error, intuitively speaking, the solver has more confidence with the prediction.
Enlarging every feature of the training set is just like having a smaller C.
Specifically, logistic regression solves the following equation for w.
min 0.5 w^T w + C ∑i log(1+exp(−yi w^T xi))
(eq(3) of LIBLINEAR paper)
For most instance, yi w^T xi is positive and larger xi implies smaller ∑i log(1+exp(−yi w^T xi)).
So the effect is somewhat similar to having a smaller C, and a smaller C implies smaller |w|.
On the other hand, enlarging the test set is the same as having a large |w|. Therefore, the effect of enlarging both training and test set is basically
(1). Having smaller |w| when training
(2). Then, having larger |w| when testing
Because the effect is more dramatic in (2) than (1), overall, enlarging both training and test set is like having a larger |w|, or, having a larger C.
We can run on the data set and multiply every features by 10^12. With C=1, we have the model and probability
> cat model.bin.m1e12.c1
solver_type L2R_LR
nr_class 2
label 1 2
nr_feature 5
bias 0
w
3.0998430106024949e-12
0
3.0998430106024949e-12
-3.0998430106024949e-12
-3.0998430106024949e-12
0
> cat test.out.m1e12.c1
labels 1 2
2 0.0431137 0.956886
Next we run on the original data set. With C=10^12, we have the probability
> cat model.bin.m1.c1e12
solver_type L2R_LR
nr_class 2
label 1 2
nr_feature 5
bias 0
w
3.0998430101989314
0
3.0998430101989314
-3.0998430101989314
-3.0998430101989314
0
> cat test.out.m1.c1e12
labels 1 2
2 0.0431137 0.956886
Therefore, because larger C means more strict penalty on error, so intuitively the solver has more confident with prediction.
d) Could my changes affect other more complex trainings in a bad way?
From (c) we know your changes is like having a larger C, and that will result in a better training accuracy. But it almost can be sure that the model is over fitting the training set when C goes too large. As a result, the model cannot endure the noise in training set and will perform badly in test accuracy.
As for finding a good C, a popular way is by cross validation (-v option).
Finally,
it may be off-topic but you may want to see how to pre-process the text data. It is common (e.g., suggested by the author of liblinear here) to instance-wise normalize the data.
For document classification, our experience indicates that if you normalize each document to unit length, then not only the training time is shorter, but also the performance is better.

Constructing ROC curve for FAR and FRR values

I have a one-vs-all classifier set. This set consists of, let's say, 3 classifiers (LibSVM SVMs) each trained on data for a class and all other class data. The current setup for a sample is that the classifier of the 3 classes that gives the highest score is said to be the matching class.
This setup gives a FAR and FRR result. The issue is that the FAR and FRR results are not enough to construct an ROC curve, which I need. I am wondering what I can do to produce and ROC curve.
This can be done using "multiclass ROC curves" (see e.g. this answer for more details). Usually, you either look at each class individually, or even at each pair of classes individually. I'll provide a short R example of how the first one could look, which is less complicated and still gives a good feeling for how well individual classes could be recognized.
You first need to obtain some class probabilities (for reproducibility, this is what you already have):
# Computing some class probabilities for a 3 class problem using repeated cross validation
library(caret)
model <- train(x = iris[,1:2], y = iris[,5], method = 'svmLinear', trControl = trainControl(method = 'repeatedcv', number = 10, repeats = 10, classProbs = T, savePredictions = T))
# those are the class probabilities for each sample
> model$pred
pred obs setosa versicolor virginica rowIndex C Resample
[...]
11 virginica virginica 1.202911e-02 0.411723759 0.57624713 116 1 Fold01.Rep01
12 versicolor virginica 4.970032e-02 0.692146087 0.25815359 122 1 Fold01.Rep01
13 virginica virginica 5.258769e-03 0.310586094 0.68415514 125 1 Fold01.Rep01
14 virginica virginica 4.321882e-05 0.202372698 0.79758408 131 1 Fold01.Rep01
15 versicolor virginica 1.057353e-03 0.559993337 0.43894931 147 1 Fold01.Rep01
[...]
Now you can look at the ROC curve for each class individually. For each curve, the FRR indicates the rate how often samples of this class were predicted as samples of some other class, while the FAR indicates the rate how often a sample of some other class was predicted as a sample of this class:
plot(roc(predictor = model$pred$setosa, response = model$pred$obs=='setosa'), xlab = 'FAR', ylab = '1-FRR')
plot(roc(predictor = model$pred$versicolor, response = model$pred$obs=='versicolor'), add=T, col=2)
plot(roc(predictor = model$pred$virginica, response = model$pred$obs=='virginica'), add=T, col=3)
legend('bottomright', legend = c('setosa', 'versicolor', 'virginica'), col=1:3, lty=1)
As mentioned before, you could instead also look at the ROC curve for each pair of classes, but IMHO this transports much more information, hence it is more complicated/takes longer to grasp the contained information.

SVM-Light displays corrupted precision/recall results

I run SVM-Light classifier but the recall/precision row it outputs seem to be corrupted:
Reading model...OK. (20 support vectors read)
Classifying test examples..100..200..done
Runtime (without IO) in cpu-seconds: 0.00
Accuracy on test set: 95.50% (191 correct, 9 incorrect, 200 total)
Precision/recall on test set: 0.00%/0.00%
What should I configure to get valid precision and recall?
For example, if your classifier is always predicting "-1" -- the negative class; your test dataset, however, contains 191 "-1" and 9 "+1" as golden labels, you will get 191 of them correctly classified and 9 of them incorrect.
True positives : 0 (TP)
True negatives : 191 (TN)
False negatives: 9 (FN)
False positives: 0 (FP)
Thus:
TP 0
Precision = ----------- = --------- = undefined
TP + FP 0 + 0
TP 0
Recall = ----------- = --------- = 0
TP + FN 0 + 9
From the formula above, you know that as long as your TP is zero, your precision/recall is either zero or undefined.
To debug, you should output (for each test example) the golden label and the predicted label so that you know where the issue is.
Thank you greeness. your answer helped me too.
To avoid this issue, make sure that the test and training datasets are chosen/grouped such that they have a fair mix of positive and negative values.

Step by step guide to train a multilayer perceptron for the XOR case in Weka?

I'm just getting started with Weka and having trouble with the first steps.
We've got our training set:
#relation PerceptronXOR
#attribute X1 numeric
#attribute X2 numeric
#attribute Output numeric
#data
1,1,-1
-1,1,1
1,-1,1
-1,-1,-1
First step I want to do is just train, and then classify a set using the Weka gui.
What I've been doing so far:
Using Weka 3.7.0.
Start GUI.
Explorer.
Open file -> choose my arff file.
Classify tab.
Use training set radio button.
Choose-> functions>multilayer_perceptron
Click the 'multilayer perceptron' text at the top to open settings.
Set Hidden layers to '2'. (if gui is selected true,t his show that this is the correct network we want). Click ok.
click start.
outputs:
=== Run information ===
Scheme: weka.classifiers.functions.MultilayerPerceptron -L 0.3 -M 0.2 -N 500 -V 0 -S 0 -E 20 -H 2 -R
Relation: PerceptronXOR
Instances: 4
Attributes: 3
X1
X2
Output
Test mode: evaluate on training data
=== Classifier model (full training set) ===
Linear Node 0
Inputs Weights
Threshold 0.21069691964232443
Node 1 1.8781169869419072
Node 2 -1.8403146612166397
Sigmoid Node 1
Inputs Weights
Threshold -3.7331156814378685
Attrib X1 3.6380519730323164
Attrib X2 -1.0420815868133226
Sigmoid Node 2
Inputs Weights
Threshold -3.64785119182632
Attrib X1 3.603244645539393
Attrib X2 0.9535137571446323
Class
Input
Node 0
Time taken to build model: 0 seconds
=== Evaluation on training set ===
=== Summary ===
Correlation coefficient 0.7047
Mean absolute error 0.6073
Root mean squared error 0.7468
Relative absolute error 60.7288 %
Root relative squared error 74.6842 %
Total Number of Instances 4
It seems odd that 500 iterations at 0.3 doesn't get it the error, but 5000 # 0.1 does, so lets go with that.
Now use the test data set:
#relation PerceptronXOR
#attribute X1 numeric
#attribute X2 numeric
#attribute Output numeric
#data
1,1,-1
-1,1,1
1,-1,1
-1,-1,-1
0.5,0.5,-1
-0.5,0.5,1
0.5,-0.5,1
-0.5,-0.5,-1
Radio button to 'Supplied test set'
Select my test set arff.
Click start.
=== Run information ===
Scheme: weka.classifiers.functions.MultilayerPerceptron -L 0.1 -M 0.2 -N 5000 -V 0 -S 0 -E 20 -H 2 -R
Relation: PerceptronXOR
Instances: 4
Attributes: 3
X1
X2
Output
Test mode: user supplied test set: size unknown (reading incrementally)
=== Classifier model (full training set) ===
Linear Node 0
Inputs Weights
Threshold -1.2208619057226187
Node 1 3.1172079341507497
Node 2 -3.212484459911485
Sigmoid Node 1
Inputs Weights
Threshold 1.091378074639599
Attrib X1 1.8621040828953983
Attrib X2 1.800744048145267
Sigmoid Node 2
Inputs Weights
Threshold -3.372580743113282
Attrib X1 2.9207154176666386
Attrib X2 2.576791630598144
Class
Input
Node 0
Time taken to build model: 0.04 seconds
=== Evaluation on test set ===
=== Summary ===
Correlation coefficient 0.8296
Mean absolute error 0.3006
Root mean squared error 0.6344
Relative absolute error 30.0592 %
Root relative squared error 63.4377 %
Total Number of Instances 8
Why is unable to classify these correctly?
Is it just because it's reached a local minimum quickly on the training data, and doesn't 'know' that that doesn't fit all the cases?
Questions.
Why does 500 # 0.3 not work? Seems odd for such a simple problem.
Why does it fail on the test set.
How do I pass in a set to classify?
Using learning rate with 0.5 does the job with 500 iterations for the both examples.
The learning rate is how much weight it gives for new examples.
Apparently the problem is difficult and it is easy to get in local minima with the 2 hidden layers. If you use a low learning rate with a high iteration number the learning process will be more conservative and more likely to high a good minimum.

How to do proper testing in Weka and how to get desired results ?

I am currently working over a application of ANN, SVM and Linear Regression methods for prediction of fruit yield of a region based on meteorological factors (13 factors )
Total data set is: 36
While Implementing those methods on WEKA I am getting BAD results:
Like in the case of MultilayerPreceptron my results are :
(i divided the dataset with 28 for training and 8 for test )
=== Run information ===
Scheme: weka.classifiers.functions.MultilayerPerceptron -L 0.3 -M 0.2 -N 500 -V 0 -S 0 -E 20 -H a -G -R
Relation: apr6_data
Instances: 28
Attributes: 15
Time taken to build model: 3.69 seconds
=== Predictions on test set ===
inst# actual predicted error
1 2.551 2.36 -0.191
2 2.126 3.079 0.953
3 2.6 1.319 -1.281
4 1.901 3.539 1.638
5 2.146 3.635 1.489
6 2.533 2.917 0.384
7 2.54 2.744 0.204
8 2.82 3.473 0.653
=== Evaluation on test set ===
=== Summary ===
Correlation coefficient -0.4415
Mean absolute error 0.8493
Root mean squared error 1.0065
Relative absolute error 144.2248 %
Root relative squared error 153.5097 %
Total Number of Instances 8
In case of SVM for regression :
inst# actual predicted error
1 2.551 2.538 -0.013
2 2.126 2.568 0.442
3 2.6 2.335 -0.265
4 1.901 2.556 0.655
5 2.146 2.632 0.486
6 2.533 2.24 -0.293
7 2.54 2.766 0.226
8 2.82 3.175 0.355
=== Evaluation on test set ===
=== Summary ===
Correlation coefficient 0.2888
Mean absolute error 0.3417
Root mean squared error 0.3862
Relative absolute error 58.0331 %
Root relative squared error 58.9028 %
Total Number of Instances 8
What can be the possible error in my application ? Please let me know !
Thanks
Do I need to normalize the data ? I guess it is being done by WEKA classifiers.
If you want to normalize data, you have to do it. Preprocess tab - > Filters (choose) -> then find normalize and then click apply.
If you want to discretize your data, you have to follow the same process.
You might have better luck with discretising the prediction e.g. into low/medium/high yield.
You need to normalize or discretize- this cannot be said based on your data or on your single run. For instance, discretization brings in better result for naive baye's classifiers. For SVM- not sure.
I did not see your Precision, Recall or F-score from your data. But as you are saying you have bad results on test set, then it is very possible that your classifier is experiencing overfitting. Try to increase training instances (36 is too less I guess). Keep us posting what is happening when you increase training instances.

Resources