<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Banso D. Wisdom</title>
    <description>The latest articles on Forem by Banso D. Wisdom (@overrideveloper).</description>
    <link>https://forem.com/overrideveloper</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F24867%2F89df3e8e-a5cb-443a-8d5a-23e86e1322ba.jpg</url>
      <title>Forem: Banso D. Wisdom</title>
      <link>https://forem.com/overrideveloper</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/overrideveloper"/>
    <language>en</language>
    <item>
      <title>2020: My Year In Review</title>
      <dc:creator>Banso D. Wisdom</dc:creator>
      <pubDate>Sat, 26 Dec 2020 13:07:02 +0000</pubDate>
      <link>https://forem.com/overrideveloper/2020-my-year-in-review-1620</link>
      <guid>https://forem.com/overrideveloper/2020-my-year-in-review-1620</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tN1_E2Os--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ubwu21p4jv3f8cc29267.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tN1_E2Os--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ubwu21p4jv3f8cc29267.jpg" alt="2020 in Review"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See you next year!&lt;/p&gt;

</description>
      <category>2020</category>
      <category>yearinreview</category>
    </item>
    <item>
      <title>2019: My year in review</title>
      <dc:creator>Banso D. Wisdom</dc:creator>
      <pubDate>Tue, 31 Dec 2019 18:42:27 +0000</pubDate>
      <link>https://forem.com/overrideveloper/2019-my-year-in-review-39i</link>
      <guid>https://forem.com/overrideveloper/2019-my-year-in-review-39i</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mhTOZ3h---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/c8spvuckzoojvtvb8r0w.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mhTOZ3h---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/c8spvuckzoojvtvb8r0w.jpg" alt="Cut the cameras. Deadass"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>2019</category>
      <category>review</category>
      <category>recap</category>
    </item>
    <item>
      <title>Understanding the Confusion Matrix (II)</title>
      <dc:creator>Banso D. Wisdom</dc:creator>
      <pubDate>Sun, 05 May 2019 18:40:28 +0000</pubDate>
      <link>https://forem.com/overrideveloper/understanding-the-confusion-matrix-264i</link>
      <guid>https://forem.com/overrideveloper/understanding-the-confusion-matrix-264i</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/overrideveloper/understanding-the-confusion-matrix-2dk8"&gt;first part of this article&lt;/a&gt;, I talked about the confusion matrix in general, the 2-class confusion matrix, how to calculate accuracy, precision and other metrics using it and also how to generate a confusion matrix in python.&lt;/p&gt;

&lt;p&gt;In this article, we'll be looking at the multi-class confusion matrix.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the multi-class confusion matrix?
&lt;/h3&gt;

&lt;p&gt;​ As the name implies, it is a confusion matrix that deals with multiple classes (i.e. more than 2 classes). Just like the 2-class confusion matrix, it describes the performance of a multi-class classification model.&lt;/p&gt;

&lt;p&gt;For the purpose of this article, we'll be assuming that our multi-class classification model is one that classifies images of dogs into the following breeds: &lt;strong&gt;Greyhound&lt;/strong&gt;, &lt;strong&gt;Mastiff&lt;/strong&gt; and &lt;strong&gt;Samoyed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A confusion matrix for this classifier can be visualized as such:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fklp6umvp2h3oalxwz00a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fklp6umvp2h3oalxwz00a.png" alt="multi-class classifier" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this visualization, we have two sections which have been outlined. We have the &lt;strong&gt;predicted&lt;/strong&gt; classifications section which contains three subsections for each of the classes we want to classify into and the &lt;strong&gt;actual&lt;/strong&gt; classifications section which has three subsections for each of the classes.&lt;/p&gt;

&lt;p&gt;Having visualized this confusion matrix, we can use this visualization to calculate the following metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;True Positives.&lt;/li&gt;
&lt;li&gt;True Negatives.&lt;/li&gt;
&lt;li&gt;False Positives.&lt;/li&gt;
&lt;li&gt;False Negatives.&lt;/li&gt;
&lt;li&gt;Accuracy.&lt;/li&gt;
&lt;li&gt;Precision.&lt;/li&gt;
&lt;li&gt;True Positive Rate is also known as &lt;strong&gt;Sensitivity&lt;/strong&gt; or &lt;strong&gt;Recall&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;True Negative Rate is also known as &lt;strong&gt;Specificity&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before we calculate these metrics, let's define the variables in the visualization:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PGG&lt;/strong&gt;&lt;br&gt;
​ This variable represents the number of predictions where images of a &lt;strong&gt;Greyhound&lt;/strong&gt; were correctly classified [as a &lt;strong&gt;Greyhound&lt;/strong&gt;]. This is also the &lt;strong&gt;True Positive&lt;/strong&gt; for the &lt;strong&gt;Greyhound&lt;/strong&gt; class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PMG&lt;/strong&gt;&lt;br&gt;
​ This variable represents the number of predictions where images of a &lt;strong&gt;Greyhound&lt;/strong&gt; were incorrectly classified as a &lt;strong&gt;Mastiff&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PSG&lt;/strong&gt;&lt;br&gt;
​ This variable represents the number of predictions where images of a &lt;strong&gt;Greyhound&lt;/strong&gt; were incorrectly classified as a &lt;strong&gt;Samoyed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PGM&lt;/strong&gt;&lt;br&gt;
​ This variable represents the number of predictions where images of a &lt;strong&gt;Mastiff&lt;/strong&gt; were incorrectly classified as a &lt;strong&gt;Greyhound&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PMM&lt;/strong&gt;&lt;br&gt;
​ This variable represents the number of predictions where images of a &lt;strong&gt;Mastiff&lt;/strong&gt; were correctly classified [as a &lt;strong&gt;Mastiff&lt;/strong&gt;]. This is also the &lt;strong&gt;True Positive&lt;/strong&gt; for the &lt;strong&gt;Mastiff&lt;/strong&gt; class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PSM&lt;/strong&gt;&lt;br&gt;
​ This variable represents the number of predictions where images of a &lt;strong&gt;Mastiff&lt;/strong&gt; were incorrectly classified as a &lt;strong&gt;Samoyed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PGS&lt;/strong&gt;&lt;br&gt;
​ This variable represents the number of predictions where images of a &lt;strong&gt;Samoyed&lt;/strong&gt; were incorrectly classified as a &lt;strong&gt;Greyhound&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PMS&lt;/strong&gt;&lt;br&gt;
​ This variable represents the number of predictions where images of a &lt;strong&gt;Samoyed&lt;/strong&gt; were incorrectly classified as a &lt;strong&gt;Mastiff&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PSS&lt;/strong&gt;&lt;br&gt;
​ This variable represents the number of predictions where images of a &lt;strong&gt;Samoyed&lt;/strong&gt; were correctly classified [as a &lt;strong&gt;Samoyed&lt;/strong&gt;]. This is also the &lt;strong&gt;True Positive&lt;/strong&gt; for the &lt;strong&gt;Samoyed&lt;/strong&gt; class.&lt;/p&gt;

&lt;p&gt;Now that we have defined these variables, we can now calculate the aforementioned metrics.&lt;/p&gt;

&lt;h4&gt;
  
  
  True Positives
&lt;/h4&gt;

&lt;p&gt;​ The definition for the &lt;strong&gt;True Positive&lt;/strong&gt; is the same as in the 2-class confusion matrix. However, here we calculate the &lt;strong&gt;True Positives&lt;/strong&gt; for each class in the confusion matrix unlike the general or absolute &lt;strong&gt;True Positives&lt;/strong&gt; in the 2-class confusion matrix.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;True Positives&lt;/strong&gt; is the number of predictions where data labelled to belong to a particular class was correctly classified as the said class. E.g Number of predictions where images of a Samoyed was correctly classified as a Samoyed.&lt;/p&gt;

&lt;p&gt;From the definition of the matrix variables, we have already identified the &lt;strong&gt;True Positives&lt;/strong&gt; for each of the classes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;True Positives&lt;/strong&gt; for the &lt;strong&gt;Greyhound&lt;/strong&gt; class is the variable &lt;strong&gt;PGG&lt;/strong&gt; in the confusion matrix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;True Positives&lt;/strong&gt; for the &lt;strong&gt;Mastiff&lt;/strong&gt; class is the variable &lt;strong&gt;PMM&lt;/strong&gt; in the confusion matrix.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;True Positives&lt;/strong&gt; for the &lt;strong&gt;Samoyed&lt;/strong&gt; class is the variable &lt;strong&gt;PSS&lt;/strong&gt; in the confusion matrix.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  True Negatives
&lt;/h4&gt;

&lt;p&gt;​ The definition of the &lt;strong&gt;True Negative&lt;/strong&gt; is the same as in the 2-class confusion matrix. Here we calculate the &lt;strong&gt;True Negatives&lt;/strong&gt; for each class in the confusion matrix unlike the general or absolute &lt;strong&gt;True Negatives&lt;/strong&gt; in the 2-class confusion matrix.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;True Negatives&lt;/strong&gt; for a particular class is calculated by taking the sum of the values in every row and column except the row and column of the class we're trying to find the &lt;strong&gt;True Negatives&lt;/strong&gt; for.&lt;/p&gt;

&lt;p&gt;For example, calculating the &lt;strong&gt;True Negatives&lt;/strong&gt; for the &lt;strong&gt;Greyhound&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcaxxo1qiw69hjfp6aaev.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcaxxo1qiw69hjfp6aaev.png" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We omit the row and columns belonging to the &lt;strong&gt;Greyhound&lt;/strong&gt; class and sum the variables that are left, which are the rows and columns of the other classes (&lt;strong&gt;Mastiff&lt;/strong&gt; and &lt;strong&gt;Samoyed&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;Therefore the &lt;strong&gt;True Negatives&lt;/strong&gt; for the &lt;strong&gt;Greyhound&lt;/strong&gt; class is:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;TN&lt;/strong&gt; = &lt;strong&gt;PMM&lt;/strong&gt; + &lt;strong&gt;PSM&lt;/strong&gt; + &lt;strong&gt;PMS&lt;/strong&gt; + &lt;strong&gt;PSS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Similarly, we can calculate the &lt;strong&gt;True Negatives&lt;/strong&gt; for the other classes.&lt;/p&gt;

&lt;p&gt;Calculating the &lt;strong&gt;True Negatives&lt;/strong&gt; for the &lt;strong&gt;Mastiff&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftgndyy38ihhyvfq9uenk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftgndyy38ihhyvfq9uenk.png" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;True Negatives&lt;/strong&gt; for the &lt;strong&gt;Mastiff&lt;/strong&gt; class is:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;TN&lt;/strong&gt; = &lt;strong&gt;PGG&lt;/strong&gt; + &lt;strong&gt;PSG&lt;/strong&gt; + &lt;strong&gt;PGS&lt;/strong&gt; + &lt;strong&gt;PSS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Calculating the &lt;strong&gt;True Negatives&lt;/strong&gt; for the &lt;strong&gt;Samoyed&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffszchb5a3aj6b8ufj76g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffszchb5a3aj6b8ufj76g.png" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;True Negatives&lt;/strong&gt; for the &lt;strong&gt;Samoyed&lt;/strong&gt; class is:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;TN&lt;/strong&gt; = &lt;strong&gt;PGG&lt;/strong&gt; + &lt;strong&gt;PMG&lt;/strong&gt; + &lt;strong&gt;PGM&lt;/strong&gt; + &lt;strong&gt;PMM&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  False Positives
&lt;/h4&gt;

&lt;p&gt;​ The definition of the &lt;strong&gt;False Positive&lt;/strong&gt; is the same as in the 2-class confusion matrix. Here we calculate the &lt;strong&gt;False Positives&lt;/strong&gt; for each class in the confusion matrix unlike the general or absolute &lt;strong&gt;False Positives&lt;/strong&gt; in the 2-class confusion matrix.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;False Positives&lt;/strong&gt; for a particular class can be calculated by taking the sum of all the values in the column corresponding to that class except the &lt;strong&gt;True Positives&lt;/strong&gt; value.&lt;/p&gt;

&lt;p&gt;For example, calculating the &lt;strong&gt;False Positives&lt;/strong&gt; for the &lt;strong&gt;Greyhound&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27478rcyr3qdtjvobp0h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27478rcyr3qdtjvobp0h.png" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;​ We sum all the values in the highlighted area, which is the column corresponding to the &lt;strong&gt;Greyhound&lt;/strong&gt; class with the exception of the variable &lt;strong&gt;PGG&lt;/strong&gt; which we had earlier identified to be the &lt;strong&gt;True Positives&lt;/strong&gt; for the &lt;strong&gt;Greyhound&lt;/strong&gt; class.&lt;/p&gt;

&lt;p&gt;​ Therefore the &lt;strong&gt;False Positives&lt;/strong&gt; for &lt;strong&gt;Greyhound&lt;/strong&gt; class is:&lt;/p&gt;

&lt;p&gt;​     &lt;strong&gt;FP&lt;/strong&gt; = &lt;strong&gt;PGM&lt;/strong&gt; + &lt;strong&gt;PGS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Similarly, we can calculate the &lt;strong&gt;False Positives&lt;/strong&gt; for the other classes.&lt;/p&gt;

&lt;p&gt;Calculating the &lt;strong&gt;False Positives&lt;/strong&gt; for the &lt;strong&gt;Mastiff&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dmak279kqav6wtb89h7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dmak279kqav6wtb89h7.png" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;​ The &lt;strong&gt;False Positives&lt;/strong&gt; for the &lt;strong&gt;Mastiff&lt;/strong&gt; class is:&lt;/p&gt;

&lt;p&gt;​     &lt;strong&gt;FP&lt;/strong&gt; = &lt;strong&gt;PMG&lt;/strong&gt; + &lt;strong&gt;PMS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Calculating the &lt;strong&gt;False Positives&lt;/strong&gt; for the &lt;strong&gt;Samoyed&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxeiqr664iyst1l708crh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxeiqr664iyst1l708crh.png" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;​ The &lt;strong&gt;False Positives&lt;/strong&gt; for the &lt;strong&gt;Samoyed&lt;/strong&gt; class is:&lt;/p&gt;

&lt;p&gt;​     &lt;strong&gt;FP&lt;/strong&gt; = &lt;strong&gt;PSG&lt;/strong&gt; + &lt;strong&gt;PSM&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  False Negatives
&lt;/h4&gt;

&lt;p&gt;​ The definition of the &lt;strong&gt;False Negative&lt;/strong&gt; is the same as in the 2-class confusion matrix. Here we calculate the &lt;strong&gt;False Negatives&lt;/strong&gt; for each class in the confusion matrix unlike the general or absolute &lt;strong&gt;False Positives&lt;/strong&gt; in the 2-class confusion matrix.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;False Negatives&lt;/strong&gt; for a particular class can be calculated by taking the sum of all the values in the row corresponding to that class except the &lt;strong&gt;True Positives&lt;/strong&gt; value.&lt;/p&gt;

&lt;p&gt;For example, calculating the &lt;strong&gt;False Negatives&lt;/strong&gt; for the &lt;strong&gt;Greyhound&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2g14upkrzrcyk4trvz6z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2g14upkrzrcyk4trvz6z.png" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;​ We sum all the values in the highlighted area, which is the row corresponding to the &lt;strong&gt;Greyhound&lt;/strong&gt; class with the exception of the variable &lt;strong&gt;PGG&lt;/strong&gt; which we had earlier identified to be the &lt;strong&gt;True Positives&lt;/strong&gt; for the &lt;strong&gt;Greyhound&lt;/strong&gt; class.&lt;/p&gt;

&lt;p&gt;​ Therefore the &lt;strong&gt;False Negatives&lt;/strong&gt; for &lt;strong&gt;Greyhound&lt;/strong&gt; class is:&lt;/p&gt;

&lt;p&gt;​     &lt;strong&gt;FN&lt;/strong&gt; = &lt;strong&gt;PMG&lt;/strong&gt; + &lt;strong&gt;PSG&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Similarly, we can calculate the &lt;strong&gt;False Negatives&lt;/strong&gt; for the other classes.&lt;/p&gt;

&lt;p&gt;Calculating the &lt;strong&gt;False Negatives&lt;/strong&gt; for the &lt;strong&gt;Mastiff&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb14ufnrvspkaudmctwgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb14ufnrvspkaudmctwgt.png" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;​ The &lt;strong&gt;False Negatives&lt;/strong&gt; for the &lt;strong&gt;Mastiff&lt;/strong&gt; class is:&lt;/p&gt;

&lt;p&gt;​     &lt;strong&gt;FN&lt;/strong&gt; = &lt;strong&gt;PGM&lt;/strong&gt; + &lt;strong&gt;PSM&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Calculating the &lt;strong&gt;False Negatives&lt;/strong&gt; for the &lt;strong&gt;Samoyed&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0939k5mkzn32c9nm78no.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0939k5mkzn32c9nm78no.png" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;​ The &lt;strong&gt;False Negatives&lt;/strong&gt; for the &lt;strong&gt;Samoyed&lt;/strong&gt; class is:&lt;/p&gt;

&lt;p&gt;​     &lt;strong&gt;FN&lt;/strong&gt; = &lt;strong&gt;PGS&lt;/strong&gt; + &lt;strong&gt;PMS&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Accuracy
&lt;/h4&gt;

&lt;p&gt;​ &lt;strong&gt;Accuracy&lt;/strong&gt; is calculated as the ratio of the number of correct classifications to the total number of classifications. From our confusion matrix, the correct classifications are the &lt;strong&gt;True Positives&lt;/strong&gt; and &lt;strong&gt;True Negatives&lt;/strong&gt; for each class and the total number of classifications is the sum of every value in the confusion matrix, including the &lt;strong&gt;True Positives&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;​ Therefore, the accuracy is:&lt;/p&gt;

&lt;p&gt;​     &lt;strong&gt;AC&lt;/strong&gt; = (&lt;strong&gt;TP(G)&lt;/strong&gt; + &lt;strong&gt;TP(M)&lt;/strong&gt; + &lt;strong&gt;TP(S)&lt;/strong&gt; + &lt;strong&gt;TN(G)&lt;/strong&gt; + &lt;strong&gt;TN(M)&lt;/strong&gt; + &lt;strong&gt;TN(S)&lt;/strong&gt;) / (&lt;strong&gt;TP(G)&lt;/strong&gt; + &lt;strong&gt;TP(M)&lt;/strong&gt; + &lt;strong&gt;TP(S)&lt;/strong&gt; + &lt;strong&gt;TN(G)&lt;/strong&gt; + &lt;strong&gt;TN(M)&lt;/strong&gt; + &lt;strong&gt;TN(S)&lt;/strong&gt; + &lt;strong&gt;FP(G)&lt;/strong&gt; + &lt;strong&gt;FP(M)&lt;/strong&gt; + &lt;strong&gt;FP(S)&lt;/strong&gt; + &lt;strong&gt;FN(G)&lt;/strong&gt; + &lt;strong&gt;FN(M)&lt;/strong&gt; + &lt;strong&gt;FN(S)&lt;/strong&gt;)&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;TP(x)&lt;/em&gt; is the &lt;strong&gt;True Positives&lt;/strong&gt; value for a class.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;TN(x)&lt;/em&gt; is the &lt;strong&gt;True Negatives&lt;/strong&gt; value for a class.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;FP(x)&lt;/em&gt; is the &lt;strong&gt;False Positives&lt;/strong&gt; value for a class.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;FN(x)&lt;/em&gt; is the &lt;strong&gt;False Negatives&lt;/strong&gt; value for a class.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Precision
&lt;/h4&gt;

&lt;p&gt;​ &lt;strong&gt;Precision&lt;/strong&gt; is a multi-class confusion matrix is the measure of the accuracy relative to the prediction of a specific class. It is calculated as the ratio of the &lt;strong&gt;True Positives&lt;/strong&gt; of the class in question to the sum of its &lt;strong&gt;True Positives&lt;/strong&gt; and &lt;strong&gt;False Positives&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, calculating the Precision of the &lt;strong&gt;Greyhound&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;Precision&lt;/strong&gt; (&lt;strong&gt;G&lt;/strong&gt;) = &lt;strong&gt;TP&lt;/strong&gt; / (&lt;strong&gt;TP + FP&lt;/strong&gt;)&lt;br&gt;
​             =  &lt;strong&gt;PGG&lt;/strong&gt; / (&lt;strong&gt;PGG&lt;/strong&gt; + (&lt;strong&gt;PGM + PGS&lt;/strong&gt;))&lt;/p&gt;

&lt;p&gt;Similarly, we can calculate the Precision of other classes.&lt;/p&gt;

&lt;p&gt;Calculating the Precision of the &lt;strong&gt;Mastiff&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;Precision (M)&lt;/strong&gt; = &lt;strong&gt;TP / (TP + FP)&lt;/strong&gt;&lt;br&gt;
​             = &lt;strong&gt;PMM&lt;/strong&gt; / (&lt;strong&gt;PMM&lt;/strong&gt; + (&lt;strong&gt;PMG&lt;/strong&gt; + &lt;strong&gt;PMS&lt;/strong&gt;))&lt;/p&gt;

&lt;p&gt;Calculating the Precision of the &lt;strong&gt;Samoyed&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;Precision (S)&lt;/strong&gt; = &lt;strong&gt;TP&lt;/strong&gt; / &lt;strong&gt;(TP + FP)&lt;/strong&gt;&lt;br&gt;
​             = &lt;strong&gt;PSS&lt;/strong&gt; / (&lt;strong&gt;PSS&lt;/strong&gt; + (&lt;strong&gt;PSG&lt;/strong&gt; + &lt;strong&gt;PSM&lt;/strong&gt;))&lt;/p&gt;

&lt;h4&gt;
  
  
  True Positive Rate
&lt;/h4&gt;

&lt;p&gt;​ The &lt;strong&gt;True Positive Rate&lt;/strong&gt; (also known as &lt;strong&gt;Recall&lt;/strong&gt; or &lt;strong&gt;Sensitivity&lt;/strong&gt;) is calculated as the ratio of the &lt;strong&gt;True Positives&lt;/strong&gt; of a specific class to the sum of its &lt;strong&gt;True Positives&lt;/strong&gt; and &lt;strong&gt;False Negatives&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, calculating the &lt;strong&gt;True Positive Rate&lt;/strong&gt; of the &lt;strong&gt;Greyhound&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;TPR (G)&lt;/strong&gt; = &lt;strong&gt;TP&lt;/strong&gt; / (&lt;strong&gt;TP + FN&lt;/strong&gt;)&lt;br&gt;
​         = &lt;strong&gt;PGG&lt;/strong&gt; / (&lt;strong&gt;PGG&lt;/strong&gt; + (&lt;strong&gt;PMG + PSG&lt;/strong&gt;))&lt;/p&gt;

&lt;p&gt;Similarly, we can calculate the True Positive Rate of other classes.&lt;/p&gt;

&lt;p&gt;Calculating the True Positive Rate of the &lt;strong&gt;Mastiff&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;TPR (M)&lt;/strong&gt; = &lt;strong&gt;TP&lt;/strong&gt; / (&lt;strong&gt;TP + FN&lt;/strong&gt;)&lt;br&gt;
​         = &lt;strong&gt;PMM&lt;/strong&gt; / (&lt;strong&gt;PMM&lt;/strong&gt; + (&lt;strong&gt;PGM + PSM&lt;/strong&gt;)) &lt;/p&gt;

&lt;p&gt;Calculating the True Positive Rate of the &lt;strong&gt;Samoyed&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;TPR (S)&lt;/strong&gt; = &lt;strong&gt;TP&lt;/strong&gt; / (&lt;strong&gt;TP + FN&lt;/strong&gt;)&lt;br&gt;
​         = &lt;strong&gt;PSS&lt;/strong&gt; / (&lt;strong&gt;PSS&lt;/strong&gt; + (&lt;strong&gt;PGS + PMS&lt;/strong&gt;))&lt;/p&gt;

&lt;h4&gt;
  
  
  True Negative Rate
&lt;/h4&gt;

&lt;p&gt;​ The &lt;strong&gt;True Negative Rate&lt;/strong&gt; (also known as &lt;strong&gt;Specificity&lt;/strong&gt;) is calculated as the ratio of the &lt;strong&gt;True Negatives&lt;/strong&gt; of a specific class to the sum of its &lt;strong&gt;True Negatives&lt;/strong&gt; and &lt;strong&gt;False Positives&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, calculating the &lt;strong&gt;True Negative Rate&lt;/strong&gt; of the &lt;strong&gt;Greyhound&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;TNR (G)&lt;/strong&gt; = &lt;strong&gt;TN&lt;/strong&gt; / (&lt;strong&gt;TN + FP&lt;/strong&gt;)&lt;br&gt;
​         =  (&lt;strong&gt;PMM&lt;/strong&gt; + &lt;strong&gt;PSM&lt;/strong&gt; + &lt;strong&gt;PMS&lt;/strong&gt; + &lt;strong&gt;PSS&lt;/strong&gt;) / ((&lt;strong&gt;PMM&lt;/strong&gt; + &lt;strong&gt;PSM&lt;/strong&gt; + &lt;strong&gt;PMS&lt;/strong&gt; + &lt;strong&gt;PSS&lt;/strong&gt;) + (&lt;strong&gt;PGM + PGS&lt;/strong&gt;))&lt;/p&gt;

&lt;p&gt;Similarly, we can calculate the True Negative Rate of other classes.&lt;/p&gt;

&lt;p&gt;Calculating the True Negative Rate of the &lt;strong&gt;Mastiff&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;TNR (M)&lt;/strong&gt; = &lt;strong&gt;TN&lt;/strong&gt; / (&lt;strong&gt;TN + FP&lt;/strong&gt;)&lt;br&gt;
​         = (&lt;strong&gt;PGG&lt;/strong&gt; + &lt;strong&gt;PSG&lt;/strong&gt; + &lt;strong&gt;PGS&lt;/strong&gt; + &lt;strong&gt;PSS&lt;/strong&gt;)  / ((&lt;strong&gt;PGG&lt;/strong&gt; + &lt;strong&gt;PSG&lt;/strong&gt; + &lt;strong&gt;PGS&lt;/strong&gt; + &lt;strong&gt;PSS&lt;/strong&gt;) + (&lt;strong&gt;PMG&lt;/strong&gt; + &lt;strong&gt;PMS&lt;/strong&gt;))&lt;/p&gt;

&lt;p&gt;Calculating the True Negative Rate of the &lt;strong&gt;Samoyed&lt;/strong&gt; class:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;TNR (S)&lt;/strong&gt; = &lt;strong&gt;TN&lt;/strong&gt; / (&lt;strong&gt;TN + FP&lt;/strong&gt;)&lt;br&gt;
​         = (&lt;strong&gt;PGG&lt;/strong&gt; + &lt;strong&gt;PMG&lt;/strong&gt; + &lt;strong&gt;PGM&lt;/strong&gt; + &lt;strong&gt;PMM&lt;/strong&gt;) / ((&lt;strong&gt;PGG&lt;/strong&gt; + &lt;strong&gt;PMG&lt;/strong&gt; + &lt;strong&gt;PGM&lt;/strong&gt; + &lt;strong&gt;PMM&lt;/strong&gt;) + (&lt;strong&gt;PSG&lt;/strong&gt; + &lt;strong&gt;PSM&lt;/strong&gt;))&lt;/p&gt;

&lt;p&gt;Phewww, that was a lot. 😅😅&lt;/p&gt;

&lt;h3&gt;
  
  
  Now, a quick example
&lt;/h3&gt;

&lt;p&gt;​ Suppose we have the image below as the visualized confusion matrix for our classifier, we can use the information in the visualization and the metrics defined above to evaluate its performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygr3vf7e08rde0vpb18u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygr3vf7e08rde0vpb18u.png" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From this confusion matrix, we can identify that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;The variable &lt;strong&gt;PGG&lt;/strong&gt; and the &lt;strong&gt;True Positives&lt;/strong&gt; of the &lt;strong&gt;Greyhound&lt;/strong&gt; class is &lt;strong&gt;250&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The variable &lt;strong&gt;PMM&lt;/strong&gt; and the &lt;strong&gt;True Positives&lt;/strong&gt; of the &lt;strong&gt;Mastiff&lt;/strong&gt; class is &lt;strong&gt;320&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The variable &lt;strong&gt;PSS&lt;/strong&gt; and the &lt;strong&gt;True Positives&lt;/strong&gt; of the &lt;strong&gt;Samoyed&lt;/strong&gt; class is &lt;strong&gt;180&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The variable &lt;strong&gt;PMG&lt;/strong&gt; is &lt;strong&gt;25&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The variable &lt;strong&gt;PSG&lt;/strong&gt; is &lt;strong&gt;18&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The variable &lt;strong&gt;PGM&lt;/strong&gt; is &lt;strong&gt;21&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The variable &lt;strong&gt;PSM&lt;/strong&gt; is &lt;strong&gt;24&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The variable &lt;strong&gt;PGS&lt;/strong&gt; is &lt;strong&gt;22&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The variable &lt;strong&gt;PMS&lt;/strong&gt; is &lt;strong&gt;12&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using this information that we've "extracted", we can calculate the metrics mentioned earlier and thus evaluate the performance of the classifier.&lt;/p&gt;

&lt;h5&gt;
  
  
  True Negatives
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TN&lt;/strong&gt; (&lt;strong&gt;Greyhound&lt;/strong&gt;) = &lt;strong&gt;PMM + PSM + PMS + PSS&lt;/strong&gt;
​             = 320 + 24 + 12 + 180
​             = &lt;strong&gt;536&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TN&lt;/strong&gt; (&lt;strong&gt;Mastiff&lt;/strong&gt;) = &lt;strong&gt;PGG + PSG + PGS + PSS&lt;/strong&gt;
​         = 250 + 18 + 22 + 180
​         = &lt;strong&gt;470&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TN&lt;/strong&gt; (&lt;strong&gt;Samoyed&lt;/strong&gt;) = &lt;strong&gt;PGG + PMG + PGM + PMM&lt;/strong&gt;
​         = 250 + 25 + 21 + 320
​         = &lt;strong&gt;616&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  False Positives
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FP&lt;/strong&gt; (&lt;strong&gt;Greyhound&lt;/strong&gt;) = &lt;strong&gt;PGM + PGS&lt;/strong&gt;
​             = 21 + 22
​             = &lt;strong&gt;43&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FP&lt;/strong&gt; (&lt;strong&gt;Mastiff&lt;/strong&gt;) = &lt;strong&gt;PMG + PMS&lt;/strong&gt;
​         = 25 + 12
​         = &lt;strong&gt;37&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FP&lt;/strong&gt; (&lt;strong&gt;Samoyed&lt;/strong&gt;) = &lt;strong&gt;PSG + PSM&lt;/strong&gt;
​         = 18 + 24
​         = &lt;strong&gt;42&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  False Negatives
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FN&lt;/strong&gt; (&lt;strong&gt;Greyhound&lt;/strong&gt;) = &lt;strong&gt;PMG + PSG&lt;/strong&gt;
​             = 25 + 18
​             = &lt;strong&gt;43&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FN&lt;/strong&gt; (&lt;strong&gt;Mastiff&lt;/strong&gt;) = &lt;strong&gt;PGM + PSM&lt;/strong&gt;
​         = 21 + 24
​         = &lt;strong&gt;45&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FN&lt;/strong&gt; (&lt;strong&gt;Samoyed&lt;/strong&gt;) = &lt;strong&gt;PGS + PMS&lt;/strong&gt;
​             = 22 + 12
​             = &lt;strong&gt;34&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  True Positive Rate / Recall / Sensitivity
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TPR&lt;/strong&gt; (&lt;strong&gt;Greyhound&lt;/strong&gt;) = &lt;strong&gt;TP&lt;/strong&gt; / (&lt;strong&gt;TP + FN&lt;/strong&gt;)
​              = 250 / (250 + 43)
​              = 250 / 293
​              = 0.8532423208
​              = &lt;strong&gt;0.85&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TPR&lt;/strong&gt; (&lt;strong&gt;Mastiff&lt;/strong&gt;) = &lt;strong&gt;TP&lt;/strong&gt; / (&lt;strong&gt;TP + FN&lt;/strong&gt;)
​          = 320 / (320 + 45)
​          = 320 / 365
​          = 0.8767123288
​          = &lt;strong&gt;0.88&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TPR&lt;/strong&gt; (&lt;strong&gt;Samoyed&lt;/strong&gt;) = &lt;strong&gt;TP&lt;/strong&gt; / (&lt;strong&gt;TP + FN&lt;/strong&gt;)
​              = 180 / (180 + 34)
​              = 180 / 214
​              = 0.8411214953
​              = &lt;strong&gt;0.81&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  True Negative Rate / Specificity
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TNR&lt;/strong&gt; &lt;strong&gt;(Greyhound)&lt;/strong&gt; = &lt;strong&gt;TN&lt;/strong&gt; / (&lt;strong&gt;TN + FP&lt;/strong&gt;)
​               = 536 / (536 + 43)
​               = 536 / 579
​               = 0.92573402417962
​               = &lt;strong&gt;0.93&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TNR&lt;/strong&gt; &lt;strong&gt;(Mastiff)&lt;/strong&gt; = &lt;strong&gt;TN&lt;/strong&gt; / (&lt;strong&gt;TN + FP&lt;/strong&gt;)
​           = 470 / (470 + 37)
​           = 470 / 507
​           = 0.9270216963
​           = &lt;strong&gt;0.93&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TNR&lt;/strong&gt; &lt;strong&gt;(Samoyed)&lt;/strong&gt; = &lt;strong&gt;TN&lt;/strong&gt; / (&lt;strong&gt;TN + FP&lt;/strong&gt;)
​               = 616 / (616 + 42)
​               = 616 / 658
​               = 0.9361702128
​               = &lt;strong&gt;0.94&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  Precision
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Precision&lt;/strong&gt; (&lt;strong&gt;Greyhound&lt;/strong&gt;) = &lt;strong&gt;TP&lt;/strong&gt; / (&lt;strong&gt;TP + FP&lt;/strong&gt;)
​                    = 250 / (250 + 43)
​                    = 250 / 293
​                    = 0.8532423208
​                    = &lt;strong&gt;0.85&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Therefore, the classifier has a precision of &lt;strong&gt;0.85&lt;/strong&gt;, which is &lt;strong&gt;85%&lt;/strong&gt;, in classifying images of Greyhounds.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Precision&lt;/strong&gt; (&lt;strong&gt;Mastiff&lt;/strong&gt;) = &lt;strong&gt;TP&lt;/strong&gt; / (&lt;strong&gt;TP + FP&lt;/strong&gt;)
​                = 320 + (320 + 37)
​                = 320 / 357
​                = 0.8963585434
​                = &lt;strong&gt;0.90&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Therefore, the classifier has a precision of &lt;strong&gt;0.90&lt;/strong&gt;, which is &lt;strong&gt;90%&lt;/strong&gt;, in classifying images of Mastiffs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Precision&lt;/strong&gt; (&lt;strong&gt;Samoyed&lt;/strong&gt;) = &lt;strong&gt;TP&lt;/strong&gt; / (&lt;strong&gt;TP + FP&lt;/strong&gt;)
​                    = 180 / (180 + 42)
​                    = 180 / 222
​                    = 0.8108108108
​                    = &lt;strong&gt;0.81&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Therefore, the classifier has a precision of &lt;strong&gt;0.81&lt;/strong&gt;, which is &lt;strong&gt;81%&lt;/strong&gt;, in classifying images of Samoyeds.&lt;/p&gt;

&lt;h5&gt;
  
  
  Accuracy
&lt;/h5&gt;

&lt;p&gt;​ &lt;strong&gt;AC&lt;/strong&gt; =  (&lt;strong&gt;TP(G)&lt;/strong&gt; + &lt;strong&gt;TP(M)&lt;/strong&gt; + &lt;strong&gt;TP(S)&lt;/strong&gt; + &lt;strong&gt;TN(G)&lt;/strong&gt; + &lt;strong&gt;TN(M)&lt;/strong&gt; + &lt;strong&gt;TN(S)&lt;/strong&gt;) / (&lt;strong&gt;TP(G)&lt;/strong&gt; + &lt;strong&gt;TP(M)&lt;/strong&gt; + &lt;strong&gt;TP(S)&lt;/strong&gt; + &lt;strong&gt;TN(G)&lt;/strong&gt; + &lt;strong&gt;TN(M)&lt;/strong&gt; + &lt;strong&gt;TN(S)&lt;/strong&gt; + &lt;strong&gt;FP(G)&lt;/strong&gt; + &lt;strong&gt;FP(M)&lt;/strong&gt; + &lt;strong&gt;FP(S)&lt;/strong&gt; + &lt;strong&gt;FN(G)&lt;/strong&gt; + &lt;strong&gt;FN(M)&lt;/strong&gt; + &lt;strong&gt;FN(S)&lt;/strong&gt;)&lt;br&gt;
​     = (250 + 320 + 180 + 536 + 470 + 616) / (250 + 320 + 180 + 536 + 470 + 616 + 43 + 37 + 42 + 43 + 45 + 34)&lt;br&gt;
        = 2372 / 2616&lt;br&gt;
​     = 0.90672782874&lt;br&gt;
​     = &lt;strong&gt;0.90&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;​ Therefore, the classifier has a total accuracy of &lt;strong&gt;0.90&lt;/strong&gt; which is &lt;strong&gt;90%&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How to generate a multi-class confusion matrix in Python
&lt;/h3&gt;

&lt;p&gt;​ A multi-class confusion matrix is created in the same way as a 2-class confusion matrix. See the &lt;a href="https://dev.to/overrideveloper/understanding-the-confusion-matrix-2dk8"&gt;first part of this article&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>ai</category>
    </item>
    <item>
      <title>Understanding the Confusion Matrix</title>
      <dc:creator>Banso D. Wisdom</dc:creator>
      <pubDate>Mon, 22 Apr 2019 21:02:35 +0000</pubDate>
      <link>https://forem.com/overrideveloper/understanding-the-confusion-matrix-2dk8</link>
      <guid>https://forem.com/overrideveloper/understanding-the-confusion-matrix-2dk8</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5s8xw56ad21s6skkmjuh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5s8xw56ad21s6skkmjuh.png" alt="visual"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A confusion matrix is a table that describes the performance of a classifier/classification model. It contains information about the &lt;strong&gt;actual and prediction classifications&lt;/strong&gt; done by the classifier and this information is used to evaluate the performance of the classifier.&lt;/p&gt;

&lt;p&gt;Note that the confusion matrix is only used for classification tasks, and as such cannot be used in regression models or other non-classification models.&lt;/p&gt;

&lt;p&gt;Before we go on, let's look at some terms.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Classifier: A classifier is basically an algorithm that uses "knowledge" gotten from training data to map input data to a particular category or class. Classifiers are either binary classifiers or multi-class/multi-categorical/multi-label/multi-output classifiers.&lt;/li&gt;
&lt;li&gt;Training and test data: When building a classification model/classifier, datasets are split into &lt;strong&gt;training data&lt;/strong&gt; and &lt;strong&gt;test data&lt;/strong&gt; which have associated labels. A label is an expected output which is the category or class data belongs to.&lt;/li&gt;
&lt;li&gt;Actual classifications: This is the expected output (labels) on the data.&lt;/li&gt;
&lt;li&gt;Prediction classifications: This is the output given by the classifier for a particular input data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;An example&lt;/strong&gt;: Let's say we have built a classifier to categorize an input image of a car as either a sedan or not, and we have an image in our dataset that has been labeled as a non-sedan but the classification model classifies as a sedan.&lt;br&gt;
In this scenario, the actual classification is &lt;strong&gt;non-sedan&lt;/strong&gt; while the prediction classification is &lt;strong&gt;sedan&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Types of Confusion Matrices
&lt;/h3&gt;

&lt;p&gt;There are two types of confusion matrices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2-class confusion matrix&lt;/li&gt;
&lt;li&gt;Multi-class confusion matrix&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2-Class Confusion Matrix
&lt;/h3&gt;

&lt;p&gt;A 2-class as the name implies is a confusion matrix that describes the performance of a binary classification model. A 2-class matrix for the &lt;strong&gt;sedan&lt;/strong&gt; classifier I described earlier can be visualized as such:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fx5jengc1mjseexyl0r1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fx5jengc1mjseexyl0r1b.png" alt="visual"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this visualization, we have two sections which have been outlined. We have the &lt;strong&gt;predicted&lt;/strong&gt; classifications section which contains two subsections for each of the classes and the &lt;strong&gt;actual&lt;/strong&gt; classifications section which has two subsections for each of the classes.&lt;/p&gt;

&lt;p&gt;If this is your first time seeing a confusion matrix, I know you must be wondering what all the variables in the table represent. It is quite simple actually, I will explain as simply as I can, but before I do it is important to know that these variables represent a number of predictions.&lt;/p&gt;

&lt;h5&gt;
  
  
  The variable a
&lt;/h5&gt;

&lt;p&gt;The variable &lt;strong&gt;a&lt;/strong&gt; falls under the &lt;strong&gt;Non-sedan&lt;/strong&gt; sub-section in both the &lt;strong&gt;Actual&lt;/strong&gt; and &lt;strong&gt;Predicted&lt;/strong&gt; classification sections. This means &lt;strong&gt;a&lt;/strong&gt; predictions were made that correctly classified an image of a non-sedan [as a non-sedan].&lt;/p&gt;

&lt;h5&gt;
  
  
  The variable b
&lt;/h5&gt;

&lt;p&gt;The variable &lt;strong&gt;b&lt;/strong&gt; falls under the &lt;strong&gt;Non-sedan&lt;/strong&gt; sub-section in the &lt;strong&gt;Actual&lt;/strong&gt; classification section and under the &lt;strong&gt;Sedan&lt;/strong&gt; sub-section in the &lt;strong&gt;Predicted&lt;/strong&gt; classification section. This means &lt;strong&gt;b&lt;/strong&gt; predictions were made that incorrectly classified an image of a non-sedan as a sedan.&lt;/p&gt;

&lt;h5&gt;
  
  
  The variable c
&lt;/h5&gt;

&lt;p&gt;The variable &lt;strong&gt;c&lt;/strong&gt; falls under the &lt;strong&gt;Sedan&lt;/strong&gt; sub-section in the &lt;strong&gt;Actual&lt;/strong&gt; classification section and under the &lt;strong&gt;Non-sedan&lt;/strong&gt; sub-section in the &lt;strong&gt;Predicted&lt;/strong&gt; classification section. This means &lt;strong&gt;c&lt;/strong&gt; predictions were made that incorrectly classified an image of a sedan as a non-sedan.&lt;/p&gt;

&lt;h5&gt;
  
  
  The variable d
&lt;/h5&gt;

&lt;p&gt;The variable &lt;strong&gt;d&lt;/strong&gt; falls under the &lt;strong&gt;Sedan&lt;/strong&gt; sub-section in both the &lt;strong&gt;Actual&lt;/strong&gt; and &lt;strong&gt;Predicted&lt;/strong&gt; classification sections. This means &lt;strong&gt;d&lt;/strong&gt; predictions were made that correctly classified an image of a sedan [as a sedan].&lt;/p&gt;

&lt;p&gt;Easy peasy lemon squeezy. (I hope? 😅)&lt;/p&gt;

&lt;h5&gt;
  
  
  But wait, we're not done yet.......
&lt;/h5&gt;

&lt;p&gt;Now we have our confusion matrix for our &lt;strong&gt;sedan&lt;/strong&gt; classifier, but how does this help us ascertain our classifier's performance/efficiency?&lt;br&gt;
To ascertain the performance of a classifier using the confusion matrix and the data it contains, there are some standard metrics that we can calculate [for] using the data(variables) in the confusion matrix.&lt;/p&gt;

&lt;h5&gt;
  
  
  Accuracy
&lt;/h5&gt;

&lt;p&gt;Accuracy in a 2-Class confusion matrix is the ratio of the total number of correct predictions to the total number of predictions. &lt;br&gt;
From our confusion matrix, we can see that &lt;strong&gt;a&lt;/strong&gt; and &lt;strong&gt;d&lt;/strong&gt; predictions were made that correctly classified the input image and &lt;strong&gt;b&lt;/strong&gt; and &lt;strong&gt;c&lt;/strong&gt; predictions were made that incorrectly classified the input image.&lt;/p&gt;

&lt;p&gt;Therefore, accuracy can be calculated as: &lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;Accuracy&lt;/strong&gt; = (&lt;strong&gt;a + d&lt;/strong&gt;) / (&lt;strong&gt;a + b + c + d&lt;/strong&gt;)&lt;/p&gt;

&lt;p&gt;​ Where, &lt;strong&gt;a + d&lt;/strong&gt; is the total number of correct predictions and &lt;strong&gt;a + b + c + d&lt;/strong&gt; is the total number of predictions made.&lt;/p&gt;

&lt;h5&gt;
  
  
  True positives, True negatives, False positives and False negative
&lt;/h5&gt;

&lt;p&gt;With relation to our classifier and confusion matrix:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;True positives (TP)&lt;/strong&gt; are the number of predictions where an image of a sedan is correctly classified [as a sedan]. &lt;br&gt;
From our confusion matrix, the variable &lt;strong&gt;d&lt;/strong&gt; is also the &lt;strong&gt;TP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;True negatives (TN)&lt;/strong&gt; are the number of predictions where an image of a non-sedan is correctly classified [as a non-sedan]. &lt;br&gt;
From our confusion matrix, the variable &lt;strong&gt;a&lt;/strong&gt; is also our &lt;strong&gt;TN&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;False positives (FP)&lt;/strong&gt; are the number of predictions where an image of a non-sedan is incorrectly classified as a sedan. &lt;br&gt;
From our confusion matrix, the variable &lt;strong&gt;b&lt;/strong&gt; is also our &lt;strong&gt;FP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;False negatives (FN)&lt;/strong&gt; are the number of predictions where an image of a sedan is incorrectly classified as a non-sedan. &lt;br&gt;
From our confusion matrix, the variable &lt;strong&gt;c&lt;/strong&gt; is also our &lt;strong&gt;FN&lt;/strong&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  True Positive Rate
&lt;/h5&gt;

&lt;p&gt;The true positive rate is a ratio of the &lt;strong&gt;true positives&lt;/strong&gt; to the sum of the &lt;strong&gt;true positives&lt;/strong&gt; and &lt;strong&gt;false negatives&lt;/strong&gt;. It shows how often the classifier classifies an image of a sedan as a sedan.&lt;/p&gt;

&lt;p&gt;Therefore, the true positive rate can be calculated as:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;True Positive Rate&lt;/strong&gt; = &lt;strong&gt;d&lt;/strong&gt; / (&lt;strong&gt;c + d&lt;/strong&gt;)&lt;br&gt;
​ Where &lt;strong&gt;d&lt;/strong&gt; is &lt;strong&gt;TP&lt;/strong&gt; and &lt;strong&gt;c&lt;/strong&gt; is &lt;strong&gt;FN&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;True positive rate is also known as &lt;strong&gt;recall&lt;/strong&gt; or &lt;strong&gt;sensitivity&lt;/strong&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  False Positive Rate
&lt;/h5&gt;

&lt;p&gt;The false positive rate is a ratio of the &lt;strong&gt;false positives&lt;/strong&gt; to the sum of the &lt;strong&gt;true negatives&lt;/strong&gt; and &lt;strong&gt;false positives&lt;/strong&gt;. It shows how often the classifier classifies an image of a non-sedan as a sedan.&lt;/p&gt;

&lt;p&gt;Therefore, the false positive rate can be calculated as:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;False Positive Rate&lt;/strong&gt; = &lt;strong&gt;b&lt;/strong&gt; / (&lt;strong&gt;a + b&lt;/strong&gt;)&lt;br&gt;
​ Where &lt;strong&gt;a&lt;/strong&gt; is &lt;strong&gt;TN&lt;/strong&gt; and b is &lt;strong&gt;FP&lt;/strong&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  True Negative Rate
&lt;/h5&gt;

&lt;p&gt;The true negative rate is a ratio of the &lt;strong&gt;true negatives&lt;/strong&gt; to the sum of the &lt;strong&gt;true negatives&lt;/strong&gt; and &lt;strong&gt;false positives&lt;/strong&gt;. It shows how often the classifier classifies an image of a non-sedan as a non-sedan.&lt;/p&gt;

&lt;p&gt;Therefore, the false positive rate can be calculated as:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;True Negative Rate&lt;/strong&gt; = &lt;strong&gt;a&lt;/strong&gt; / (&lt;strong&gt;a + b&lt;/strong&gt;)&lt;br&gt;
​ Where &lt;strong&gt;a&lt;/strong&gt; is &lt;strong&gt;TN&lt;/strong&gt; and b is &lt;strong&gt;FP&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The true negative rate is also known as &lt;strong&gt;specificity&lt;/strong&gt;.&lt;/p&gt;

&lt;h5&gt;
  
  
  False Negative Rate
&lt;/h5&gt;

&lt;p&gt;The false negative rate is a ratio of the &lt;strong&gt;false negatives&lt;/strong&gt; to the sum of the &lt;strong&gt;false negatives&lt;/strong&gt; and &lt;strong&gt;true positives&lt;/strong&gt;. It shows how often the classifier classifies an image of a sedan as a non-sedan.&lt;/p&gt;

&lt;p&gt;Therefore, the false positive rate can be calculated as:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;False Negative Rate&lt;/strong&gt; = &lt;strong&gt;c&lt;/strong&gt; / (&lt;strong&gt;c + d&lt;/strong&gt;)&lt;br&gt;
​ Where &lt;strong&gt;d&lt;/strong&gt; is &lt;strong&gt;TP&lt;/strong&gt; and &lt;strong&gt;c&lt;/strong&gt; is &lt;strong&gt;FN&lt;/strong&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Precision
&lt;/h5&gt;

&lt;p&gt;The precision is a ratio of the &lt;strong&gt;true positives&lt;/strong&gt; to the sum of the &lt;strong&gt;true positives&lt;/strong&gt; and &lt;strong&gt;false positives&lt;/strong&gt;. It shows how often the classifier classifies an input image as a sedan and it turns out to be correct.&lt;/p&gt;

&lt;p&gt;It is calculated as:&lt;/p&gt;

&lt;p&gt;​ &lt;strong&gt;Precision&lt;/strong&gt; = &lt;strong&gt;d&lt;/strong&gt; / &lt;strong&gt;(b + d)&lt;/strong&gt;&lt;br&gt;
​ Where &lt;strong&gt;d&lt;/strong&gt; is &lt;strong&gt;TP&lt;/strong&gt; and &lt;strong&gt;b&lt;/strong&gt; is &lt;strong&gt;FP&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  An Example
&lt;/h3&gt;

&lt;p&gt;Suppose we have the image below as the confusion matrix for our classifier, we can use the metrics defined above to evaluate its performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F29erno9l9601wqb9zbqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F29erno9l9601wqb9zbqs.png" alt="sample"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the confusion matrix, we can see that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;4252 predictions were made that correctly classified a non-sedan [as a non-sedan].
Therefore, our variable &lt;strong&gt;a&lt;/strong&gt; and the &lt;strong&gt;True Negative (TN)&lt;/strong&gt; is 4252.&lt;/li&gt;
&lt;li&gt;875 predictions were made that incorrectly classified a non-sedan as a sedan.
Therefore, our variable &lt;strong&gt;b&lt;/strong&gt; and the &lt;strong&gt;False Positive (FP)&lt;/strong&gt; is 875.&lt;/li&gt;
&lt;li&gt;421 predictions were made that incorrectly classified a sedan as a non-sedan.
Therefore, our variable &lt;strong&gt;c&lt;/strong&gt; and the &lt;strong&gt;False Negative (FN)&lt;/strong&gt; is 421.&lt;/li&gt;
&lt;li&gt;4706 predictions were made that correctly classified a sedan [as a sedan].
Therefore, our variable &lt;strong&gt;d&lt;/strong&gt; and the &lt;strong&gt;True Positive (TP)&lt;/strong&gt; is 4706&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;​ Using the data we've "extracted", we can calculate the aforementioned metrics and ascertain the performance of the classifier. We can already tell that the classifier performs well since the number of correct predictions is greater than the number of incorrect predictions.&lt;/p&gt;

&lt;h5&gt;
  
  
  Accuracy
&lt;/h5&gt;

&lt;p&gt;​ Accuracy =  &lt;strong&gt;(a + d)&lt;/strong&gt; / &lt;strong&gt;(a + b + c + d)&lt;/strong&gt;&lt;br&gt;
​         = &lt;strong&gt;(4252 + 4706)&lt;/strong&gt; / &lt;strong&gt;(4252 + 875 + 421 + 4706)&lt;/strong&gt;&lt;br&gt;
​         = &lt;strong&gt;(8958)&lt;/strong&gt; / &lt;strong&gt;(10254)&lt;/strong&gt;&lt;br&gt;
​         = &lt;strong&gt;0.8736102984201287&lt;/strong&gt;&lt;br&gt;
​ Accuracy = &lt;strong&gt;0.87&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;​ Therefore the classifier has an accuracy of 0.87 which is 87%&lt;/p&gt;

&lt;h5&gt;
  
  
  True Positive Rate
&lt;/h5&gt;

&lt;p&gt;​ TPR = &lt;strong&gt;TP / (TP + FN)&lt;/strong&gt;&lt;br&gt;
​     = &lt;strong&gt;4706&lt;/strong&gt; / &lt;strong&gt;(4706 + 421)&lt;/strong&gt;&lt;br&gt;
​     = &lt;strong&gt;4706&lt;/strong&gt; / &lt;strong&gt;5127&lt;/strong&gt;&lt;br&gt;
​     = &lt;strong&gt;0.917885703140238&lt;/strong&gt;&lt;br&gt;
​ TPR = &lt;strong&gt;0.92&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;​ Therefore the classifier has a True Positive Rate of 0.92 which is 92%&lt;/p&gt;

&lt;h5&gt;
  
  
  False Positive Rate
&lt;/h5&gt;

&lt;p&gt;​ FPR = &lt;strong&gt;FP / (FP + TN)&lt;/strong&gt;&lt;br&gt;
​     = &lt;strong&gt;875&lt;/strong&gt; /  &lt;strong&gt;(875 + 4252)&lt;/strong&gt;&lt;br&gt;
​     = &lt;strong&gt;875&lt;/strong&gt; / &lt;strong&gt;5127&lt;/strong&gt;&lt;br&gt;
​     = &lt;strong&gt;0.1706651062999805&lt;/strong&gt;&lt;br&gt;
​ FPR = &lt;strong&gt;0.17&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;​ Therefore the classifier has a False Positive Rate of 0.17 which is 17%&lt;/p&gt;

&lt;h5&gt;
  
  
  True Negative Rate
&lt;/h5&gt;

&lt;p&gt;​ TNR = &lt;strong&gt;TN / (TN + FP)&lt;/strong&gt;&lt;br&gt;
​     = &lt;strong&gt;4252 / (4252 + 875)&lt;/strong&gt;&lt;br&gt;
​     = &lt;strong&gt;4252 / 5127&lt;/strong&gt;&lt;br&gt;
​     = &lt;strong&gt;0.8293348937000195&lt;/strong&gt;&lt;br&gt;
​ TNR = &lt;strong&gt;0.83&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;​ Therefore the classifier has a True Negative Rate of 0.83 which is 83%&lt;/p&gt;

&lt;h5&gt;
  
  
  False Negative Rate
&lt;/h5&gt;

&lt;p&gt;​ FNR = &lt;strong&gt;FN / (FN + TP)&lt;/strong&gt;&lt;br&gt;
​     = &lt;strong&gt;421 / (421 + 4706)&lt;/strong&gt;&lt;br&gt;
​     = &lt;strong&gt;421 / 5127&lt;/strong&gt;&lt;br&gt;
​     = &lt;strong&gt;0.082114296859762&lt;/strong&gt;&lt;br&gt;
​ FNR = &lt;strong&gt;0.08&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;​ Therefore the classifier has a False Negative Rate of 0.08 which is 8%&lt;/p&gt;

&lt;h5&gt;
  
  
  Precision
&lt;/h5&gt;

&lt;p&gt;​ Precision = &lt;strong&gt;TP / (TP + FP)&lt;/strong&gt;&lt;br&gt;
​          = &lt;strong&gt;4706 / (4706 + 875)&lt;/strong&gt;&lt;br&gt;
​          = &lt;strong&gt;4706 / 5581&lt;/strong&gt;&lt;br&gt;
​          = &lt;strong&gt;0.8293348937000195&lt;/strong&gt;&lt;br&gt;
​ Precision = &lt;strong&gt;0.83&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;​ Therefore the classifier has a Precision of 0.83 which is 83%&lt;/p&gt;

&lt;h3&gt;
  
  
  How to generate a confusion matrix using Python
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;matplotlib.pylab&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.metrics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;confusion_matrix&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plot_confusion_matrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interpolation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nearest&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Blues&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Confusion matrix&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;colorbar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;tick_marks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tick_marks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;yticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tick_marks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;cm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;float&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[:,&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;newaxis&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;thresh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;2.&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;itertools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])):&lt;/span&gt;
        &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                 &lt;span class="n"&gt;horizontalalignment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;center&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;white&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cm&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;thresh&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;black&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tight_layout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Actual&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Predicted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;dict_characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Non-sedan&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Sedan&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;y_pred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y_pred_classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;argmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_pred&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y_true&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;argmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_labels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;confusion_mat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;confusion_matrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_pred_classes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;plot_confusion_matrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;confusion_mat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dict_characters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To generate a confusion matrix, we utilize numpy, matplotlib.pylab to visualize the matrix, the confusion_matrix function from the sklearn.metrics package to generate the confusion matrix, and itertools for looping/iteration.&lt;/p&gt;

&lt;p&gt;First, we define a function &lt;strong&gt;plot_confusion_matrix&lt;/strong&gt; that takes the generated confusion matrix and expected/possible classes as arguments and the uses matplotlib.pylab to visualize the confusion matrix.&lt;/p&gt;

&lt;p&gt;In the snippet, we assume we have already have our trained model and training and test data with associated labels. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dict_characters&lt;/strong&gt; is a dictionary of the two possible classes, in our case, "&lt;strong&gt;non-sedan&lt;/strong&gt;" and "&lt;strong&gt;sedan&lt;/strong&gt;".&lt;br&gt;
&lt;strong&gt;y_pred&lt;/strong&gt; is a numpy array of predictions done by the classifier on the test data&lt;br&gt;
&lt;strong&gt;model&lt;/strong&gt; is our trained classifier/algorithm&lt;br&gt;
&lt;strong&gt;test_data&lt;/strong&gt; is our test data&lt;br&gt;
&lt;strong&gt;y_pred_classes&lt;/strong&gt; is a numpy array of indices relative to &lt;strong&gt;y_pred&lt;/strong&gt; which is the array of predictions done by the classifier on the test data.&lt;br&gt;
&lt;strong&gt;y_true&lt;/strong&gt; is a numpy array of indices relative to the actual/correct labels of the test_data.&lt;br&gt;
&lt;strong&gt;test_labels&lt;/strong&gt; is a list of labels of the test data.&lt;/p&gt;

&lt;p&gt;Using the above, we use the &lt;strong&gt;confusion_matrix&lt;/strong&gt; function from &lt;strong&gt;sklearn.metrics&lt;/strong&gt; to generate the confusion matrix, passing in the correct values (&lt;strong&gt;y_true&lt;/strong&gt;) and the estimated values returned by the classifier (&lt;strong&gt;y_pred_classes&lt;/strong&gt;) and we store the generated confusion matrix in a variable &lt;strong&gt;confusion_mat&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We then pass the confusion matrix (&lt;strong&gt;confusion_mat&lt;/strong&gt;) and a list of the values of our possible classes (&lt;strong&gt;dict_characters&lt;/strong&gt;) as arguments to the &lt;strong&gt;plot_confusion_matrix&lt;/strong&gt; function which then visualizes the confusion matrix.&lt;/p&gt;

&lt;p&gt;In my next post, I [hopefully] would be writing on the multi-class confusion matrix.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>python</category>
      <category>deeplearning</category>
    </item>
    <item>
      <title>A Quick Look at Constructable Stylesheets</title>
      <dc:creator>Banso D. Wisdom</dc:creator>
      <pubDate>Fri, 05 Apr 2019 21:29:37 +0000</pubDate>
      <link>https://forem.com/overrideveloper/a-first-look-at-constructable-stylesheets-3ae</link>
      <guid>https://forem.com/overrideveloper/a-first-look-at-constructable-stylesheets-3ae</guid>
      <description>&lt;p&gt;"Constructable Stylesheets". This might be the first time you're hearing of this and you must be thinking "what the flux is that?", and that's fine, that was my reaction when I first heard of it too.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Constructable Stylesheets?
&lt;/h2&gt;

&lt;p&gt;Simply put, Constructable Stylesheets are a way to create and distribute reusable styles when working with the &lt;strong&gt;Shadow DOM&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Shadow DOM?
&lt;/h2&gt;

&lt;p&gt;To understand how Constructable Stylesheets work, we need to understand what the Shadow DOM is and to do that we need to understand what the &lt;strong&gt;DOM&lt;/strong&gt; is.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;DOM&lt;/strong&gt; which stands for &lt;strong&gt;Document Object Model&lt;/strong&gt; is a representation of an HTML document, it is used in Javascript to modify a page's content and is also utilized by browsers to figure out what to render on a page.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Shadow DOM&lt;/strong&gt; is a DOM within "&lt;strong&gt;The DOM&lt;/strong&gt;". It is a completely separate DOM tree from "&lt;strong&gt;The DOM&lt;/strong&gt;" with its own elements and styling. It was created for the purpose of encapsulation and most applications of the Shadow DOM revolve around creating complex components/elements in such a way that the styling of these components/elements is unaffected by other style rules in "&lt;strong&gt;The DOM&lt;/strong&gt;".&lt;br&gt;
A good example of this is Ionic 4 UI components.&lt;/p&gt;

&lt;p&gt;To better understand how the DOM and Shadow DOM works, here is an article &lt;a href="https://bitsofco.de/what-is-the-shadow-dom" rel="noopener noreferrer"&gt;What is the Shadow DOM&lt;/a&gt; by Ire Aderinokun.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Constructable Stylesheets?
&lt;/h2&gt;

&lt;p&gt;"Why do we need a new way of creating stylesheets?" you might ask. I asked the same question too. As we all might know, we have always created/been able to create stylesheets on the fly using Javascript like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;style&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and obtain a reference to the underlying &lt;strong&gt;CssStyleSheet&lt;/strong&gt; instance by accessing the sheet property.&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fje6eikculjcae850blir.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fje6eikculjcae850blir.gif" alt="Accessing the sheet property"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This method works quite alright, but it has a few downsides, some of which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It can result in duplicate CSS code and thus cause CSS bloat.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  What is CSS Bloat?
&lt;/h5&gt;

&lt;p&gt;CSS bloat is unnecessarily repeated CSS code and while it directly doesn't affect your performance it indirectly affects your performance as having redundant selectors and rules increases your bundle size and makes your page heavier to load and slow to render.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It can lead to FOUC.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  What is FOUC?
&lt;/h5&gt;

&lt;p&gt;FOUC - Flash of Unstyled Content is a scenario where the content web page loads un-styled briefly then shortly after appears styled. This occurs when the browser renders the page before completely loading all the required assets.&lt;br&gt;
  FOUC can be caused by having duplicate CSS code (CSS bloat) which in turn causes a larger and heavier bundle which is slow to render.&lt;/p&gt;

&lt;p&gt;The aforementioned problems are easily solved by using Constructable Stylesheets.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use Constructable Stylesheets
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Creating a Stylesheet
&lt;/h4&gt;

&lt;p&gt;To create a stylesheet according to the Constructable Stylesheets specification, we do by invoking the CSSStyleSheet() constructor.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CSSStyleSheet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The resulting object, in this case, &lt;strong&gt;sheet&lt;/strong&gt; has two methods that we can use to add and update stylesheet rules without the risk of FOUC. These methods both take a single argument which is a string of style rules.&lt;/p&gt;

&lt;p&gt;These methods are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;replace(): This method allows the use of external references i.e. &lt;strong&gt;@import&lt;/strong&gt; in addition to CSS rules and it returns a promise that resolves once any imports are loaded.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

  &lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@import url("app.css"); p { color: #a1a1a1 }&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sheet&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Imports added and styles added&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error adding styles: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;replaceSync(): This method doesn't allow &lt;strong&gt;@import&lt;/strong&gt;, only CSS Rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

  &lt;span class="c1"&gt;// this works&lt;/span&gt;
  &lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p { color: #a1a1a1 }&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// this throws an exception&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@import url("app.css"); p { color: #a1a1a1 }&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Using a Constructed Stylesheet
&lt;/h4&gt;

&lt;p&gt;After creating a stylesheet, we'd like to use it, of course. We use created stylesheets by using the &lt;strong&gt;adoptedStyleSheets&lt;/strong&gt; property which Documents and Shadow DOMs possess.&lt;br&gt;
This property lets us explicitly apply the styles we have defined in our Constructed Stylesheet to a DOM subtree by setting the value of this &lt;strong&gt;adoptedStyleSheets&lt;/strong&gt;  property to an array of stylesheets. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// applying the earlier created stylesheet to a document&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;adoptedStyleSheets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// creating an element and applying stylesheet to its shadow root&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shadowRoot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;open&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;adoptedStyleSheets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can also create new stylesheets and add them to the adoptedStyleSheets property. &lt;br&gt;
Now normally, since the property is an array, using mutations like &lt;strong&gt;push()&lt;/strong&gt; would be the way to go. However, in this case, it's not so. &lt;/p&gt;

&lt;p&gt;This is because the adoptedStyleSheets property array is frozen and therefore in-place mutations like &lt;strong&gt;push()&lt;/strong&gt; won't work.&lt;/p&gt;

&lt;h5&gt;
  
  
  When is an array said to be frozen?
&lt;/h5&gt;

&lt;p&gt;A frozen array is an array which has been frozen as an object via the Object.freeze() method. The Object.freeze() method "freezes" an object which prevents new properties from being added to it, prevents the values of existing properties from being changed and also prevents the object's prototype from being changed.&lt;/p&gt;

&lt;h5&gt;
  
  
  What is an in-place mutation?
&lt;/h5&gt;

&lt;p&gt;The term "&lt;strong&gt;in-place&lt;/strong&gt;" is used to describe an algorithm that transforms the input given to it without using any additional data structure. While an algorithm that utilizes an additional data structure in transforming input is said to be &lt;strong&gt;out-of-place&lt;/strong&gt;/&lt;strong&gt;not-in-place&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Consider the following methods, both to reverse the order of an array:&lt;/p&gt;

&lt;p&gt;P.S: This is just for explanation purposes.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reverseOutOfPlace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reverseInPlace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;They both reverse the order of a given array, however, the &lt;strong&gt;reverseOutOfPlace&lt;/strong&gt; method uses an additional array &lt;strong&gt;output&lt;/strong&gt; to reverse the input while the &lt;strong&gt;reverseInPlace&lt;/strong&gt; method doesn't use any additional arrays, as such the former is &lt;strong&gt;out-of-place&lt;/strong&gt; while the latter is &lt;strong&gt;in-place&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Array [mutation] methods like &lt;strong&gt;pop&lt;/strong&gt; and &lt;strong&gt;push&lt;/strong&gt; are &lt;strong&gt;in-place&lt;/strong&gt; because they don't use any additional arrays while others like &lt;strong&gt;concat&lt;/strong&gt; and &lt;strong&gt;map&lt;/strong&gt; are &lt;strong&gt;out-of-place&lt;/strong&gt; because they use additional arrays in transforming the input array.&lt;/p&gt;

&lt;p&gt;Since the adoptedStyleSheets property array is frozen and the values of its properties cannot be changed, the best way to add new stylesheets to the array is using &lt;strong&gt;concat()&lt;/strong&gt; or the &lt;strong&gt;spread&lt;/strong&gt; operator&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newSheet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CSSStyleSheet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;br&gt;
&lt;span class="nx"&gt;newSheet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p { color: #eaeaea }&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c1"&gt;// using concat&lt;/span&gt;&lt;br&gt;
&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;adoptedStyleSheets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;adoptedStyleSheets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newSheet&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c1"&gt;// using the spread operator&lt;/span&gt;&lt;br&gt;
&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;adoptedStyleSheets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;adoptedStyleSheets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newSheet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  What can I do with Constructable Stylesheets&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Constructable Stylesheets has wide possibilities of usages, below are some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create shared CSS styles on the fly and apply them to the document or multiple Shadow roots without CSS bloat.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When a shared CSSStyleSheet has been applied to elements, any updates to it reflect on all the elements that it has been applied to. This can be used to implement hot replacement of styles within Shadow DOMs.&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcn58yq5mg1obby7brc2r.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcn58yq5mg1obby7brc2r.gif" alt="Hot replacement of styles"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Change CSS custom properties on the fly for specific DOM subtrees.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a central theme that is used by/applied to several components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As a direct interface to the browser's parser to preload stylesheets.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://codepen.io/Overrideveloper/pen/zXBqOG" rel="noopener noreferrer"&gt;Here is a pen&lt;/a&gt; I made that shows most of what is in this post.&lt;/p&gt;

&lt;p&gt;For more information on Constructable StyleSheets, check out these posts: &lt;a href="https://developers.google.com/web/updates/2019/02/constructable-stylesheets" rel="noopener noreferrer"&gt;Constructable Stylesheets: Seamless reusable styles&lt;/a&gt;  and &lt;a href="https://wicg.github.io/construct-stylesheets" rel="noopener noreferrer"&gt;Constructable Stylesheet Objects&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;P.S: At the time of writing this article, Constructable StyleSheets has only shipped to Chrome, so the aforementioned pen will work on only chromium-based browsers. &lt;/p&gt;

</description>
      <category>css</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Machine Learning at A Glance</title>
      <dc:creator>Banso D. Wisdom</dc:creator>
      <pubDate>Tue, 27 Nov 2018 09:51:50 +0000</pubDate>
      <link>https://forem.com/overrideveloper/machine-learning-at-a-glance-1108</link>
      <guid>https://forem.com/overrideveloper/machine-learning-at-a-glance-1108</guid>
      <description>&lt;p&gt;Hi there! It's been a while since I last wrote anything. I've been really busy, so it's been difficult to write.&lt;/p&gt;

&lt;p&gt;This article is one which I had drafted a while ago but I hadn't just gotten around to writing. It's "Machine Learning at a glance" and it aims to help demystify machine learning, make it as easy as possible to comprehend and serve as a beginner roadmap.&lt;/p&gt;

&lt;p&gt;This article outlines stuff from my talk on the same topic at the &lt;a href="https://ncdevfest.com" rel="noopener noreferrer"&gt;North-Central Devfest&lt;/a&gt;  of the Google Developer Group in Nigeria in 2017. I know, it's been a while since then, but this stuff is still relevant as I occasionally meet people who say they have interest in machine learning and artificial intelligence, but do not know how to go about it or what it entails. I hope this article helps provide some sort of insight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Artificial Intelligence
&lt;/h2&gt;

&lt;p&gt;Artificial intelligence (AI) has become a household term over the past couple of years, we see it been referred to and depicted in games, movies (remember J.A.R.V.I.S?) and in books, but what really is artificial intelligence?&lt;/p&gt;

&lt;p&gt;AI is simply intelligence exhibited by/in machines, these machines are called intelligent machines. An intelligent machine is any device(from small devices like our smartphones to larger devices like TVs) that perceives its environment and takes action that maximizes it chances at success at some goal.&lt;/p&gt;

&lt;p&gt;Simply put, an intelligent machine is a device that studies its environment, learns from it and adapts to changes in the environment by adjusting its actions in order to better perform specific tasks; tasks it was designed to accomplish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applications of Artificial Intelligence
&lt;/h2&gt;

&lt;p&gt;We've all seen artificial intelligence been depicted in movies, games and books, but there are also real-world applications of artificial intelligence, some of which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finance&lt;/li&gt;
&lt;li&gt;Health care/Medicine&lt;/li&gt;
&lt;li&gt;Customer service/Chatbots&lt;/li&gt;
&lt;li&gt;Education&lt;/li&gt;
&lt;li&gt;Transportation&lt;/li&gt;
&lt;li&gt;Technology&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI of the past were limited to a few functions like error-reporting and all that basic stuff. AI of the near future is projected to be able to do much more complex stuff, and we are already seeing some of that in the present. &lt;br&gt;
The question is "How do we develop AI to such a level? How do we build intelligent machines capable of complex stuff", the answer is machine learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Machine Learning
&lt;/h2&gt;

&lt;p&gt;Compared to AI, the term "Machine learning" might not be so common or it might be, but most people don't have even the faintest idea of what it's about.&lt;/p&gt;

&lt;p&gt;Machine learning (ML) is an approach to achieving Artificial Intelligence. That being said, we can say the goal is to develop intelligent machines and that machine learning is a way of achieving that goal.&lt;br&gt;
ML deals with developing systems that learn without being explicitly told what to do, similar to how humans learn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traditional Programming vs Machine Learning
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Traditional Programming
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwr0i7h1zc3c95k4lgto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqwr0i7h1zc3c95k4lgto.png" alt="Traditional Programming" width="441" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In traditional programming, we provide the rules and data as input and the algorithm provides us answers as output. Let me show a quick example, using simple interest.&lt;/p&gt;

&lt;p&gt;We all know simple interest from math, yeah? And when starting out with programming, after writing the usually "hello world" program, simple arithmetic programs are usually the next thing to do; so this example should be straightforward.&lt;/p&gt;

&lt;p&gt;Now, the formula for simple interest is &lt;strong&gt;(PRT)/100&lt;/strong&gt;. Using the diagram above, we can analyse a program that calculates simple interest thus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data: The data provided as input would be the variables &lt;strong&gt;P&lt;/strong&gt;, &lt;strong&gt;R&lt;/strong&gt; and &lt;strong&gt;T&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Rules: The rules would be the formula &lt;strong&gt;SI = (PRT)/100&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Answer: And the answer would be the variable &lt;strong&gt;SI&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is basically how traditional programming works.&lt;/p&gt;

&lt;h4&gt;
  
  
  Machine Learning
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe69pcxld6kzlf7dwmr30.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe69pcxld6kzlf7dwmr30.png" alt="Machine Learning" width="439" height="208"&gt;&lt;/a&gt;&lt;br&gt;
In machine learning, it's way different from traditional programming. Here, we provide the data and expected answers as input and the algorithm generates rules as output.&lt;br&gt;
An example is a machine learning system that differentiates between real and counterfeit bank notes. Using the diagram above, we can analyse such a system thus:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data: The data provided as input would be several thousand images of both counterfeit and real banknotes.&lt;/li&gt;
&lt;li&gt;Answer: The answers provided as input would be labels on these images which specify whether or not a particular image is that of a real or a counterfeit banknote.&lt;/li&gt;
&lt;li&gt;Rules: The rules would then be generated by the machine learning algorithm, these rules are more or less the algorithms understanding of how it can differentiate real banknotes from the counterfeit notes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why should we care about Machine Learning?
&lt;/h2&gt;

&lt;p&gt;I often get asked questions like "Why should I care about machine learning? Why is it suddenly important? Why now?",&lt;br&gt;
Here are a following reasons why we should care about machine learning and why it's "suddenly" important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data availability: There is a lot of data being generated right now, A LOT(big data sound familiar?). This data is generated by our smart devices, embedded systems and several other sources. There is so much data now than ever before and this data can be analysed to discover patterns, trends and associations that can be used to make intelligent decisions, so why don't we do that?&lt;/li&gt;
&lt;li&gt;Computing power: Current hardware have enough computing power to analyse data. We have PCs with crazy hardware, we have phones with more computing power than the computers that took man to the moon. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Between the large amount of data and devices with sufficient computing power to analyse them, I believe there is no better time to care about machine learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  The machine learning process
&lt;/h2&gt;

&lt;p&gt;The machine learning process can be defined as a sequence of steps which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data collection&lt;/strong&gt;: This involves sourcing of data to be used as input. Data could be in different formats: XML, JSON, CSV, text files, images, etc and can be gotten from various sources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data preparation&lt;/strong&gt;: This involves analyzing and filtering data based on the requirements of the machine learning system to be developed and removing poor, bad and unnecessary data. This also involves splitting the prepared data into training and test sets, the training set will be used to train the algorithm and the test set will be used for validation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Training&lt;/strong&gt;: This is the part of the machine learning process where the algorithm is trained using the training set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluation&lt;/strong&gt;: After training, the trained model evaluated using the test set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimization&lt;/strong&gt;: Based on the results of the evaluation, the model can be optimized to reduce margin of error and increase efficiency. Optimization might involve tweaking a few things in the algorithm, introducing a new variable to increase efficiency or changing the entire model/algorithm completely.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Machine learning algorithms
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7m5yufkhfchqza6npux.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7m5yufkhfchqza6npux.png" alt="Machine Learning Algos" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
There are three major classes of machine learning algorithms, they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supervised Learning.&lt;/li&gt;
&lt;li&gt;Unsupervised Learning.&lt;/li&gt;
&lt;li&gt;Reinforcement Learning.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Supervised Learning
&lt;/h4&gt;

&lt;p&gt;Supervised Learning is a class of machine learning algorithms that are used to build predictive models. They are "predictive models" because their aim is to predict future outcome based on historic data. &lt;br&gt;
In Supervised Learning, &lt;strong&gt;the desired output is already known&lt;/strong&gt; and as such data is labelled and the machine learning models are given clear instructions on what they are to learn and how they are how to learn it.&lt;/p&gt;

&lt;p&gt;There are two main tasks/problems in supervised learning, they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Classification&lt;/strong&gt;: This is a machine learning task/problem that deals with classifying items into categories. For example, real and counterfeit banknotes, cats and dogs, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regression&lt;/strong&gt;: This is a machine learning task/problem that deals with predicting real values such as weight, money, etc. For example, predicting the price of fuel in 2023, predicting the cost of a 30-inch pizza(a 30-inch pizza would be such a sight!), predicting the amount of rainfall in 2020, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://dev.to/overrideveloper/an-intro-to-supervised-learning-the-good-the-bad-and-the-ugly-1oo"&gt;See here to read a little more on Supervised Learning&lt;/a&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  Unsupervised Learning
&lt;/h4&gt;

&lt;p&gt;Unsupervised Learning is a class of machine learning algorithms that are used to build descriptive models. They are "descriptive models" because their aim is to determine and define structure and similarities from unstructured and unlabelled data.&lt;br&gt;
In Unsupervised Learning, &lt;strong&gt;the desired output is not known&lt;/strong&gt; and as such data is unlabelled and models are not told how to learn, but must do so entirely on their own.&lt;/p&gt;

&lt;p&gt;The major task in unsupervised learning is &lt;strong&gt;Clustering&lt;/strong&gt;; a machine learning task/problem that deals with determining structure in unlabelled data.&lt;/p&gt;

&lt;h4&gt;
  
  
  Reinforcement Learning
&lt;/h4&gt;

&lt;p&gt;Reinforcement Learning is a class of machine learning algorithms that are used to build models that use &lt;em&gt;trial and error&lt;/em&gt; to determine which actions yield the greatest rewards. The aim of these models and reinforcement learning is to maximize rewards.&lt;br&gt;
Reinforcement learning models are mostly used but not restricted to robotics, gaming and navigation.&lt;/p&gt;

&lt;p&gt;Other machine learning algorithms include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Semi-supervised learning&lt;/strong&gt;: This uses a small amount of labelled data and a large amount of unlabelled data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active learning&lt;/strong&gt;: Here, the model interactively queries the user to obtain new knowledge.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources to get you started with Machine Learning
&lt;/h2&gt;

&lt;p&gt;Here are a few resources to get you started with machine learning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google's Machine Learning Crash Course: Google, being one of the big players in machine learning has a &lt;a href="https://developers.google.com/machine-learning/crash-course/" rel="noopener noreferrer"&gt;machine learning crash course&lt;/a&gt; designed to teach the basics of machine learning.&lt;/li&gt;
&lt;li&gt;Udacity Machine Learning Nanodegree: Udacity offers an in-depth &lt;a href="https://www.udacity.com/course/machine-learning-engineer-nanodegree--nd009t" rel="noopener noreferrer"&gt;machine learning nanodegree&lt;/a&gt; which takes you through machine learning fundamentals and principles via projects.&lt;/li&gt;
&lt;li&gt;Kaggle: &lt;a href="https://www.kaggle.com" rel="noopener noreferrer"&gt;Kaggle&lt;/a&gt; is one of the largest communities of data scientists and machine learning engineers and enthusiasts. It provides you access to a lot of datasets and the opportunity to explore and build models, learn and also participate in machine learning and data science competitions.&lt;/li&gt;
&lt;li&gt;scikit-learn: &lt;a href="https://scikit-learn.org/stable/" rel="noopener noreferrer"&gt;sci-kit learn&lt;/a&gt; is an open source machine library in Python. It provides simple and accessible tools for data analysis and building machine learning models. It has an easy learning and I recommend using it for beginner-level stuff.&lt;/li&gt;
&lt;li&gt;Zindi: Zindi is an African community of data scientists and machine learning engineers and enthusiasts. Zindi provides access to data sets sourced from Africa as well as the opportunity to participate in data science competitions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now is the time to get involved in machine learning and I hope this gives an insightful overview of what machine learning is and helps you get started. Good luck, and keep on learning!&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>ai</category>
      <category>stem</category>
    </item>
    <item>
      <title>An Intro. To Supervised Learning: The Good, The Bad and The Ugly</title>
      <dc:creator>Banso D. Wisdom</dc:creator>
      <pubDate>Sun, 01 Oct 2017 00:38:25 +0000</pubDate>
      <link>https://forem.com/overrideveloper/an-intro-to-supervised-learning-the-good-the-bad-and-the-ugly-1oo</link>
      <guid>https://forem.com/overrideveloper/an-intro-to-supervised-learning-the-good-the-bad-and-the-ugly-1oo</guid>
      <description>&lt;p&gt;Hey there. How goes it? In this article, I'll be talking about &lt;strong&gt;Supervised Learning&lt;/strong&gt;, its merits and demerits. Supervised learning is a class of learning algorithms, which is under &lt;strong&gt;Machine Learning&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Surely, in this day and age almost everybody has heard of and applies Machine Learning.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is machine learning?
&lt;/h3&gt;

&lt;p&gt;Machine learning, just as the name implies is when a machine/computer program learns. When then can we say a computer program learns? Just as humans learn from experience with a particular task, so do computer programs learn.&lt;br&gt;
Computer programs are said to learn from experience with respect to a set of tasks while their performance at said tasks is measured if their performance improves with experience. Simply put: computer programs are said to learn if they get better at a particular task with time.&lt;/p&gt;

&lt;h3&gt;
  
  
  So, where can  we see Machine Learning in action?
&lt;/h3&gt;

&lt;p&gt;Machine learning is applied in several instances, some of these are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spam checkers.&lt;/li&gt;
&lt;li&gt;News categorization on news sites.&lt;/li&gt;
&lt;li&gt;E-Chess&lt;/li&gt;
&lt;li&gt;Youtube (Playlist generation based on currently playing content).&lt;/li&gt;
&lt;li&gt;E-commerce sites (Suggestion of similar items). &lt;/li&gt;
&lt;li&gt;.. and many more examples.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Learning Algorithms
&lt;/h3&gt;

&lt;p&gt;There are three basic types of learning algorithms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supervised learning.&lt;/li&gt;
&lt;li&gt;Unsupervised learning.&lt;/li&gt;
&lt;li&gt;Semi-supervised learning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Learning algorithms differ mainly by the the training.&lt;br&gt;
For this article we'll be focusing on &lt;strong&gt;Supervised learning&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supervised Learning
&lt;/h3&gt;

&lt;p&gt;In supervised learning, the training data consists of a set of input data and correct responses (labels) to each data set. The aim here is for the algorithm to generalize such as to respond correctly to every possible input. Simply put: the algorithm should be able to give correct output to inputs not included in the training data. There are two main "problems" in Supervised learning: &lt;strong&gt;Classification&lt;/strong&gt; and &lt;strong&gt;Regression&lt;/strong&gt; problems.&lt;/p&gt;

&lt;h4&gt;
  
  
  Classification Problem
&lt;/h4&gt;

&lt;p&gt;What this entails is taking the input data and deciding which class/category the input data belongs to based on the training data. This deals with instances when the expected output is a category, e.g red, blue, e.t.c.&lt;br&gt;
For example: an algorithm that sorts vehicles by colour or by type.&lt;/p&gt;

&lt;h4&gt;
  
  
  Regression Problem
&lt;/h4&gt;

&lt;p&gt;Regression deals with estimating/approximating the relationship between variables. It is used in instances when the expected output is a real value e.g. weight, currency, e.t.c&lt;br&gt;
For example: an algorithm that determines/predicts the power consumption in a particular year for a particular region.&lt;/p&gt;

&lt;p&gt;Now that we've gone through the basics, let's see the merits and demerits.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Good
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;There is greater control over the system in supervised learning. For  example, you can define how many classes you want to have in the system, you can define the classes in a specific way, you can also train the classifier in a way it distinguishes classes accurately.&lt;/li&gt;
&lt;li&gt;After training there's necessarily no need to keep training data in memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Bad and The Ugly
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Training is time-consuming as it requires a lot of computation time. Classification is also time-consuming as well as tedious.&lt;/li&gt;
&lt;li&gt;If you use examples which were not covered by the training data, you might not get a correct output(label).&lt;/li&gt;
&lt;li&gt;It's limited in terms of scalability.&lt;/li&gt;
&lt;li&gt;It requires a great deal of computational cost to get a near perfect system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this has been helpful. Thanks for reading. You can reach me on Twitter &lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/overrideveloper"&gt;@overrideveloper&lt;/a&gt;
&lt;/strong&gt;. Cheers!&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>supervisedlearning</category>
      <category>ai</category>
    </item>
    <item>
      <title>Securing Your ASP.NET Application</title>
      <dc:creator>Banso D. Wisdom</dc:creator>
      <pubDate>Sat, 16 Sep 2017 23:53:17 +0000</pubDate>
      <link>https://forem.com/overrideveloper/securing-your-aspnet-application</link>
      <guid>https://forem.com/overrideveloper/securing-your-aspnet-application</guid>
      <description>&lt;h3&gt;
  
  
  Security is a pretty important topic in software development. When developing software it is easier to leave your application insecure and open to attacks than to take security measures. Sometimes, I am guilty of slacking off when it comes to security. ðŸ˜…ðŸ˜…
&lt;/h3&gt;

&lt;p&gt;In this article, I'll be using the ASP.NET MVC template as the talking point. The MVC template is very weak/vulnerable, security-wise. One can say the template favors simplicity over security.&lt;/p&gt;

&lt;h3&gt;
  
  
  Here are a couple of tips on how to secure your ASP.NET MVC application
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Hash passwords
&lt;/h4&gt;

&lt;p&gt;I know this is sort of an obvious practice in software development. However, I still feel the need to mention it. Hashing passwords is a very crucial part of authentication, but quite an easy one to forget, especially if you're writing your own custom authentication code.&lt;/p&gt;

&lt;p&gt;Also, choice of hashing algorithm is important. NEVER use MD5 to hash passwords, MD5 is super-easy to crack.ðŸ˜’ðŸ˜’ &lt;/p&gt;

&lt;h4&gt;
  
  
  2. Use strong password validation logic
&lt;/h4&gt;

&lt;p&gt;Try to make your password validation as 'strong' as possible. Below is my personal favourite when it comes to password validation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UserManager.PasswordValidator = new PasswordValidator
{
    RequiredLength = 6,
    RequireNonLetterOrDigit = true,
    RequireDigit = true,
    RequireLowercase = true,
    RequireUppercase = true,
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Brief authentication error messages
&lt;/h4&gt;

&lt;p&gt;Make your authentication error messages as short as possible. For example, on login failure, your error message should read "username/password invalid" rather than specify which is invalid, because that'd give enough information to a potential hacker.&lt;/p&gt;

&lt;p&gt;Also, in password reset, if the entered email doesn't exist in the system, rather than return an error message, display a success page.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Turn on custom errors
&lt;/h4&gt;

&lt;p&gt;By default the template shows full stack trace of exceptions whenever an error occurs. This is very sensitive information that should be hidden. This can be done from the web.config file by adding the custom errors tag and setting its mode to on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;system.web&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;customErrors&lt;/span&gt; &lt;span class="na"&gt;mode=&lt;/span&gt;&lt;span class="s"&gt;"On"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/customErrors&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/system.web&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Secure your cookies!
&lt;/h4&gt;

&lt;p&gt;By default, the template's cookies can be accessed by JavaScript from other sites. These cookies can also be sent unencrypted over the wire. This can be fixed by adding the httpcookies tag to the web.config file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;system.web&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;httpCookies&lt;/span&gt; &lt;span class="na"&gt;httpOnlyCookies=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;requireSSL=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/system.web&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using SSL on your site, then requireSSL should be set to true.&lt;/p&gt;

&lt;h4&gt;
  
  
  6. Get rid of needless headers!
&lt;/h4&gt;

&lt;p&gt;By default the template sends a couple of HTTP headers with every request. These headers contain sensitive information such as the server type, ASP.NET version and MVC version. We can fix this by setting enableVersionHeader setting to false.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;system.web&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;httpRuntime&lt;/span&gt; &lt;span class="na"&gt;targetFramework=&lt;/span&gt;&lt;span class="s"&gt;"4.5.2"&lt;/span&gt; &lt;span class="na"&gt;enableVersionHeader=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/system.web&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After doing this, we clear custom headers&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;system.webServer&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;httpProtocol&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;customHeaders&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;clear&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/customHeaders&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/httpProtocol&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/system.webServer&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  7. Rename your cookies.
&lt;/h4&gt;

&lt;p&gt;In the MVC template, there are three basic cookies: the Application cookie, the Antiforgery Token and the Session cookie. We should rename these cookies to make the type of server we're using unknown to the user.&lt;/p&gt;

&lt;h6&gt;
  
  
  Renaming the session cookie
&lt;/h6&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;system.web&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;sessionState&lt;/span&gt; &lt;span class="na"&gt;cookieName=&lt;/span&gt;&lt;span class="s"&gt;"custom_name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/system.web&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  Renaming the Antiforgery token
&lt;/h6&gt;

&lt;p&gt;This is done in the Global.asax.cs file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            //added line
            ConfigureAntiForgeryTokens();
            //end of added line
        }
//added method
private static void ConfigureAntiForgeryTokens()
{
    AntiForgeryConfig.CookieName = "custom_name";

    // AntiForgeryConfig.RequireSsl = true;
}
//end of added method
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your site will use Ssl, uncomment the last line.&lt;/p&gt;

&lt;h6&gt;
  
  
  Renaming the Application cookie
&lt;/h6&gt;

&lt;p&gt;This is done in the Startup.Auth.cs file of the App_Start folder&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void ConfigureAuth(IAppBuilder app)
{
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        CookieName = "custom_name"
    });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  8. Disable tracing
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;system.web&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;trace&lt;/span&gt; &lt;span class="na"&gt;enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;localOnly=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/system.web&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  9. Display 403 - Forbidden response as a 404
&lt;/h4&gt;

&lt;p&gt;When you navigate to a directory in IIS and ASP.NET MVC, it causes a 403 - Forbidden response to be returned. This basically means that directory browsing is disabled. Directory browsing is a security risk, as it grants access to the web.config file with all your connection strings.&lt;br&gt;
When directory browsing returns a 403, it poses a problem as it tells a potential attacker that you're using IIS and there actually is a folder there.&lt;br&gt;
We fix this by replacing the 403 response with the standard 404.&lt;/p&gt;

&lt;p&gt;First we add httpErrors to the web.config file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;system.webServer&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Custom error pages --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;httpErrors&lt;/span&gt; &lt;span class="na"&gt;errorMode=&lt;/span&gt;&lt;span class="s"&gt;"Custom"&lt;/span&gt; &lt;span class="na"&gt;existingResponse=&lt;/span&gt;&lt;span class="s"&gt;"Replace"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Redirect IIS 403 Forbidden responses to the not found action method on error controller --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;error&lt;/span&gt; &lt;span class="na"&gt;statusCode=&lt;/span&gt;&lt;span class="s"&gt;"403"&lt;/span&gt; &lt;span class="na"&gt;subStatusCode=&lt;/span&gt;&lt;span class="s"&gt;"14"&lt;/span&gt; &lt;span class="na"&gt;responseMode=&lt;/span&gt;&lt;span class="s"&gt;"ExecuteURL"&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"/error/notfound"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/httpErrors&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/system.webServer&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we turn off IIS' default document handling. This stops IIS from returning the default document (Using whats called a courtesy redirect) when navigating to a folder e.g. navigating to â€˜/Folder’ which contains an index.html file will not return â€˜/Folder/index.html’. If it redirects to the default document, in the page url, it displays the directory's path to potential attackers and we wouldn't want that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;system.webServer&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;defaultDocument&lt;/span&gt; &lt;span class="na"&gt;enabled=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/system.webServer&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the few tips above, you can make your ASP.NET Application more secure.ðŸ˜ Thanks for reading! ðŸ˜„ðŸ™‚&lt;/p&gt;

</description>
      <category>aspnet</category>
      <category>csharp</category>
      <category>security</category>
    </item>
    <item>
      <title>CORS in ASP.Net Web API </title>
      <dc:creator>Banso D. Wisdom</dc:creator>
      <pubDate>Tue, 29 Aug 2017 14:08:16 +0000</pubDate>
      <link>https://forem.com/overrideveloper/cors-in-aspnet-web-api</link>
      <guid>https://forem.com/overrideveloper/cors-in-aspnet-web-api</guid>
      <description>

&lt;h3&gt;
  
  
  What's a cross-origin http request?
&lt;/h3&gt;

&lt;p&gt;This is a request made by a resource to a resource in a different domain, protocol, port to its own. For example, an HTML page at "&lt;a href="http://domain1.com"&gt;http://domain1.com&lt;/a&gt;" makes a request to a resource at "&lt;a href="http://domain2.com"&gt;http://domain2.com&lt;/a&gt;".&lt;/p&gt;

&lt;h3&gt;
  
  
  Why are we talking about this?
&lt;/h3&gt;

&lt;p&gt;Well, this is sort of a 'big deal' because for security purposes, browsers restrict cross-origin requests intitiated from within scripts. So web apps can only make requests within it's domain. Kind of limits the apps, don't you think? This is where CORS comes in.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is CORS?
&lt;/h3&gt;

&lt;p&gt;CORS stands for Cross-Origin Resource Sharing. It is a standard that works by adding HTTP headers that allow servers to describe the set of origins that are permitted to read information using a web browser and the kind of request that are allowed.&lt;/p&gt;

&lt;p&gt;Also, for HTTP request methods that can cause side-effects on server's data (usually HTTP requests other than GET), the specification mandates that browsers "preflight" the request i.e asking the server what methods are supported. It does this with an HTTP OPTIONS request method, and then, upon "approval" from the server, it send the actual HTTP request.&lt;/p&gt;

&lt;h3&gt;
  
  
  CORS in ASP.NET WEB API 2
&lt;/h3&gt;

&lt;p&gt;In this article, I'll be showing how to enable CORS on an ASP.NET WEB API server.&lt;br&gt;
For this article, I assume you already have a Web API project created.&lt;/p&gt;

&lt;p&gt;Enabling CORS can be done in a couple of ways, which are as follows:&lt;/p&gt;

&lt;h4&gt;
  
  
  Enabling CORS per controller.
&lt;/h4&gt;

&lt;p&gt;First, install the CORS package. In the Package Manager Console, type the following command: &lt;code&gt;Install-Package Microsoft.AspNet.WebApi.Cors&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Navigate to the App_Start folder and open the WebApiConfig.cs file. Modify the WebApiConfig.Register to reflect the following changes: &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System.Web.Http;
namespace CORSWithWebAPI
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Modification
            config.EnableCors();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, add the [EnableCors] attribute to the Controller class specifying origin, headers and methods. If you set [EnableCors] on the controller class, it applies to all the actions on the controller. To disable CORS for an action, add the [DisableCors] attribute to the action.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;

namespace CORSWithWebAPI.Controllers
{
    [EnableCors(origins: "http://client.domain", headers: "*", methods: "*")]
    public class SampleController : ApiController
    {
         public HttpResponseMessage Post() { ... }

        [DisableCors]
        public HttpResponseMessage PutItem(int id) { ... }   
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Setting the methods and headers to "*" means all headers are allowed and all methods are allowed. Specific methods and headers can also be set.&lt;/p&gt;

&lt;h4&gt;
  
  
  Enabling CORS per Action
&lt;/h4&gt;

&lt;p&gt;This is similar to enabling per controller. Except that the [EnableCors] attribute is added to actions and not the controller.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class SampleController : ApiController
{
    [EnableCors(origins: "http://client.domain", headers: "*", methods: "*")]
    public HttpResponseMessage GetSample(int id) { ... }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Enabling CORS Globally
&lt;/h4&gt;

&lt;p&gt;To enable CORS for all Web API controllers, pass an EnableCorsAttribute instance to the EnableCors method in the WebApiConfig.cs file.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var cors = new EnableCorsAttribute("client.domain", "*", "*");
        config.EnableCors(cors);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  CORS can also be enabled from the Web.Config file of the project
&lt;/h3&gt;

&lt;p&gt;In the web.config file. Under the &lt;code&gt;&amp;lt;system.webserver&amp;gt;&amp;lt;/system.webserver&amp;gt;&lt;/code&gt; section. Add the following changes:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;system.webServer&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;handlers&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;remove&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"ExtensionlessUrlHandler-Integrated-4.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;remove&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"OPTIONSVerbHandler"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;remove&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"TRACEVerbHandler"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"ExtensionlessUrlHandler-Integrated-4.0"&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"*."&lt;/span&gt; &lt;span class="na"&gt;verb=&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"System.Web.Handlers.TransferRequestHandler"&lt;/span&gt; &lt;span class="na"&gt;preCondition=&lt;/span&gt;&lt;span class="s"&gt;"integratedMode,runtimeVersionv4.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/handlers&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- New addition --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;httpProtocol&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;customHeaders&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Access-Control-Allow-Origin"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Access-Control-Allow-Credentials"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Access-Control-Allow-Headers"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Access-Control-Allow-Methods"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"GET, POST, PUT, DELETE, OPTIONS"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/customHeaders&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/httpProtocol&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- End of new addition --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/system.webServer&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This sets CORS globally for all controllers in your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preflight request errors
&lt;/h3&gt;

&lt;p&gt;I explained earlier what a preflight request is. In Web API, when making a preflight request from a script, more often than not, the preflight request returns a Http Error Code 405 even though everything is set right. This can be fixed by a little modification to the web.config and the Global.asax files.&lt;/p&gt;

&lt;p&gt;In the web.config file:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;system.webServer&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;handlers&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;remove&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"ExtensionlessUrlHandler-Integrated-4.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;remove&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"OPTIONSVerbHandler"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;remove&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"TRACEVerbHandler"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"ExtensionlessUrlHandler-Integrated-4.0"&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"*."&lt;/span&gt; &lt;span class="na"&gt;verb=&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"System.Web.Handlers.TransferRequestHandler"&lt;/span&gt; &lt;span class="na"&gt;preCondition=&lt;/span&gt;&lt;span class="s"&gt;"integratedMode,runtimeVersionv4.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- New addition --&amp;gt;&lt;/span&gt;      
      &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"OPTIONSVerbHandler"&lt;/span&gt; &lt;span class="na"&gt;path=&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="na"&gt;verb=&lt;/span&gt;&lt;span class="s"&gt;"OPTIONS"&lt;/span&gt; &lt;span class="na"&gt;modules=&lt;/span&gt;&lt;span class="s"&gt;"ProtocolSupportModule"&lt;/span&gt; &lt;span class="na"&gt;requireAccess=&lt;/span&gt;&lt;span class="s"&gt;"None"&lt;/span&gt; &lt;span class="na"&gt;responseBufferLimit=&lt;/span&gt;&lt;span class="s"&gt;"4194304"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  
      &lt;span class="c"&gt;&amp;lt;!-- End of new addition --&amp;gt;&lt;/span&gt;  
    &lt;span class="nt"&gt;&amp;lt;/handlers&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;httpProtocol&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;customHeaders&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Access-Control-Allow-Origin"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Access-Control-Allow-Credentials"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Access-Control-Allow-Headers"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;add&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Access-Control-Allow-Methods"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"GET, POST, PUT, DELETE, OPTIONS"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/customHeaders&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/httpProtocol&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/system.webServer&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And in the Global.asax file:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

        //Added code
        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                HttpContext.Current.Response.Flush();
            }
        }
        //end of added code
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I hope this helps you enable CORS easily on your Web API project. Cheers!&lt;/p&gt;


</description>
      <category>aspnet</category>
      <category>cors</category>
      <category>api</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Hi, I'm Banso D. Wisdom</title>
      <dc:creator>Banso D. Wisdom</dc:creator>
      <pubDate>Thu, 06 Jul 2017 12:36:27 +0000</pubDate>
      <link>https://forem.com/overrideveloper/hi-im-banso-d-wisdom</link>
      <guid>https://forem.com/overrideveloper/hi-im-banso-d-wisdom</guid>
      <description>&lt;p&gt;I have been coding for [1.5] years.&lt;/p&gt;

&lt;p&gt;You can find me on GitHub as &lt;a href="https://github.com/Overrideveloper" rel="noopener noreferrer"&gt;Overrideveloper&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I live in [Abuja, Nigeria].&lt;/p&gt;

&lt;p&gt;I work for [BizzDesk Global Solutions, Nigeria]&lt;/p&gt;

&lt;p&gt;I mostly program in these languages: [C# and Angular.JS].&lt;/p&gt;

&lt;p&gt;I am currently learning more about [Python and Django].&lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
