Create an account

Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Fedora - Spam Classification with ML-Pack

Spam Classification with ML-Pack


ML-Pack is a small footprint C++ machine learning library that can be easily integrated into other programs. It is an actively developed open source project and released under a BSD-3 license. Machine learning has gained popularity due to the large amount of electronic data that can be collected. Some other popular machine learning frameworks include TensorFlow, MxNet, PyTorch, Chainer and Paddle Paddle, however these are designed for more complex workflows than ML-Pack. On Fedora, ML-Pack is packaged by its lead developer Ryan Curtin. In addition to a command line interface, ML-Pack has bindings for Python and Julia. Here, we will focus on the command line interface since this may be useful for system administrators to integrate into their workflows.


You can install ML-Pack on the Fedora command line using

$ sudo dnf -y install mlpack mlpack-bin

You can also install the documentation, development headers and Python bindings by using …

$ sudo dnf -y install mlpack-doc \
mlpack-devel mlpack-python3

though they will not be used in this introduction.


As an example, we will train a machine learning model to classify spam SMS messages. To keep this article brief, linux commands will not be fully explained, but you can find out more about them by using the man command, for example for the command first command used below, wget

$ man wget

will give you information that wget will download files from the web and options you can use for it.

Get a dataset

We will use an example spam dataset in Indonesian provided by Yudi Wibisono

$ wget
$ unzip

Pre-process dataset

We will try to classify a message as spam or ham by the number of occurrences of a word in a message. We first change the file line endings, remove line 243 which is missing a label and then remove the header from the dataset. Then, we split our data into two files, labels and messages. Since the labels are at the end of the message, the message is reversed and then the label removed and placed in one file. The message is then removed and placed in another file.

$ tr 'r' 'n' < dataset_sms_spam_v1.csv > dataset.txt
$ sed '243d' dataset.txt > dataset1.csv
$ sed '1d' dataset1.csv > dataset.csv
$ rev dataset.csv | cut -c1 | rev > labels.txt
$ rev dataset.csv | cut -c2- | rev > messages.txt
$ rm dataset.csv
$ rm dataset1.csv
$ rm dataset.txt

Machine learning works on numeric data, so we will use labels of 1 for ham and 0 for spam. The dataset contains three labels, 0, normal sms (ham), 1, fraud (spam), and 2 promotion (spam). We will label all spam as 1, so promotions and fraud will be labelled as 1.

$ tr '2' '1' < labels.txt > labels.csv
$ rm labels.txt

The next step is to convert all text in the messages to lower case and for simplicity remove punctuation and any symbols that are not spaces, line endings or in the range a-z (one would need expand this range of symbols for production use)

$ tr '[:upper:]' '[:lower:]' < \
messages.txt > messagesLower.txt
$ tr -Cd 'abcdefghijklmnopqrstuvwxyz n' < \ messagesLower.txt > messagesLetters.txt
$ rm messagesLower.txt

We now obtain a sorted list of unique words used (this step may take a few minutes, so use nice to give it a low priority while you continue with other tasks on your computer).

$ nice -20 xargs -n1 < messagesLetters.txt > temp.txt
$ sort temp.txt > temp2.txt
$ uniq temp2.txt > words.txt
$ rm temp.txt
$ rm temp2.txt

We then create a matrix, where for each message, the frequency of word occurrences is counted (more on this on Wikipedia, here and here). This requires a few lines of code, so the full script, which should be saved as ‘’ is below

declare -a words=()
declare -a letterstartind=()
declare -a letterstart=()
letter=" "
while IFS= read -r line; do labels[$((i))]=$line let "i++"
done < labels.csv
while IFS= read -r line; do words[$((i))]=$line firstletter="$( echo $line | head -c 1 )" if [ "$firstletter" != "$letter" ] then letterstartind[$((lettercount))]=$((i)) letterstart[$((lettercount))]=$firstletter letter=$firstletter let "lettercount++" fi let "i++"
done < words.txt
echo "Created list of letters" touch wordfrequency.txt
rm wordfrequency.txt
touch wordfrequency.txt
messages="$( wc -l messages.txt )"
while IFS= read -r line; do let "messagenum++" declare -a wordcount=() declare -a wordarray=() read -r -a wordarray <<> wordfrequency.txt echo "Processed message ""$messagenum" let "i++"
done < messagesLetters.txt
# Create csv file
tr ' ' ',' data.csv

Since Bash is an interpreted language, this simple implementation can take upto 30 minutes to complete. If using the above Bash script on your primary workstation, run it as a task with low priority so that you can continue with other work while you wait:

$ nice -20 bash

Once the script has finished running, split the data into testing (30%) and training (70%) sets:

$ mlpack_preprocess_split \ --input_file data.csv \ --input_labels_file labels.csv \ --training_file \ --training_labels_file train.labels.csv \ --test_file \ --test_labels_file test.labels.csv \ --test_ratio 0.3 \ --verbose

Train a model

Now train a Logistic regression model:

$ mlpack_logistic_regression \
--training_file \
--labels_file train.labels.csv --lambda 0.1 \
--output_model_file lr_model.bin

Test the model

Finally we test our model by producing predictions,

$ mlpack_logistic_regression \
--input_model_file lr_model.bin \ --test_file \
--output_file lr_predictions.csv

and comparing the predictions with the exact results,

$ export incorrect=$(diff -U 0 lr_predictions.csv \
test.labels.csv | grep '^@@' | wc -l)
$ export tests=$(wc -l < lr_predictions.csv)
$ echo "scale=2; 100 * ( 1 - $((incorrect)) \
/ $((tests)))" | bc

This gives approximately 90% validation rate, similar to that obtained here.

The dataset is composed of approximately 50% spam messages, so the validation rates are quite good without doing much parameter tuning. In typical cases, datasets are unbalanced with many more entries in some categories than in others. In these cases a good validation rate can be obtained by mispredicting the class with a few entries. Thus to better evaluate these models, one can compare the number of misclassifications of spam, and the number of misclassifications of ham. Of particular importance in applications is the number of false positive spam results as these are typically not transmitted. The script below produces a confusion matrix which gives a better indication of misclassification. Save it as ‘’

declare -a labels
declare -a lr
while IFS= read -r line; do labels[i]=$line let "i++"
done < test.labels.csv
while IFS= read -r line; do lr[i]=$line let "i++"
done < lr_predictions.csv
for i in "${!labels[@]}"; do if [ "${labels[$i]}" == "1" ] then let "Positive++" if [ "${lr[$i]}" == "1" ] then let "TruePositiveLR++" else let "FalseZeroLR++" fi fi if [ "${labels[$i]}" == "0" ] then let "Zero++" if [ "${lr[$i]}" == "0" ] then let "TrueZeroLR++" else let "FalsePositiveLR++" fi fi done
echo "Logistic Regression"
echo "Total spam" $Positive
echo "Total ham" $Zero
echo "Confusion matrix"
echo " Predicted class"
echo " Ham | Spam "
echo " ---------------"
echo " Actual| Ham | " $TrueZeroLR "|" $FalseZeroLR
echo " class | Spam | " $FalsePositiveLR " |" $TruePositiveLR
echo ""

then run the script

$ bash

You should get output similar to

Logistic Regression
Total spam 183
Total ham 159
Confusion matrix

Predicted class
Ham Spam
Actual class Ham 128 26
Spam 31 157

which indicates a reasonable level of classification. Other methods you can try in ML-Pack for this problem include Naive Bayes, random forest, decision tree, AdaBoost and perceptron.

To improve the error rating, you can try other pre-processing methods on the initial data set. Neural networks can give upto 99.95% validation rates, see for example here, here and here. However, using these techniques with ML-Pack cannot be done on the command line interface at present and is best covered in another post.

For more on ML-Pack, please see the documentation.

Possibly Related Threads…
Thread Author Replies Views Last Post
  Fedora - Matthew Arnold: Why I switched to Fedora xSicKxBot 0 4 08-05-2020, 08:52 AM
Last Post: xSicKxBot
  Fedora - Fedora Classroom Session: Git 101 with Pagure xSicKxBot 0 36 07-16-2020, 09:51 AM
Last Post: xSicKxBot
  Fedora - Running Rosetta@home on a Raspberry Pi with Fedora IoT xSicKxBot 0 33 07-09-2020, 11:36 AM
Last Post: xSicKxBot
  Fedora - Docker and Fedora 32 xSicKxBot 0 50 06-27-2020, 09:28 AM
Last Post: xSicKxBot
  Fedora - Getting Started with Haskell on Fedora xSicKxBot 0 49 06-25-2020, 11:13 AM
Last Post: xSicKxBot
  Fedora - Contribute at the Fedora Test Week for Kernel 5.7 xSicKxBot 0 63 06-20-2020, 09:22 AM
Last Post: xSicKxBot
  Fedora - Fedora 32: Simple Local File-Sharing with Samba xSicKxBot 0 66 06-13-2020, 05:44 AM
Last Post: xSicKxBot
  Fedora - Contribute at the Fedora CoreOS Test Day xSicKxBot 0 76 06-06-2020, 07:29 PM
Last Post: xSicKxBot
  Fedora - How to generate an EPUB file on Fedora xSicKxBot 0 62 06-06-2020, 11:40 AM
Last Post: xSicKxBot
  Fedora - Fedora Silverblue, an introduction for developers xSicKxBot 0 70 06-05-2020, 11:22 PM
Last Post: xSicKxBot

Forum Jump:

Upcoming Events

Latest Threads
News - Nintendo Has Removed Pikmin 3 Fro...
Last Post: xSicKxBot
Yesterday 10:46 PM
» Replies: 0
» Views: 1
News - Fortnite Motorboat Mayhem Time Tr...
Last Post: xSicKxBot
Yesterday 10:46 PM
» Replies: 0
» Views: 1
Xbox Wire - Get Ready to Unleash Swimsan...
Last Post: xSicKxBot
Yesterday 08:05 PM
» Replies: 0
» Views: 3
News - What to expect when you’re expect...
Last Post: xSicKxBot
Yesterday 08:04 PM
» Replies: 0
» Views: 2
[Tut] Python One Line With Statement
Last Post: xSicKxBot
Yesterday 03:59 PM
» Replies: 0
» Views: 4
(Indie Deal) Bundles & Sales Round-up
Last Post: xSicKxBot
Yesterday 03:59 PM
» Replies: 0
» Views: 5
(Free Game Key) The Witcher: Enhanced Ed...
Last Post: xSicKxBot
Yesterday 03:59 PM
» Replies: 0
» Views: 4
News - Review: LEGO Super Mario – A Stro...
Last Post: xSicKxBot
Yesterday 03:58 PM
» Replies: 0
» Views: 4
News - NHL 20 Adds A New Way To Report T...
Last Post: xSicKxBot
Yesterday 03:58 PM
» Replies: 0
» Views: 3
News - Has The Chibi-Robo Studio Skip Pu...
Last Post: xSicKxBot
Yesterday 06:12 AM
» Replies: 0
» Views: 3


Get the Deal of the Week at

Copyright © 2012-2019